]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/monsters/monster/shambler.qc
Rename tarbaby to slime & begin cleanup of monster_attack_melee function
[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 float sham_melee ()
83 {
84         local float chance = random();
85
86         if (chance > 0.6)
87                 shambler_delayedsmash();
88         else if (chance > 0.3)
89                 shambler_swing_right ();
90         else
91                 shambler_swing_left ();
92                 
93         return TRUE;
94 }
95
96 void CastLightning ()
97 {
98         self.monster_delayedattack = func_null;
99         self.delay = -1;
100
101         local vector org = '0 0 0', dir = '0 0 0';
102         vector v = '0 0 0';
103
104         self.effects |= EF_MUZZLEFLASH;
105
106         org = self.origin + '0 0 40';
107
108         dir = self.enemy.origin + '0 0 16' - org;
109         dir = normalize (dir);
110
111         traceline (org, self.origin + dir * 1000, TRUE, self);
112                 
113         FireRailgunBullet (org, org + dir * 1000, autocvar_g_monster_shambler_attack_lightning_damage * monster_skill, 0, 0, 0, 0, 0, DEATH_MONSTER_SHAMBLER_ZAP);
114         
115         // teamcolor / hit beam effect
116         v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
117         WarpZone_TrailParticles(world, particleeffectnum("TE_TEI_G3"), org, v);
118 }
119
120 void shambler_magic ()
121 {
122         monsters_setframe(shambler_anim_magic);
123         self.attack_finished_single = time + 1.1;
124         self.monster_delayedattack = CastLightning;
125         self.delay = time + 0.6;
126 }
127         
128 float sham_lightning ()
129 {
130         shambler_magic();
131         return TRUE;
132 }
133
134 void shambler_die ()
135 {
136         Monster_CheckDropCvars ("shambler");
137         
138         self.think = monster_dead_think;
139         self.nextthink = time + self.ticrate;
140         self.ltime = time + 5;
141         monsters_setframe(shambler_anim_death);
142         
143         monster_hook_death(); // for post-death mods
144 }
145
146 void shambler_spawn ()
147 {
148         if not(self.health)
149                 self.health = autocvar_g_monster_shambler_health;
150
151         self.damageforcescale   = 0.003;
152         self.classname                  = "monster_shambler";
153         self.attack_melee               = sham_melee;
154         self.checkattack                = GenericCheckAttack;
155         self.attack_ranged              = sham_lightning;
156         self.nextthink                  = time + random() * 0.5 + 0.1;
157         self.think                              = shambler_think;
158         self.weapon                             = WEP_NEX;
159         
160         monsters_setframe(shambler_anim_stand);
161         
162         monster_setupsounds("shambler");
163         
164         monster_hook_spawn(); // for post-spawn mods
165 }
166
167 void spawnfunc_monster_shambler ()
168 {       
169         if not(autocvar_g_monster_shambler) { remove(self); return; }
170         
171         self.monster_spawnfunc = spawnfunc_monster_shambler;
172         
173         if(Monster_CheckAppearFlags(self))
174                 return;
175         
176         self.scale = 1.3;
177         
178         if not (monster_initialize(
179                          "Shambler", MONSTER_SHAMBLER,
180                          SHAMBLER_MIN, SHAMBLER_MAX,
181                          FALSE,
182                          shambler_die, shambler_spawn))
183         {
184                 remove(self);
185                 return;
186         }
187 }
188
189 #endif // SVQC