]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/monsters/monster/brute.qc
Minor cleanup
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / monsters / monster / brute.qc
1 const vector BRUTE_MIN = '-36 -36 -20';
2 const vector BRUTE_MAX = '36 36 50';
3
4 string BRUTE_MODEL = "models/monsters/ogre.dpm";
5
6 #ifdef SVQC
7 float autocvar_g_monster_brute;
8 float autocvar_g_monster_brute_health;
9 float autocvar_g_monster_brute_chainsaw_damage;
10 float autocvar_g_monster_brute_speed_walk;
11 float autocvar_g_monster_brute_speed_run;
12 float autocvar_g_monster_brute_attack_uzi_bullets;
13 float autocvar_g_monster_brute_attack_uzi_damage;
14 float autocvar_g_monster_brute_attack_uzi_force;
15 float autocvar_g_monster_brute_attack_uzi_chance;
16 float autocvar_g_monster_brute_attack_grenade_damage;
17 float autocvar_g_monster_brute_attack_grenade_edgedamage;
18 float autocvar_g_monster_brute_attack_grenade_force;
19 float autocvar_g_monster_brute_attack_grenade_radius;
20
21 const float brute_anim_idle             = 0;
22 const float brute_anim_walk             = 1;
23 const float brute_anim_run                      = 2;
24 const float brute_anim_pain             = 3;
25 const float brute_anim_swing            = 4;
26 const float brute_anim_die                      = 5;
27
28 .float brute_cycles;
29
30 void brute_think()
31 {
32         self.think = brute_think;
33         self.nextthink = time + self.ticrate;
34         
35         monster_move(autocvar_g_monster_brute_speed_run, autocvar_g_monster_brute_speed_walk, 300, brute_anim_run, brute_anim_walk, brute_anim_idle);
36 }
37
38 void brute_blade()
39 {
40         self.brute_cycles += 1;
41         self.angles_y = self.angles_y + random()* 25;
42         self.delay = time + 0.2;
43         self.monster_delayedattack = brute_blade;
44         
45         monster_melee(self.enemy, autocvar_g_monster_brute_chainsaw_damage, 0.3, DEATH_MONSTER_BRUTE_BLADE, TRUE);
46         
47         if(self.brute_cycles >= 4)
48         {
49                 self.monster_delayedattack = func_null;
50                 self.delay = -1;
51         }
52 }
53
54 void brute_uzi()
55 {
56         self.brute_cycles += 1;
57         
58         if(self.brute_cycles > autocvar_g_monster_brute_attack_uzi_bullets)
59         {
60                 self.monster_delayedattack = func_null;
61                 self.delay = -1;
62                 return;
63         }
64         
65         monster_makevectors(self.enemy);
66         
67         W_SetupShot (self, autocvar_g_antilag_bullets && 18000 >= autocvar_g_antilag_bullets, 0, "weapons/uzi_fire.wav", CH_WEAPON_A, autocvar_g_monster_brute_attack_uzi_damage);
68         fireBallisticBullet(w_shotorg, w_shotdir, 0.02, 18000, 5, autocvar_g_monster_brute_attack_uzi_damage, autocvar_g_monster_brute_attack_uzi_force, DEATH_MONSTER_BRUTE_UZI, 0, 1, 115);
69         endFireBallisticBullet();
70         
71         self.delay = time + 0.1;
72         self.monster_delayedattack = brute_uzi;
73 }
74
75 void brute_grenade_explode()
76 {
77         pointparticles(particleeffectnum("grenade_explode"), self.origin, '0 0 0', 1);
78         sound(self, CH_SHOTS, "weapons/grenade_impact.wav", VOL_BASE, ATTN_NORM);
79
80         self.event_damage = func_null;
81         self.takedamage = DAMAGE_NO;
82
83         if(self.movetype == MOVETYPE_NONE)
84                 self.velocity = self.oldvelocity;
85
86         RadiusDamage (self, self.realowner, autocvar_g_monster_brute_attack_grenade_damage, autocvar_g_monster_brute_attack_grenade_edgedamage, autocvar_g_monster_brute_attack_grenade_radius, world, autocvar_g_monster_brute_attack_grenade_force, self.projectiledeathtype, other);
87
88         remove (self);
89 }
90
91 void brute_grenade_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
92 {
93         if (self.health <= 0)
94                 return;
95                 
96         if (!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, -1)) // no exceptions
97                 return; // g_projectiles_damage says to halt
98                 
99         self.health = self.health - damage;
100         
101         if (self.health <= 0)
102                 W_PrepareExplosionByDamage(attacker, self.use);
103 }
104
105 void brute_grenade_touch()
106 {
107         PROJECTILE_TOUCH;
108         
109         self.use ();
110 }
111
112 void brute_grenade_think()
113 {
114         self.nextthink = time;
115         if (time > self.cnt)
116         {
117                 other = world;
118                 brute_grenade_explode();
119                 return;
120         }
121 }
122
123 void brute_grenade()
124 {
125         entity gren;
126
127         W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', FALSE, 4, "weapons/grenade_fire.wav", CH_WEAPON_A, autocvar_g_monster_brute_attack_grenade_damage);
128         w_shotdir = v_forward; // no TrueAim for grenades please
129
130         gren = spawn ();
131         gren.owner = gren.realowner = self;
132         gren.classname = "grenade";
133         gren.bot_dodge = TRUE;
134         gren.bot_dodgerating = autocvar_g_monster_brute_attack_grenade_damage;
135         gren.movetype = MOVETYPE_BOUNCE;
136         PROJECTILE_MAKETRIGGER(gren);
137         gren.projectiledeathtype = DEATH_MONSTER_BRUTE_GRENADE;
138         setorigin(gren, w_shotorg);
139         setsize(gren, '-3 -3 -3', '3 3 3');
140
141         gren.cnt = time + 5;
142         gren.nextthink = time;
143         gren.think = brute_grenade_think;
144         gren.use = brute_grenade_explode;
145         gren.touch = brute_grenade_touch;
146
147         gren.takedamage = DAMAGE_YES;
148         gren.health = autocvar_g_balance_grenadelauncher_primary_health;
149         gren.damageforcescale = autocvar_g_balance_grenadelauncher_primary_damageforcescale;
150         gren.event_damage = brute_grenade_damage;
151         gren.damagedbycontents = TRUE;
152         gren.missile_flags = MIF_SPLASH | MIF_ARC;
153         W_SETUPPROJECTILEVELOCITY_UP(gren, g_balance_grenadelauncher_primary);
154
155         gren.angles = vectoangles (gren.velocity);
156         gren.flags = FL_PROJECTILE;
157
158         CSQCProjectile(gren, TRUE, PROJECTILE_GRENADE, TRUE);
159 }
160
161 float brute_attack(float attack_type)
162 {
163         switch(attack_type)
164         {
165                 case MONSTER_ATTACK_MELEE:
166                 {
167                         self.brute_cycles = 0;
168                         monsters_setframe(brute_anim_swing);
169                         self.attack_finished_single = time + 1.3;
170                         brute_blade();
171                         
172                         return TRUE;
173                 }
174                 case MONSTER_ATTACK_RANGED:
175                 {
176                         self.brute_cycles = 0;
177                         if(random() <= autocvar_g_monster_brute_attack_uzi_chance)
178                         {
179                                 monsters_setframe(brute_anim_pain);
180                                 self.attack_finished_single = time + 0.8;
181                                 self.delay = time + 0.1;
182                                 self.monster_delayedattack = brute_uzi;
183                         }
184                         else
185                         {
186                                 monster_makevectors(self.enemy);
187                                 brute_grenade();
188                                 monsters_setframe(brute_anim_pain);
189                                 self.attack_finished_single = time + 1.2;
190                         }
191                         
192                         return TRUE;
193                 }
194         }
195         
196         return FALSE;
197 }
198
199 void brute_die()
200 {
201         Monster_CheckDropCvars ("brute");
202         
203         self.think = monster_dead_think;
204         self.nextthink = time + self.ticrate;
205         self.ltime = time + 5;
206         monsters_setframe(brute_anim_die);
207                 
208         monster_hook_death(); // for post-death mods
209 }
210
211 void brute_spawn()
212 {
213         if not(self.health)
214                 self.health = autocvar_g_monster_brute_health;
215
216         self.damageforcescale   = 0.003;
217         self.classname                  = "monster_brute";
218         self.monster_attackfunc = brute_attack;
219         self.nextthink                  = time + random() * 0.5 + 0.1;
220         self.think                              = brute_think;
221         self.weapon                             = WEP_GRENADE_LAUNCHER;
222         
223         monsters_setframe(brute_anim_idle);
224         
225         monster_setupsounds("brute");
226         
227         monster_hook_spawn(); // for post-spawn mods
228 }
229
230 void spawnfunc_monster_brute()
231 {
232         if not(autocvar_g_monster_brute) { remove(self); return; }
233         
234         self.monster_spawnfunc = spawnfunc_monster_brute;
235         
236         if(Monster_CheckAppearFlags(self))
237                 return;
238         
239         if not (monster_initialize(
240                          "Brute", MONSTER_BRUTE,
241                          BRUTE_MIN, BRUTE_MAX,
242                          FALSE,
243                          brute_die, brute_spawn))
244         {
245                 remove(self);
246                 return;
247         }
248 }
249
250 #endif // SVQC