]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/w_porto.qc
create portals below creatures, not walkers
[divverent/nexuiz.git] / data / qcsrc / server / w_porto.qc
1 .entity porto_current;
2 .vector porto_v_angle; // holds "held" view angles
3 .float porto_v_angle_held;
4 .vector right_vector;
5
6 void W_Porto_Success (void)
7 {
8         if(self.owner == world)
9         {
10                 objerror("Cannot succeed successfully: no owner\n");
11                 return;
12         }
13
14         self.owner.porto_current = world;
15         remove(self);
16 }
17
18 float W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo);
19 void W_Porto_Fail (float failhard)
20 {
21         if(self.owner == world)
22         {
23                 objerror("Cannot fail successfully: no owner\n");
24                 return;
25         }
26
27         // no portals here!
28         Portal_ClearWithID(self.owner, self.portal_id);
29         self.owner.porto_current = world;
30
31         if(!failhard && self.owner.playerid == self.playerid && self.owner.deadflag == DEAD_NO && !(self.owner.weapons & WEPBIT_PORTO))
32         {
33                 setsize (self, '-16 -16 0', '16 16 32');
34                 setorigin(self, self.origin + trace_plane_normal);
35                 if(move_out_of_solid(self))
36                 {
37                         self.flags = FL_ITEM;
38                         self.velocity = trigger_push_calculatevelocity(self.origin, self.owner, 128);
39                         tracetoss(self, self);
40                         if(vlen(trace_endpos - self.owner.origin) < 128)
41                         {
42                                 W_ThrowNewWeapon(self.owner, WEP_PORTO, 0, self.origin, self.velocity);
43                                 centerprint(self.owner, "^1Portal deployment failed.\n\n^2Catch it to try again!");
44                         }
45                 }
46         }
47         remove(self);
48 }
49
50 void W_Porto_Remove (entity p)
51 {
52         if(p.porto_current)
53         {
54                 entity oldself;
55                 oldself = self;
56                 self = p.porto_current;
57                 W_Porto_Fail(1);
58                 self = oldself;
59         }
60 }
61
62 void W_Porto_Think (void)
63 {
64         trace_plane_normal = '0 0 0';
65         if(self.owner.playerid != self.playerid)
66                 remove(self);
67         else
68                 W_Porto_Fail(0);
69 }
70
71 void W_Porto_Touch (void)
72 {
73         vector norm;
74
75         if(other.classname == "portal")
76                 return; // handled by the portal
77
78         norm = trace_plane_normal;
79         if(trace_ent.iscreature)
80         {
81                 traceline(trace_ent.origin, trace_ent.origin + '0 0 2' * PL_MIN_z, MOVE_NORMAL, self);
82                 if(trace_fraction >= 1)
83                         return;
84                 if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK || trace_dphitcontents & DPCONTENTS_PLAYERCLIP)
85                         return;
86                 if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
87                         return;
88         }
89
90         if(self.owner.playerid != self.playerid)
91         {
92                 sound(self, CHAN_PROJECTILE, "porto/unsupported.ogg", VOL_BASE, ATTN_NORM);
93                 remove(self);
94         }
95         else if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK || trace_dphitcontents & DPCONTENTS_PLAYERCLIP)
96         {
97                 sound(self, CHAN_PROJECTILE, "porto/bounce.ogg", VOL_BASE, ATTN_NORM);
98                 // just reflect
99                 self.right_vector = self.right_vector - 2 * trace_plane_normal * (self.right_vector * trace_plane_normal);
100                 self.angles = vectoangles(self.velocity - 2 * trace_plane_normal * (self.velocity * trace_plane_normal));
101         }
102         else if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
103         {
104                 sound(self, CHAN_PROJECTILE, "porto/unsupported.ogg", VOL_BASE, ATTN_NORM);
105                 W_Porto_Fail(0);
106         }
107         else if(self.effects & EF_RED)
108         {
109                 self.effects += EF_BLUE - EF_RED;
110                 if(Portal_SpawnInPortalAtTrace(self.owner, self.right_vector, self.portal_id))
111                 {
112                         sound(self, CHAN_PROJECTILE, "porto/create.ogg", VOL_BASE, ATTN_NORM);
113                         trace_plane_normal = norm;
114                         centerprint(self.owner, "^1In^7-portal created.\n");
115                         self.right_vector = self.right_vector - 2 * trace_plane_normal * (self.right_vector * norm);
116                         self.angles = vectoangles(self.velocity - 2 * trace_plane_normal * (self.velocity * norm));
117                 }
118                 else
119                 {
120                         sound(self, CHAN_PROJECTILE, "porto/unsupported.ogg", VOL_BASE, ATTN_NORM);
121                         trace_plane_normal = norm;
122                         W_Porto_Fail(0);
123                 }
124         }
125         else
126         {
127                 if(self.owner.portal_in.portal_id == self.portal_id)
128                 {
129                         if(Portal_SpawnOutPortalAtTrace(self.owner, self.right_vector, self.portal_id))
130                         {
131                                 sound(self, CHAN_PROJECTILE, "porto/create.ogg", VOL_BASE, ATTN_NORM);
132                                 trace_plane_normal = norm;
133                                 centerprint(self.owner, "^4Out^7-portal created.\n");
134                                 W_Porto_Success();
135                         }
136                         else
137                         {
138                                 sound(self, CHAN_PROJECTILE, "porto/unsupported.ogg", VOL_BASE, ATTN_NORM);
139                                 W_Porto_Fail(0);
140                         }
141                 }
142                 else
143                 {
144                         sound(self, CHAN_PROJECTILE, "porto/unsupported.ogg", VOL_BASE, ATTN_NORM);
145                         W_Porto_Fail(0);
146                 }
147         }
148
149 }
150
151 void W_Porto_Attack (void)
152 {
153         local entity gren;
154
155         if not(self.items & IT_UNLIMITED_SUPERWEAPONS)
156                 self.weapons = self.weapons - (self.weapons & WEPBIT_PORTO);
157         W_SetupShot (self, '0 0 0', FALSE, 4, "porto/fire.ogg");
158
159         //pointparticles(particleeffectnum("grenadelauncher_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
160
161         gren = spawn ();
162         gren.owner = self;
163         gren.playerid = self.playerid;
164         gren.classname = "porto";
165         gren.bot_dodge = TRUE;
166         gren.bot_dodgerating = 200;
167         gren.movetype = MOVETYPE_BOUNCEMISSILE;
168         gren.solid = SOLID_BBOX;
169         gren.effects = EF_LOWPRECISION | EF_RED | EF_ADDITIVE;
170         gren.scale = 4;
171         gren.modelflags = MF_GRENADE;
172         setmodel(gren, "models/grenademodel.md3"); // precision set above
173         setsize(gren, '0 0 0', '0 0 0');
174         setorigin(gren, w_shotorg);
175
176         gren.nextthink = time + cvar("g_balance_porto_primary_lifetime");
177         gren.think = W_Porto_Think;
178         gren.touch = W_Porto_Touch;
179         gren.velocity = w_shotdir * cvar("g_balance_porto_primary_speed");
180         if(self.items & IT_STRENGTH)
181                 gren.velocity = gren.velocity * cvar("g_balance_powerup_strength_force");
182         W_SetupProjectileVelocity(gren);
183
184         gren.angles = vectoangles (gren.velocity);
185         gren.flags = FL_PROJECTILE;
186
187         gren.portal_id = time;
188         self.porto_current = gren;
189         gren.playerid = self.playerid;
190         fixedmakevectors(vectoangles(gren.velocity));
191         gren.right_vector = v_right;
192
193         gren.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP;
194 }
195
196 void spawnfunc_weapon_porto (void)
197 {
198         weapon_defaultspawnfunc(WEP_PORTO);
199 }
200
201 float w_porto(float req)
202 {
203         vector v_angle_save;
204
205         if (req == WR_AIM)
206         {
207                 self.BUTTON_ATCK = FALSE;
208                 self.BUTTON_ATCK2 = FALSE;
209                 if(bot_aim(cvar("g_balance_porto_primary_speed"), 0, cvar("g_balance_grenadelauncher_primary_lifetime"), FALSE))
210                         self.BUTTON_ATCK = TRUE;
211         }
212         else if (req == WR_THINK)
213         {
214                 if(self.porto_v_angle_held)
215                 {
216                         if(!self.BUTTON_ATCK2)
217                         {
218                                 msg_entity = self;
219                                 WRITESPECTATABLE_MSG_ONE_VARNAME(dummy1, {
220                                         WriteByte(MSG_ONE, SVC_TEMPENTITY);
221                                         WriteByte(MSG_ONE, TE_CSQC_HOLDANGLES);
222                                         WriteByte(MSG_ONE, WEP_PORTO);
223                                         WriteByte(MSG_ONE, 0);
224                                 });
225                                 self.porto_v_angle_held = 0;
226                         }
227                 }
228                 else
229                 {
230                         if(self.BUTTON_ATCK2)
231                         {
232                                 self.porto_v_angle = self.v_angle;
233                                 msg_entity = self;
234                                 WRITESPECTATABLE_MSG_ONE_VARNAME(dummy2, {
235                                         WriteByte(MSG_ONE, SVC_TEMPENTITY);
236                                         WriteByte(MSG_ONE, TE_CSQC_HOLDANGLES);
237                                         WriteByte(MSG_ONE, WEP_PORTO);
238                                         WriteByte(MSG_ONE, 1);
239                                         WriteCoord(MSG_ONE, self.v_angle_x);
240                                         WriteCoord(MSG_ONE, self.v_angle_y);
241                                 });
242                                 self.porto_v_angle_held = 1;
243                         }
244                 }
245                 v_angle_save = self.v_angle;
246                 if(self.porto_v_angle_held)
247                         makevectors(self.porto_v_angle); // override the previously set angles
248
249                 if (self.BUTTON_ATCK)
250                 if (!self.porto_current)
251                 if (!self.porto_forbidden)
252                 if (weapon_prepareattack(0, cvar("g_balance_porto_primary_refire")))
253                 {
254                         W_Porto_Attack();
255                         weapon_thinkf(WFRAME_FIRE1, cvar("g_balance_porto_primary_animtime"), w_ready);
256                 }
257         }
258         else if (req == WR_PRECACHE)
259         {
260                 precache_model ("models/grenademodel.md3");
261                 precache_model ("models/weapons/g_porto.md3");
262                 precache_model ("models/weapons/v_porto.md3");
263                 precache_model ("models/weapons/w_porto.zym");
264                 precache_model ("models/portal.md3");
265                 precache_sound ("porto/bounce.ogg");
266                 precache_sound ("porto/create.ogg");
267                 precache_sound ("porto/expire.ogg");
268                 precache_sound ("porto/explode.ogg");
269                 precache_sound ("porto/fire.ogg");
270                 precache_sound ("porto/unsupported.ogg");
271         }
272         else if (req == WR_SETUP)
273                 weapon_setup(WEP_PORTO);
274         else if (req == WR_SUICIDEMESSAGE)
275                 w_deathtypestring = "did the impossible";
276         else if (req == WR_KILLMESSAGE)
277                 w_deathtypestring = "felt # doing the impossible to him";
278         return TRUE;
279 };