1 enum // static entity types
2 {
3 NOTUSED = 0, // entity slot not in use in map
4 LIGHT, // lightsource, attr1 = radius, attr2 = intensity
5 PLAYERSTART, // attr1 = angle, attr2 = team
6 I_CLIPS, I_AMMO, I_GRENADE,
7 I_HEALTH, I_HELMET, I_ARMOUR, I_AKIMBO,
8 // helmet : 2010may16 -> mapversion:8
9 MAPMODEL, // attr1 = angle, attr2 = idx
10 CARROT, // attr1 = tag, attr2 = type
11 LADDER,
12 CTF_FLAG, // attr1 = angle, attr2 = red/blue
13 SOUND,
14 CLIP,
15 PLCLIP,
16 MAXENTTYPES
17 };
18
19 enum {MAP_IS_BAD, MAP_IS_EDITABLE, MAP_IS_GOOD};
20
21 extern const char *entnames[MAXENTTYPES];
22 #define isitem(i) ((i) >= I_CLIPS && (i) <= I_AKIMBO)
23
24 struct persistent_entity // map entity
25 {
26 short x, y, z; // cube aligned position
27 short attr1;
28 uchar type; // type is one of the above
29 uchar attr2, attr3, attr4;
persistent_entitypersistent_entity30 persistent_entity(short x, short y, short z, uchar type, short attr1, uchar attr2, uchar attr3, uchar attr4) : x(x), y(y), z(z), attr1(attr1), type(type), attr2(attr2), attr3(attr3), attr4(attr4) {}
persistent_entitypersistent_entity31 persistent_entity() {}
32 };
33
34 struct entity : persistent_entity
35 {
36 bool spawned; //the dynamic states of a map entity
37 int lastmillis;
entityentity38 entity(short x, short y, short z, uchar type, short attr1, uchar attr2, uchar attr3, uchar attr4) : persistent_entity(x, y, z, type, attr1, attr2, attr3, attr4), spawned(false) {}
entityentity39 entity() {}
fitsmodeentity40 bool fitsmode(int gamemode) { return !m_noitems && isitem(type) && !(m_noitemsnade && type!=I_GRENADE) && !(m_pistol && type==I_AMMO); }
transformtypeentity41 void transformtype(int gamemode)
42 {
43 if(m_noitemsnade && type==I_CLIPS) type = I_GRENADE;
44 else if(m_pistol && ( type==I_AMMO || type==I_GRENADE )) type = I_CLIPS;
45 }
46 };
47
48 enum { GUN_KNIFE = 0, GUN_PISTOL, GUN_CARBINE, GUN_SHOTGUN, GUN_SUBGUN, GUN_SNIPER, GUN_ASSAULT, GUN_CPISTOL, GUN_GRENADE, GUN_AKIMBO, NUMGUNS };
49 #define reloadable_gun(g) (g != GUN_KNIFE && g != GUN_GRENADE)
50
51 #define SGRAYS 21
52 #define SGDMGTOTAL 90
53
54 #define SGDMGBONUS 65
55 #define SGDMGDISTB 50
56
57 #define SGCCdmg 500
58 #define SGCCbase 0
59 #define SGCCrange 40
60
61 #define SGCMdmg 375
62 #define SGCMbase 25
63 #define SGCMrange 60
64
65 #define SGCOdmg 125
66 #define SGCObase 45
67 #define SGCOrange 75
68
69 #define SGMAXDMGABS 105
70 #define SGMAXDMGLOC 84
71 #define SGBONUSDIST 80
72 #define SGSEGDMG_O 3
73 #define SGSEGDMG_M 6
74 #define SGSEGDMG_C 4
75 #define SGSPREAD 2.25
76 #define EXPDAMRAD 10
77
78 struct itemstat { int add, start, max, sound; };
79 extern itemstat ammostats[NUMGUNS];
80 extern itemstat powerupstats[I_ARMOUR-I_HEALTH+1];
81
82 struct guninfo { string modelname; short sound, reload, reloadtime, attackdelay, damage, piercing, projspeed, part, spread, recoil, magsize, mdl_kick_rot, mdl_kick_back, recoilincrease, recoilbase, maxrecoil, recoilbackfade, pushfactor; bool isauto; };
83 extern guninfo guns[NUMGUNS];
84
reloadtime(int gun)85 static inline int reloadtime(int gun) { return guns[gun].reloadtime; }
attackdelay(int gun)86 static inline int attackdelay(int gun) { return guns[gun].attackdelay; }
magsize(int gun)87 static inline int magsize(int gun) { return guns[gun].magsize; }
88
89 /** roseta stone:
90 0000, 0001, 0010, 0011, 0100, 0101, 0110 */
91 enum { TEAM_CLA = 0, TEAM_RVSF, TEAM_CLA_SPECT, TEAM_RVSF_SPECT, TEAM_SPECT, TEAM_NUM, TEAM_ANYACTIVE };
92 extern const char *teamnames[TEAM_NUM+1];
93 extern const char *teamnames_s[TEAM_NUM+1];
94
95 #define TEAM_VOID TEAM_NUM
96 #define isteam(a,b) (m_teammode && (a) == (b))
97 #define team_opposite(o) (team_isvalid(o) && (o) < TEAM_SPECT ? (o) ^ 1 : TEAM_SPECT)
98 #define team_base(t) ((t) & 1)
99 #define team_basestring(t) ((t) == 1 ? teamnames[1] : ((t) == 0 ? teamnames[0] : "SPECT"))
100 #define team_isvalid(t) ((int(t)) >= 0 && (t) < TEAM_NUM)
101 #define team_isactive(t) ((t) == TEAM_CLA || (t) == TEAM_RVSF)
102 #define team_isspect(t) ((t) > TEAM_RVSF && (t) < TEAM_VOID)
103 #define team_group(t) ((t) == TEAM_SPECT ? TEAM_SPECT : team_base(t))
104 #define team_tospec(t) ((t) == TEAM_SPECT ? TEAM_SPECT : team_base(t) + TEAM_CLA_SPECT - TEAM_CLA)
105 // note: team_isactive and team_base can/should be used to check the limits for arrays of size '2'
106 static inline const char *team_string(int t, bool abbr = false) { const char **n = abbr ? teamnames_s : teamnames; return team_isvalid(t) ? n[t] : n[TEAM_NUM]; }
107
108 enum { ENT_PLAYER = 0, ENT_BOT, ENT_CAMERA, ENT_BOUNCE };
109 enum { CS_ALIVE = 0, CS_DEAD, CS_SPAWNING, CS_LAGGED, CS_EDITING, CS_SPECTATE };
110 enum { CR_DEFAULT = 0, CR_ADMIN };
111 enum { SM_NONE = 0, SM_DEATHCAM, SM_FOLLOW1ST, SM_FOLLOW3RD, SM_FOLLOW3RD_TRANSPARENT, SM_FLY, SM_OVERVIEW, SM_NUM };
112 enum { FPCN_VOID = -4, FPCN_DEATHCAM = -2, FPCN_FLY = -2, FPCN_OVERVIEW = -1 };
113
114 class worldobject
115 {
116 public:
~worldobject()117 virtual ~worldobject() {};
118 };
119
120 class physent : public worldobject
121 {
122 public:
123 vec o, vel, vel_t; // origin, velocity
124 vec deltapos, newpos; // movement interpolation
125 float yaw, pitch, roll; // used as vec in one place
126 float pitchvel;
127 float maxspeed; // cubes per second, 24 for player
128 int timeinair; // used for fake gravity
129 float radius, eyeheight, maxeyeheight, aboveeye; // bounding box size
130 bool inwater;
131 bool onfloor, onladder, jumpnext, crouching, crouchedinair, trycrouch, cancollide, stuck, scoping, shoot;
132 int lastjump;
133 float lastjumpheight;
134 int lastsplash;
135 char move, strafe;
136 uchar state, type;
137 float eyeheightvel;
138 int last_pos;
139
physent()140 physent() : o(0, 0, 0), deltapos(0, 0, 0), newpos(0, 0, 0), yaw(270), pitch(0), roll(0), pitchvel(0),
141 crouching(false), crouchedinair(false), trycrouch(false), cancollide(true), stuck(false), scoping(false), shoot(false), lastjump(0), lastjumpheight(0), lastsplash(0), state(CS_ALIVE), last_pos(0)
142 {
143 reset();
144 }
~physent()145 virtual ~physent() {}
146
resetinterp()147 void resetinterp()
148 {
149 newpos = o;
150 newpos.z -= eyeheight;
151 deltapos = vec(0, 0, 0);
152 }
153
reset()154 void reset()
155 {
156 vel.x = vel.y = vel.z = eyeheightvel = vel_t.x = vel_t.y = vel_t.z = 0.0f;
157 move = strafe = 0;
158 timeinair = lastjump = lastsplash = 0;
159 onfloor = onladder = inwater = jumpnext = crouching = crouchedinair = trycrouch = stuck = false;
160 last_pos = 0;
161 }
162
oncollision()163 virtual void oncollision() {}
onmoved(const vec & dist)164 virtual void onmoved(const vec &dist) {}
165 };
166
167 class dynent : public physent // animated ent
168 {
169 public:
170 bool k_left, k_right, k_up, k_down; // see input code
171
172 animstate prev[2], current[2]; // md2's need only [0], md3's need both for the lower&upper model
173 int lastanimswitchtime[2];
174 void *lastmodel[2];
175 int lastrendered;
176
stopmoving()177 void stopmoving()
178 {
179 k_left = k_right = k_up = k_down = jumpnext = false;
180 move = strafe = 0;
181 }
182
resetanim()183 void resetanim()
184 {
185 loopi(2)
186 {
187 prev[i].reset();
188 current[i].reset();
189 lastanimswitchtime[i] = -1;
190 lastmodel[i] = NULL;
191 }
192 lastrendered = 0;
193 }
194
reset()195 void reset()
196 {
197 physent::reset();
198 stopmoving();
199 }
200
dynent()201 dynent() { reset(); resetanim(); }
~dynent()202 virtual ~dynent() {}
203 };
204
205 #define MAXNAMELEN 15
206
207 class bounceent;
208
209 #define POSHIST_SIZE 7
210
211 struct poshist
212 {
213 int nextupdate, curpos, numpos;
214 vec pos[POSHIST_SIZE];
215
poshistposhist216 poshist() : nextupdate(0) { reset(); }
217
sizeposhist218 const int size() const { return numpos; }
219
resetposhist220 void reset()
221 {
222 curpos = 0;
223 numpos = 0;
224 }
225
addposposhist226 void addpos(const vec &o)
227 {
228 pos[curpos] = o;
229 curpos++;
230 if(curpos>=POSHIST_SIZE) curpos = 0;
231 if(numpos<POSHIST_SIZE) numpos++;
232 }
233
getposposhist234 const vec &getpos(int i) const
235 {
236 i = curpos-1-i;
237 if(i < 0) i += POSHIST_SIZE;
238 return pos[i];
239 }
240
updateposhist241 void update(const vec &o, int lastmillis)
242 {
243 if(lastmillis<nextupdate) return;
244 if(o.dist(pos[0]) >= 4.0f) addpos(o);
245 nextupdate = lastmillis + 100;
246 }
247 };
248
249 class playerstate
250 {
251 public:
252 int health, armour;
253 int primary, nextprimary;
254 int gunselect;
255 bool akimbo;
256 int ammo[NUMGUNS], mag[NUMGUNS], gunwait[NUMGUNS];
257 int pstatshots[NUMGUNS], pstatdamage[NUMGUNS];
258
playerstate()259 playerstate() : armour(0), primary(GUN_ASSAULT), nextprimary(GUN_ASSAULT), akimbo(false) {}
~playerstate()260 virtual ~playerstate() {}
261
resetstats()262 void resetstats() { loopi(NUMGUNS) pstatshots[i] = pstatdamage[i] = 0; }
263
itemstats(int type)264 itemstat &itemstats(int type)
265 {
266 switch(type)
267 {
268 case I_CLIPS: return ammostats[GUN_PISTOL];
269 case I_AMMO: return ammostats[primary];
270 case I_GRENADE: return ammostats[GUN_GRENADE];
271 case I_AKIMBO: return ammostats[GUN_AKIMBO];
272 case I_HEALTH:
273 case I_HELMET:
274 case I_ARMOUR:
275 return powerupstats[type-I_HEALTH];
276 default:
277 return *(itemstat *)0;
278 }
279 }
280
canpickup(int type)281 bool canpickup(int type)
282 {
283 switch(type)
284 {
285 case I_CLIPS: return ammo[akimbo ? GUN_AKIMBO : GUN_PISTOL]<ammostats[akimbo ? GUN_AKIMBO : GUN_PISTOL].max;
286 case I_AMMO: return ammo[primary]<ammostats[primary].max;
287 case I_GRENADE: return mag[GUN_GRENADE]<ammostats[GUN_GRENADE].max;
288 case I_HEALTH: return health<powerupstats[type-I_HEALTH].max;
289 case I_HELMET:
290 case I_ARMOUR: return armour<powerupstats[type-I_HEALTH].max;
291 case I_AKIMBO: return !akimbo;
292 default: return false;
293 }
294 }
295
additem(itemstat & is,int & v)296 void additem(itemstat &is, int &v)
297 {
298 v += is.add;
299 if(v > is.max) v = is.max;
300 }
301
pickup(int type)302 void pickup(int type)
303 {
304 switch(type)
305 {
306 case I_CLIPS:
307 additem(ammostats[GUN_PISTOL], ammo[GUN_PISTOL]);
308 additem(ammostats[GUN_AKIMBO], ammo[GUN_AKIMBO]);
309 break;
310 case I_AMMO: additem(ammostats[primary], ammo[primary]); break;
311 case I_GRENADE: additem(ammostats[GUN_GRENADE], mag[GUN_GRENADE]); break;
312 case I_HEALTH: additem(powerupstats[type-I_HEALTH], health); break;
313 case I_HELMET:
314 case I_ARMOUR:
315 additem(powerupstats[type-I_HEALTH], armour); break;
316 case I_AKIMBO:
317 akimbo = true;
318 mag[GUN_AKIMBO] = guns[GUN_AKIMBO].magsize;
319 additem(ammostats[GUN_AKIMBO], ammo[GUN_AKIMBO]);
320 break;
321 }
322 }
323
respawn()324 void respawn()
325 {
326 health = 100;
327 armour = 0;
328 gunselect = GUN_PISTOL;
329 akimbo = false;
330 loopi(NUMGUNS) ammo[i] = mag[i] = gunwait[i] = 0;
331 ammo[GUN_KNIFE] = mag[GUN_KNIFE] = 1;
332 }
333
spawnstate(int gamemode)334 virtual void spawnstate(int gamemode)
335 {
336 if(m_pistol) primary = GUN_PISTOL;
337 else if(m_osok) primary = GUN_SNIPER;
338 else if(m_lss) primary = GUN_KNIFE;
339 else primary = nextprimary;
340
341 if(!m_nopistol)
342 {
343 ammo[GUN_PISTOL] = ammostats[GUN_PISTOL].start-magsize(GUN_PISTOL);//ammostats[GUN_PISTOL].max-magsize(GUN_PISTOL);
344 mag[GUN_PISTOL] = magsize(GUN_PISTOL);
345 }
346
347 if(!m_noprimary)
348 {
349 ammo[primary] = ammostats[primary].start-magsize(primary);
350 mag[primary] = magsize(primary);
351 }
352
353 gunselect = primary;
354
355 if(m_osok) health = 1;
356 if(m_lms) // Survivor && Team-Survivor : 2010nov19
357 {
358 health = 100;
359 armour = 100;
360 ammo[GUN_GRENADE] = 2;
361 }
362 }
363
364 // just subtract damage here, can set death, etc. later in code calling this
dodamage(int damage,int gun)365 int dodamage(int damage, int gun)
366 {
367 guninfo gi = guns[gun];
368 if(damage == INT_MAX)
369 {
370 damage = health;
371 armour = health = 0;
372 return damage;
373 }
374
375 // 4-level armour - tiered approach: 16%, 33%, 37%, 41%
376 // Please update ./ac_website/htdocs/docs/introduction.html if this changes.
377 int armoursection = 0;
378 int ad = damage;
379 if(armour > 25) armoursection = 1;
380 if(armour > 50) armoursection = 2;
381 if(armour > 75) armoursection = 3;
382 switch(armoursection)
383 {
384 case 0: ad = (int) (16.0f/25.0f * armour); break; // 16
385 case 1: ad = (int) (17.0f/25.0f * armour) - 1; break; // 33
386 case 2: ad = (int) (4.0f/25.0f * armour) + 25; break; // 37
387 case 3: ad = (int) (4.0f/25.0f * armour) + 25; break; // 41
388 default: break;
389 }
390
391 //ra - reduced armor
392 //rd - reduced damage
393 int ra = (int) (ad * damage/100.0f);
394 int rd = ra-(ra*(gi.piercing/100.0f)); //Who cares about rounding errors anyways?
395
396 armour -= ra;
397 damage -= rd;
398
399 health -= damage;
400 return damage;
401 }
402 };
403
404 #ifndef STANDALONE
405 #define HEADSIZE 0.4f
406
407 class playerent : public dynent, public playerstate
408 {
409 private:
410 int curskin, nextskin[2];
411 public:
412 int clientnum, lastupdate, plag, ping;
413 enet_uint32 address;
414 int lifesequence; // sequence id for each respawn, used in damage test
415 int frags, flagscore, deaths, points, tks;
416 int lastaction, lastmove, lastpain, lastvoicecom;
417 int clientrole;
418 bool attacking;
419 string name;
420 int team;
421 int weaponchanging;
422 int nextweapon; // weapon we switch to
423 int spectatemode, followplayercn;
424 int eardamagemillis;
425 int respawnoffset;
allowmove()426 bool allowmove() { return state!=CS_DEAD || spectatemode==SM_FLY; }
427
428 weapon *weapons[NUMGUNS];
429 weapon *prevweaponsel, *weaponsel, *nextweaponsel, *primweap, *nextprimweap, *lastattackweapon;
430
431 poshist history; // Previous stored locations of this player
432
433 const char *skin_noteam, *skin_cla, *skin_rvsf;
434
435 float deltayaw, deltapitch, newyaw, newpitch;
436 int smoothmillis;
437
438 vec head;
439
440 bool ignored, muted;
441
playerent()442 playerent() : curskin(0), clientnum(-1), lastupdate(0), plag(0), ping(0), address(0), lifesequence(0), frags(0), flagscore(0), deaths(0), points(0), tks(0), lastpain(0), lastvoicecom(0), clientrole(CR_DEFAULT),
443 team(TEAM_SPECT), spectatemode(SM_NONE), followplayercn(FPCN_VOID), eardamagemillis(0), respawnoffset(0),
444 prevweaponsel(NULL), weaponsel(NULL), nextweaponsel(NULL), primweap(NULL), nextprimweap(NULL), lastattackweapon(NULL),
445 smoothmillis(-1),
446 head(-1, -1, -1), ignored(false), muted(false)
447 {
448 type = ENT_PLAYER;
449 name[0] = 0;
450 maxeyeheight = 4.5f;
451 aboveeye = 0.7f;
452 radius = 1.1f;
453 maxspeed = 16.0f;
454 skin_noteam = skin_cla = skin_rvsf = NULL;
455 loopi(2) nextskin[i] = 0;
456 respawn();
457 }
458
~playerent()459 virtual ~playerent()
460 {
461 extern void removebounceents(playerent *owner);
462 extern void removedynlights(physent *owner);
463 extern void zapplayerflags(playerent *owner);
464 extern void cleanplayervotes(playerent *owner);
465 extern physent *camera1;
466 extern void togglespect();
467 removebounceents(this);
468 audiomgr.detachsounds(this);
469 removedynlights(this);
470 zapplayerflags(this);
471 cleanplayervotes(this);
472 if(this==camera1) togglespect();
473 }
474
damageroll(float damage)475 void damageroll(float damage)
476 {
477 extern void clamproll(physent *pl);
478 float damroll = 2.0f*damage;
479 roll += roll>0 ? damroll : (roll<0 ? -damroll : (rnd(2) ? damroll : -damroll)); // give player a kick
480 clamproll(this);
481 }
482
hitpush(int damage,const vec & dir,playerent * actor,int gun)483 void hitpush(int damage, const vec &dir, playerent *actor, int gun)
484 {
485 if(gun<0 || gun>NUMGUNS) return;
486 vec push(dir);
487 push.mul(damage/100.0f*guns[gun].pushfactor);
488 vel.add(push);
489 extern int lastmillis;
490 if(gun==GUN_GRENADE && damage > 50) eardamagemillis = lastmillis+damage*100;
491 }
492
resetspec()493 void resetspec()
494 {
495 spectatemode = SM_NONE;
496 followplayercn = FPCN_VOID;
497 }
498
respawn()499 void respawn()
500 {
501 dynent::reset();
502 playerstate::respawn();
503 history.reset();
504 if(weaponsel) weaponsel->reset();
505 lastaction = 0;
506 lastattackweapon = NULL;
507 attacking = false;
508 extern int lastmillis;
509 weaponchanging = lastmillis - weapons[gunselect]->weaponchangetime/2; // 2011jan16:ft: for a little no-shoot after spawn
510 resetspec();
511 eardamagemillis = 0;
512 eyeheight = maxeyeheight;
513 curskin = nextskin[team_base(team)];
514 }
515
spawnstate(int gamemode)516 void spawnstate(int gamemode)
517 {
518 playerstate::spawnstate(gamemode);
519 prevweaponsel = weaponsel = weapons[gunselect];
520 primweap = weapons[primary];
521 nextprimweap = weapons[nextprimary];
522 curskin = nextskin[team_base(team)];
523 }
524
selectweapon(int w)525 void selectweapon(int w) { if (weaponsel) prevweaponsel = weaponsel; weaponsel = weapons[(gunselect = w)]; if (!prevweaponsel) prevweaponsel = weaponsel; }
setprimary(int w)526 void setprimary(int w) { primweap = weapons[(primary = w)]; }
setnextprimary(int w)527 void setnextprimary(int w) { nextprimweap = weapons[(nextprimary = w)]; }
isspectating()528 bool isspectating() { return state==CS_SPECTATE || (state==CS_DEAD && spectatemode > SM_NONE); }
weaponswitch(weapon * w)529 void weaponswitch(weapon *w)
530 {
531 if(!w) return;
532 extern int lastmillis;
533 weaponsel->ondeselecting();
534 weaponchanging = lastmillis;
535 nextweaponsel = w;
536 w->onselecting();
537 }
538 int skin(int t = -1) { return nextskin[team_base(t < 0 ? team : t)]; }
setskin(int t,int s)539 void setskin(int t, int s)
540 {
541 const int maxskin[2] = { 4, 6 };
542 t = team_base(t < 0 ? team : t);
543 nextskin[t] = iabs(s) % maxskin[t];
544 }
545 };
546
547
548
549 class CBot;
550
551 class botent : public playerent
552 {
553 public:
554 // Added by Rick
555 CBot *pBot; // Only used if this is a bot, points to the bot class if we are the host,
556 // for other clients its NULL
557 // End add by Rick
558
559 playerent *enemy; // monster wants to kill this entity
560 // Added by Rick: targetpitch
561 float targetpitch; // monster wants to look in this direction
562 // End add
563 float targetyaw; // monster wants to look in this direction
564
botent()565 botent() : pBot(NULL), enemy(NULL) { type = ENT_BOT; }
~botent()566 ~botent() { }
567
deaths()568 int deaths() { return lifesequence; }
569 };
570 #endif //#ifndef STANDALONE
571
572 // flag-mode entities
573
574 enum { CTFF_INBASE = 0, CTFF_STOLEN, CTFF_DROPPED, CTFF_IDLE };
575
576 struct flaginfo
577 {
578 int team;
579 entity *flagent;
580 int actor_cn;
581 playerent *actor;
582 vec pos;
583 int state; // one of CTFF_*
584 bool ack;
flaginfoflaginfo585 flaginfo() : flagent(0), actor(0), state(CTFF_INBASE), ack(false) {}
586 };
587
588 // nades, gibs
589
590 enum { BT_NONE, BT_NADE, BT_GIB };
591
592 class bounceent : public physent
593 {
594 public:
595 int millis, timetolive, bouncetype; // see enum above
596 float rotspeed;
597 bool plclipped;
598 playerent *owner;
599
bounceent()600 bounceent() : bouncetype(BT_NONE), rotspeed(1.0f), plclipped(false), owner(NULL)
601 {
602 type = ENT_BOUNCE;
603 maxspeed = 40;
604 radius = 0.2f;
605 eyeheight = maxeyeheight = 0.3f;
606 aboveeye = 0.0f;
607 }
608
~bounceent()609 virtual ~bounceent() {}
610
isalive(int lastmillis)611 bool isalive(int lastmillis) { return lastmillis - millis < timetolive; }
destroy()612 virtual void destroy() {}
applyphysics()613 virtual bool applyphysics() { return true; }
614 };
615
616 struct hitmsg
617 {
618 int target, lifesequence, info;
619 ivec dir;
620 };
621
622 class grenadeent : public bounceent
623 {
624 public:
625 bool local;
626 int nadestate;
627 float distsincebounce;
628 grenadeent(playerent *owner, int millis = 0);
629 ~grenadeent();
630 void activate(const vec &from, const vec &to);
631 void _throw(const vec &from, const vec &vel);
632 void explode();
633 void splash();
634 virtual void destroy();
635 virtual bool applyphysics();
636 void moveoutsidebbox(const vec &direction, playerent *boundingbox);
637 void oncollision();
638 void onmoved(const vec &dist);
639 };
640
641 enum {MD_FRAGS = 0, MD_DEATHS, END_MDS};
642 struct medalsst {bool assigned; int cn; int item;};
643
644 #define MAXKILLMSGLEN 16
645 extern char killmessages[2][NUMGUNS][MAXKILLMSGLEN];
646 inline const char *killmessage(int gun, bool gib = false)
647 {
648 if(gun<0 || gun>=NUMGUNS) return "";
649
650 return killmessages[gib?1:0][gun];
651 }
652
653 #ifndef STANDALONE
654 struct pckserver
655 {
656 char *addr;
657 bool pending, responsive;
658 int ping;
659
pckserverpckserver660 pckserver() : addr(NULL), pending(false), responsive(true), ping(-1) {}
661 };
662
663 enum { PCK_TEXTURE, PCK_SKYBOX, PCK_MAPMODEL, PCK_AUDIO, PCK_MAP, PCK_NUM };
664
665 struct package
666 {
667 char *name;
668 int type, number;
669 bool pending;
670 pckserver *source;
671 CURL *curl;
672
packagepackage673 package() : name(NULL), type(-1), number(0), pending(false), source(NULL), curl(NULL) {}
674 };
675 #endif