]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/monsters/monster/spider.qc
Rename tarbaby to slime & begin cleanup of monster_attack_melee function
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / monsters / monster / spider.qc
1 // size
2 const vector SPIDER_MIN = '-18 -18 -25';
3 const vector SPIDER_MAX = '18 18 30';
4
5 // model
6 string SPIDER_MODEL = "models/monsters/spider.dpm";
7
8 #ifdef SVQC
9 // cvars
10 float autocvar_g_monster_spider;
11 float autocvar_g_monster_spider_stopspeed;
12 float autocvar_g_monster_spider_attack_leap_delay;
13 float autocvar_g_monster_spider_attack_stand_damage;
14 float autocvar_g_monster_spider_attack_stand_delay;
15 float autocvar_g_monster_spider_attack_fire_time;
16 float autocvar_g_monster_spider_health;
17 float autocvar_g_monster_spider_speed_walk;
18 float autocvar_g_monster_spider_speed_run;
19 float autocvar_g_monster_spider_attack_type;
20
21 // animations
22 const float spider_anim_idle            = 0;
23 const float spider_anim_walk            = 1;
24 const float spider_anim_attack          = 2;
25 const float spider_anim_attack2         = 3;
26
27 .float spider_type; // used to switch between fire & ice attacks
28 const float SPIDER_TYPE_ICE             = 0;
29 const float SPIDER_TYPE_FIRE    = 1;
30
31 float spider_attack_standing()
32 {       
33         monster_melee(self.enemy, autocvar_g_monster_spider_attack_stand_damage, 0.3, DEATH_MONSTER_SPIDER, TRUE);
34         
35         monsters_setframe((random() > 0.5) ? spider_anim_attack : spider_anim_attack2);
36
37         self.attack_finished_single = time + autocvar_g_monster_spider_attack_stand_delay;
38         
39         return TRUE;
40 }
41
42 void spider_web_explode ()
43 {
44         float damg = 0, edamg = 0, rad = 1;
45         switch(self.realowner.spider_type)
46         {
47                 case SPIDER_TYPE_ICE:
48                         break; // no change
49                 case SPIDER_TYPE_FIRE:
50                         damg = 15;
51                         rad = 25;
52                         edamg = 6;
53                         break;
54         }
55         
56         RadiusDamage (self, self.realowner, damg, edamg, rad, world, 0, self.projectiledeathtype, other);
57         
58         remove (self);
59 }
60
61 void spider_web_touch ()
62 {
63         PROJECTILE_TOUCH;
64         
65         if(other.takedamage == DAMAGE_AIM)
66         if(other.health > 0)
67         switch(self.realowner.spider_type)
68         {
69                 case SPIDER_TYPE_ICE:
70                         Freeze(other, 0.3, 2);
71                         break;
72                 case SPIDER_TYPE_FIRE:
73                         Fire_AddDamage(other, self.realowner, 5 * monster_skill, autocvar_g_monster_spider_attack_fire_time, DEATH_MONSTER_SPIDER_FIRE);
74                         break;
75         }
76                 
77         spider_web_explode();
78 }
79
80 void spider_shootweb(float ptype)
81 {
82         float p = 0, dt = 0;
83         string snd = "";
84         switch(ptype)
85         {
86                 case SPIDER_TYPE_ICE:
87                         p = PROJECTILE_ELECTRO;
88                         dt = WEP_ELECTRO;
89                         snd = "weapons/electro_fire2.wav";
90                         break;
91                 case SPIDER_TYPE_FIRE:
92                         p = PROJECTILE_FIREMINE;
93                         dt = WEP_FIREBALL;
94                         snd = "weapons/fireball_fire.wav";
95                         break;
96         }
97         
98         vector fmins = '-4 -4 -4', fmaxs = '4 4 4';
99
100         W_SetupShot_ProjectileSize(self, fmins, fmaxs, FALSE, 2, snd, CH_WEAPON_A, 0);
101
102         w_shotdir = v_forward; // no TrueAim for grenades please
103
104         entity proj = spawn ();
105         proj.classname = "plasma";
106         proj.owner = proj.realowner = self;
107         proj.use = spider_web_touch;
108         proj.think = adaptor_think2use_hittype_splash;
109         proj.bot_dodge = TRUE;
110         proj.bot_dodgerating = 0;
111         proj.nextthink = time + 5;
112         PROJECTILE_MAKETRIGGER(proj);
113         proj.projectiledeathtype = dt | HITTYPE_SECONDARY;
114         setorigin(proj, w_shotorg);
115
116         //proj.glow_size = 50;
117         //proj.glow_color = 45;
118         proj.movetype = MOVETYPE_BOUNCE;
119         W_SETUPPROJECTILEVELOCITY_UP(proj, g_monster_spider_attack_web);
120         proj.touch = spider_web_touch;
121         setsize(proj, fmins, fmaxs);
122         proj.takedamage = DAMAGE_NO;
123         proj.damageforcescale = 0;
124         proj.health = 500;
125         proj.event_damage = func_null;
126         proj.flags = FL_PROJECTILE;
127         proj.damagedbycontents = TRUE;
128
129         proj.bouncefactor = 0.3;
130         proj.bouncestop = 0.05;
131         proj.missile_flags = MIF_SPLASH | MIF_ARC;
132
133         CSQCProjectile(proj, TRUE, p, FALSE); // no culling, it has sound
134 }
135
136 void spider_attack_leap()
137 {
138         vector angles_face = vectoangles(self.enemy.origin - self.origin);
139
140         // face the enemy
141         monsters_setframe(spider_anim_attack2);
142         self.angles_y = angles_face_y ;
143         self.attack_finished_single = time + autocvar_g_monster_spider_attack_leap_delay;
144         
145         monster_makevectors(self.enemy);
146         
147         spider_shootweb(self.spider_type);
148 }
149
150 float spider_attack_ranged()
151 {
152         if(self.enemy.frozen)
153                 return FALSE;
154                 
155         spider_attack_leap();
156         return TRUE;
157 }
158
159 void spider_think()
160 {
161         self.think = spider_think;
162         self.nextthink = time + self.ticrate;
163         
164         monster_move(autocvar_g_monster_spider_speed_run, autocvar_g_monster_spider_speed_walk, autocvar_g_monster_spider_stopspeed, spider_anim_walk, spider_anim_walk, spider_anim_idle);
165 }
166
167 void spider_die ()
168 {
169         Monster_CheckDropCvars ("spider");
170         
171         self.think = monster_dead_think;
172         self.nextthink = time + self.ticrate;
173         self.ltime = time + 5;
174         monsters_setframe(spider_anim_attack);
175         self.angles += '180 0 0';
176         
177         monster_hook_death(); // for post-death mods
178 }
179
180 void spider_spawn() 
181 {
182         if not(self.health)
183                 self.health = autocvar_g_monster_spider_health;
184         
185         self.classname                  = "monster_spider";
186         self.nextthink                  = time + random() * 0.5 + 0.1;
187         self.checkattack                = GenericCheckAttack;
188         self.attack_melee               = spider_attack_standing;
189         self.attack_ranged              = spider_attack_ranged;
190         self.think                              = spider_think;
191         
192         monsters_setframe(spider_anim_idle);
193         
194         monster_setupsounds("spider");
195         
196         if not(self.spider_type)
197                 self.spider_type = autocvar_g_monster_spider_attack_type;
198         
199         monster_hook_spawn(); // for post-spawn mods
200 }
201
202 void spawnfunc_monster_spider() 
203 {
204         if not(autocvar_g_monster_spider) { remove(self); return; }
205         
206         self.monster_spawnfunc = spawnfunc_monster_spider;
207         
208         if(Monster_CheckAppearFlags(self))
209                 return;
210         
211         if not (monster_initialize(
212                          "Spider", MONSTER_SPIDER,
213                          SPIDER_MIN, SPIDER_MAX,
214                          FALSE,
215                          spider_die, spider_spawn))
216         {
217                 remove(self);
218                 return;
219         }
220 }
221
222 #endif // SVQC