d18b268878d5516f7c18ef82402d34827e28c233
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / weapons / weapon / rpc.qc
1 #ifndef IMPLEMENTATION
2 CLASS(RocketPropelledChainsaw, Weapon)
3 /* ammotype  */ ATTRIB(RocketPropelledChainsaw, ammo_field, .int, ammo_rockets)
4 /* impulse   */ ATTRIB(RocketPropelledChainsaw, impulse, int, 7)
5 /* flags     */ ATTRIB(RocketPropelledChainsaw, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_FLAG_RELOADABLE | WEP_TYPE_SPLASH | WEP_FLAG_SUPERWEAPON);
6 /* rating    */ ATTRIB(RocketPropelledChainsaw, bot_pickupbasevalue, float, BOT_PICKUP_RATING_HIGH);
7 /* color     */ ATTRIB(RocketPropelledChainsaw, wpcolor, vector, '0.5 0.5 0');
8 /* modelname */ ATTRIB(RocketPropelledChainsaw, mdl, string, "ok_rl");
9 #ifndef MENUQC
10 /* model     */ ATTRIB(RocketPropelledChainsaw, m_model, Model, MDL_RPC_ITEM);
11 #endif
12 /* crosshair */ ATTRIB(RocketPropelledChainsaw, w_crosshair, string, "gfx/crosshairrocketlauncher");
13 /* crosshair */ ATTRIB(RocketPropelledChainsaw, w_crosshair_size, float, 0.6);
14 /* wepimg    */ ATTRIB(RocketPropelledChainsaw, model2, string, "weaponrpc");
15 /* refname   */ ATTRIB(RocketPropelledChainsaw, netname, string, "rpc");
16 /* wepname   */ ATTRIB(RocketPropelledChainsaw, message, string, _("Rocket Propelled Chainsaw"));
17 ENDCLASS(RocketPropelledChainsaw)
18 REGISTER_WEAPON(RPC, NEW(RocketPropelledChainsaw));
19
20 #define RPC_SETTINGS(w_cvar,w_prop) RPC_SETTINGS_LIST(w_cvar, w_prop, RPC, rpc)
21 #define RPC_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
22         w_cvar(id, sn, NONE, ammo) \
23         w_cvar(id, sn, NONE, animtime) \
24         w_cvar(id, sn, NONE, damage) \
25         w_cvar(id, sn, NONE, damage2) \
26         w_cvar(id, sn, NONE, damageforcescale) \
27         w_cvar(id, sn, NONE, edgedamage) \
28         w_cvar(id, sn, NONE, force) \
29         w_cvar(id, sn, NONE, health) \
30         w_cvar(id, sn, NONE, lifetime) \
31         w_cvar(id, sn, NONE, radius) \
32         w_cvar(id, sn, NONE, refire) \
33         w_cvar(id, sn, NONE, speed) \
34         w_cvar(id, sn, NONE, speedaccel) \
35         w_prop(id, sn, float,  reloading_ammo, reload_ammo) \
36         w_prop(id, sn, float,  reloading_time, reload_time) \
37         w_prop(id, sn, float,  switchdelay_raise, switchdelay_raise) \
38         w_prop(id, sn, float,  switchdelay_drop, switchdelay_drop) \
39         w_prop(id, sn, string, weaponreplace, weaponreplace) \
40         w_prop(id, sn, float,  weaponstart, weaponstart) \
41         w_prop(id, sn, float,  weaponstartoverride, weaponstartoverride) \
42         w_prop(id, sn, float,  weaponthrowable, weaponthrowable)
43
44 #ifdef SVQC
45 RPC_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
46 #endif
47 #endif
48 #ifdef IMPLEMENTATION
49 #ifdef SVQC
50 void spawnfunc_weapon_rpc() { weapon_defaultspawnfunc(WEP_RPC.m_id); }
51
52 void W_RocketPropelledChainsaw_Explode()
53 {SELFPARAM();
54         self.event_damage = func_null;
55         self.takedamage = DAMAGE_NO;
56
57         RadiusDamage (self, self.realowner, WEP_CVAR(rpc, damage), WEP_CVAR(rpc, edgedamage), WEP_CVAR(rpc, radius), world, world, WEP_CVAR(rpc, force), self.projectiledeathtype, other);
58
59         remove (self);
60 }
61
62 void W_RocketPropelledChainsaw_Touch (void)
63 {SELFPARAM();
64         if(WarpZone_Projectile_Touch())
65                 if(wasfreed(self))
66                         return;
67
68         W_RocketPropelledChainsaw_Explode();
69 }
70
71 void W_RocketPropelledChainsaw_Damage (entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
72 {SELFPARAM();
73         if (self.health <= 0)
74                 return;
75
76         if (!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, -1)) // no exceptions
77                 return; // g_projectiles_damage says to halt
78
79         self.health = self.health - damage;
80
81         if (self.health <= 0)
82                 W_PrepareExplosionByDamage(attacker, W_RocketPropelledChainsaw_Explode);
83 }
84
85 void W_RocketPropelledChainsaw_Think()
86 {SELFPARAM();
87         if(self.cnt <= time)
88         {
89                 remove(self);
90                 return;
91         }
92
93         self.cnt = vlen(self.velocity);
94         self.wait = self.cnt * sys_frametime;
95         self.pos1 = normalize(self.velocity);
96
97         tracebox(self.origin, self.mins, self.maxs, self.origin + self.pos1 * (2 * self.wait), MOVE_NORMAL, self);
98         if(IS_PLAYER(trace_ent))
99                 Damage (trace_ent, self, self.realowner, WEP_CVAR(rpc, damage2), self.projectiledeathtype, self.origin, normalize(self.origin - other.origin) * WEP_CVAR(rpc, force));
100
101         self.velocity = self.pos1 * (self.cnt + (WEP_CVAR(rpc, speedaccel) * sys_frametime));
102
103         UpdateCSQCProjectile(self);
104         self.nextthink = time;
105 }
106
107 void W_RocketPropelledChainsaw_Attack (Weapon thiswep)
108 {SELFPARAM();
109         entity missile = spawn(); //WarpZone_RefSys_SpawnSameRefSys(self);
110         entity flash = spawn ();
111
112         W_DecreaseAmmo(thiswep, WEP_CVAR(rpc, ammo));
113         W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', false, 5, SND(ROCKET_FIRE), CH_WEAPON_A, WEP_CVAR(rpc, damage));
114         Send_Effect(EFFECT_ROCKET_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
115         PROJECTILE_MAKETRIGGER(missile);
116
117         missile.owner = missile.realowner = self;
118         missile.bot_dodge = true;
119         missile.bot_dodgerating = WEP_CVAR(rpc, damage) * 2;
120
121         missile.takedamage = DAMAGE_YES;
122         missile.damageforcescale = WEP_CVAR(rpc, damageforcescale);
123         missile.health = WEP_CVAR(rpc, health);
124         missile.event_damage = W_RocketPropelledChainsaw_Damage;
125         missile.damagedbycontents = true;
126         missile.movetype = MOVETYPE_FLY;
127
128         missile.projectiledeathtype = WEP_RPC.m_id;
129         setsize (missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
130
131         setorigin (missile, w_shotorg - v_forward * 3); // move it back so it hits the wall at the right point
132         W_SetupProjVelocity_Basic(missile, WEP_CVAR(rpc, speed), 0);
133
134         missile.touch = W_RocketPropelledChainsaw_Touch;
135
136         missile.think = W_RocketPropelledChainsaw_Think;
137         missile.cnt = time + WEP_CVAR(rpc, lifetime);
138         missile.nextthink = time;
139         missile.flags = FL_PROJECTILE;
140
141         CSQCProjectile(missile, true, PROJECTILE_RPC, false);
142
143         setmodel(flash, MDL_RPC_MUZZLEFLASH); // precision set below
144         SUB_SetFade (flash, time, 0.1);
145         flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
146         W_AttachToShotorg(flash, '5 0 0');
147         missile.pos1 = missile.velocity;
148
149         MUTATOR_CALLHOOK(EditProjectile, self, missile);
150 }
151
152                 METHOD(RocketPropelledChainsaw, wr_aim, bool(entity thiswep))
153                 {
154                         self.BUTTON_ATCK = bot_aim(WEP_CVAR(rpc, speed), 0, WEP_CVAR(rpc, lifetime), false);
155                         return true;
156                 }
157                 METHOD(RocketPropelledChainsaw, wr_think, bool(entity thiswep, bool fire1, bool fire2))
158                 {
159                         if(WEP_CVAR(rpc, reload_ammo) && self.clip_load < WEP_CVAR(rpc, ammo)) {
160                                 Weapon w = get_weaponinfo(self.weapon);
161                                 w.wr_reload(w);
162                         } else
163                         {
164                                 if (fire1)
165                                 {
166                                         if(weapon_prepareattack(false, WEP_CVAR(rpc, refire)))
167                                         {
168                                                 W_RocketPropelledChainsaw_Attack(thiswep);
169                                                 weapon_thinkf(WFRAME_FIRE1, WEP_CVAR(rpc, animtime), w_ready);
170                                         }
171                                 }
172
173                                 if (fire2)
174                                 {
175                                         // to-do
176                                 }
177                         }
178
179                         return true;
180                 }
181                 METHOD(RocketPropelledChainsaw, wr_init, bool(entity thiswep))
182                 {
183                         RPC_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
184                         return true;
185                 }
186                 METHOD(RocketPropelledChainsaw, wr_checkammo1, bool(entity thiswep))
187                 {
188                         float ammo_amount = self.WEP_AMMO(RPC) >= WEP_CVAR(rpc, ammo);
189                         ammo_amount += self.(weapon_load[WEP_RPC.m_id]) >= WEP_CVAR(rpc, ammo);
190                         return ammo_amount;
191                 }
192                 METHOD(RocketPropelledChainsaw, wr_checkammo2, bool(entity thiswep))
193                 {
194                         return false;
195                 }
196                 METHOD(RocketPropelledChainsaw, wr_config, bool(entity thiswep))
197                 {
198                         RPC_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS);
199                         return true;
200                 }
201                 METHOD(RocketPropelledChainsaw, wr_reload, bool(entity thiswep))
202                 {
203                         W_Reload(WEP_CVAR(rpc, ammo), SND(RELOAD));
204                         return true;
205                 }
206                 METHOD(RocketPropelledChainsaw, wr_suicidemessage, bool(entity thiswep))
207                 {
208                         if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
209                                 return WEAPON_RPC_SUICIDE_SPLASH;
210                         else
211                                 return WEAPON_RPC_SUICIDE_DIRECT;
212                 }
213                 METHOD(RocketPropelledChainsaw, wr_killmessage, bool(entity thiswep))
214                 {
215                         if(w_deathtype & HITTYPE_SECONDARY)
216                                 return WEAPON_BLASTER_MURDER;
217                         else if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
218                                 return WEAPON_RPC_MURDER_SPLASH;
219                         else
220                                 return WEAPON_RPC_MURDER_DIRECT;
221                 }
222
223 #endif
224
225 #ifdef CSQC
226
227                 METHOD(RocketPropelledChainsaw, wr_impacteffect, bool(entity thiswep))
228                 {
229                         vector org2;
230                         org2 = w_org + w_backoff * 12;
231                         pointparticles(particleeffectnum(EFFECT_ROCKET_EXPLODE), org2, '0 0 0', 1);
232                         if(!w_issilent)
233                                 sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
234
235                         return true;
236                 }
237                 METHOD(RocketPropelledChainsaw, wr_init, bool(entity thiswep))
238                 {
239                         return true;
240                 }
241                 METHOD(RocketPropelledChainsaw, wr_zoomreticle, bool(entity thiswep))
242                 {
243                         // no weapon specific image for this weapon
244                         return false;
245                 }
246
247 #endif
248 #endif