]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/monsters/monster/ogre.qc
Fix TD monster spawn protection. Improve TD monster pathfinding
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / monsters / monster / ogre.qc
1 // size
2 const vector OGRE_MIN = '-32 -32 -24';
3 const vector OGRE_MAX = '32 32 32';
4  
5 // cvars
6 float autocvar_g_monster_ogre;
7 float autocvar_g_monster_ogre_health;
8 float autocvar_g_monster_ogre_chainsaw_damage;
9 float autocvar_g_monster_ogre_speed_walk;
10 float autocvar_g_monster_ogre_speed_run;
11 float autocvar_g_monster_ogre_attack_uzi_bullets;
12
13 // animations
14 #define ogre_anim_stand         0
15 #define ogre_anim_walk          1
16 #define ogre_anim_run           2
17 #define ogre_anim_swing         3
18 #define ogre_anim_smash         4
19 #define ogre_anim_shoot         5
20 #define ogre_anim_pain1         6
21 #define ogre_anim_pain2         7
22 #define ogre_anim_pain3         8
23 #define ogre_anim_pain4         9
24 #define ogre_anim_pain5         10
25 #define ogre_anim_death1        11
26 #define ogre_anim_death2        12
27 #define ogre_anim_pull          13
28
29 void chainsaw (float side)
30 {
31         if (!self.enemy)
32                 return;
33
34         if (enemy_range() > 100 * self.scale)
35                 return;
36
37         Damage(self.enemy, self, self, autocvar_g_monster_ogre_chainsaw_damage * monster_skill, DEATH_MONSTER_OGRE_CHAINSAW, self.enemy.origin, normalize(self.enemy.origin - self.origin));
38 }
39
40 void ogre_think ()
41 {
42         self.think = ogre_think;
43         self.nextthink = time + 0.1;
44         
45         if(self.delay != -1)
46                 self.nextthink = self.delay;
47         
48         monster_move(autocvar_g_monster_ogre_speed_run, autocvar_g_monster_ogre_speed_walk, 300, ogre_anim_run, ogre_anim_walk, ogre_anim_stand);
49 }
50
51 .float ogre_cycles;
52 void ogre_swing ()
53 {
54         self.ogre_cycles += 1;
55         self.frame = ogre_anim_swing;
56         if(self.ogre_cycles == 1)
57                 self.attack_finished_single = time + 1.3;
58         self.angles_y = self.angles_y + random()* 25;
59         self.nextthink = time + 0.2;
60         self.think = ogre_swing;
61         
62         if(self.ogre_cycles <= 3)
63                 chainsaw(200);
64         else if(self.ogre_cycles <= 8)
65                 chainsaw(-200);
66         else
67                 chainsaw(0);
68         
69         if(self.ogre_cycles >= 10)
70                 self.think = ogre_think;
71 }
72
73 void ogre_smash_2 ()
74 {
75         chainsaw(0);
76 }
77
78 void ogre_smash ()
79 {
80         self.frame = ogre_anim_smash;
81         self.attack_finished_single = time + 0.5;
82         chainsaw(0);
83         self.monster_delayedattack = ogre_smash_2;
84         self.delay = time + 0.1;
85 }
86
87 void ogre_uzi_fire ()
88 {
89         self.ogre_cycles += 1;
90         
91         if(self.ogre_cycles > autocvar_g_monster_ogre_attack_uzi_bullets)
92         {
93                 self.monster_delayedattack = func_null;
94                 self.delay = -1;
95                 return;
96         }
97         W_UZI_Attack(DEATH_MONSTER_OGRE_NAIL);
98         self.delay = time + 0.1;
99         self.monster_delayedattack = ogre_uzi_fire;
100 }
101
102 void ogre_uzi ()
103 {
104         self.frame = ogre_anim_shoot;
105         self.attack_finished_single = time + 0.8;
106         self.delay = time + 0.1;
107         self.monster_delayedattack = ogre_uzi_fire;
108 }
109
110 void ogre_gl ()
111 {
112         W_Grenade_Attack2();
113         self.frame = ogre_anim_shoot;
114         self.attack_finished_single = time + 0.8;
115 }
116
117 float ogre_missile ()
118 {
119         self.ogre_cycles = 0;
120         if (random() < 0.20)
121         {
122                 ogre_uzi();
123                 return TRUE;
124         }
125         else
126         {
127                 ogre_gl();
128                 return TRUE;
129         }
130 }
131
132 void ogre_melee ()
133 {
134         self.ogre_cycles = 0;
135         if (random() > 0.5)
136                 ogre_smash();
137         else
138                 ogre_swing();
139 }
140
141 void ogre_die()
142 {
143         Monster_CheckDropCvars ("ogre");
144         
145         self.solid                      = SOLID_NOT;
146         self.takedamage         = DAMAGE_NO;
147         self.event_damage   = func_null;
148         self.enemy                      = world;
149         self.nextthink          = time + 2.1;
150         self.pain_finished  = self.nextthink;
151         self.movetype           = MOVETYPE_TOSS;
152         self.think                      = Monster_Fade;
153         
154         W_ThrowNewWeapon(self, WEP_GRENADE_LAUNCHER, 0, self.origin, self.velocity);
155         if (random() < 0.5)
156                 self.frame = ogre_anim_death1;
157         else
158                 self.frame = ogre_anim_death2;
159                 
160         monster_hook_death(); // for post-death mods
161 }
162
163 void ogre_spawn ()
164 {
165         if not(self.health)
166                 self.health = autocvar_g_monster_ogre_health * self.scale;
167
168         self.damageforcescale   = 0.003;
169         self.classname                  = "monster_ogre";
170         self.checkattack                = GenericCheckAttack;
171         self.attack_melee               = ogre_melee;
172         self.frame                              = ogre_anim_pull;
173         self.attack_ranged              = ogre_missile;
174         self.nextthink                  = time + 1;
175         self.think                              = ogre_think;
176         self.sprite_height              = 40 * self.scale;
177         
178         monster_hook_spawn(); // for post-spawn mods
179 }
180
181 void spawnfunc_monster_ogre ()
182 {       
183         if not(autocvar_g_monster_ogre)
184         {
185                 remove(self);
186                 return;
187         }
188         
189         self.monster_spawnfunc = spawnfunc_monster_ogre;
190         
191         if(self.spawnflags & MONSTERFLAG_APPEAR)
192         {
193                 self.think = func_null;
194                 self.nextthink = -1;
195                 self.use = Monster_Appear;
196                 return;
197         }
198         
199         self.scale = 1.3;
200         
201         if not (monster_initialize(
202                          "Ogre",
203                          "models/monsters/ogre.mdl",
204                          OGRE_MIN, OGRE_MAX,
205                          FALSE,
206                          ogre_die, ogre_spawn))
207         {
208                 remove(self);
209                 return;
210         }
211         
212         weapon_action(WEP_GRENADE_LAUNCHER, WR_PRECACHE);
213 }