- Fixed Triggers to work properly with TF maps (one entity needs a function though..)
[divverent/nexuiz.git] / TeamNexuiz / game / gamec / class.c
1 \r
2 void PlayerKilled (float unnatural_death, entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force);\r
3 \r
4 \r
5 \r
6 /*\r
7 =============\r
8 NameOfClass\r
9 \r
10 Translates class number to a string for printing\r
11 =============\r
12 */\r
13 string NameOfClass(float cl)\r
14 {\r
15         if(cl == CLASS_SCOUT)\r
16                 return "Scout";\r
17         if(cl == CLASS_SPY)\r
18                 return "Spy";\r
19         if(cl == CLASS_SOLDIER)\r
20                 return "Soldier";\r
21         if(cl == CLASS_PYRO)\r
22                 return "Pryo";\r
23         if(cl == CLASS_MEDIC)\r
24                 return "Medic";\r
25         if(cl == CLASS_ENGINEER)\r
26                 return "Engineer";\r
27         if(cl == CLASS_CIVILIAN)\r
28                 return "Civilian";\r
29         return "Invalid Class";\r
30 }\r
31 \r
32 /*\r
33 =============\r
34 GetPlayerClass\r
35 \r
36 Returns the player's class by checking his model name\r
37 =============\r
38 */\r
39 float GetPlayerClass()\r
40 {\r
41         //string s;\r
42         //s = substring(self.playermodel,13,3);\r
43 \r
44         //bprint("Class Prefix: ");\r
45         //bprint(s);\r
46         //bprint("\n");\r
47 \r
48         // only the prefix matters;\r
49         // thus, you could have multiple medic models, such as a male and female.\r
50         if(substring(self.playermodel,13,5)\r
51                 == "scout")\r
52                 return CLASS_SCOUT;\r
53         if(substring(self.playermodel,13,3)\r
54                 == "spy")\r
55                 return CLASS_SPY;\r
56         if(substring(self.playermodel,13,7)\r
57                 == "soldier")\r
58                 return CLASS_SOLDIER;\r
59         if(substring(self.playermodel,13,4)\r
60                 == "pyro")\r
61                 return CLASS_PYRO;\r
62         if(substring(self.playermodel,13,5)\r
63                 == "medic")\r
64                 return CLASS_MEDIC;\r
65         if(substring(self.playermodel,13,8)\r
66                 == "engineer")\r
67                 return CLASS_ENGINEER;\r
68 \r
69         return -1;\r
70 }\r
71 \r
72 /*\r
73 =============\r
74 ChangeClass\r
75 \r
76 Changes the player's class\r
77 =============\r
78 */\r
79 \r
80 void ChangeClass(float announce_change, float instant_change)\r
81 {\r
82         float portion, aportion;\r
83         if(announce_change)\r
84                 bprint(self.netname, " becomes a ", NameOfClass(self.class), "\n");\r
85 \r
86         portion = 1.0;\r
87 \r
88         if(instant_change)\r
89         {\r
90                 // health\r
91                 if(self.health < self.max_health)\r
92                         aportion = self.health / self.max_health;\r
93                 else\r
94                         aportion = 1.0;\r
95 \r
96                 if(aportion < portion)\r
97                         portion = aportion;\r
98 \r
99                 // armor\r
100                 if(self.armorvalue < self.max_armor)\r
101                         aportion = self.armorvalue / self.max_armor;\r
102                 else\r
103                         aportion = 1.0;\r
104 \r
105                 if(aportion < portion)\r
106                         portion = aportion;\r
107         }\r
108 \r
109         if(self.class == CLASS_SCOUT)\r
110                 BecomeScout(portion);\r
111 \r
112         if(self.class == CLASS_SPY)\r
113                 BecomeSpy(portion);\r
114 \r
115         if(self.class == CLASS_SOLDIER)\r
116                 BecomeSoldier(portion);\r
117 \r
118         if(self.class == CLASS_PYRO)\r
119                 BecomePyro(portion);\r
120 \r
121         if(self.class == CLASS_MEDIC)\r
122                 BecomeMedic(portion);\r
123 \r
124         if(self.class == CLASS_ENGINEER)\r
125                 BecomeEngineer(portion);\r
126 \r
127         if(self.class == CLASS_CIVILIAN)\r
128                 BecomeCivilian(portion);\r
129 \r
130 \r
131         // set starting health\r
132         if(!instant_change && self.class != CLASS_CIVILIAN)//portion == 1.0)\r
133                 self.health = ceil(self.max_health * 1.2);\r
134         else\r
135                 self.health = self.max_health;\r
136         // set starting armor\r
137         if(!instant_change)//portion == 1.0)\r
138                 self.armorvalue = ceil(self.max_armor * 1.2);\r
139         else\r
140                 self.armorvalue = self.max_armor;\r
141 \r
142         // test code\r
143         //if(instant_change)\r
144         //      self.health = 2 + self.health * 0.8;\r
145 };\r
146 \r
147 float SetPlayerMass(entity pl)\r
148 {\r
149         float m, extra_mass;\r
150         if(self.class == CLASS_SCOUT)\r
151         {\r
152                 m = cvar("g_balance_class_scout_mass");\r
153         }\r
154         else if(self.class == CLASS_SPY)\r
155         {\r
156                 m = cvar("g_balance_class_spy_mass");\r
157         }\r
158         else if(self.class == CLASS_SOLDIER)\r
159         {\r
160                 m = cvar("g_balance_class_soldier_mass");\r
161         }\r
162         else if(self.class == CLASS_PYRO)\r
163         {\r
164                 m = cvar("g_balance_class_pyro_mass");\r
165         }\r
166         else if(self.class == CLASS_MEDIC)\r
167         {\r
168                 m = cvar("g_balance_class_medic_mass");\r
169         }\r
170         else if(self.class == CLASS_ENGINEER)\r
171         {\r
172                 m = cvar("g_balance_class_engineer_mass");\r
173         }\r
174         else\r
175                 m = cvar("sv_maxspeed");\r
176 \r
177         // fixme: if I'm carrying a flag or extra weapon, add that mass\r
178         extra_mass = 0;\r
179 \r
180         if(self.wpn5.mass)\r
181                 extra_mass = extra_mass + self.wpn5.mass;\r
182 \r
183 \r
184         self.mass = m + extra_mass;\r
185 \r
186         return m; // return what my natural mass is\r
187 };\r
188 \r
189 void SetPlayerSpeed(entity pl)\r
190 {\r
191         local float s, m, plmass;\r
192         string temp;\r
193         if(self.class == CLASS_SCOUT)\r
194         {\r
195                 s = cvar("g_balance_class_scout_speed");\r
196                 //m = cvar("g_balance_class_scout_mass");\r
197         }\r
198         else if(self.class == CLASS_SPY)\r
199         {\r
200                 s = cvar("g_balance_class_spy_speed");\r
201                 //m = cvar("g_balance_class_spy_mass");\r
202         }\r
203         else if(self.class == CLASS_SOLDIER)\r
204         {\r
205                 s = cvar("g_balance_class_soldier_speed");\r
206                 //m = cvar("g_balance_class_soldier_mass");\r
207         }\r
208         else if(self.class == CLASS_PYRO)\r
209         {\r
210                 s = cvar("g_balance_class_pyro_speed");\r
211                 //m = cvar("g_balance_class_pyro_mass");\r
212         }\r
213         else if(self.class == CLASS_MEDIC)\r
214         {\r
215                 s = cvar("g_balance_class_medic_speed");\r
216                 //m = cvar("g_balance_class_medic_mass");\r
217         }\r
218         else if(self.class == CLASS_ENGINEER)\r
219         {\r
220                 s = cvar("g_balance_class_engineer_speed");\r
221                 //m = cvar("g_balance_class_engineer_mass");\r
222         }\r
223         else if(self.class == CLASS_CIVILIAN)\r
224         {\r
225                 s = cvar("g_balance_class_civilian_speed");\r
226         }\r
227 \r
228 \r
229 \r
230         // fixme: if I'm in a manned turret, set my speed to 0\r
231         // fixme: if I'm piloting a vehicle, what to do?\r
232 \r
233 \r
234         // if my mass is different because of what I'm carrying,\r
235         // slow me down\r
236 \r
237         m = SetPlayerMass(pl);\r
238 \r
239         if(pl.mass == 0)\r
240                 plmass = 1;\r
241         else\r
242                 plmass = pl.mass;\r
243         s = ceil( s * (m / plmass ) );\r
244 \r
245         if(s != pl.speed)\r
246         {\r
247                 //bprint("debug: adjusting speed\n");\r
248                 temp = ftos(s);\r
249                 \r
250                 //stuffcmd( pl, strcat("cl_movement_maxspeed ", temp , "\n"));\r
251                 //stuffcmd( pl, strcat("cl_movement_maxairspeed ", temp , "\n"));\r
252 \r
253                 //stuffcmd( pl, strcat("cl_forwardspeed ", temp , "\n"));\r
254                 //stuffcmd( pl, strcat("cl_backspeed ", temp , "\n"));\r
255                 //stuffcmd( pl, strcat("cl_sidespeed ", temp , "\n"));\r
256                 //stuffcmd( pl, strcat("cl_upspeed ", temp , "\n"));\r
257         }\r
258 \r
259         pl.speed = s;\r
260 }\r
261 \r
262 \r
263 \r
264 /*\r
265 =============\r
266 ResetPlayerModel\r
267 \r
268 Resets the player's model to what it should be when returning from invisibility,\r
269  or trying to change class but not being allowed.\r
270 =============\r
271 */\r
272 \r
273 void ResetPlayerModel(entity pl)\r
274 {\r
275         local vector m1, m2;\r
276         m1 = pl.mins;\r
277         m2 = pl.maxs;\r
278         //precache_model (self.playermodel); needed?\r
279         setmodel (pl, pl.playermodel);\r
280         setsize (pl, m1, m2);\r
281 }\r
282 \r
283 /*\r
284 =============\r
285 CheckForClassChange\r
286 \r
287 Returns the player's class by checking his model.\r
288 Called from PlayerPreThink whenever the player changes his model, before change is made.\r
289 =============\r
290 */\r
291 \r
292 void() respawn;\r
293 float CheckForClassChange()\r
294 {\r
295         float cl;\r
296         float tfcl;\r
297 \r
298         // FIXME: need an option to not allow class changes at all once the player has changed once\r
299 \r
300         //bprint("check if allow change\n");\r
301 \r
302         // don't monitor the player's model when he's dead.\r
303         // this means he can change class when dead and respawn as the new class.\r
304         //if(self.health <= 0) // fixme: or if player is an observer\r
305         //      return 0;\r
306 \r
307 //      bprint("healthy\n");\r
308 \r
309         if(self.playermodel == self.mdl)\r
310                 return 0; // haven't changed models since last legitimate change\r
311 \r
312         //bprint("model has changed\n");\r
313 \r
314         cl = GetPlayerClass();\r
315         if(self.class == cl) // changed models, but it didn't affect my class\r
316         {\r
317                 if(self.change_mdl_on_respawn) // if was going to change class, but I just switched models of the same class I'm in now, undo the future class change\r
318                         self.change_mdl_on_respawn = "";\r
319                 return 0;\r
320         }\r
321 \r
322         //bprint("class changed\n");\r
323 \r
324 \r
325         // it's changed; now figure out what to do about it\r
326 \r
327         // don't allow player class\r
328         if(cvar("g_classchange_not_allowed"))\r
329         {\r
330                 self.playermodel = self.mdl;    // return to old model\r
331                 ResetPlayerModel(self);\r
332 \r
333                 /*local vector m1, m2;\r
334                 self.playermodel = self.model;  // return to old model\r
335                 m1 = self.mins;\r
336                 m2 = self.maxs;\r
337                 //precache_model (self.playermodel); needed?\r
338                 setmodel (self, self.playermodel);\r
339                 setsize (self, m1, m2);*/\r
340                 return 0;\r
341         }\r
342 \r
343         if (cl == CLASS_SCOUT)\r
344         {\r
345                 tfcl = TF_CLASS_SCOUT;\r
346         }\r
347         else if (cl == CLASS_SOLDIER)\r
348         {\r
349                 tfcl = TF_CLASS_SOLDIER;\r
350         }\r
351         else if (cl == CLASS_MEDIC)\r
352         {\r
353                 tfcl = TF_CLASS_MEDIC;\r
354         }\r
355         else if (cl == CLASS_PYRO)\r
356         {\r
357                 tfcl = TF_CLASS_PYRO;\r
358         }\r
359         else if (cl == CLASS_ENGINEER)\r
360         {\r
361                 tfcl = TF_CLASS_ENGINEER;\r
362         }\r
363         else if (cl == CLASS_SPY)\r
364         {\r
365                 tfcl = TF_CLASS_SPY;\r
366         }\r
367 \r
368         if (self.lives == 0)\r
369         {\r
370                 self.playermodel = self.mdl;    // return to old model\r
371                 ResetPlayerModel(self);\r
372                 sprint(self, "You have no lives left.\n");\r
373                 return 0;\r
374         }\r
375         if (!IsLegalClass(tfcl))                // Checks if class is legal for the map\r
376         {\r
377                 self.playermodel = self.mdl;    // return to old model\r
378                 ResetPlayerModel(self);\r
379                 sprint(self, "You cannot play that playerclass on this map. \n");\r
380                 TeamFortress_DisplayLegalClasses();\r
381                 return 0;\r
382         }\r
383         self.respawn_as_new_class = tfcl;       // makes sure conversion from TF .playerclass goes through\r
384 \r
385         // allow change, but don't take effect until death\r
386         if(cvar("g_classchange_delay_until_death"))\r
387         {\r
388                 self.change_mdl_on_respawn = self.playermodel;\r
389                 self.change_mdl_on_respawn = strzone(self.change_mdl_on_respawn);\r
390                 self.playermodel = self.model;\r
391                 if (self.team_no > 0)\r
392                 {\r
393                         sprint (self, "After dying, you will return as a ");\r
394                         TeamFortress_PrintClassName (self, cl, (self.tfstate & 8));\r
395                 }\r
396 //                      sprint(self, "You will change class after you die\n");\r
397                 return 0;\r
398         }\r
399 \r
400         // allow change, possibly with stipulations (like force respawn)\r
401 \r
402         //bprint("allowing change\n");\r
403 \r
404         if(self.class == CLASS_SPY)\r
405                 SpyDecloak();\r
406 \r
407         self.class = cl;\r
408         //self.mdl = strzone(self.playermodel);\r
409 \r
410 \r
411         // allow change, but instant kill & respawn\r
412         if(cvar("g_classchange_force_respawn"))\r
413         {\r
414                 PlayerKilled(TRUE, world, world, 1, DEATH_CLASSCHANGE, '0 0 0', '0 0 0');\r
415                 respawn();\r
416                 return 1;\r
417         }\r
418 \r
419         // allow class change without a hitch\r
420         ChangeClass(TRUE, TRUE);\r
421         return 0;\r
422 }\r
423 \r
424 void ClassSpecial()\r
425 {\r
426         if(self.class == CLASS_SCOUT)\r
427                 ScoutSpecial();\r
428         if(self.class == CLASS_SPY)\r
429                 SpySpecial();\r
430         if(self.class == CLASS_SOLDIER)\r
431                 SoldierSpecial();\r
432         if(self.class == CLASS_PYRO)\r
433                 PyroSpecial();\r
434         if(self.class == CLASS_MEDIC)\r
435                 MedicSpecial();\r
436         if(self.class == CLASS_ENGINEER)\r
437                 EngineerSpecial();\r
438 }\r
439 \r
440 void ClassGrenade(float req)\r
441 {\r
442         if(self.grenade_time > time)\r
443                 return;\r
444 \r
445         if(self.class == CLASS_SCOUT)\r
446                 ScoutGrenade(req);\r
447         if(self.class == CLASS_SPY)\r
448                 SpyGrenade(req);\r
449         if(self.class == CLASS_SOLDIER)\r
450                 SoldierGrenade(req);\r
451         if(self.class == CLASS_PYRO)\r
452                 PyroGrenade(req);\r
453         if(self.class == CLASS_MEDIC)\r
454                 MedicGrenade(req);\r
455         if(self.class == CLASS_ENGINEER)\r
456                 EngineerGrenade(req);\r
457 }\r
458 \r
459 void ClassPreThink()\r
460 {\r
461         if(self.class == CLASS_SCOUT)\r
462                 ScoutPreThink();\r
463         if(self.class == CLASS_SPY)\r
464                 SpyPreThink();\r
465         if(self.class == CLASS_SOLDIER)\r
466                 SoldierPreThink();\r
467         if(self.class == CLASS_PYRO)\r
468                 PyroPreThink();\r
469         if(self.class == CLASS_MEDIC)\r
470                 MedicPreThink();\r
471         if(self.class == CLASS_ENGINEER)\r
472                 EngineerPreThink();\r
473         if(self.class == CLASS_CIVILIAN)\r
474                 EngineerPreThink();\r
475 }\r
476 \r
477 void ClassPostThink()\r
478 {\r
479         if(self.class == CLASS_SCOUT)\r
480                 ScoutPostThink();\r
481         if(self.class == CLASS_SPY)\r
482                 SpyPostThink();\r
483         if(self.class == CLASS_SOLDIER)\r
484                 SoldierPostThink();\r
485         if(self.class == CLASS_PYRO)\r
486                 PyroPostThink();\r
487         if(self.class == CLASS_MEDIC)\r
488                 MedicPostThink();\r
489         if(self.class == CLASS_ENGINEER)\r
490                 EngineerPostThink();\r
491         if(self.class == CLASS_CIVILIAN)\r
492                 CivilianPostThink();\r
493 }\r
494 \r
495 /*\r
496 =========================\r
497  Set MaxAmmo for classes\r
498   Wazat - edit these values to whatever\r
499                            =========================\r
500 */\r
501 void (float classnum) SetMaxAmmoFor =\r
502 {\r
503         self.is_feigning = 0;\r
504         self.leg_damage = 0;            //temp here //so leg damage doesnt stay on player respawn\r
505         // if no class is found, it will just default to these\r
506         self.maxammo_shells = 200;\r
507         self.maxammo_nails = 200;\r
508         self.maxammo_cells = 40;\r
509         self.maxammo_rockets = 40;\r
510         self.maxammo_metal = 0;\r
511         self.no_grenades_1 = 4;\r
512         self.clip_rockets = CLIP_MAX_ROCKETS;\r
513         self.clip_pistol = CLIP_MAX_PISTOL;\r
514         self.tp_grenades_1 = 1;\r
515         self.tp_grenades_2 = 0;\r
516 \r
517         if (classnum == CLASS_SCOUT)            // Scout Supplies\r
518         {\r
519                 self.maxammo_shells = 200;\r
520                 self.maxammo_nails = 200;\r
521                 self.maxammo_cells = 40;\r
522                 self.maxammo_rockets = 45;\r
523                 self.clip_crylink = CLIP_MAX_CRYLINK;\r
524                 self.tp_grenades_1 = 9;\r
525         }\r
526         else if (classnum == CLASS_SPY) {               // Spy supplies\r
527                 self.maxammo_shells = 150;\r
528                 self.maxammo_nails = 200;               // MAC10 uses nails\r
529                 self.maxammo_cells = 70;\r
530                 self.maxammo_rockets = 15;\r
531                 self.ammo_nails = 100;\r
532                 self.tp_grenades_1 = 9;\r
533                 self.no_grenades_2 = 1;\r
534         }\r
535         else if (classnum == CLASS_SOLDIER) {\r
536                 self.ammo_rockets = 62;                 //translates to 20\r
537                 self.maxammo_rockets = 40;\r
538                 self.tp_grenades_2 = 3;\r
539                 self.no_grenades_2 = 1;\r
540         }\r
541         else if (classnum == CLASS_PYRO) {\r
542                 self.clip_pipegrenades = 6;\r
543         }\r
544         else if (classnum == CLASS_ENGINEER) {\r
545                 self.maxammo_cells = 200;\r
546                 self.ammo_cells = 100;\r
547                 self.ammo_metal = 0;\r
548                 self.maxammo_metal = 200;\r
549         }\r
550         else if (classnum == CLASS_CIVILIAN) {\r
551 //              self.health = 50;\r
552         }\r
553 };\r