]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/monsters/monster/wizard.qc
Fix scrag not falling when killed
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / monsters / monster / wizard.qc
1 #ifndef MENUQC
2 // size
3 const vector WIZARD_MIN = '-16 -16 -45';
4 const vector WIZARD_MAX = '16 16 16';
5
6 // model
7 string WIZARD_MODEL = "models/monsters/wizard.mdl";
8
9 #endif
10
11 #ifdef SVQC
12 // cvars
13 float autocvar_g_monster_wizard;
14 float autocvar_g_monster_wizard_health;
15 float autocvar_g_monster_wizard_speed_walk;
16 float autocvar_g_monster_wizard_speed_run;
17 float autocvar_g_monster_wizard_spike_damage;
18 float autocvar_g_monster_wizard_spike_edgedamage;
19 float autocvar_g_monster_wizard_spike_radius;
20 float autocvar_g_monster_wizard_spike_speed;
21
22 // animations
23 const float wizard_anim_hover   = 0;
24 const float wizard_anim_fly     = 1;
25 const float wizard_anim_magic   = 2;
26 const float wizard_anim_pain    = 3;
27 const float wizard_anim_death   = 4;
28
29 void Wiz_FastExplode()
30 {
31         self.event_damage = func_null;
32         self.takedamage = DAMAGE_NO;
33         RadiusDamage (self, self.realowner, autocvar_g_monster_wizard_spike_damage, autocvar_g_monster_wizard_spike_edgedamage, autocvar_g_monster_wizard_spike_radius, world, 0, self.projectiledeathtype, other);
34
35         remove (self);
36 }
37
38 void Wiz_FastTouch ()
39 {
40         if(other == self.owner)
41                 return;
42                 
43         PROJECTILE_TOUCH;
44                 
45         pointparticles(particleeffectnum("TE_WIZSPIKE"), self.origin, '0 0 0', 1);
46         
47         Wiz_FastExplode();
48 }
49
50 void Wiz_StartFast ()
51 {
52         entity missile;
53         vector dir = normalize((self.enemy.origin + '0 0 10') - self.origin);
54         
55         self.attack_finished_single = time + 0.2;
56         
57         self.v_angle = self.angles;
58         makevectors (self.angles);
59
60         missile = spawn ();
61         missile.owner = missile.realowner = self;
62         setsize (missile, '0 0 0', '0 0 0');            
63         setorigin (missile, self.origin + v_forward * 14 + '0 0 30' + v_right * 14);
64         missile.enemy = self.enemy;
65         missile.nextthink = time + 3;
66         missile.think = Wiz_FastExplode;
67         missile.velocity = dir * autocvar_g_monster_wizard_spike_speed;
68         missile.avelocity = '300 300 300';
69         missile.solid = SOLID_BBOX;
70         missile.movetype = MOVETYPE_FLYMISSILE;
71         missile.touch = Wiz_FastTouch;
72         missile.projectiledeathtype = DEATH_MONSTER_SCRAG;
73         CSQCProjectile(missile, TRUE, PROJECTILE_CRYLINK, TRUE);
74         
75         missile = spawn ();
76         missile.owner = missile.realowner = self;
77         setsize (missile, '0 0 0', '0 0 0');            
78         setorigin (missile, self.origin + v_forward * 14 + '0 0 30' + v_right * -14);
79         missile.enemy = self.enemy;
80         missile.nextthink = time + 3;
81         missile.touch = Wiz_FastTouch;
82         missile.solid = SOLID_BBOX;
83         missile.movetype = MOVETYPE_FLYMISSILE;
84         missile.think = Wiz_FastExplode;
85         missile.velocity = dir * autocvar_g_monster_wizard_spike_speed;
86         missile.avelocity = '300 300 300';
87         missile.projectiledeathtype = DEATH_MONSTER_SCRAG;
88         CSQCProjectile(missile, TRUE, PROJECTILE_CRYLINK, TRUE);
89 }
90
91 void wizard_think ()
92 {
93         self.think = wizard_think;
94         self.nextthink = time + self.ticrate;
95         
96         monster_move(autocvar_g_monster_wizard_speed_run, autocvar_g_monster_wizard_speed_walk, 300, wizard_anim_fly, wizard_anim_hover, wizard_anim_hover);
97 }
98
99 void wizard_fastattack ()
100 {
101         Wiz_StartFast();
102 }
103
104 void wizard_dead_think()
105 {
106         self.think = wizard_dead_think;
107         self.nextthink = time + self.ticrate;
108
109         if(time >= self.ltime)
110         {
111                 Monster_Fade();
112                 return;
113         }
114         
115         self.SendFlags |= MSF_MOVE; // keep up to date on the monster's location
116 }
117
118 void wizard_die ()
119 {
120         Monster_CheckDropCvars ("wizard");
121         
122         self.think                      = wizard_dead_think; // exception for wizard, as it needs to keep moving
123         self.ltime                      = time + 5;
124         self.nextthink          = time + self.ticrate;
125         self.velocity_x         = -200 + 400 * random();
126         self.velocity_y         = -200 + 400 * random();
127         self.velocity_z         = 100 + 100 * random();
128         
129         monsters_setframe(wizard_anim_death);
130         
131         monster_hook_death(); // for post-death mods
132 }
133
134 float Wiz_Missile ()
135 {
136         wizard_fastattack();
137         return TRUE;
138 }
139
140 void wizard_spawn ()
141 {
142         if not(self.health)
143                 self.health = autocvar_g_monster_wizard_health * self.scale;
144         
145         self.classname                  = "monster_wizard";
146         self.checkattack                = GenericCheckAttack;
147         self.attack_ranged              = Wiz_Missile;
148         self.nextthink                  = time + random() * 0.5 + 0.1;
149         self.movetype                   = MOVETYPE_FLY; // TODO: make it fly up/down
150         self.flags                         |= FL_FLY;
151         self.think                              = wizard_think;
152         self.sprite_height              = 30;
153         
154         monster_hook_spawn(); // for post-spawn mods
155 }
156
157 void spawnfunc_monster_wizard ()
158 {       
159         if not(autocvar_g_monster_wizard) { remove(self); return; }
160         
161         self.monster_spawnfunc = spawnfunc_monster_wizard;
162         
163         if(Monster_CheckAppearFlags(self))
164                 return;
165         
166         self.scale = 1.3;
167         
168         if not (monster_initialize(
169                          "Scrag", MONSTER_SCRAG,
170                          WIZARD_MIN, WIZARD_MAX,
171                          TRUE,
172                          wizard_die, wizard_spawn))
173         {
174                 remove(self);
175                 return;
176         }
177 }
178
179 // compatibility with old spawns
180 void spawnfunc_monster_scrag () { spawnfunc_monster_wizard(); }
181
182 #endif // SVQC