Merge branch 'master' into Mario/turrets
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / turrets / unit / ewheel.qc
1 #ifdef REGISTER_TURRET
2 REGISTER_TURRET(
3 /* TUR_##id   */ EWHEEL,
4 /* function   */ t_ewheel,
5 /* spawnflags */ TUR_FLAG_PLAYER | TUR_FLAG_MOVE | TUR_FLAG_ROAM,
6 /* mins,maxs  */ '-32 -32 0', '32 32 48',
7 /* model      */ "ewheel-base2.md3",
8 /* head_model */ "ewheel-gun1.md3",
9 /* netname    */ "ewheel",
10 /* fullname   */ _("eWheel Turret")
11 );
12 #else
13 #ifdef SVQC
14 float autocvar_g_turrets_unit_ewheel_speed_fast;
15 float autocvar_g_turrets_unit_ewheel_speed_slow;
16 float autocvar_g_turrets_unit_ewheel_speed_slower;
17 float autocvar_g_turrets_unit_ewheel_speed_stop;
18 float autocvar_g_turrets_unit_ewheel_turnrate;
19
20 const float ewheel_anim_stop = 0;
21 const float ewheel_anim_fwd_slow = 1;
22 const float ewheel_anim_fwd_fast = 2;
23 const float ewheel_anim_bck_slow = 3;
24 const float ewheel_anim_bck_fast = 4;
25
26 //#define EWHEEL_FANCYPATH
27 void ewheel_move_path()
28 {
29 #ifdef EWHEEL_FANCYPATH
30         // Are we close enougth to a path node to switch to the next?
31         if (vlen(self.origin  - self.pathcurrent.origin) < 64)
32                 if (self.pathcurrent.path_next == world)
33                 {
34                         // Path endpoint reached
35                         pathlib_deletepath(self.pathcurrent.owner);
36                         self.pathcurrent = world;
37
38                         if (self.pathgoal)
39                         {
40                                 if (self.pathgoal.use)
41                                         self.pathgoal.use();
42
43                                 if (self.pathgoal.enemy)
44                                 {
45                                         self.pathcurrent = pathlib_astar(self.pathgoal.origin,self.pathgoal.enemy.origin);
46                                         self.pathgoal = self.pathgoal.enemy;
47                                 }
48                         }
49                         else
50                                 self.pathgoal = world;
51                 }
52                 else
53                         self.pathcurrent = self.pathcurrent.path_next;
54
55 #else
56         if (vlen(self.origin - self.pathcurrent.origin) < 64)
57                 self.pathcurrent = self.pathcurrent.enemy;
58 #endif
59
60         if (self.pathcurrent)
61         {
62
63                 self.moveto = self.pathcurrent.origin;
64                 self.steerto = steerlib_attract2(self.moveto, 0.5, 500, 0.95);
65
66                 movelib_move_simple(v_forward, (autocvar_g_turrets_unit_ewheel_speed_fast), 0.4);
67         }
68 }
69
70 void ewheel_move_enemy()
71 {
72         float newframe;
73
74         self.steerto = steerlib_arrive(self.enemy.origin,self.target_range_optimal);
75         
76         self.moveto  = self.origin + self.steerto * 128;
77
78         if (self.tur_dist_enemy > self.target_range_optimal)
79         {
80                 if ( self.tur_head.spawnshieldtime < 1 )
81                 {
82                         newframe = ewheel_anim_fwd_fast;
83                         movelib_move_simple(v_forward, (autocvar_g_turrets_unit_ewheel_speed_fast), 0.4);
84                 }
85                 else if (self.tur_head.spawnshieldtime < 2)
86                 {
87
88                         newframe = ewheel_anim_fwd_slow;
89                         movelib_move_simple(v_forward, (autocvar_g_turrets_unit_ewheel_speed_slow), 0.4);
90            }
91                 else
92                 {
93                         newframe = ewheel_anim_fwd_slow;
94                         movelib_move_simple(v_forward, (autocvar_g_turrets_unit_ewheel_speed_slower), 0.4);
95                 }
96         }
97         else if (self.tur_dist_enemy < self.target_range_optimal * 0.5)
98         {
99                 newframe = ewheel_anim_bck_slow;
100                 movelib_move_simple(v_forward * -1, (autocvar_g_turrets_unit_ewheel_speed_slow), 0.4);
101         }
102         else
103         {
104                 newframe = ewheel_anim_stop;
105                 movelib_beak_simple((autocvar_g_turrets_unit_ewheel_speed_stop));
106         }
107
108         turrets_setframe(newframe, false);
109 }
110
111 void ewheel_move_idle()
112 {
113         if(self.frame != 0)
114         {
115                 self.SendFlags |= TNSF_ANIM;
116                 self.anim_start_time = time;
117         }
118
119         self.frame = 0;
120         if (vlen(self.velocity))
121                 movelib_beak_simple((autocvar_g_turrets_unit_ewheel_speed_stop));
122 }
123
124 void spawnfunc_turret_ewheel() { if(!turret_initialize(TUR_EWHEEL)) remove(self); }
125
126 float t_ewheel(float req)
127 {
128         switch(req)
129         {
130                 case TR_ATTACK:
131                 {
132                         float i;
133                         entity _mis;
134
135                         for (i = 0; i < 1; ++i)
136                         {
137                                 turret_do_updates(self);
138
139                                 _mis = turret_projectile("weapons/lasergun_fire.wav", 1, 0, DEATH_TURRET_EWHEEL, PROJECTILE_BLASTER, TRUE, TRUE);
140                                 _mis.missile_flags = MIF_SPLASH;
141
142                                 pointparticles(particleeffectnum("laser_muzzleflash"), self.tur_shotorg, self.tur_shotdir_updated * 1000, 1);
143
144                                 self.tur_head.frame += 2;
145
146                                 if (self.tur_head.frame > 3)
147                                         self.tur_head.frame = 0;
148                         }
149                         
150                         return true;
151                 }
152                 case TR_THINK:
153                 {
154                         float vz;
155                         vector wish_angle, real_angle;
156
157                         vz = self.velocity_z;
158
159                         self.angles_x = anglemods(self.angles_x);
160                         self.angles_y = anglemods(self.angles_y);
161
162                         fixedmakevectors(self.angles);
163
164                         wish_angle = normalize(self.steerto);
165                         wish_angle = vectoangles(wish_angle);
166                         real_angle = wish_angle - self.angles;
167                         real_angle = shortangle_vxy(real_angle, self.tur_head.angles);
168
169                         self.tur_head.spawnshieldtime = fabs(real_angle_y);
170                         real_angle_y  = bound(-self.tur_head.aim_speed, real_angle_y, self.tur_head.aim_speed);
171                         self.angles_y = (self.angles_y + real_angle_y);
172
173                         if(self.enemy)
174                                 ewheel_move_enemy();
175                         else if(self.pathcurrent)
176                                 ewheel_move_path();
177                         else
178                                 ewheel_move_idle();
179
180                         self.velocity_z = vz;
181
182                         if(vlen(self.velocity))
183                                 self.SendFlags |= TNSF_MOVE;
184                 
185                         return true;
186                 }
187                 case TR_DEATH:
188                 {
189                         self.velocity = '0 0 0';
190
191 #ifdef EWHEEL_FANCYPATH
192                         if (self.pathcurrent)
193                                 pathlib_deletepath(self.pathcurrent.owner);
194 #endif
195                         self.pathcurrent = world;
196         
197                         return true;
198                 }
199                 case TR_SETUP:
200                 {
201                         entity e;
202                         
203                         if(self.movetype == MOVETYPE_WALK)
204                         {
205                                 self.velocity = '0 0 0';
206                                 self.enemy = world;
207
208                                 setorigin(self, self.pos1);
209
210                                 if (self.target != "")
211                                 {
212                                         e = find(world, targetname, self.target);
213                                         if (!e)
214                                         {
215                                                 dprint("Initital waypoint for ewheel does NOT exsist, fix your map!\n");
216                                                 self.target = "";
217                                         }
218
219                                         if (e.classname != "turret_checkpoint")
220                                                 dprint("Warning: not a turrret path\n");
221                                         else
222                                         {
223
224 #ifdef EWHEEL_FANCYPATH
225                                                 self.pathcurrent = WALKER_PATH(self.origin,e.origin);
226                                                 self.pathgoal = e;
227 #else
228                                                 self.pathcurrent  = e;
229 #endif
230                                         }
231                                 }
232                         }
233                         
234                         self.iscreature                         = true;
235                         self.teleportable                       = TELEPORT_NORMAL;
236                         self.damagedbycontents          = true;
237                         self.movetype                           = MOVETYPE_WALK;
238                         self.solid                                      = SOLID_SLIDEBOX;
239                         self.takedamage                         = DAMAGE_AIM;
240                         self.idle_aim                           = '0 0 0';
241                         self.pos1                                       = self.origin;
242                         self.target_select_flags        = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS;
243                         self.target_validate_flags      = TFL_TARGETSELECT_PLAYERS | TFL_TARGETSELECT_RANGELIMITS | TFL_TARGETSELECT_TEAMCHECK | TFL_TARGETSELECT_LOS;
244                         self.frame                                      = self.tur_head.frame = 1;
245                         self.ammo_flags                         = TFL_AMMO_ENERGY | TFL_AMMO_RECHARGE | TFL_AMMO_RECIEVE;
246                         
247                         // Convert from dgr / sec to dgr / tic
248                         self.tur_head.aim_speed = (autocvar_g_turrets_unit_ewheel_turnrate);
249                         self.tur_head.aim_speed = self.tur_head.aim_speed / (1 / self.ticrate);
250                 
251                         return true;
252                 }
253                 case TR_PRECACHE:
254                 {
255                         precache_model ("models/turrets/ewheel-base2.md3");
256                         precache_model ("models/turrets/ewheel-gun1.md3");
257                         return true;
258                 }
259         }
260
261         return true;
262 }
263
264 #endif // SVQC
265 #ifdef CSQC
266
267 void ewheel_draw()
268 {
269         float dt;
270
271         dt = time - self.move_time;
272         self.move_time = time;
273         if(dt <= 0)
274                 return;
275
276         fixedmakevectors(self.angles);
277         setorigin(self, self.origin + self.velocity * dt);
278         self.tur_head.angles += dt * self.tur_head.move_avelocity;
279         self.angles_y = self.move_angles_y;
280
281         if (self.health < 127)
282         if(random() < 0.05)
283                 te_spark(self.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16);
284 }
285
286 float t_ewheel(float req)
287 {
288         switch(req)
289         {
290                 case TR_SETUP:
291                 {
292                         self.gravity            = 1;
293                         self.movetype           = MOVETYPE_BOUNCE;
294                         self.move_movetype      = MOVETYPE_BOUNCE;
295                         self.move_origin        = self.origin;
296                         self.move_time          = time;
297                         self.draw                       = ewheel_draw;
298                         
299                         return true;
300                 }
301                 case TR_PRECACHE:
302                 {
303                         return true;
304                 }
305         }
306
307         return true;
308 }
309
310 #endif // CSQC
311 #endif // REGISTER_TURRET