2 float autocvar_g_monster_spider;
3 float autocvar_g_monster_spider_stopspeed;
4 float autocvar_g_monster_spider_attack_leap_delay;
5 float autocvar_g_monster_spider_attack_stand_damage;
6 float autocvar_g_monster_spider_attack_stand_delay;
7 float autocvar_g_monster_spider_health;
8 float autocvar_g_monster_spider_speed_walk;
9 float autocvar_g_monster_spider_speed_run;
10 float autocvar_g_monster_spider_attack_type;
13 #define spider_anim_idle 0
14 #define spider_anim_walk 1
15 #define spider_anim_attack 2
16 #define spider_anim_attack2 3
18 const vector SPIDER_MIN = '-18 -18 -25';
19 const vector SPIDER_MAX = '18 18 30';
21 .float spider_type; // used to switch between fire & ice attacks
22 const float SPIDER_TYPE_ICE = 0;
23 const float SPIDER_TYPE_FIRE = 1;
26 void spawnfunc_monster_spider();
31 Monster_CheckDropCvars ("spider");
33 self.angles += '180 0 0';
34 self.solid = SOLID_NOT;
35 self.takedamage = DAMAGE_NO;
36 self.event_damage = func_null;
38 self.movetype = MOVETYPE_TOSS;
39 self.think = Monster_Fade;
40 self.nextthink = time + 2.1;
41 self.pain_finished = self.nextthink;
42 self.frame = spider_anim_attack;
44 monster_hook_death(); // for post-death mods
48 * Performe a standing attack on self.enemy.
50 void spider_attack_standing() {
51 float dot = 0, bigdmg = autocvar_g_monster_spider_attack_stand_damage * self.scale;
56 if(self.monster_owner == self.enemy)
62 makevectors (self.angles);
63 dot = normalize (self.enemy.origin - self.origin) * v_forward;
66 Damage(self.enemy, self, self, bigdmg * monster_skill, DEATH_MONSTER_MELEE, self.origin, '0 0 0');
69 if (!monster_isvalidtarget(self.enemy, self, FALSE))
73 self.frame = spider_anim_attack;
75 self.frame = spider_anim_attack2;
77 self.nextthink = time + autocvar_g_monster_spider_attack_stand_delay;
80 void spider_web_explode ()
82 RadiusDamage (self, self.realowner, 0, 0, 1, world, 0, self.projectiledeathtype, other);
86 void spider_web_touch ()
89 if (other.takedamage == DAMAGE_AIM)
95 void spider_shootweb()
97 // clone of the electro secondary attack, with less bouncing
100 makevectors(self.angles);
102 W_SetupShot_ProjectileSize (self, '0 0 -4', '0 0 -4', FALSE, 2, "weapons/electro_fire2.wav", CH_WEAPON_A, 0);
104 w_shotdir = v_forward; // no TrueAim for grenades please
106 pointparticles(particleeffectnum("electro_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
109 proj.classname = "plasma";
110 proj.owner = proj.realowner = self;
111 proj.use = spider_web_touch;
112 proj.think = adaptor_think2use_hittype_splash;
113 proj.bot_dodge = TRUE;
114 proj.bot_dodgerating = 0;
115 proj.nextthink = time + autocvar_g_balance_electro_secondary_lifetime;
116 PROJECTILE_MAKETRIGGER(proj);
117 proj.projectiledeathtype = WEP_ELECTRO | HITTYPE_SECONDARY;
118 setorigin(proj, w_shotorg);
120 //proj.glow_size = 50;
121 //proj.glow_color = 45;
122 proj.movetype = MOVETYPE_BOUNCE;
123 W_SETUPPROJECTILEVELOCITY_UP(proj, g_balance_electro_secondary);
124 proj.touch = spider_web_touch;
125 setsize(proj, '0 0 -4', '0 0 -4');
126 proj.takedamage = DAMAGE_YES;
127 proj.damageforcescale = 0;
129 proj.event_damage = W_Plasma_Damage;
130 proj.flags = FL_PROJECTILE;
131 proj.damagedbycontents = TRUE;
133 proj.bouncefactor = 0.3;
134 proj.bouncestop = 0.05;
135 proj.missile_flags = MIF_SPLASH | MIF_ARC;
137 CSQCProjectile(proj, TRUE, PROJECTILE_ELECTRO, FALSE); // no culling, it has sound
139 other = proj; MUTATOR_CALLHOOK(EditProjectile);
142 void spider_attack_leap()
144 vector angles_face = vectoangles(self.enemy.origin - self.origin);
147 self.frame = spider_anim_attack2;
148 self.angles_y = angles_face_y ;
149 self.nextthink = time + autocvar_g_monster_spider_attack_leap_delay;
151 makevectors(self.angles);
153 switch(self.spider_type)
156 case SPIDER_TYPE_ICE:
157 spider_shootweb(); break; // must... remember... breaks!
158 case SPIDER_TYPE_FIRE:
159 W_Fireball_Attack2(); break;
163 float spider_attack_ranged()
165 if(self.enemy.frozen || self.enemy.freezetag_frozen)
168 spider_attack_leap();
174 self.think = spider_think;
175 self.nextthink = time + 0.1;
177 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);
186 self.health = autocvar_g_monster_spider_health * self.scale;
188 self.classname = "monster_spider";
189 self.nextthink = time + random() * 0.5 + 0.1;
190 self.pain_finished = self.nextthink;
191 self.frame = spider_anim_idle;
192 self.checkattack = GenericCheckAttack;
193 self.attack_melee = spider_attack_standing;
194 self.attack_ranged = spider_attack_ranged;
195 self.think = spider_think;
196 self.sprite_height = 40 * self.scale;
198 monster_hook_spawn(); // for post-spawn mods
201 /*QUAKED monster_spider (1 0 0) (-18 -18 -25) (18 18 47)
202 Spider, 60 health points.
203 -------- KEYS --------
204 -------- SPAWNFLAGS --------
205 MONSTERFLAG_APPEAR: monster will spawn when triggered.
206 ---------NOTES----------
207 -------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
208 modeldisabled="models/monsters/spider.dpm"
210 void spawnfunc_monster_spider()
212 if not(autocvar_g_monster_spider) { remove(self); return; }
214 self.monster_spawnfunc = spawnfunc_monster_spider;
215 self.classname = "monster_spider";
216 if(!self.spider_type)
217 self.spider_type = autocvar_g_monster_spider_attack_type;
219 if(self.spawnflags & MONSTERFLAG_APPEAR)
221 self.think = func_null;
223 self.use = Monster_Appear;
227 if not (monster_initialize(
229 "models/monsters/spider.dpm",
230 SPIDER_MIN, SPIDER_MAX,
232 spider_die, spider_spawn))