2 struct entities
: icliententities
6 vector
<extentity
*> ents
;
8 entities(fpsclient
&_cl
) : cl(_cl
)
12 vector
<extentity
*> &getents() { return ents
; }
14 const char *itemname(int i
)
16 int t
= ents
[i
]->type
;
17 if(t
<I_SHELLS
|| t
>I_QUAD
) return NULL
;
18 return itemstats
[t
-I_SHELLS
].name
;
21 const char *entmdlname(int type
)
23 static const char *entmdlnames
[] =
25 NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
,
26 "ammo/shells", "ammo/bullets", "ammo/rockets", "ammo/rrounds", "ammo/grenades", "ammo/cartridges",
27 "health", "boost", "armor/green", "armor/yellow", "quad", "teleporter",
35 return entmdlnames
[type
];
38 void preloadentities()
42 const char *mdl
= entmdlname(i
);
44 loadmodel(mdl
, -1, true);
48 void renderent(extentity
&e
, int type
, float z
, float yaw
, int anim
= ANIM_MAPMODEL
|ANIM_LOOP
, int basetime
= 0, float speed
= 10.0f
)
50 const char *mdlname
= entmdlname(type
);
52 rendermodel(e
.color
, e
.dir
, mdlname
, anim
, 0, 0, vec(e
.o
).add(vec(0, 0, z
)), yaw
, 0, speed
, basetime
, NULL
, MDL_SHADOW
| MDL_CULL_VFC
| MDL_CULL_DIST
| MDL_CULL_OCCLUDED
);
59 extentity
&e
= *ents
[i
];
60 if(e
.type
==CARROT
|| e
.type
==RESPAWNPOINT
)
62 renderent(e
, e
.type
, (float)(1+sin(cl
.lastmillis
/100.0+e
.o
.x
+e
.o
.y
)/20), cl
.lastmillis
/(e
.attr2
? 1.0f
: 10.0f
));
65 if(!e
.spawned
&& e
.type
!=TELEPORT
) continue;
66 if(e
.type
<I_SHELLS
|| e
.type
>TELEPORT
) continue;
67 renderent(e
, e
.type
, (float)(1+sin(cl
.lastmillis
/100.0+e
.o
.x
+e
.o
.y
)/20), cl
.lastmillis
/10.0f
);
71 void rumble(const extentity
&e
)
73 playsound(S_RUMBLE
, &e
.o
);
76 void trigger(extentity
&e
)
86 void addammo(int type
, int &v
, bool local
= true)
88 itemstat
&is
= itemstats
[type
-I_SHELLS
];
90 if(v
>is
.max
) v
= is
.max
;
91 if(local
) cl
.playsoundc(is
.sound
);
94 void repammo(fpsent
*d
, int type
)
96 addammo(type
, d
->ammo
[type
-I_SHELLS
+GUN_SG
]);
99 // these two functions are called when the server acknowledges that you really
100 // picked up the item (in multiplayer someone may grab it before you).
102 void pickupeffects(int n
, fpsent
*d
)
104 if(!ents
.inrange(n
)) return;
105 int type
= ents
[n
]->type
;
106 if(type
<I_SHELLS
|| type
>I_QUAD
) return;
107 ents
[n
]->spawned
= false;
109 itemstat
&is
= itemstats
[type
-I_SHELLS
];
110 if(d
!=cl
.player1
|| isthirdperson()) particle_text(d
->abovehead(), is
.name
, 15);
111 playsound(itemstats
[type
-I_SHELLS
].sound
, d
!=cl
.player1
? &d
->o
: NULL
);
112 if(d
!=cl
.player1
) return;
117 conoutf("\f2you have a permanent +10 health bonus! (%d)", d
->maxhealth
);
118 playsound(S_V_BOOST
);
122 conoutf("\f2you got the quad!");
128 // these functions are called when the client touches the item
130 void teleport(int n
, fpsent
*d
) // also used by monsters
132 int e
= -1, tag
= ents
[n
]->attr1
, beenhere
= -1;
135 e
= findentity(TELEDEST
, e
+1);
136 if(e
==beenhere
|| e
<0) { conoutf("no teleport destination for tag %d", tag
); return; }
137 if(beenhere
<0) beenhere
= e
;
138 if(ents
[e
]->attr2
==tag
)
141 d
->yaw
= ents
[e
]->attr1
;
143 d
->vel
= vec(0, 0, 0);//vec(cosf(RAD*(d->yaw-90)), sinf(RAD*(d->yaw-90)), 0);
145 cl
.playsoundc(S_TELEPORT
, d
);
151 void trypickup(int n
, fpsent
*d
)
153 switch(ents
[n
]->type
)
156 if(d
->canpickup(ents
[n
]->type
))
158 cl
.cc
.addmsg(SV_ITEMPICKUP
, "ri", n
);
159 ents
[n
]->spawned
= false; // even if someone else gets it first
165 if(d
->lastpickup
==ents
[n
]->type
&& cl
.lastmillis
-d
->lastpickupmillis
<500) break;
166 d
->lastpickup
= ents
[n
]->type
;
167 d
->lastpickupmillis
= cl
.lastmillis
;
173 if(d
!=cl
.player1
) break;
174 if(n
==cl
.respawnent
) break;
176 conoutf("\f2respawn point set!");
177 playsound(S_V_RESPAWNPOINT
);
182 if(d
->lastpickup
==ents
[n
]->type
&& cl
.lastmillis
-d
->lastpickupmillis
<300) break;
183 d
->lastpickup
= ents
[n
]->type
;
184 d
->lastpickupmillis
= cl
.lastmillis
;
185 vec
v((int)(char)ents
[n
]->attr3
*10.0f
, (int)(char)ents
[n
]->attr2
*10.0f
, ents
[n
]->attr1
*12.5f
);
187 d
->gravity
= vec(0, 0, 0);
191 cl
.playsoundc(S_JUMPPAD
, d
);
197 void checkitems(fpsent
*d
)
199 if(d
==cl
.player1
&& (editmode
|| cl
.cc
.spectator
)) return;
204 extentity
&e
= *ents
[i
];
205 if(e
.type
==NOTUSED
) continue;
206 if(!e
.spawned
&& e
.type
!=TELEPORT
&& e
.type
!=JUMPPAD
&& e
.type
!=RESPAWNPOINT
) continue;
207 float dist
= e
.o
.dist(o
);
208 if(dist
<(e
.type
==TELEPORT
? 16 : 12)) trypickup(i
, d
);
212 void checkquad(int time
, fpsent
*d
)
214 if(d
->quadmillis
&& (d
->quadmillis
-= time
)<=0)
217 cl
.playsoundc(S_PUPOUT
, d
);
218 if(d
==cl
.player1
) conoutf("\f2quad damage is over");
222 void putitems(ucharbuf
&p
, int gamemode
) // puts items in network stream and also spawns them locally
224 loopv(ents
) if(ents
[i
]->type
>=I_SHELLS
&& ents
[i
]->type
<=I_QUAD
&& (!m_capture
|| ents
[i
]->type
<I_SHELLS
|| ents
[i
]->type
>I_CARTRIDGES
))
227 putint(p
, ents
[i
]->type
);
229 ents
[i
]->spawned
= (m_sp
|| (ents
[i
]->type
!=I_QUAD
&& ents
[i
]->type
!=I_BOOST
));
233 void resetspawns() { loopv(ents
) ents
[i
]->spawned
= false; }
234 void setspawn(int i
, bool on
) { if(ents
.inrange(i
)) ents
[i
]->spawned
= on
; }
236 extentity
*newentity() { return new fpsentity(); }
238 void fixentity(extentity
&e
)
252 e
.attr1
= (int)cl
.player1
->yaw
;
256 void entradius(extentity
&e
, float &radius
, float &angle
, vec
&dir
)
261 loopv(ents
) if(ents
[i
]->type
== TELEDEST
&& e
.attr1
==ents
[i
]->attr2
)
263 radius
= e
.o
.dist(ents
[i
]->o
);
264 dir
= vec(ents
[i
]->o
).sub(e
.o
).normalize();
271 dir
= vec((int)(char)e
.attr3
*10.0f
, (int)(char)e
.attr2
*10.0f
, e
.attr1
*12.5f
).normalize();
283 vecfromyawpitch(e
.attr1
, 0, 1, 0, dir
);
288 const char *entnameinfo(entity
&e
) { return ""; }
289 const char *entname(int i
)
291 static const char *entnames
[] =
293 "none?", "light", "mapmodel", "playerstart", "envmap", "particles", "sound", "spotlight",
294 "shells", "bullets", "rockets", "riflerounds", "grenades", "cartridges",
295 "health", "healthboost", "greenarmour", "yellowarmour", "quaddamage",
296 "teleport", "teledest",
297 "monster", "carrot", "jumppad",
298 "base", "respawnpoint",
300 "platform", "elevator",
303 return i
>=0 && size_t(i
)<sizeof(entnames
)/sizeof(entnames
[0]) ? entnames
[i
] : "";
306 int extraentinfosize() { return 0; } // size in bytes of what the 2 methods below read/write... so it can be skipped by other games
308 void writeent(entity
&e
, char *buf
) // write any additional data to disk (except for ET_ ents)
312 void readent(entity
&e
, char *buf
) // read from disk, and init
314 int ver
= getmapversion();
317 if(e
.type
>= 7) e
.type
++;
321 if(e
.type
>= 8) e
.type
++;
327 extentity
&e
= *ents
[i
];
328 cl
.cc
.addmsg(SV_EDITENT
, "ri9", i
, (int)(e
.o
.x
*DMF
), (int)(e
.o
.y
*DMF
), (int)(e
.o
.z
*DMF
), e
.type
, e
.attr1
, e
.attr2
, e
.attr3
, e
.attr4
);
331 float dropheight(entity
&e
)
333 if(e
.type
==MAPMODEL
|| e
.type
==BASE
) return 0.0f
;