]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/monsters/monster/shambler.qc
Replace enforcer model with e-wheel
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / monsters / monster / shambler.qc
1 // size
2 const vector SHAMBLER_MIN = '-32 -32 -24';
3 const vector SHAMBLER_MAX = '32 32 64';
4
5 // cvars
6 float autocvar_g_monster_shambler;
7 float autocvar_g_monster_shambler_health;
8 float autocvar_g_monster_shambler_damage;
9 float autocvar_g_monster_shambler_attack_lightning_damage;
10 float autocvar_g_monster_shambler_attack_claw_damage;
11 float autocvar_g_monster_shambler_speed_walk;
12 float autocvar_g_monster_shambler_speed_run;
13
14 // animations
15 #define shambler_anim_stand     0
16 #define shambler_anim_walk              1
17 #define shambler_anim_run               2
18 #define shambler_anim_smash     3
19 #define shambler_anim_swingr    4
20 #define shambler_anim_swingl    5
21 #define shambler_anim_magic     6
22 #define shambler_anim_pain              7
23 #define shambler_anim_death     8
24
25 void shambler_think ()
26 {
27         self.think = shambler_think;
28         self.nextthink = time + 0.1;
29         
30         monster_move(autocvar_g_monster_shambler_speed_run, autocvar_g_monster_shambler_speed_walk, 300, shambler_anim_run, shambler_anim_walk, shambler_anim_stand);
31 }
32
33 void shambler_smash ()
34 {
35         float bigdmg = autocvar_g_monster_shambler_damage * self.scale;
36         
37         self.think = shambler_think;
38         self.attack_finished_single = time + 0.4;
39         self.nextthink = self.attack_finished_single;
40
41         if (!self.enemy)
42                 return;
43
44         if (enemy_range() > 100 * self.scale)
45                 return;
46         
47         Damage(self.enemy, self, self, bigdmg * monster_skill, DEATH_MONSTER_SHAMBLER_MELEE, self.enemy.origin, normalize(self.enemy.origin - self.origin));
48 }
49
50 void shambler_delayedsmash ()
51 {
52         self.frame = shambler_anim_smash;
53         self.think = shambler_smash;
54         self.nextthink = time + 0.7;
55 }
56
57 void ShamClaw (float side)
58 {
59         float bigdmg = autocvar_g_monster_shambler_attack_claw_damage * self.scale;
60         
61         monster_melee(self.enemy, bigdmg * monster_skill, 100, DEATH_MONSTER_SHAMBLER_CLAW);
62 }
63
64 void() shambler_swing_right;
65 void shambler_swing_left ()
66 {
67         self.frame = shambler_anim_swingl;
68         ShamClaw(250);
69         self.attack_finished_single = time + 0.8;
70         self.nextthink = self.attack_finished_single;
71         self.think = shambler_think;
72         if(random() < 0.5)
73                 self.think = shambler_swing_right;
74 }
75
76 void shambler_swing_right ()
77 {
78         self.frame = shambler_anim_swingr;
79         ShamClaw(-250);
80         self.attack_finished_single = time + 0.8;
81         self.nextthink = self.attack_finished_single;
82         self.think = shambler_think;
83         if(random() < 0.5)
84                 self.think = shambler_swing_left;
85 }
86
87 void sham_melee ()
88 {
89         local float chance = random();
90
91         if (chance > 0.6)
92                 shambler_delayedsmash();
93         else if (chance > 0.3)
94                 shambler_swing_right ();
95         else
96                 shambler_swing_left ();
97 }
98
99 void CastLightning ()
100 {
101         self.nextthink = time + 0.4;
102         self.think = shambler_think;
103         
104         local vector org = '0 0 0', dir = '0 0 0';
105         vector v = '0 0 0';
106
107         self.effects |= EF_MUZZLEFLASH;
108
109         org = self.origin + '0 0 40' * self.scale;
110
111         dir = self.enemy.origin + '0 0 16' - org;
112         dir = normalize (dir);
113
114         traceline (org, self.origin + dir * 1000, TRUE, self);
115                 
116         FireRailgunBullet (org, org + dir * 1000, autocvar_g_monster_shambler_attack_lightning_damage * monster_skill, 0, 0, 0, 0, 0, DEATH_MONSTER_SHAMBLER_LIGHTNING);
117         
118         // teamcolor / hit beam effect
119         v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
120         WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3"), org, v);
121 }
122
123 void shambler_magic ()
124 {
125         self.frame = shambler_anim_magic;
126         self.attack_finished_single = time + 1.1;
127         self.nextthink = time + 0.6;
128         self.think = CastLightning;
129 }
130         
131 float sham_lightning ()
132 {
133         shambler_magic();
134         return TRUE;
135 }
136
137 void shambler_die ()
138 {
139         Monster_CheckDropCvars ("shambler");
140         
141         W_ThrowNewWeapon(self, WEP_NEX, 0, self.origin, self.velocity);
142         
143         self.think                      = Monster_Fade;
144         self.solid                      = SOLID_NOT;
145         self.takedamage         = DAMAGE_NO;
146         self.event_damage   = func_null;
147         self.enemy                      = world;
148         self.nextthink          = time + 2.1;
149         self.frame                      = shambler_anim_death;
150         self.pain_finished  = self.nextthink;
151         self.movetype           = MOVETYPE_TOSS;
152         
153         monster_hook_death(); // for post-death mods
154 }
155
156 void shambler_spawn ()
157 {
158         if not(self.health)
159                 self.health = autocvar_g_monster_shambler_health * self.scale;
160
161         self.damageforcescale   = 0.003;
162         self.classname                  = "monster_shambler";
163         self.attack_melee               = sham_melee;
164         self.checkattack                = GenericCheckAttack;
165         self.attack_ranged              = sham_lightning;
166         self.nextthink                  = time + random() * 0.5 + 0.1;
167         self.frame                              = shambler_anim_stand;
168         self.think                              = shambler_think;
169         self.sprite_height              = 70 * self.scale;
170         
171         monster_hook_spawn(); // for post-spawn mods
172 }
173
174 void spawnfunc_monster_shambler ()
175 {       
176         if not(autocvar_g_monster_shambler) { remove(self); return; }
177         
178         self.monster_spawnfunc = spawnfunc_monster_shambler;
179         
180         if(self.spawnflags & MONSTERFLAG_APPEAR)
181         {
182                 self.think = func_null;
183                 self.nextthink = -1;
184                 self.use = Monster_Appear;
185                 return;
186         }
187         
188         self.scale = 1.3;
189         
190         if not (monster_initialize(
191                          "Shambler",
192                          "models/monsters/shambler.mdl",
193                          SHAMBLER_MIN, SHAMBLER_MAX,
194                          FALSE,
195                          shambler_die, shambler_spawn))
196         {
197                 remove(self);
198                 return;
199         }
200         
201         precache_model ("progs/beam.mdl");
202         precache_model ("models/weapons/g_nex.md3");
203         
204         precache_sound ("weapons/lgbeam_fire.wav");
205 }