set g_td_pvp 0
set g_td_monsters_skill_start 1
set g_td_monsters_skill_increment 0.1
-set g_td_monster_spawn_protection_radius 300
+set g_td_monsters_spawnshield_time 2
set g_td_max_waves 8
set g_td_kill_points 5
set g_td_turretkill_points 3
set g_monster_spider 1 "Enable Spiders"
set g_monster_spider_attack_type 0 "Spider attack type (0 = ice, 1 = fire, ...)"
set g_monster_spider_attack_leap_delay 1.5 "Delay after spider attack leap"
-set g_monster_spider_attack_leap_range 96 "Range of spider attack leap"
set g_monster_spider_attack_stand_damage 35 "Damage when spider hits from a standing position"
set g_monster_spider_attack_stand_delay 1.2 "Delay after a spider hits from a standing position"
-set g_monster_spider_attack_stand_range 48 "Range of a spider standing position attack"
set g_monster_spider_health 200 "Spider health"
set g_monster_spider_idle_timer_min 1 "Minimum time a spider can stay idle"
set g_monster_spider_speed_walk 150 "Spider walk speed"
set g_monster_spider_speed_run 400 "Spider run speed"
set g_monster_spider_stopspeed 100 Speed at which spider stops"
-set g_monster_spider_target_recheck_delay 5 How much time should a spider run afer an enemy before checking if it's still in range"
-set g_monster_spider_target_range 1200 How far the spider can see an enemy"
set g_monster_spider_drop health "Spider drops this item on death"
set g_monster_spider_drop_size large "Size of the item spiders drop. Possible values are: small, medium, large"
\ No newline at end of file
float autocvar_g_td_tower_buff_cost;
float autocvar_g_td_monsters_skill_start;
float autocvar_g_td_monsters_skill_increment;
-float autocvar_g_td_monster_spawn_protection_radius;
+float autocvar_g_td_monsters_spawnshield_time;
float autocvar_g_za_monster_count;
float autocvar_g_monsters;
float autocvar_g_monsters_max;
return;
if(self.enemy != other)
+ if not(other.flags & FL_MONSTER)
if(monster_isvalidtarget(other, self, FALSE))
self.enemy = other;
}
entity FindTarget (entity ent)
{
- if(MUTATOR_CALLHOOK(MonsterFindTarget)) { return ent.goalentity; } // Handled by a mutator
+ if(MUTATOR_CALLHOOK(MonsterFindTarget)) { return ent.enemy; } // Handled by a mutator
local entity e;
for(e = world; (e = findflags(e, monster_attack, TRUE)); )
{
void demon_think ()
{
self.think = demon_think;
- self.nextthink = time + 0.3;
+ self.nextthink = time + 0.1;
monster_move(autocvar_g_monster_demon_speed_run, autocvar_g_monster_demon_speed_walk, 100, demon_anim_run, demon_anim_walk, demon_anim_stand);
}
void dog_think ()
{
self.think = dog_think;
- self.nextthink = time + 0.3;
+ self.nextthink = time + 0.1;
monster_move(autocvar_g_monster_dog_speed_run, autocvar_g_monster_dog_speed_walk, 50, dog_anim_run, dog_anim_walk, dog_anim_idle);
}
void enforcer_think ()
{
self.think = enforcer_think;
- self.nextthink = time + 0.3;
+ self.nextthink = time + 0.1;
if(self.delay != -1)
self.nextthink = self.delay;
void fish_think ()
{
self.think = fish_think;
- self.nextthink = time + 0.3;
+ self.nextthink = time + 0.1;
monster_move(autocvar_g_monster_fish_speed_run, autocvar_g_monster_fish_speed_walk, 10, fish_anim_swim, fish_anim_swim, fish_anim_swim);
}
void hellknight_think ()
{
self.think = hellknight_think;
- self.nextthink = time + 0.3;
+ self.nextthink = time + 0.1;
monster_move(autocvar_g_monster_hellknight_speed_run, autocvar_g_monster_hellknight_speed_walk, 100, hellknight_anim_run, hellknight_anim_walk, hellknight_anim_stand);
}
void knight_think ()
{
self.think = knight_think;
- self.nextthink = time + 0.3;
+ self.nextthink = time + 0.1;
monster_move(autocvar_g_monster_knight_speed_run, autocvar_g_monster_knight_speed_walk, 50, knight_anim_run, knight_anim_walk, knight_anim_stand);
}
void ogre_think ()
{
self.think = ogre_think;
- self.nextthink = time + 0.3;
+ self.nextthink = time + 0.1;
if(self.delay != -1)
self.nextthink = self.delay;
void shalrath_think ()
{
self.think = shalrath_think;
- self.nextthink = time + 0.3;
+ self.nextthink = time + 0.1;
if(self.delay != -1)
self.nextthink = self.delay;
void shambler_think ()
{
self.think = shambler_think;
- self.nextthink = time + 0.3;
+ self.nextthink = time + 0.1;
monster_move(autocvar_g_monster_shambler_speed_run, autocvar_g_monster_shambler_speed_walk, 300, shambler_anim_run, shambler_anim_walk, shambler_anim_stand);
}
void soldier_think ()
{
self.think = soldier_think;
- self.nextthink = time + 0.3;
+ self.nextthink = time + 0.1;
if(self.delay != -1)
self.nextthink = self.delay;
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_leap_range;
float autocvar_g_monster_spider_attack_stand_damage;
float autocvar_g_monster_spider_attack_stand_delay;
-float autocvar_g_monster_spider_attack_stand_range;
float autocvar_g_monster_spider_health;
-float autocvar_g_monster_spider_idle_timer_min;
float autocvar_g_monster_spider_speed_walk;
float autocvar_g_monster_spider_speed_run;
-float autocvar_g_monster_spider_target_recheck_delay;
-float autocvar_g_monster_spider_target_range;
float autocvar_g_monster_spider_attack_type;
// spider animations
}
}
-void spider_think()
+float spider_attack_ranged()
{
- float finished = FALSE, enemyDistance = 0, mySpeed = 0;
+ spider_attack_leap();
+ return TRUE;
+}
+void spider_think()
+{
self.think = spider_think;
+ self.nextthink = time + 0.1;
- if(self.enemy && !monster_isvalidtarget(self.enemy, self, FALSE))
- self.enemy = world;
-
- if (self.enemy)
- if (self.enemy.team == self.team || self.monster_owner == self.enemy)
- self.enemy = world;
-
- if(teamplay && autocvar_g_monsters_teams && self.monster_owner.team != self.team)
- self.monster_owner = world;
-
- // remove enemy that ran away
- if (self.enemy)
- if (self.delay <= time) // check if we can do the rescan now
- if (vlen(self.origin - self.enemy.origin) > autocvar_g_monster_spider_target_range * self.scale)
- {
- //print("removing enemy, he is too far: ", ftos(vlen(self.origin - self.enemy.origin)), "\n");
- //print("delay was ", ftos(self.delay), "\n");
- self.enemy = world;
- }
- else
- self.delay = time + autocvar_g_monster_spider_target_recheck_delay;
-
- // find an enemy if no enemy available
- if not(self.enemy)
- {
- self.enemy = FindTarget(self);
- if (self.enemy)
- self.delay = time + autocvar_g_monster_spider_target_recheck_delay;
- }
-
- if (self.enemy)
- {
- // this spider has an enemy, attack if close enough, go to it if not!
- traceline(self.origin, self.enemy.origin, FALSE, self);
- enemyDistance = vlen(trace_endpos - self.origin);
- mySpeed = vlen(self.velocity);
-
- //print("speed ", ftos(mySpeed), "\n");
-
- if (trace_ent == self.enemy)
- if (self.enemy.deadflag == DEAD_NO)
- if (enemyDistance <= autocvar_g_monster_spider_attack_stand_range * self.scale && mySpeed <= 30)
- {
-
- //RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity ignore, float forceintensity, float deathtype, entity directhitentity)
- spider_attack_standing();
- finished = TRUE;
- }
- else if (enemyDistance <= autocvar_g_monster_spider_attack_leap_range * self.scale && !self.enemy.frozen)
- {
- // do attackleap (set yaw, velocity, and check do damage on the first player entity it touches)
- spider_attack_leap();
- finished = TRUE;
- }
-
- }
-
- self.nextthink = time + 1;
-
- if not(finished)
- {
- 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);
-
- if (self.enemy || self.monster_owner)
- {
- self.nextthink = time + 0.1;
- return;
- }
- }
-
- if not(self.enemy || self.monster_owner || self.goalentity)
- {
- // stay idle
- //print("spider is idling while waiting for some fresh meat...\n");
- if (mySpeed <= 10)
- self.frame = spider_anim_idle;
- else
- self.frame = spider_anim_walk;
- self.nextthink = time + autocvar_g_monster_spider_idle_timer_min * random();
- }
+ 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.nextthink = time + random() * 0.5 + 0.1;
self.pain_finished = self.nextthink;
self.frame = spider_anim_idle;
+ self.attack_melee = spider_attack_standing;
+ self.attack_ranged = spider_attack_ranged;
self.think = spider_think;
self.sprite_height = 40 * self.scale;
void tarbaby_think ()
{
self.think = tarbaby_think;
- self.nextthink = time + 0.3;
+ self.nextthink = time + 0.1;
monster_move(autocvar_g_monster_tarbaby_speed_run, autocvar_g_monster_tarbaby_speed_walk, 20, tarbaby_anim_run, tarbaby_anim_walk, tarbaby_anim_walk);
}
void wizard_think ()
{
self.think = wizard_think;
- self.nextthink = time + 0.3;
+ self.nextthink = time + 0.1;
monster_move(autocvar_g_monster_wizard_speed_run, autocvar_g_monster_wizard_speed_walk, 300, wizard_anim_fly, wizard_anim_hover, wizard_anim_hover);
}
void zombie_think()
{
self.think = zombie_think;
- self.nextthink = time + 0.3;
+ self.nextthink = time + 0.1;
monster_move(autocvar_g_monster_zombie_speed_run, autocvar_g_monster_zombie_speed_walk, autocvar_g_monster_zombie_stopspeed, zombie_anim_runforward, zombie_anim_runforward, zombie_anim_idle);
}
totalmonsters = ((self.monstercount) ? self.monstercount : autocvar_g_td_monster_count);
wave_count = ((self.startwave) ? self.startwave : autocvar_g_td_start_wave);
max_turrets = ((self.maxturrets) ? self.maxturrets : autocvar_g_td_turret_max);
+ build_time = ((self.buildtime) ? self.buildtime : autocvar_g_td_buildphase_time);
wave_end(TRUE);
}
default:
self.classname = "monster_swarm"; break;
}
-
- if(!self.protection_radius)
- self.protection_radius = autocvar_g_td_monster_spawn_protection_radius;
if(self.target2 != "")
{
GameLogEcho(sprintf(":buildphase:%d:%d", wave_count, totalmonsters));
self.think = combat_phase_announce;
- self.nextthink = time + autocvar_g_td_buildphase_time - 6;
+ self.nextthink = time + build_time - 6;
}
void wave_end(float starting)
if(frag_attacker.realowner == frag_target)
frag_damage = 0;
+ if(frag_target.flags & FL_MONSTER && time < frag_target.spawnshieldtime)
+ frag_damage = 0;
+
if(frag_target.vehicle_flags & VHF_ISVEHICLE && !DEATH_ISMONSTER(frag_deathtype))
frag_damage = 0;
return FALSE;
}
+ if((vlen(self.goalentity.origin - self.origin) <= 100 && self.goalentity.classname == "td_waypoint") || (vlen(self.goalentity.origin - self.origin) <= 200 && self.flags & FL_FLY && self.goalentity.classname == "td_waypoint"))
+ {
+ self.target = self.goalentity.target;
+ self.goalentity = find(world, targetname, self.target);
+ }
+
+ if(self.goalentity == world)
+ self.goalentity = generator;
+
monster_speed_run = 110 * monster_skill;
monster_speed_walk = 75 * monster_skill;
- if(vlen(self.realowner.origin - self.origin) < self.realowner.protection_radius && self.realowner.classname == "monster_swarm")
- self.takedamage = DAMAGE_NO;
- else
- self.takedamage = DAMAGE_AIM;
-
return FALSE;
}
return TRUE;
}
+ self.spawnshieldtime = time + autocvar_g_td_monsters_spawnshield_time;
+
self.lastcheck = time;
self.drop_size = self.health * 0.05;
FOR_EACH_PLAYER(player) { ++n_players; }
if(n_players < 1) // no players online, so do nothing
- {
return TRUE;
- }
-
- if(vlen(self.goalentity.origin - self.origin) <= 100 && self.goalentity.classname == "waypoint")
- self.goalentity.lastchecked = self;
-
- if((vlen(self.goalentity.origin - self.origin) <= 100 && self.goalentity.classname == "td_waypoint") || (vlen(self.goalentity.origin - self.origin) <= 200 && self.flags & FL_FLY && self.goalentity.classname == "td_waypoint"))
- {
- self.goalentity = find(world, targetname, self.goalentity.target);
- self.target = self.goalentity.target;
- }
if(generator == world)
{
if((vlen(trace_endpos - self.origin) < 100 && e.turrcaps_flags & TFL_TURRCAPS_ISTURRET) || (vlen(trace_endpos - self.origin) < 200 && e != generator) || (vlen(trace_endpos - self.origin) < 500 && e == generator))
{
self.enemy = e;
- return TRUE;
- }
- }
- if(self.target) // follow target if available
- {
- self.goalentity = find(world, targetname, self.target);
- if(self.goalentity == world)
- self.goalentity = generator;
- return TRUE;
- }
- else
- self.goalentity = generator;
-
- for(e = world;(e = find(e, classname, "waypoint")); )
- {
- if(vlen(e.origin - self.origin) < 500)
- if(e.lastchecked != self)
- if(vlen(e.origin - self.origin) > 50)
- {
- //print(strcat("Goal found at ", vtos(e.origin), "\n"));
- self.goalentity = e;
}
}
float SWARM_STRONG = 2;
float SWARM_FLY = 3;
float SWARM_SWIM = 4;
+float build_time;
float td_dont_end;
.float lastcheck;
void(float starting) wave_end;
float td_gencount;
void() spawnfunc_td_controller;
float oldrespawncvar;
-.float protection_radius;
float current_phase;
#define PHASE_BUILD 1
#define PHASE_COMBAT 2
.float startwave;
.float dontend;
.float maxturrets;
+.float buildtime;
// Generator
float gendestroyed;
-.entity lastchecked;
entity generator; // global generator entity (TODO: replace with a script for multi generator support?)
float gendmg;
#define GENERATOR_MIN '-52 -52 -14'