]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/weapons/weapon/blaster.qc
Push down spawning logic from spawnfuncs to dedicated spawning functions
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / weapons / weapon / blaster.qc
1 #include "blaster.qh"
2
3 #ifdef SVQC
4
5 void W_Blaster_Touch(entity this, entity toucher)
6 {
7         PROJECTILE_TOUCH(this, toucher);
8
9         this.event_damage = func_null;
10
11         RadiusDamage(
12                 this,
13                 this.realowner,
14                 this.blaster_damage,
15                 this.blaster_edgedamage,
16                 this.blaster_radius,
17                 NULL,
18                 NULL,
19                 this.blaster_force,
20                 this.projectiledeathtype,
21                 toucher
22         );
23
24         delete(this);
25 }
26
27 void W_Blaster_Think(entity this)
28 {
29         set_movetype(this, MOVETYPE_FLY);
30         setthink(this, SUB_Remove);
31         this.nextthink = time + this.blaster_lifetime;
32         CSQCProjectile(this, true, PROJECTILE_BLASTER, true);
33 }
34
35 void W_Blaster_Attack(
36         entity actor,
37         .entity weaponentity,
38         float atk_deathtype,
39         float atk_shotangle,
40         float atk_damage,
41         float atk_edgedamage,
42         float atk_radius,
43         float atk_force,
44         float atk_speed,
45         float atk_spread,
46         float atk_delay,
47         float atk_lifetime)
48 {
49         vector s_forward = v_forward * cos(atk_shotangle * DEG2RAD) + v_up * sin(atk_shotangle * DEG2RAD);
50
51         W_SetupShot_Dir(actor, weaponentity, s_forward, false, 3, SND_LASERGUN_FIRE, CH_WEAPON_B, atk_damage);
52         Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
53
54         entity missile = new(blasterbolt);
55         missile.owner = missile.realowner = actor;
56         missile.bot_dodge = true;
57         missile.bot_dodgerating = atk_damage;
58         PROJECTILE_MAKETRIGGER(missile);
59
60         missile.blaster_damage = atk_damage;
61         missile.blaster_edgedamage = atk_edgedamage;
62         missile.blaster_radius = atk_radius;
63         missile.blaster_force = atk_force;
64         missile.blaster_lifetime = atk_lifetime;
65
66         setorigin(missile, w_shotorg);
67         setsize(missile, '0 0 0', '0 0 0');
68
69         W_SetupProjVelocity_Explicit(
70                 missile,
71                 w_shotdir,
72                 v_up,
73                 atk_speed,
74                 0,
75                 0,
76                 atk_spread,
77                 false
78         );
79
80         missile.angles = vectoangles(missile.velocity);
81
82         //missile.glow_color = 250; // 244, 250
83         //missile.glow_size = 120;
84
85         settouch(missile, W_Blaster_Touch);
86         missile.flags = FL_PROJECTILE;
87         IL_PUSH(g_projectiles, missile);
88         IL_PUSH(g_bot_dodge, missile);
89         missile.missile_flags = MIF_SPLASH;
90         missile.projectiledeathtype = atk_deathtype;
91         setthink(missile, W_Blaster_Think);
92         missile.nextthink = time + atk_delay;
93
94         MUTATOR_CALLHOOK(EditProjectile, actor, missile);
95
96         if (time >= missile.nextthink)
97         {
98                 getthink(missile)(missile);
99         }
100 }
101
102 METHOD(Blaster, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
103 {
104     if(WEP_CVAR(blaster, secondary))
105     {
106         if((random() * (WEP_CVAR_PRI(blaster, damage) + WEP_CVAR_SEC(blaster, damage))) > WEP_CVAR_PRI(blaster, damage))
107             { PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, WEP_CVAR_SEC(blaster, speed), 0, WEP_CVAR_SEC(blaster, lifetime), false); }
108         else
109             { PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(blaster, speed), 0, WEP_CVAR_PRI(blaster, lifetime), false); }
110     }
111     else
112         { PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(blaster, speed), 0, WEP_CVAR_PRI(blaster, lifetime), false); }
113 }
114
115 METHOD(Blaster, wr_think, void(Blaster thiswep, entity actor, .entity weaponentity, int fire))
116 {
117     if(fire & 1)
118     {
119         if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(blaster, refire)))
120         {
121             W_Blaster_Attack(
122                 actor,
123                 weaponentity,
124                 WEP_BLASTER.m_id,
125                 WEP_CVAR_PRI(blaster, shotangle),
126                 WEP_CVAR_PRI(blaster, damage),
127                 WEP_CVAR_PRI(blaster, edgedamage),
128                 WEP_CVAR_PRI(blaster, radius),
129                 WEP_CVAR_PRI(blaster, force),
130                 WEP_CVAR_PRI(blaster, speed),
131                 WEP_CVAR_PRI(blaster, spread),
132                 WEP_CVAR_PRI(blaster, delay),
133                 WEP_CVAR_PRI(blaster, lifetime)
134             );
135             weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(blaster, animtime), w_ready);
136         }
137     }
138     else if(fire & 2)
139     {
140         switch(WEP_CVAR(blaster, secondary))
141         {
142             case 0: // switch to last used weapon
143             {
144                 if(actor.(weaponentity).m_switchweapon == WEP_BLASTER) // don't do this if already switching
145                     W_LastWeapon(actor, weaponentity);
146                 break;
147             }
148
149             case 1: // normal projectile secondary
150             {
151                 if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(blaster, refire)))
152                 {
153                     W_Blaster_Attack(
154                         actor,
155                         weaponentity,
156                         WEP_BLASTER.m_id | HITTYPE_SECONDARY,
157                         WEP_CVAR_SEC(blaster, shotangle),
158                         WEP_CVAR_SEC(blaster, damage),
159                         WEP_CVAR_SEC(blaster, edgedamage),
160                         WEP_CVAR_SEC(blaster, radius),
161                         WEP_CVAR_SEC(blaster, force),
162                         WEP_CVAR_SEC(blaster, speed),
163                         WEP_CVAR_SEC(blaster, spread),
164                         WEP_CVAR_SEC(blaster, delay),
165                         WEP_CVAR_SEC(blaster, lifetime)
166                     );
167                     weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(blaster, animtime), w_ready);
168                 }
169
170                 break;
171             }
172         }
173     }
174 }
175
176 METHOD(Blaster, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
177 {
178     return true; // infinite ammo
179 }
180
181 METHOD(Blaster, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
182 {
183     return true; // blaster has infinite ammo
184 }
185
186 METHOD(Blaster, wr_suicidemessage, Notification(entity thiswep))
187 {
188     return WEAPON_BLASTER_SUICIDE;
189 }
190
191 METHOD(Blaster, wr_killmessage, Notification(entity thiswep))
192 {
193     return WEAPON_BLASTER_MURDER;
194 }
195
196 #endif
197 #ifdef CSQC
198
199 METHOD(Blaster, wr_impacteffect, void(entity thiswep, entity actor))
200 {
201     vector org2;
202     org2 = w_org + w_backoff * 6;
203     pointparticles(EFFECT_BLASTER_IMPACT, org2, w_backoff * 1000, 1);
204     if(!w_issilent) { sound(actor, CH_SHOTS, SND_LASERIMPACT, VOL_BASE, ATTN_NORM); }
205 }
206
207 #endif