Merge branch 'master' into TimePath/unified_weapons
[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 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, self, 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(self, flash, '5 0 0');
147         missile.pos1 = missile.velocity;
148
149         MUTATOR_CALLHOOK(EditProjectile, self, missile);
150 }
151
152                 METHOD(RocketPropelledChainsaw, wr_aim, void(entity thiswep))
153                 {
154                         self.BUTTON_ATCK = bot_aim(WEP_CVAR(rpc, speed), 0, WEP_CVAR(rpc, lifetime), false);
155                 }
156                 METHOD(RocketPropelledChainsaw, wr_think, void(entity thiswep, entity actor, bool fire1, bool fire2))
157                 {
158                         if(WEP_CVAR(rpc, reload_ammo) && actor.clip_load < WEP_CVAR(rpc, ammo)) {
159                                 Weapon w = get_weaponinfo(actor.weapon);
160                                 w.wr_reload(w);
161                         } else
162                         {
163                                 if (fire1)
164                                 {
165                                         if(weapon_prepareattack(actor, false, WEP_CVAR(rpc, refire)))
166                                         {
167                                                 W_RocketPropelledChainsaw_Attack(thiswep);
168                                                 weapon_thinkf(actor, WFRAME_FIRE1, WEP_CVAR(rpc, animtime), w_ready);
169                                         }
170                                 }
171
172                                 if (fire2)
173                                 {
174                                         // to-do
175                                 }
176                         }
177                 }
178                 METHOD(RocketPropelledChainsaw, wr_init, void(entity thiswep))
179                 {
180                         RPC_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP);
181                 }
182                 METHOD(RocketPropelledChainsaw, wr_checkammo1, bool(entity thiswep))
183                 {
184                         float ammo_amount = self.WEP_AMMO(RPC) >= WEP_CVAR(rpc, ammo);
185                         ammo_amount += self.(weapon_load[WEP_RPC.m_id]) >= WEP_CVAR(rpc, ammo);
186                         return ammo_amount;
187                 }
188                 METHOD(RocketPropelledChainsaw, wr_checkammo2, bool(entity thiswep))
189                 {
190                         return false;
191                 }
192                 METHOD(RocketPropelledChainsaw, wr_config, void(entity thiswep))
193                 {
194                         RPC_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS);
195                 }
196                 METHOD(RocketPropelledChainsaw, wr_reload, void(entity thiswep))
197                 {
198                         W_Reload(self, WEP_CVAR(rpc, ammo), SND(RELOAD));
199                 }
200                 METHOD(RocketPropelledChainsaw, wr_suicidemessage, int(entity thiswep))
201                 {
202                         if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
203                                 return WEAPON_RPC_SUICIDE_SPLASH;
204                         else
205                                 return WEAPON_RPC_SUICIDE_DIRECT;
206                 }
207                 METHOD(RocketPropelledChainsaw, wr_killmessage, int(entity thiswep))
208                 {
209                         if(w_deathtype & HITTYPE_SECONDARY)
210                                 return WEAPON_BLASTER_MURDER;
211                         else if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
212                                 return WEAPON_RPC_MURDER_SPLASH;
213                         else
214                                 return WEAPON_RPC_MURDER_DIRECT;
215                 }
216
217 #endif
218
219 #ifdef CSQC
220
221                 METHOD(RocketPropelledChainsaw, wr_impacteffect, void(entity thiswep))
222                 {
223                         vector org2;
224                         org2 = w_org + w_backoff * 12;
225                         pointparticles(particleeffectnum(EFFECT_ROCKET_EXPLODE), org2, '0 0 0', 1);
226                         if(!w_issilent)
227                                 sound(self, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
228                 }
229
230 #endif
231 #endif