]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/monsters/monster/shambler.qc
Merge branch 'master' into Mario/monsters
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / monsters / monster / shambler.qc
1 // size
2 const vector SHAMBLER_MIN = '-41 -41 -31';
3 const vector SHAMBLER_MAX = '41 41 65';
4
5 // model
6 string SHAMBLER_MODEL = "models/monsters/shambler.mdl";
7
8 #ifdef SVQC
9 // cvars
10 float autocvar_g_monster_shambler;
11 float autocvar_g_monster_shambler_health;
12 float autocvar_g_monster_shambler_damage;
13 float autocvar_g_monster_shambler_attack_lightning_damage;
14 float autocvar_g_monster_shambler_attack_claw_damage;
15 float autocvar_g_monster_shambler_speed_walk;
16 float autocvar_g_monster_shambler_speed_run;
17
18 // animations
19 const float shambler_anim_stand         = 0;
20 const float shambler_anim_walk          = 1;
21 const float shambler_anim_run           = 2;
22 const float shambler_anim_smash         = 3;
23 const float shambler_anim_swingr        = 4;
24 const float shambler_anim_swingl        = 5;
25 const float shambler_anim_magic         = 6;
26 const float shambler_anim_pain          = 7;
27 const float shambler_anim_death         = 8;
28
29 void shambler_think ()
30 {
31         self.think = shambler_think;
32         self.nextthink = time + self.ticrate;
33         
34         monster_move(autocvar_g_monster_shambler_speed_run, autocvar_g_monster_shambler_speed_walk, 300, shambler_anim_run, shambler_anim_walk, shambler_anim_stand);
35 }
36
37 void shambler_smash ()
38 {
39         self.monster_delayedattack = func_null;
40         self.delay = -1;
41         
42         monster_melee(self.enemy, autocvar_g_monster_shambler_damage, 0.3, DEATH_MONSTER_SHAMBLER_SMASH, TRUE);
43 }
44
45 void shambler_delayedsmash ()
46 {
47         monsters_setframe(shambler_anim_smash);
48         self.monster_delayedattack = shambler_smash;
49         self.delay = time + 0.7;
50         self.attack_finished_single = time + 1.1;
51 }
52
53 void() shambler_swing_right;
54 void shambler_swing_left ()
55 {
56         monsters_setframe(shambler_anim_swingl);
57         monster_melee(self.enemy, autocvar_g_monster_shambler_attack_claw_damage, 0.3, DEATH_MONSTER_SHAMBLER_CLAW, TRUE);
58         self.attack_finished_single = time + 0.8;
59         self.delay = -1;
60         self.monster_delayedattack = func_null;
61         if(random() < 0.5)
62         {
63                 self.monster_delayedattack = shambler_swing_right;
64                 self.delay = time + 0.5;
65         }
66 }
67
68 void shambler_swing_right ()
69 {
70         monsters_setframe(shambler_anim_swingr);
71         monster_melee(self.enemy, autocvar_g_monster_shambler_attack_claw_damage, 0.3, DEATH_MONSTER_SHAMBLER_CLAW, TRUE);
72         self.attack_finished_single = time + 0.8;
73         self.monster_delayedattack = func_null;
74         self.delay = -1;
75         if(random() < 0.5)
76         {
77                 self.monster_delayedattack = shambler_swing_left;
78                 self.delay = time + 0.5;
79         }
80 }
81
82 void CastLightning ()
83 {
84         self.monster_delayedattack = func_null;
85         self.delay = -1;
86
87         local vector org = '0 0 0', dir = '0 0 0';
88         vector v = '0 0 0';
89
90         self.effects |= EF_MUZZLEFLASH;
91
92         org = self.origin + '0 0 40';
93
94         dir = self.enemy.origin + '0 0 16' - org;
95         dir = normalize (dir);
96
97         traceline (org, self.origin + dir * 1000, TRUE, self);
98                 
99         FireRailgunBullet (org, org + dir * 1000, autocvar_g_monster_shambler_attack_lightning_damage * monster_skill, 0, 0, 0, 0, 0, DEATH_MONSTER_SHAMBLER_ZAP);
100         
101         // teamcolor / hit beam effect
102         v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
103         WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3"), org, v);
104 }
105
106 float shambler_attack(float attack_type)
107 {
108         switch(attack_type)
109         {
110                 case MONSTER_ATTACK_MELEE:
111                 {
112                         float chance = random();
113
114                         if(chance > 0.6)
115                                 shambler_delayedsmash();
116                         else if(chance > 0.3)
117                                 shambler_swing_right();
118                         else
119                                 shambler_swing_left();
120                         
121                         return TRUE;
122                 }
123                 case MONSTER_ATTACK_RANGED:
124                 {
125                         monsters_setframe(shambler_anim_magic);
126                         self.attack_finished_single = time + 1.1;
127                         self.monster_delayedattack = CastLightning;
128                         self.delay = time + 0.6;
129                         
130                         return TRUE;
131                 }
132         }
133         
134         return FALSE;
135 }
136
137 void shambler_die ()
138 {
139         Monster_CheckDropCvars ("shambler");
140         
141         self.think = monster_dead_think;
142         self.nextthink = time + self.ticrate;
143         self.ltime = time + 5;
144         monsters_setframe(shambler_anim_death);
145         
146         monster_hook_death(); // for post-death mods
147 }
148
149 void shambler_spawn ()
150 {
151         if not(self.health)
152                 self.health = autocvar_g_monster_shambler_health;
153
154         self.damageforcescale   = 0.003;
155         self.classname                  = "monster_shambler";
156         self.monster_attackfunc = shambler_attack;
157         self.nextthink                  = time + random() * 0.5 + 0.1;
158         self.think                              = shambler_think;
159         self.weapon                             = WEP_NEX;
160         
161         monsters_setframe(shambler_anim_stand);
162         
163         monster_setupsounds("shambler");
164         
165         monster_hook_spawn(); // for post-spawn mods
166 }
167
168 void spawnfunc_monster_shambler ()
169 {       
170         if not(autocvar_g_monster_shambler) { remove(self); return; }
171         
172         self.monster_spawnfunc = spawnfunc_monster_shambler;
173         
174         if(Monster_CheckAppearFlags(self))
175                 return;
176         
177         self.scale = 1.3;
178         
179         if not (monster_initialize(
180                          "Shambler", MONSTER_SHAMBLER,
181                          SHAMBLER_MIN, SHAMBLER_MAX,
182                          FALSE,
183                          shambler_die, shambler_spawn))
184         {
185                 remove(self);
186                 return;
187         }
188 }
189
190 #endif // SVQC