Team heal feature. When a player spends time inside a team mate's stomach, they keep...
[voretournament/voretournament.git] / data / qcsrc / server / vore.qc
1 .float regurgitate_prepare;\r
2 .float swallow_delay, digest_button_delay, regurgitate_button_delay;\r
3 .float complain_swallow;\r
4 const float complain_delay = 1;\r
5 const float button_delay = 0.5;\r
6 \r
7 .float vore_oldmovetype, vore_oldsolid, vore_oldstomachload;\r
8 \r
9 entity Swallow_distance_check()\r
10 {\r
11         // check if we can swallow a player instead of firing our weapon\r
12         vector w_shotorg, w_shotdir;\r
13         w_shotorg = self.origin + self.view_ofs;\r
14         w_shotdir = v_forward;\r
15 \r
16         WarpZone_traceline_antilag(self, w_shotorg, w_shotorg + w_shotdir * cvar("g_balance_vore_swallow_range"), FALSE, self, ANTILAG_LATENCY(self));\r
17         if(trace_fraction < 1)\r
18         if(trace_ent.classname == "player")\r
19                 return trace_ent;\r
20         return world;\r
21 }\r
22 \r
23 float Swallow_condition_check(entity prey)\r
24 {\r
25         // checks the necessary conditions for swallowing another player\r
26         if(prey.classname == "player" && prey.eater.classname != "player" && prey.deadflag == DEAD_NO) // we can't swallow someone who's already in someone else's stomach\r
27         if not(vlen(self.velocity) > cvar("g_balance_vore_regurgitate_velocitylimit"))\r
28         if(self.eater.classname != "player") // we can't swallow players while inside someone's stomach ourselves\r
29         {\r
30                 if(self.stomach_load >= cvar("g_balance_vore_swallow_limit"))\r
31                 {\r
32                         if(time > self.complain_swallow)\r
33                         {\r
34                                 play2(self, "weapons/unavailable.wav");\r
35                                 sprint(self, strcat("You cannot swallow more than ^2", cvar_string("g_balance_vore_swallow_limit"), "^7 players at a time\n"));\r
36                                 self.complain_swallow = time + complain_delay;\r
37                         }\r
38                         return FALSE;\r
39                 }\r
40 \r
41                 if(cvar("g_vore_biggergut"))\r
42                 if(prey.stomach_load > self.stomach_load)\r
43                 {\r
44                         if(time > self.complain_swallow)\r
45                         {\r
46                                 play2(self, "weapons/unavailable.wav");\r
47                                 sprint(self, "You cannot swallow someone with a bigger stomach than yours\n");\r
48                                 self.complain_swallow = time + complain_delay;\r
49                         }\r
50                         return FALSE;\r
51                 }\r
52                 return TRUE;\r
53         }\r
54         return FALSE;\r
55 }\r
56 \r
57 void Vore_Weight_apply(entity e)\r
58 {\r
59         // apply stomach weight that makes you heavier the more you eat\r
60         // slowing the player is applied in cl_physics.qc\r
61         if(e.stomach_load != e.vore_oldstomachload)\r
62                 e.gravity += 1 + (e.stomach_load * cvar("g_balance_vore_weight_gravity") - e.vore_oldstomachload);\r
63         if(e.gravity == 0)\r
64                 e.gravity = 0.00001; // 0 becomes 1 for .gravity, so do this to allow 0 gravity\r
65         e.vore_oldstomachload = e.stomach_load;\r
66 }\r
67 \r
68 void Vore_Swallow(entity e)\r
69 {\r
70         // this player is beening swallowed by another player, apply the proper changes\r
71         e.vore_oldmovetype = e.movetype;\r
72         e.vore_oldsolid = e.solid;\r
73 \r
74         setorigin(e, e.eater.origin);\r
75         e.velocity = '0 0 0';\r
76         e.movetype = MOVETYPE_FOLLOW;\r
77         e.solid = SOLID_NOT;\r
78         e.alpha = -1; // best way of hiding / showing the eaten player\r
79         e.aiment = e.eater; // follow the predator. Is automatically unset\r
80         e.view_ofs_z /= 2; // best positioning for the stomach model\r
81         e.stat_eaten = TRUE;\r
82 \r
83         // drop keys (KH) and flags (CTF) when we get swallowed\r
84         kh_Key_DropAll(e, FALSE);\r
85         if(e.flagcarried)\r
86                 DropFlag(e.flagcarried, world, e.eater);\r
87 \r
88         if(stov(cvar_string("g_vore_regurgitatecolor_released")))\r
89                 e.colormod = stov(cvar_string("g_vore_regurgitatecolor_released"));\r
90 \r
91         PlayerSound(e.eater, playersound_swallow, CHAN_PAIN, VOICETYPE_PLAYERSOUND);\r
92         setanim(e.eater, e.eater.anim_pain1, FALSE, TRUE, TRUE); // looks good for swallowing \ regurgitating\r
93         e.eater.stomach_load += 1;\r
94         e.eater.regurgitate_prepare = 0;\r
95         Vore_Weight_apply(e.eater);\r
96 }\r
97 \r
98 void Vore_Regurgitate(entity e)\r
99 {\r
100         // this player is being released from their predator, apply the proper changes\r
101         e.movetype = e.vore_oldmovetype;\r
102         if(e.health > 0) // leave SOLID_NOT for dead bodies\r
103                 e.solid = e.vore_oldsolid;\r
104         e.alpha = 0; // best way of hiding / showing the eaten player\r
105         e.view_ofs_z *= 2; // best positioning for the stomach model\r
106         e.stat_eaten = FALSE;\r
107 \r
108         PlayerSound(e.eater, playersound_regurgitate, CHAN_PAIN, VOICETYPE_PLAYERSOUND);\r
109         setanim(e.eater, e.eater.anim_pain1, FALSE, TRUE, TRUE); // looks good for swallowing \ regurgitating\r
110         pointparticles(particleeffectnum("regurgitate"), e.eater.origin, '0 0 0', 1);\r
111         e.eater.stomach_load -= 1;\r
112         e.eater.regurgitate_prepare = 0;\r
113         Vore_Weight_apply(e.eater);\r
114         e.eater = world;\r
115 }\r
116 \r
117 void Vore_Disconnect()\r
118 {\r
119         // frees prey from their predators when someone disconnects or goes spectating\r
120 \r
121         // prey disconnects or goes spectating while inside someone's belly:\r
122         if(self.eater.classname == "player")\r
123         {\r
124                 self.view_ofs_z += 25;\r
125                 self.stat_eaten = FALSE;\r
126                 self.eater.stomach_load -= 1;\r
127                 Vore_Weight_apply(self.eater);\r
128                 self.eater = world;\r
129         }\r
130 \r
131         // pred disconnects or goes spectating with players in their belly:\r
132         else if(self.stomach_load > 0)\r
133         {\r
134                 entity head;\r
135                 FOR_EACH_PLAYER(head)\r
136                 {\r
137                         if(head.eater == self)\r
138                                 Vore_Regurgitate(head);\r
139                 }\r
140         }\r
141 }\r
142 \r
143 .float digestion_step;\r
144 void Vore_Digest()\r
145 {\r
146         // apply digestion to prey\r
147         if(time > self.eater.digestion_step + 0.1)\r
148         {\r
149                 Damage(self, self.eater, self.eater, cvar("g_balance_vore_digestion_damage"), DEATH_DIGESTION, self.origin, '0 0 0');\r
150                 if(cvar("g_balance_vore_digestion_vampire") && self.eater.health < cvar("g_balance_vore_digestion_vampire_stable"))\r
151                         self.eater.health += cvar("g_balance_vore_digestion_vampire");\r
152 \r
153                 if (self.eater.digestsound_finished < time)\r
154                 {\r
155                         self.eater.digestsound_finished = time + 0.5;\r
156                         sound (self.eater, CHAN_PLAYER, "player/digest.wav", VOL_BASE, ATTN_NORM);\r
157                 }\r
158                 self.eater.digestion_step = time;\r
159         }\r
160 \r
161         if(self.health <= 0)\r
162         if(stov(cvar_string("g_vore_regurgitatecolor_digested")))\r
163                 self.colormod = stov(cvar_string("g_vore_regurgitatecolor_digested"));\r
164 }\r
165 \r
166 .float teamheal_step;\r
167 void Vore_Teamheal()\r
168 {\r
169         if(cvar("g_balance_vore_teamheal") && self.health < cvar("g_balance_vore_teamheal_stable"))\r
170         if(time > self.teamheal_step + 0.1)\r
171         {\r
172                 self.health += cvar("g_balance_vore_teamheal");\r
173                 self.teamheal_step = time;\r
174         }\r
175 }\r
176 \r
177 .float stomachkick_delay;\r
178 void Vore_StomachKick()\r
179 {\r
180         // allows prey to kick the predator's stomach and do some damage, or bring the predator's digestion upon their self when there's no other option\r
181         if(self.eater.classname != "player")\r
182                 return;\r
183 \r
184         // kick the predator's stomach and do damage\r
185         if(self.BUTTON_ATCK)\r
186         if(time > self.stomachkick_delay)\r
187         {\r
188                 float damage;\r
189                 damage = ceil(random() * (cvar("g_balance_vore_kick_damage_max") - cvar("g_balance_vore_kick_damage_min")) + cvar("g_balance_vore_kick_damage_min"));\r
190 \r
191                 Damage(self.eater, self, self, damage, DEATH_STOMACHKICK, self.eater.origin, '0 0 0');\r
192                 sound(self.eater, CHAN_PROJECTILE, "weapons/stomachkick.ogg", VOL_BASE, ATTN_NORM);\r
193                 self.stomachkick_delay = time + cvar("g_balance_vore_kick_delay");\r
194         }\r
195 \r
196         // start the predator's digestion\r
197         if(self.BUTTON_ATCK2)\r
198         {\r
199                 centerprint(self.eater, strcat(self.netname, " triggered your digestion"));\r
200                 self.eater.digesting = TRUE;\r
201         }\r
202 }\r
203 \r
204 void Vore()\r
205 {\r
206         // skip the vore system under some circumstances\r
207         if(time < game_starttime)\r
208         {\r
209                 Vore_Disconnect();\r
210                 return;\r
211         }\r
212         if(self.spectatee_status)\r
213                 return;\r
214 \r
215 // --------------------------------\r
216 // Code that addresses predators:\r
217 // --------------------------------\r
218 \r
219         entity prey;\r
220         prey = Swallow_distance_check();\r
221 \r
222         // attempt to swallow our new prey if there's any in range\r
223         if(self.BUTTON_ATCK && !self.BUTTON_REGURGITATE && self.swallow_delay < time)\r
224         if(Swallow_condition_check(prey))\r
225         {\r
226                 prey.eater = self;\r
227                 Vore_Swallow(prey);\r
228                 self.swallow_delay = time + cvar("g_balance_vore_swallow_delay");\r
229 \r
230                 if(self.team == prey.team && teamplay)\r
231                         centerprint(self, "You have swallowed a team mate, use caution!");\r
232 \r
233                 // block firing for a small amount of time when voring, or we'll be firing the next frame after we swallow\r
234                 self.weapon_delay = time + 0.25;\r
235         }\r
236 \r
237         // start / stop digestion on command, if the player has someone in their stomach\r
238         if(self.BUTTON_DIGEST)\r
239         {\r
240                 if(self.stomach_load)\r
241                 {\r
242                         if(time > self.digest_button_delay)\r
243                         {\r
244                                 self.digesting = !self.digesting;\r
245                                 self.digest_button_delay = time + button_delay;\r
246                         }\r
247                 }\r
248                 else if(time > self.complain_swallow)\r
249                 {\r
250                         play2(self, "weapons/unavailable.wav");\r
251                         sprint(self, "There is nothing to digest\n");\r
252                         self.complain_swallow = time + complain_delay;\r
253                 }\r
254         }\r
255         if(!self.stomach_load)\r
256                 self.digesting = FALSE;\r
257 \r
258         // release players from this player's stomach on command\r
259         if(self.BUTTON_REGURGITATE)\r
260         {\r
261                 if(self.stomach_load)\r
262                 {\r
263                         if(time > self.regurgitate_button_delay)\r
264                         {\r
265                                 self.regurgitate_prepare = time + cvar("g_balance_vore_regurgitate_delay");\r
266                                 PlayerSound(self, playersound_regurgitate_prepare, CHAN_PAIN, VOICETYPE_PLAYERSOUND);\r
267                                 self.regurgitate_button_delay = time + button_delay;\r
268                         }\r
269                 }\r
270                 else if(time > self.complain_swallow)\r
271                 {\r
272                         play2(self, "weapons/unavailable.wav");\r
273                         sprint(self, "There is nothing to regurgitate\n");\r
274                         self.complain_swallow = time + complain_delay;\r
275                 }\r
276         }\r
277 \r
278 // --------------------------------\r
279 // Code that addresses the prey:\r
280 // --------------------------------\r
281 \r
282         if(self.eater.classname != "player")\r
283                 return;\r
284 \r
285         if(self.eater.deadflag || self.deadflag)\r
286                 Vore_Regurgitate(self);\r
287         else if(self.eater.eater.classname == "player") // don't allow a player inside a player inside another player :)\r
288                 Vore_Regurgitate(self);\r
289         else if(vlen(self.eater.velocity) > cvar("g_balance_vore_regurgitate_velocitylimit"))\r
290                 Vore_Regurgitate(self);\r
291 \r
292         // apply delayed regurgitating\r
293         if(self.eater.regurgitate_prepare && time > self.eater.regurgitate_prepare)\r
294         {\r
295                 self.eater.regurgitate_prepare = 0;\r
296                 self.eater.complain_swallow = time + complain_delay;\r
297                 Vore_Regurgitate(self);\r
298         }\r
299 \r
300         if(self.eater.digesting == TRUE)\r
301                 Vore_Digest();\r
302         if(teams_matter && self.team == self.eater.team)\r
303                 Vore_Teamheal();\r
304 \r
305         Vore_StomachKick();\r
306 }