From: Mario Date: Thu, 7 Mar 2013 01:29:09 +0000 (+1100) Subject: Fix build phase message & rename tower defense files X-Git-Tag: xonotic-v0.8.0~241^2^2~469 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=261e53194d464d75f6661847fa5b8e3067c27b5a;p=xonotic%2Fxonotic-data.pk3dir.git Fix build phase message & rename tower defense files --- diff --git a/qcsrc/common/notifications.qh b/qcsrc/common/notifications.qh index b7f1e9a1a..dd8ca7e39 100644 --- a/qcsrc/common/notifications.qh +++ b/qcsrc/common/notifications.qh @@ -336,7 +336,7 @@ void Send_Notification_WOVA( MSG_INFO_NOTIF(1, INFO_TD_NOFUEL, 0, 0, "", "", "", _("^K1You don't have enough fuel to spawn that turret\n"), "") \ MSG_INFO_NOTIF(1, INFO_TD_NOFUEL_REPAIR, 0, 1, "f1", "", "", _("^K1You need %s fuel to repair this turret\n"), "") \ MSG_INFO_NOTIF(1, INFO_TD_NOFUEL_UPGRADE, 0, 1, "f1", "", "", _("^K1You need %s fuel to increase this turret's power\n"), "") \ - MSG_INFO_NOTIF(1, INFO_TD_PHASE_BUILD, 1, 0, "s1", "", "", _("^BG%s\n"), "") \ + MSG_INFO_NOTIF(1, INFO_TD_PHASE_BUILD, 0, 3, "f1 f2 f3", "", "", _("^F2Wave %s^BG build phase... Next monsters: ^F2%s^BG, wave starts in ^F2%s seconds\n"), "") \ MSG_INFO_NOTIF(1, INFO_TD_PHASE_COMBAT, 0, 0, "", "", "", _("^K1Combat phase!\n"), "") \ MSG_INFO_NOTIF(1, INFO_TD_REMOVE, 0, 0, "", "", "", _("^BGTurret removed\n"), "") \ MSG_INFO_NOTIF(1, INFO_TD_REPAIR, 0, 0, "", "", "", _("^F1Turret repaired by 100 health points!\n"), "") \ @@ -520,7 +520,7 @@ void Send_Notification_WOVA( MSG_CENTER_NOTIF(1, CENTER_TD_ANNOUNCE_SPAWN, 1, 0, "s1", CPID_TOWERDEFENSE, "3 0", _("^K1A ^K2%s^K1 has arrived!"), "") \ MSG_CENTER_NOTIF(1, CENTER_TD_GENDAMAGED, 0, 0, "", CPID_TOWERDEFENSE, "0 0", _("^K1The generator is under attack!"), "") \ MSG_CENTER_NOTIF(1, CENTER_TD_GENDESTROYED, 0, 0, "", CPID_TOWERDEFENSE, "0 0", _("^K1A generator was destroyed!"), "") \ - MSG_CENTER_NOTIF(1, CENTER_TD_PHASE_BUILD, 1, 0, "s1", CPID_TOWERDEFENSE, "5 0", _("^BG%s"), "") \ + MSG_CENTER_NOTIF(1, CENTER_TD_PHASE_BUILD, 0, 3, "f1 f2 f3", CPID_TOWERDEFENSE, "5 0", _("^BGWave ^F2%s^BG build phase... Next monsters: ^F2%s^BG, wave starts in ^F2%s seconds"), "") \ MSG_CENTER_NOTIF(1, CENTER_TD_PHASE_COMBAT, 0, 0, "", CPID_TOWERDEFENSE, "0 0", _("^K1Combat phase!"), "") \ MSG_CENTER_NOTIF(1, CENTER_TD_VICTORY, 1, 0, "s1", CPID_TOWERDEFENSE, "0 0", _("^F1%s^F1 victory!"), "") \ MULTITEAM_CENTER(1, CENTER_TEAMCHANGE_, 4, 0, 1, "", CPID_TEAMCHANGE, "1 f1", _("^K1Changing to ^TC^TT^K1 in ^COUNT"), "") \ diff --git a/qcsrc/server/mutators/gamemode_td.qc b/qcsrc/server/mutators/gamemode_td.qc deleted file mode 100644 index 2f962d799..000000000 --- a/qcsrc/server/mutators/gamemode_td.qc +++ /dev/null @@ -1,1104 +0,0 @@ -// Tower Defense -// Gamemode by Mario - -void spawnfunc_td_controller() -{ - if not(g_td) { remove(self); return; } - - if(autocvar_g_td_force_settings) - { - // TODO: find a better way to do this? - self.dontend = FALSE; - self.maxwaves = 0; - self.monstercount = 0; - self.startwave = 0; - self.maxturrets = 0; - self.buildtime = 0; - self.mspeed_walk = 0; - self.mspeed_run = 0; - self.spawndelay = 0; - self.maxcurrent = 0; - self.ignoreturrets = 0; - } - - self.netname = "Tower Defense controller entity"; - self.classname = "td_controller"; - - gensurvived = FALSE; - td_dont_end = ((self.dontend) ? self.dontend : autocvar_g_td_generator_dontend); - max_waves = ((self.maxwaves) ? self.maxwaves : autocvar_g_td_max_waves); - 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); - m_speed_walk = ((self.mspeed_walk) ? self.mspeed_walk : autocvar_g_td_monsters_speed_walk); - m_speed_run = ((self.mspeed_run) ? self.mspeed_run : autocvar_g_td_monsters_speed_run); - spawn_delay = ((self.spawndelay) ? self.spawndelay : autocvar_g_td_monsters_spawn_delay); - max_current = ((self.maxcurrent) ? self.maxcurrent : autocvar_g_td_current_monsters); - ignore_turrets = ((self.ignoreturrets) ? self.ignoreturrets : autocvar_g_td_monsters_ignore_turrets); - - if(autocvar_g_td_monsters_skill_start) - monster_skill = autocvar_g_td_monsters_skill_start; - - wave_end(TRUE); -} - -void td_generator_die() -{ - if(autocvar_sv_eventlog) - GameLogEcho(":gendestroyed"); - - gendestroyed = TRUE; - - Send_Notification(NOTIF_ALL, world, MSG_MULTI, MULTI_TD_GENDESTROYED); - - setmodel(self, "models/onslaught/generator_dead.md3"); - self.solid = SOLID_NOT; - self.takedamage = DAMAGE_NO; - self.event_damage = func_null; - self.enemy = world; - td_gencount -= 1; - - pointparticles(particleeffectnum("explosion_medium"), self.origin, '0 0 0', 1); - - WaypointSprite_Kill(self.sprite); -} - -void td_generator_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) -{ - if(attacker.classname == STR_PLAYER || attacker.turrcaps_flags & TFL_TURRCAPS_ISTURRET || attacker.vehicle_flags & VHF_ISVEHICLE) - return; - - Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_TD_GENDAMAGED); - - self.health -= damage; - - WaypointSprite_UpdateHealth(self.sprite, self.health); - - if(self.health <= 0) - td_generator_die(); -} - -void spawnfunc_td_generator() -{ - if not(g_td) { remove(self); return; } - - gendestroyed = FALSE; - - if not(self.health) - self.health = autocvar_g_td_generator_health; - - // precache generator model - precache_model("models/onslaught/generator.md3"); - precache_model("models/onslaught/generator_dead.md3"); - - self.model = "models/onslaught/generator.md3"; - setmodel(self, self.model); - self.classname = "td_generator"; - self.solid = SOLID_BBOX; - self.takedamage = DAMAGE_AIM; - self.event_damage = td_generator_damage; - self.enemy = world; - self.nextthink = -1; - self.think = func_null; - self.max_health = self.health; - self.movetype = MOVETYPE_NONE; - self.monster_attack = TRUE; - td_gencount += 1; - self.netname = "Generator"; - - setsize(self, GENERATOR_MIN, GENERATOR_MAX); - - droptofloor(); - - WaypointSprite_SpawnFixed(self.netname, self.origin + '0 0 60', self, sprite, RADARICON_OBJECTIVE, '1 0.5 0'); - WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health); - WaypointSprite_UpdateHealth(self.sprite, self.health); -} - -entity PickGenerator() -{ - entity generator, head; - if(td_gencount == 1) - generator = find(world, classname, "td_generator"); - else - { - RandomSelection_Init(); - for(head = world;(head = find(head, classname, "td_generator")); ) - { - RandomSelection_Add(head, 0, string_null, 1, 1); - } - generator = RandomSelection_chosen_ent; - } - return generator; -} - -void spawn_td_fuel(float fuel_size) -{ - if not(g_td) {remove(self); return; } - - self.ammo_fuel = fuel_size * monster_skill; - StartItem("models/items/g_fuel.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "Turret Fuel", IT_FUEL, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW); - - self.velocity = randomvec() * 175 + '0 0 325'; -} - -void spawnfunc_td_waypoint() -{ - if not(g_td) { remove(self); return; } - - self.classname = "td_waypoint"; -} - -void spawnfunc_monster_swarm() -{ - if not(g_td) { remove(self); return; } - - self.flags = SWARM_NORMAL; // marked as a spawnpoint - self.classname = "monster_swarm"; - - if(self.spawntype == SWARM_SWIM) waterspawns_count += 1; - if(self.spawntype == SWARM_FLY) flyspawns_count += 1; - - WaypointSprite_SpawnFixed("Monsters", self.origin + '0 0 60', self, sprite, RADARICON_HERE, '0 0 1'); - - if(self.target == "") - dprint("Warning: monster_swarm entity without a set target\n"); -} - -void barricade_touch() -{ - if not(other.flags & FL_MONSTER) - return; - - if(time < self.dmg_time) - return; - - Damage(other, self, self, autocvar_g_td_barricade_damage, DEATH_HURTTRIGGER, self.origin, '0 0 0'); - - self.dmg_time = time + 1; -} - -void barricade_die() -{ - self.takedamage = DAMAGE_NO; - self.event_damage = func_null; - - WaypointSprite_Kill(self.sprite); - - pointparticles(particleeffectnum("explosion_medium"), self.origin, '0 0 0', 1); - sound(self, CH_SHOTS, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM); - - if(self.realowner) - self.realowner.turret_cnt -= 1; - - self.think = SUB_Remove; - self.nextthink = time; -} - -void barricade_damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) -{ - if not(attacker.flags & FL_MONSTER) return; - - self.health -= damage; - - WaypointSprite_UpdateHealth(self.sprite, self.health); - - if(self.health < 1) - barricade_die(); -} - -void spawn_barricade() -{ - self.health = 2000; - self.max_health = self.health; - self.dmg_time = time; - self.touch = barricade_touch; - self.think = func_null; - self.nextthink = -1; - self.takedamage = DAMAGE_AIM; - self.turrcaps_flags = TFL_TURRCAPS_ISTURRET; // for turretremove commands etc. - self.solid = SOLID_CORPSE; // hax - self.event_damage = barricade_damage; - self.netname = "Barricade"; - - WaypointSprite_Spawn(self.netname, 0, 1200, self, '0 0 110', world, 0, self, sprite, FALSE, RADARICON_DOMPOINT, '1 1 0'); - WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health); - WaypointSprite_UpdateHealth(self.sprite, self.health); - - precache_model("models/td/barricade.md3"); - setmodel(self, "models/td/barricade.md3"); - - droptofloor(); - - self.movetype = MOVETYPE_NONE; -} - -void spawnturret(entity spawnedby, entity own, string turet, vector orig) -{ - if(spawnedby.classname != STR_PLAYER) - { - dprint("Warning: A non-player entity tried to spawn a turret\n"); - return; - } - - entity oldself; - - oldself = self; - self = spawn(); - - setorigin(self, orig); - self.spawnflags = TSL_NO_RESPAWN; - self.monster_attack = TRUE; - self.realowner = own; - self.angles_y = spawnedby.v_angle_y; - spawnedby.turret_cnt += 1; - self.colormap = spawnedby.colormap; - - switch(turet) - { - default: - case "plasma": spawnfunc_turret_plasma(); break; - case "mlrs": spawnfunc_turret_mlrs(); break; - case "phaser": spawnfunc_turret_phaser(); break; - case "hellion": spawnfunc_turret_hellion(); break; - case "walker": spawnfunc_turret_walker(); break; - case "flac": spawnfunc_turret_flac(); break; - case "tesla": spawnfunc_turret_tesla(); break; - case "fusionreactor": spawnfunc_turret_fusionreactor(); break; - case "barricade": spawn_barricade(); break; - } - - self = oldself; -} - -void buffturret (entity tur, float buff) -{ - tur.turret_buff += 1; - tur.max_health *= buff; - tur.tur_health = tur.max_health; - tur.health = tur.max_health; - tur.ammo_max *= buff; - tur.ammo_recharge *= buff; - tur.shot_dmg *= buff; - tur.shot_refire -= buff * 0.2; - tur.shot_radius *= buff; - tur.shot_speed *= buff; - tur.shot_spread *= buff; - tur.shot_force *= buff; -} - -void AnnounceSpawn(string anounce) -{ - Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_TD_ANNOUNCE_SPAWN, anounce); -} - -entity PickSpawn (float strngth, float type) -{ - entity e; - RandomSelection_Init(); - for(e = world;(e = find(e, classname, "monster_swarm")); ) - { - if(flyspawns_count > 0 && type == SWARM_FLY && e.spawntype != SWARM_FLY) continue; - if(waterspawns_count > 0 && type == SWARM_SWIM && e.spawntype != SWARM_SWIM) continue; - - RandomSelection_Add(e, 0, string_null, 1, 1); - } - - return RandomSelection_chosen_ent; -} - -void TD_SpawnMonster(string mnster, float strngth, float type) -{ - entity e, mon; - - e = PickSpawn(strngth, type); - - if(e == world) // couldn't find anything for our class, so check for normal spawns - e = PickSpawn(SWARM_NORMAL, SWARM_NORMAL); - - if(e == world) - { - dprint("Warning: couldn't find any monster_swarm spawnpoints, no monsters will spawn!\n"); - return; - } - - mon = spawnmonster(mnster, e, e, e.origin, FALSE, 0); - if(e.target2) - { - if(random() > 0.5) - mon.target = e.target2; - else - mon.target = e.target; - } - else - mon.target = e.target; -} - -float Monster_GetStrength(string mnster) -{ - switch(mnster) - { - case "knight": - case "wizard": - case "soldier": - case "enforcer": - case "zombie": - case "tarbaby": - case "dog": - case "spider": - case "fish": - return SWARM_WEAK; - case "ogre": - case "shambler": - case "shalrath": - case "hellknight": - case "demon": - return SWARM_STRONG; - default: - return SWARM_NORMAL; - } -} - -float Monster_GetType(string mnster) -{ - switch(mnster) - { - default: - case "knight": - case "soldier": - case "enforcer": - case "zombie": - case "spider": - case "tarbaby": - case "dog": - case "ogre": - case "shambler": - case "shalrath": - case "hellknight": - case "demon": - return SWARM_NORMAL; - case "wizard": - return SWARM_FLY; - case "fish": - return SWARM_SWIM; - } -} - -string RandomMonster() -{ - RandomSelection_Init(); - - if(n_demons) RandomSelection_Add(world, 0, "demon", 1, 1); - if(n_shalraths) RandomSelection_Add(world, 0, "vore", 1, 1); - if(n_soldiers) RandomSelection_Add(world, 0, "soldier", 1, 1); - if(n_hknights) RandomSelection_Add(world, 0, "hellknight", 1, 1); - if(n_enforcers) RandomSelection_Add(world, 0, "enforcer", 1, 1); - if(n_zombies) RandomSelection_Add(world, 0, "zombie", 1, 1); - if(n_spiders) RandomSelection_Add(world, 0, "spider", 1, 1); - if(n_ogres) RandomSelection_Add(world, 0, "ogre", 1, 1); - if(n_dogs) RandomSelection_Add(world, 0, "dog", 1, 1); - if(n_knights) RandomSelection_Add(world, 0, "knight", 1, 1); - if(n_shamblers) RandomSelection_Add(world, 0, "shambler", 0.2, 0.2); - if(n_tarbabies) RandomSelection_Add(world, 0, "spawn", 0.2, 0.2); - if(n_wizards && flyspawns_count) RandomSelection_Add(world, 0, "scrag", 1, 1); - if(n_fish && waterspawns_count) RandomSelection_Add(world, 0, "fish", 0.2, 0.2); - - return RandomSelection_chosen_string; -} - -void combat_phase() -{ - string whichmon; - float mstrength, montype; - - current_phase = PHASE_COMBAT; - - if(monster_count <= 0) - { - wave_end(FALSE); - return; - } - - self.think = combat_phase; - - whichmon = RandomMonster(); - - mstrength = Monster_GetStrength(whichmon); - montype = Monster_GetType(whichmon); - - if(current_monsters <= max_current && whichmon != "") - { - TD_SpawnMonster(whichmon, mstrength, montype); - self.nextthink = time + spawn_delay; - } - else - self.nextthink = time + 6; -} - -void queue_monsters(float maxmonsters) -{ - float mc = 11; // note: shambler + tarbaby = 1 - - if(waterspawns_count > 0) - mc += 1; - if(flyspawns_count > 0) - mc += 1; - - DistributeEvenly_Init(maxmonsters, mc); - n_demons = DistributeEvenly_Get(1); - n_ogres = DistributeEvenly_Get(1); - n_dogs = DistributeEvenly_Get(1); - n_knights = DistributeEvenly_Get(1); - n_shalraths = DistributeEvenly_Get(1); - n_soldiers = DistributeEvenly_Get(1); - n_hknights = DistributeEvenly_Get(1); - n_enforcers = DistributeEvenly_Get(1); - n_zombies = DistributeEvenly_Get(1); - n_spiders = DistributeEvenly_Get(1); - n_tarbabies = DistributeEvenly_Get(0.7); - n_shamblers = DistributeEvenly_Get(0.3); - if(flyspawns_count > 0) - n_wizards = DistributeEvenly_Get(1); - if(waterspawns_count > 0) - n_fish = DistributeEvenly_Get(1); -} - -void combat_phase_begin() -{ - monster_count = totalmonsters; - entity gen; - - Send_Notification(NOTIF_ALL, world, MSG_MULTI, MULTI_TD_PHASE_COMBAT); - - if(autocvar_sv_eventlog) - GameLogEcho(":combatphase"); - - self.think = combat_phase; - self.nextthink = time + 1; - - for(gen = world;(gen = find(gen, classname, "td_generator")); ) - gen.takedamage = DAMAGE_AIM; -} - -float cphase_updates; -void combat_phase_announce() // TODO: clean up these fail nextthinks... -{ - cphase_updates += 1; - - if(cphase_updates == 0) - Announce("prepareforbattle"); - else if(cphase_updates == 3) - Announce("3"); - else if(cphase_updates == 4) - Announce("2"); - else if(cphase_updates == 5) - Announce("1"); - else if(cphase_updates == 6) - { - Announce("begin"); - combat_phase_begin(); - } - - if(cphase_updates >= 6) - return; - - self.think = combat_phase_announce; - self.nextthink = time + 1; -} - -void build_phase() -{ - entity head; - float n_players = 0, gen_washealed = FALSE, player_washealed = FALSE; - string buildmsg, healmsg, countmsg, startmsg, genhealmsg, mainmsg; - - current_phase = PHASE_BUILD; - - for(head = world;(head = find(head, classname, "td_generator")); ) - { - if(head.health <= 5 && head.max_health > 10) - Announce("lastsecond"); - - if(head.health < head.max_health) - { - gen_washealed = TRUE; - head.health = head.max_health; - WaypointSprite_UpdateHealth(head.sprite, head.health); - } - head.takedamage = DAMAGE_NO; - } - - FOR_EACH_PLAYER(head) - { - if(head.health < 100) - { - player_washealed = TRUE; - break; // we found 1, so no need to check the others - } - } - - totalmonsters += autocvar_g_td_monster_count_increment * wave_count; - monster_skill += autocvar_g_td_monsters_skill_increment; - - if(wave_count < 1) wave_count = 1; - - // TODO: make this play better with the notification system? - genhealmsg = (gen_washealed) ? ((td_gencount == 1) ? " and generator " : " and generators ") : ""; - buildmsg = sprintf("%s build phase... ", (wave_count == max_waves) ? "^1Final wave^3" : strcat("Wave ", ftos(wave_count))); - healmsg = (player_washealed) ? strcat("All players ", genhealmsg, "healed. ") : ""; - countmsg = strcat("Next monsters: ", ftos(totalmonsters), ". "); - startmsg = strcat("Wave starts in ", ftos(autocvar_g_td_buildphase_time), " seconds"); - mainmsg = strcat(buildmsg, healmsg, countmsg, startmsg); - - Send_Notification(NOTIF_ALL, world, MSG_MULTI, MULTI_TD_PHASE_BUILD, mainmsg); - - FOR_EACH_PLAYER(head) - { - if(head.health < 100) head.health = 100; - - if(gen_washealed) PlayerScore_Add(head, SP_TD_SCORE, -autocvar_g_td_generator_damaged_points); - - n_players += 1; - } - - FOR_EACH_MONSTER(head) - { - if(head.health <= 0) - continue; - - dprint(strcat("Warning: Monster still alive during build phase! Monster name: ", head.netname, "\n")); - - WaypointSprite_Kill(head.sprite); - remove(head); - } - - if(n_players >= 2) - { - totalmonsters += n_players; - monster_skill += n_players * 0.05; - } - - if(monster_skill < 1) monster_skill = 1; - - if(totalmonsters < 1) totalmonsters = ((autocvar_g_td_monster_count > 0) ? autocvar_g_td_monster_count : 10); - - monsters_total = totalmonsters; - monsters_killed = 0; - - queue_monsters(totalmonsters); - - cphase_updates = -1; - - if(autocvar_sv_eventlog) - GameLogEcho(strcat(":buildphase:", ftos(wave_count), ":", ftos(totalmonsters))); - - self.think = combat_phase_announce; - self.nextthink = time + build_time - 6; -} - -void wave_end(float starting) -{ - if not(starting) - { - Send_Notification(NOTIF_ALL, world, MSG_MULTI, MULTI_TD_VICTORY, ((wave_count >= max_waves) ? "Level" : "Wave")); - - if(autocvar_sv_eventlog) - GameLogEcho(strcat(":wave:", ftos(wave_count), ":victory")); - } - - if(wave_count >= max_waves) - { - gensurvived = TRUE; - return; - } - - if not(starting) - wave_count += 1; - - self.think = build_phase; - self.nextthink = time + 3; -} - -void td_ScoreRules() -{ - ScoreInfo_SetLabel_PlayerScore(SP_TD_SCORE, "score", SFL_SORT_PRIO_PRIMARY); - ScoreInfo_SetLabel_PlayerScore(SP_TD_KILLS, "kills", SFL_LOWER_IS_BETTER); - ScoreInfo_SetLabel_PlayerScore(SP_TD_TURKILLS, "frags", SFL_LOWER_IS_BETTER); - ScoreInfo_SetLabel_PlayerScore(SP_TD_DEATHS, "deaths", SFL_LOWER_IS_BETTER); - ScoreInfo_SetLabel_PlayerScore(SP_TD_SUICIDES, "suicides", SFL_LOWER_IS_BETTER | SFL_ALLOW_HIDE); - ScoreRules_basics_end(); -} - -void td_SpawnController() -{ - entity oldself = self; - self = spawn(); - self.classname = "td_controller"; - spawnfunc_td_controller(); - self = oldself; -} - -void td_DelayedInit() -{ - if(find(world, classname, "td_controller") == world) - { - print("No ""td_controller"" entity found on this map, creating it anyway.\n"); - td_SpawnController(); - } - - td_ScoreRules(); -} - -void td_Init() -{ - InitializeEntity(world, td_DelayedInit, INITPRIO_GAMETYPE); -} - -MUTATOR_HOOKFUNCTION(td_TurretValidateTarget) -{ - if(turret_flags & TFL_TARGETSELECT_MISSILESONLY) - if(turret_target.flags & FL_PROJECTILE) - if(turret_target.owner.flags & FL_MONSTER) - return TRUE; // flac support - - if(turret.turrcaps_flags & TFL_TURRCAPS_SUPPORT && turret_target.turrcaps_flags & TFL_TURRCAPS_ISTURRET) - return TRUE; - if not(turret_target.flags & FL_MONSTER) - turret_target = world; - - return FALSE; -} - -MUTATOR_HOOKFUNCTION(td_PlayerThink) -{ - self.stat_current_wave = wave_count; - self.stat_totalwaves = max_waves; - - return FALSE; -} - -MUTATOR_HOOKFUNCTION(td_PlayerSpawn) -{ - self.bot_attack = FALSE; - - return FALSE; -} - -MUTATOR_HOOKFUNCTION(td_PlayerDies) -{ - if(frag_attacker.flags & FL_MONSTER) - PlayerScore_Add(frag_target, SP_TD_DEATHS, 1); - - if(frag_target == frag_attacker) - PlayerScore_Add(frag_attacker, SP_TD_SUICIDES, 1); - - return FALSE; -} - -MUTATOR_HOOKFUNCTION(td_GiveFragsForKill) -{ - frag_score = 0; - - return TRUE; // no frags counted in td -} - -MUTATOR_HOOKFUNCTION(td_PlayerDamage) -{ - 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 && !(frag_attacker.flags & FL_MONSTER)) - frag_damage = 0; - - if(frag_attacker.vehicle_flags & VHF_ISVEHICLE && !(frag_target.flags & FL_MONSTER)) - frag_damage = 0; - - if(!autocvar_g_td_pvp && frag_attacker != frag_target && frag_target.classname == STR_PLAYER && frag_attacker.classname == STR_PLAYER) - frag_damage = 0; - - if(frag_attacker.turrcaps_flags & TFL_TURRCAPS_ISTURRET && frag_target.classname == STR_PLAYER) - frag_damage = 0; - - if((frag_target.turrcaps_flags & TFL_TURRCAPS_ISTURRET) && !(frag_attacker.flags & FL_MONSTER || frag_attacker.turrcaps_flags & TFL_TURRCAPS_SUPPORT)) - frag_damage = 0; - - return TRUE; -} - -MUTATOR_HOOKFUNCTION(td_TurretDies) -{ - if(self.realowner) - self.realowner.turret_cnt -= 1; - - return FALSE; -} - -MUTATOR_HOOKFUNCTION(td_MonsterCheckBossFlag) -{ - // No minibosses in tower defense - return TRUE; -} - -MUTATOR_HOOKFUNCTION(td_MonsterMove) -{ - entity player; - float n_players = 0; - FOR_EACH_PLAYER(player) { ++n_players; } - - if(n_players < 1) // no players online, so do nothing - { - monster_target = world; - monster_speed_run = monster_speed_walk = 0; - return FALSE; - } - - if not(self.enemy) // don't change targets while attacking - 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")) - { - if(self.goalentity.target2) - { - if(random() > 0.5) - self.target = self.goalentity.target2; - else - self.target = self.goalentity.target; - } - else - self.target = self.goalentity.target; - - self.goalentity = find(world, targetname, self.target); - - if(self.goalentity == world) - self.goalentity = PickGenerator(); - } - - monster_speed_run = m_speed_run * monster_skill; - monster_speed_walk = m_speed_walk * monster_skill; - - return FALSE; -} - -MUTATOR_HOOKFUNCTION(td_MonsterSpawn) -{ - if(self.realowner == world) // nothing spawned it, so kill it - { - WaypointSprite_Kill(self.sprite); - remove(self); - return TRUE; - } - - current_monsters += 1; - - self.spawnshieldtime = time + autocvar_g_td_monsters_spawnshield_time; - - self.drop_size = self.health * 0.05; - - if(self.drop_size < 1) self.drop_size = 1; - - self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_BODY; - - self.origin += '0 0 25'; // hopefully this fixes monsters falling through the floor - - switch(self.classname) - { - case "monster_knight": n_knights -= 1; break; - case "monster_dog": n_dogs -= 1; break; - case "monster_ogre": n_ogres -= 1; break; - case "monster_shambler": n_shamblers -= 1; AnnounceSpawn("Shambler"); break; - case "monster_wizard": n_wizards -= 1; break; - case "monster_shalrath": n_shalraths -= 1; break; - case "monster_soldier": n_soldiers -= 1; break; - case "monster_hellknight": n_hknights -= 1; break; - case "monster_enforcer": n_enforcers -= 1; break; - case "monster_demon": n_demons -= 1; break; - case "monster_zombie": n_zombies -= 1; break; - case "monster_spider": n_spiders -= 1; break; - case "monster_tarbaby": n_tarbabies -= 1; break; - } - - return TRUE; -} - -MUTATOR_HOOKFUNCTION(td_MonsterDies) -{ - entity oldself; - vector backuporigin; - - monster_count -= 1; - current_monsters -= 1; - monsters_killed += 1; - - if(frag_attacker.classname == STR_PLAYER) - { - PlayerScore_Add(frag_attacker, SP_TD_SCORE, autocvar_g_td_kill_points); - PlayerScore_Add(frag_attacker, SP_TD_KILLS, 1); - } - else if(frag_attacker.realowner.classname == STR_PLAYER) - { - PlayerScore_Add(frag_attacker.realowner, SP_TD_SCORE, autocvar_g_td_turretkill_points); - PlayerScore_Add(frag_attacker.realowner, SP_TD_TURKILLS, 1); - } - - backuporigin = self.origin; - oldself = self; - self = spawn(); - - self.gravity = 1; - setorigin(self, backuporigin + '0 0 5'); - spawn_td_fuel(oldself.drop_size); - self.touch = M_Item_Touch; - if(self == world) - { - self = oldself; - return FALSE; - } - SUB_SetFade(self, time + 5, 1); - - self = oldself; - - return FALSE; -} - -MUTATOR_HOOKFUNCTION(td_MonsterFindTarget) -{ - float n_players = 0; - entity player; - local entity e; - - FOR_EACH_PLAYER(player) { ++n_players; } - - if(n_players < 1) // no players online, so do nothing - { - self.enemy = world; - return TRUE; - } - - for(e = world;(e = findflags(e, monster_attack, TRUE)); ) - { - if(ignore_turrets) - if(e.turrcaps_flags & TFL_TURRCAPS_ISTURRET) - continue; - - if(monster_isvalidtarget(e, self, FALSE)) - if((vlen(trace_endpos - self.origin) < 200 && e.turrcaps_flags & TFL_TURRCAPS_ISTURRET) || (vlen(trace_endpos - self.origin) < 200 && e.classname != "td_generator") || (vlen(trace_endpos - self.origin) < 500 && e.classname == "td_generator")) - { - self.enemy = e; - } - } - - return TRUE; -} - -MUTATOR_HOOKFUNCTION(td_SetStartItems) -{ - start_ammo_fuel = 150; // to be nice... - - return FALSE; -} - -MUTATOR_HOOKFUNCTION(td_TurretSpawn) -{ - if(self.realowner == world) - return TRUE; // wasn't spawned by a player - - self.bot_attack = FALSE; - self.turret_buff = 1; - - return FALSE; -} - -MUTATOR_HOOKFUNCTION(td_DisableVehicles) -{ - // you shall not spawn! - return TRUE; -} - -MUTATOR_HOOKFUNCTION(td_PlayerCommand) -{ - if(MUTATOR_RETURNVALUE) { return FALSE; } // command was already handled? - - makevectors(self.v_angle); - WarpZone_TraceLine(self.origin + self.view_ofs, self.origin + self.view_ofs + v_forward * 100, MOVE_NORMAL, self); - - if(cmd_name == "turretspawn") - { - if(argv(1) == "list") - { - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_LIST, "mlrs walker plasma towerbuff flac barricade"); - return TRUE; - } - if(self.classname != STR_PLAYER || self.health <= 0) - { - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_CANTSPAWN); - return TRUE; - } - if(self.turret_cnt >= max_turrets) - { - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_MAXTURRETS, max_turrets); - return TRUE; - } - switch(argv(1)) - { - case "plasma": - { - if(self.ammo_fuel < autocvar_g_td_turret_plasma_cost) break; - self.ammo_fuel -= autocvar_g_td_turret_plasma_cost; - spawnturret(self, self, "plasma", trace_endpos); - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_SPAWN); - return TRUE; - } - case "mlrs": - { - if(self.ammo_fuel < autocvar_g_td_turret_mlrs_cost) break; - self.ammo_fuel -= autocvar_g_td_turret_mlrs_cost; - spawnturret(self, self, "mlrs", trace_endpos); - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_SPAWN); - return TRUE; - } - case "flac": - { - if(self.ammo_fuel < autocvar_g_td_turret_flac_cost) break; - self.ammo_fuel -= autocvar_g_td_turret_flac_cost; - spawnturret(self, self, "flac", trace_endpos); - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_SPAWN); - return TRUE; - } - case "walker": - { - if(self.ammo_fuel < autocvar_g_td_turret_walker_cost) break; - self.ammo_fuel -= autocvar_g_td_turret_walker_cost; - spawnturret(self, self, "walker", trace_endpos); - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_SPAWN); - return TRUE; - } - case "towerbuff": - { - if(self.ammo_fuel < autocvar_g_td_tower_buff_cost) break; - self.ammo_fuel -= autocvar_g_td_tower_buff_cost; - spawnturret(self, self, "fusionreactor", trace_endpos); - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_SPAWN); - return TRUE; - } - case "barricade": - { - if(self.ammo_fuel < autocvar_g_td_barricade_cost) break; - self.ammo_fuel -= autocvar_g_td_barricade_cost; - spawnturret(self, self, "barricade", trace_endpos); - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_SPAWN); - return TRUE; - } - default: - { - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_INVALID); - return TRUE; - } - } - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_NOFUEL); - return TRUE; - } - if(cmd_name == "repairturret") - { - if(trace_ent.realowner != self || !(trace_ent.turrcaps_flags & TFL_TURRCAPS_ISTURRET)) - { - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_AIM_REPAIR); - return TRUE; - } - if(self.ammo_fuel < autocvar_g_td_turret_repair_cost) - { - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_NOFUEL_REPAIR, autocvar_g_td_turret_repair_cost); - return TRUE; - } - if(trace_ent.health >= trace_ent.max_health) - { - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_MAXHEALTH); - return TRUE; - } - - self.ammo_fuel -= autocvar_g_td_turret_repair_cost; - trace_ent.SendFlags |= TNSF_STATUS; - trace_ent.health = bound(1, trace_ent.health + 100, trace_ent.max_health); - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_REPAIR); - - return TRUE; - } - if(cmd_name == "buffturret") - { - if(trace_ent.realowner != self || !(trace_ent.turrcaps_flags & TFL_TURRCAPS_ISTURRET)) - { - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_AIM_UPGRADE); - return TRUE; - } - if(self.ammo_fuel < autocvar_g_td_turret_upgrade_cost) - { - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_NOFUEL_UPGRADE, autocvar_g_td_turret_upgrade_cost); - return TRUE; - } - if(trace_ent.turret_buff >= 3) - { - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_MAXPOWER); - return TRUE; - } - - self.ammo_fuel -= autocvar_g_td_turret_upgrade_cost; - trace_ent.SendFlags |= TNSF_STATUS; - buffturret(trace_ent, 1.2); - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_UPGRADE); - - return TRUE; - } - if(cmd_name == "turretremove") - { - if((trace_ent.turrcaps_flags & TFL_TURRCAPS_ISTURRET) && trace_ent.realowner == self) - { - self.turret_cnt -= 1; - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_REMOVE); - WaypointSprite_Kill(trace_ent.sprite); - remove(trace_ent.tur_head); - remove(trace_ent); - return TRUE; - } - Send_Notification(NOTIF_ONE, self, MSG_INFO, INFO_TD_AIM_REMOVE); - return TRUE; - } - - return FALSE; -} - -MUTATOR_DEFINITION(gamemode_td) -{ - MUTATOR_HOOK(MonsterSpawn, td_MonsterSpawn, CBC_ORDER_ANY); - MUTATOR_HOOK(MonsterDies, td_MonsterDies, CBC_ORDER_ANY); - MUTATOR_HOOK(MonsterMove, td_MonsterMove, CBC_ORDER_ANY); - MUTATOR_HOOK(MonsterFindTarget, td_MonsterFindTarget, CBC_ORDER_ANY); - MUTATOR_HOOK(MonsterCheckBossFlag, td_MonsterCheckBossFlag, CBC_ORDER_ANY); - MUTATOR_HOOK(SetStartItems, td_SetStartItems, CBC_ORDER_ANY); - MUTATOR_HOOK(TurretValidateTarget, td_TurretValidateTarget, CBC_ORDER_ANY); - MUTATOR_HOOK(TurretSpawn, td_TurretSpawn, CBC_ORDER_ANY); - MUTATOR_HOOK(TurretDies, td_TurretDies, CBC_ORDER_ANY); - MUTATOR_HOOK(GiveFragsForKill, td_GiveFragsForKill, CBC_ORDER_ANY); - MUTATOR_HOOK(PlayerPreThink, td_PlayerThink, CBC_ORDER_ANY); - MUTATOR_HOOK(PlayerDies, td_PlayerDies, CBC_ORDER_ANY); - MUTATOR_HOOK(PlayerDamage_Calculate, td_PlayerDamage, CBC_ORDER_ANY); - MUTATOR_HOOK(PlayerSpawn, td_PlayerSpawn, CBC_ORDER_ANY); - MUTATOR_HOOK(VehicleSpawn, td_DisableVehicles, CBC_ORDER_ANY); - MUTATOR_HOOK(SV_ParseClientCommand, td_PlayerCommand, CBC_ORDER_ANY); - - MUTATOR_ONADD - { - if(time > 1) // game loads at time 1 - error("This is a game type and it cannot be added at runtime."); - cvar_settemp("g_monsters", "1"); - cvar_settemp("g_turrets", "1"); - td_Init(); - } - - MUTATOR_ONREMOVE - { - error("This is a game type and it cannot be removed at runtime."); - } - - return FALSE; -} diff --git a/qcsrc/server/mutators/gamemode_td.qh b/qcsrc/server/mutators/gamemode_td.qh deleted file mode 100644 index b199fd5e8..000000000 --- a/qcsrc/server/mutators/gamemode_td.qh +++ /dev/null @@ -1,62 +0,0 @@ -// Counters -float monster_count, totalmonsters; -float n_knights, n_dogs, n_ogres, n_shamblers, n_wizards, n_shalraths, n_soldiers, n_hknights, n_enforcers, n_demons, n_zombies, n_tarbabies, n_fish, n_spiders; -float current_monsters; -float waterspawns_count, flyspawns_count; -float wave_count, max_waves; -float max_turrets; - -// Monster defs -.float drop_size; -float m_speed_run; -float m_speed_walk; - -// Turret defs -.float turret_buff; - -// TD defs -.float stat_current_wave; -.float stat_totalwaves; -.float spawntype; -float spawn_delay; -float max_current; -float ignore_turrets; -float SWARM_NORMAL = 0; -float SWARM_WEAK = 1; -float SWARM_STRONG = 2; -float SWARM_FLY = 3; -float SWARM_SWIM = 4; -float build_time; -float td_dont_end; -void(float starting) wave_end; -.float turret_cnt; -float td_gencount; -void() spawnfunc_td_controller; -float current_phase; -#define PHASE_BUILD 1 -#define PHASE_COMBAT 2 - -// Scores -#define SP_TD_KILLS 0 -#define SP_TD_TURKILLS 2 -#define SP_TD_SCORE 4 -#define SP_TD_DEATHS 6 -#define SP_TD_SUICIDES 8 - -// Controller -.float maxwaves; -.float monstercount; -.float startwave; -.float dontend; -.float maxturrets; -.float buildtime; -.float mspeed_run; -.float mspeed_walk; -.float spawndelay; -.float maxcurrent; -.float ignoreturrets; - -// Generator -float gendestroyed; -#define GENERATOR_MIN '-52 -52 -14' -#define GENERATOR_MAX '52 52 75' \ No newline at end of file diff --git a/qcsrc/server/progs.src b/qcsrc/server/progs.src index 41838650b..9f44783b4 100644 --- a/qcsrc/server/progs.src +++ b/qcsrc/server/progs.src @@ -41,7 +41,7 @@ mutators/gamemode_keyhunt.qh // TODO fix this mutators/gamemode_keepaway.qh mutators/gamemode_nexball.qh mutators/mutator_dodging.qh -mutators/gamemode_td.qh +mutators/gamemode_towerdefense.qh mutators/gamemode_rts.qh //// tZork Turrets //// @@ -225,7 +225,7 @@ mutators/gamemode_keyhunt.qc mutators/gamemode_keepaway.qc mutators/gamemode_nexball.qc mutators/gamemode_onslaught.qc -mutators/gamemode_td.qc +mutators/gamemode_towerdefense.qc mutators/gamemode_rts.qc mutators/mutator_invincibleproj.qc mutators/mutator_new_toys.qc