-// cvars
+const vector SPIDER_MIN = '-18 -18 -25';
+const vector SPIDER_MAX = '18 18 30';
+
+string SPIDER_MODEL = "models/monsters/spider.dpm";
+
+#ifdef SVQC
float autocvar_g_monster_spider;
float autocvar_g_monster_spider_stopspeed;
float autocvar_g_monster_spider_attack_leap_delay;
float autocvar_g_monster_spider_attack_stand_damage;
float autocvar_g_monster_spider_attack_stand_delay;
+float autocvar_g_monster_spider_attack_fire_time;
float autocvar_g_monster_spider_health;
float autocvar_g_monster_spider_speed_walk;
float autocvar_g_monster_spider_speed_run;
float autocvar_g_monster_spider_attack_type;
-// spider animations
-#define spider_anim_idle 0
-#define spider_anim_walk 1
-#define spider_anim_attack 2
-#define spider_anim_attack2 3
-
-const vector SPIDER_MIN = '-18 -18 -25';
-const vector SPIDER_MAX = '18 18 30';
+const float spider_anim_idle = 0;
+const float spider_anim_walk = 1;
+const float spider_anim_attack = 2;
+const float spider_anim_attack2 = 3;
.float spider_type; // used to switch between fire & ice attacks
const float SPIDER_TYPE_ICE = 0;
const float SPIDER_TYPE_FIRE = 1;
-void spider_spawn();
-void spawnfunc_monster_spider();
-void spider_think();
-
-void spider_die ()
+void spider_think()
{
- Monster_CheckDropCvars ("spider");
-
- self.angles += '180 0 0';
- self.solid = SOLID_NOT;
- self.takedamage = DAMAGE_NO;
- self.event_damage = func_null;
- self.enemy = world;
- self.movetype = MOVETYPE_TOSS;
- self.think = Monster_Fade;
- self.nextthink = time + 2.1;
- self.pain_finished = self.nextthink;
- self.frame = spider_anim_attack;
+ self.think = spider_think;
+ self.nextthink = time + self.ticrate;
- monster_hook_death(); // for post-death mods
+ 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);
}
-/**
- * Performe a standing attack on self.enemy.
- */
-void spider_attack_standing() {
- float dot = 0, bigdmg = autocvar_g_monster_spider_attack_stand_damage * self.scale;
-
- self.velocity_x = 0;
- self.velocity_y = 0;
-
- if(self.monster_owner == self.enemy)
- {
- self.enemy = world;
- return;
- }
-
- makevectors (self.angles);
- dot = normalize (self.enemy.origin - self.origin) * v_forward;
- if(dot > 0.3)
+void spider_web_explode()
+{
+ entity e;
+ if(self)
{
- Damage(self.enemy, self, self, bigdmg * monster_skill, DEATH_MONSTER_MELEE, self.origin, '0 0 0');
- }
-
- if (!monster_isvalidtarget(self.enemy, self, FALSE))
- self.enemy = world;
+ float damg = 0, edamg = 0, rad = 1;
+ switch(self.realowner.spider_type)
+ {
+ case SPIDER_TYPE_ICE:
+ rad = 25;
+ pointparticles(particleeffectnum("electro_impact"), self.origin, '0 0 0', 1);
+ break;
+ case SPIDER_TYPE_FIRE:
+ pointparticles(particleeffectnum("fireball_explode"), self.origin, '0 0 0', 1);
+ damg = 15;
+ rad = 25;
+ edamg = 6;
+ break;
+ }
- if(random() < 0.50)
- self.frame = spider_anim_attack;
- else
- self.frame = spider_anim_attack2;
-
- self.nextthink = time + autocvar_g_monster_spider_attack_stand_delay;
-}
-
-void spider_web_explode ()
-{
- RadiusDamage (self, self.realowner, 0, 0, 1, world, 0, self.projectiledeathtype, other);
- remove (self);
+ RadiusDamage(self, self.realowner, damg, edamg, 0, world, rad, DEATH_MONSTER_SPIDER_FIRE, world); // ice deals no damage anyway
+
+ for(e = findradius(self.origin, rad); e; e = e.chain) if(e.takedamage && e.deadflag == DEAD_NO)
+ {
+ switch(self.realowner.spider_type)
+ {
+ case SPIDER_TYPE_ICE:
+ Freeze(e, 0.3, 2, FALSE);
+ break;
+ case SPIDER_TYPE_FIRE:
+ Fire_AddDamage(e, self.realowner, 5 * monster_skill, autocvar_g_monster_spider_attack_fire_time, DEATH_MONSTER_SPIDER_FIRE);
+ break;
+ }
+ }
+
+ remove(self);
+ }
}
-void spider_web_touch ()
+void spider_web_touch()
{
PROJECTILE_TOUCH;
- if (other.takedamage == DAMAGE_AIM)
- Freeze(other, 0.3);
-
+
spider_web_explode();
}
-void spider_shootweb()
+void spider_shootweb(float ptype)
{
- // clone of the electro secondary attack, with less bouncing
- entity proj = world;
+ float p = 0;
+ string snd = "";
+ switch(ptype)
+ {
+ case SPIDER_TYPE_ICE:
+ p = PROJECTILE_ELECTRO;
+ snd = "weapons/electro_fire2.wav";
+ break;
+ case SPIDER_TYPE_FIRE:
+ p = PROJECTILE_FIREMINE;
+ snd = "weapons/fireball_fire.wav";
+ break;
+ }
- makevectors(self.angles);
+ vector fmins = '-4 -4 -4', fmaxs = '4 4 4';
- W_SetupShot_ProjectileSize (self, '0 0 -4', '0 0 -4', FALSE, 2, "weapons/electro_fire2.wav", CH_WEAPON_A, 0);
+ W_SetupShot_ProjectileSize(self, fmins, fmaxs, FALSE, 2, snd, CH_WEAPON_A, 0);
w_shotdir = v_forward; // no TrueAim for grenades please
- pointparticles(particleeffectnum("electro_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
-
- proj = spawn ();
+ entity proj = spawn ();
proj.classname = "plasma";
proj.owner = proj.realowner = self;
proj.use = spider_web_touch;
proj.think = adaptor_think2use_hittype_splash;
proj.bot_dodge = TRUE;
proj.bot_dodgerating = 0;
- proj.nextthink = time + autocvar_g_balance_electro_secondary_lifetime;
+ proj.nextthink = time + 5;
PROJECTILE_MAKETRIGGER(proj);
- proj.projectiledeathtype = WEP_ELECTRO | HITTYPE_SECONDARY;
+ proj.projectiledeathtype = DEATH_MONSTER_SPIDER_FIRE;
setorigin(proj, w_shotorg);
//proj.glow_size = 50;
//proj.glow_color = 45;
proj.movetype = MOVETYPE_BOUNCE;
- W_SETUPPROJECTILEVELOCITY_UP(proj, g_balance_electro_secondary);
+ W_SETUPPROJECTILEVELOCITY_UP(proj, g_monster_spider_attack_web);
proj.touch = spider_web_touch;
- setsize(proj, '0 0 -4', '0 0 -4');
- proj.takedamage = DAMAGE_YES;
+ setsize(proj, fmins, fmaxs);
+ proj.takedamage = DAMAGE_NO;
proj.damageforcescale = 0;
proj.health = 500;
- proj.event_damage = W_Plasma_Damage;
+ proj.event_damage = func_null;
proj.flags = FL_PROJECTILE;
proj.damagedbycontents = TRUE;
proj.bouncestop = 0.05;
proj.missile_flags = MIF_SPLASH | MIF_ARC;
- CSQCProjectile(proj, TRUE, PROJECTILE_ELECTRO, FALSE); // no culling, it has sound
-
- other = proj; MUTATOR_CALLHOOK(EditProjectile);
+ CSQCProjectile(proj, TRUE, p, TRUE);
}
-void spider_attack_leap()
+float spider_attack(float attack_type)
{
- vector angles_face = vectoangles(self.enemy.origin - self.origin);
-
- // face the enemy
- self.frame = spider_anim_attack2;
- self.angles_y = angles_face_y ;
- self.nextthink = time + autocvar_g_monster_spider_attack_leap_delay;
-
- makevectors(self.angles);
-
- switch(self.spider_type)
+ switch(attack_type)
{
- default:
- case SPIDER_TYPE_ICE:
- spider_shootweb(); break; // must... remember... breaks!
- case SPIDER_TYPE_FIRE:
- W_Fireball_Attack2(); break;
+ case MONSTER_ATTACK_MELEE:
+ {
+ monster_melee(self.enemy, autocvar_g_monster_spider_attack_stand_damage, 0.3, DEATH_MONSTER_SPIDER, TRUE);
+ monsters_setframe((random() > 0.5) ? spider_anim_attack : spider_anim_attack2);
+ self.attack_finished_single = time + autocvar_g_monster_spider_attack_stand_delay;
+
+ return TRUE;
+ }
+ case MONSTER_ATTACK_RANGED:
+ {
+ if(self.enemy.frozen)
+ return FALSE;
+
+ monsters_setframe(spider_anim_attack2);
+ self.attack_finished_single = time + autocvar_g_monster_spider_attack_leap_delay;
+ monster_makevectors(self.enemy);
+ spider_shootweb(self.spider_type);
+
+ return TRUE;
+ }
}
+
+ return FALSE;
}
-float spider_attack_ranged()
-{
- if(self.enemy.frozen || self.enemy.freezetag_frozen)
- return FALSE;
-
- spider_attack_leap();
- return TRUE;
-}
-
-void spider_think()
+void spider_die()
{
- self.think = spider_think;
- self.nextthink = time + 0.1;
+ Monster_CheckDropCvars ("spider");
- 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);
+ self.think = monster_dead_think;
+ self.nextthink = time + self.ticrate;
+ self.ltime = time + 5;
+ monsters_setframe(spider_anim_attack);
+ self.angles += '180 0 0';
+
+ monster_hook_death(); // for post-death mods
}
-/**
- * Spawn the spider.
- */
void spider_spawn()
{
if not(self.health)
- self.health = autocvar_g_monster_spider_health * self.scale;
+ self.health = autocvar_g_monster_spider_health;
self.classname = "monster_spider";
self.nextthink = time + random() * 0.5 + 0.1;
- self.pain_finished = self.nextthink;
- self.frame = spider_anim_idle;
- self.checkattack = GenericCheckAttack;
- self.attack_melee = spider_attack_standing;
- self.attack_ranged = spider_attack_ranged;
+ self.monster_attackfunc = spider_attack;
self.think = spider_think;
- self.sprite_height = 40 * self.scale;
+
+ monsters_setframe(spider_anim_idle);
+
+ monster_setupsounds("spider");
+
+ if not(self.spider_type)
+ self.spider_type = autocvar_g_monster_spider_attack_type;
monster_hook_spawn(); // for post-spawn mods
}
-/*QUAKED monster_spider (1 0 0) (-18 -18 -25) (18 18 47)
-Spider, 60 health points.
--------- KEYS --------
--------- SPAWNFLAGS --------
-MONSTERFLAG_APPEAR: monster will spawn when triggered.
----------NOTES----------
--------- MODEL FOR RADIANT ONLY - DO NOT SET THIS AS A KEY --------
-modeldisabled="models/monsters/spider.dpm"
-*/
void spawnfunc_monster_spider()
{
- if not(autocvar_g_monster_spider)
- {
- remove(self);
- return;
- }
+ if not(autocvar_g_monster_spider) { remove(self); return; }
self.monster_spawnfunc = spawnfunc_monster_spider;
- self.classname = "monster_spider";
- if(!self.spider_type)
- self.spider_type = autocvar_g_monster_spider_attack_type;
- if(self.spawnflags & MONSTERFLAG_APPEAR)
- {
- self.think = func_null;
- self.nextthink = -1;
- self.use = Monster_Appear;
+ if(Monster_CheckAppearFlags(self))
return;
- }
if not (monster_initialize(
- "Spider",
- "models/monsters/spider.dpm",
+ "Spider", MONSTER_SPIDER,
SPIDER_MIN, SPIDER_MAX,
FALSE,
spider_die, spider_spawn))
return;
}
}
+
+#endif // SVQC