+++ /dev/null
-// Real-Time Strategy
-// Gamemode by Mario
-
-// basically a fusion reactor with a new classname
-void spawnfunc_healing_tower()
-{
- self.spawnflags = TSL_NO_RESPAWN; // healing towers don't respawn?
- self.netname = "Monster Healing Tower"; // not used by waypoints...
- spawnfunc_turret_fusionreactor();
- self.classname = "healing_tower";
- self.target_range = 1000;
- self.shot_dmg = 30;
-}
-
-void rts_waypoint_think()
-{
- float goalcount = 0;
- entity e;
-
- self.nextthink = time + 0.1;
-
- for(e = world; (e = findentity(e, goalentity, self)); )
- {
- ++goalcount;
- }
-
- if(goalcount < 1)
- {
- WaypointSprite_Kill(self.sprite);
- remove(self);
- return;
- }
-}
-
-MUTATOR_HOOKFUNCTION(rts_PlayerSpawn)
-{
- if(self.rts_viewangle)
- self.angles_x = self.rts_viewangle;
- else
- self.angles_x = 30;
-
- self.effects |= EF_NODRAW;
- self.oldorigin = self.origin;
- self.monster_attack = FALSE;
- self.last_click = time;
- self.takedamage = DAMAGE_NO;
- self.flags |= FL_NOTARGET;
- self.movetype = MOVETYPE_NOCLIP;
- stuffcmd(self, "cl_cmd settemp cl_prydoncursor 1\n");
- return FALSE;
-}
-
-MUTATOR_HOOKFUNCTION(rts_FilterItem)
-{
- // no items... yet
- return TRUE;
-}
-
-MUTATOR_HOOKFUNCTION(rts_SetStartItems)
-{
- WEPSET_COPY_AW(start_weapons, 0);
-
- return FALSE;
-}
-
-MUTATOR_HOOKFUNCTION(rts_PlayerThink)
-{
- if not(IS_PLAYER(self))
- return FALSE; // dont do any checks for spectators
-
- switch(self.impulse)
- {
- case 10:
- case 15:
- case 18:
- self.oldorigin_z += 50;
- break;
- case 12:
- case 16:
- case 19:
- self.oldorigin_z -= 50;
- break;
- }
- self.hasweapon_complain_spam = time + 9999999999; // no spam
-
- entity head, wp = world;
- if(!self.cursor_trace_ent && self.BUTTON_ATCK && time >= self.last_click)
- {
- FOR_EACH_MONSTER(head)
- {
- if(head.owner != self) continue;
-
- head.selected = FALSE;
-
- if(!self.enemy)
- head.owner = world;
- }
- }
- if(self.cursor_trace_ent.flags & FL_MONSTER && self.BUTTON_ATCK && time >= self.last_click)
- {
- if(self.cursor_trace_ent.owner != self && self.cursor_trace_ent.owner != world)
- return FALSE; // someone else owns it
- else if(self.cursor_trace_ent.team != self.team)
- return FALSE; // not our team
- else if(self.cursor_trace_ent.selected)
- {
- self.cursor_trace_ent.selected = FALSE;
- self.cursor_trace_ent.owner = world;
- self.last_click = time + 0.5; // prevent spamming
- }
- else
- {
- self.cursor_trace_ent.owner = self;
- self.cursor_trace_ent.selected = TRUE;
- self.last_click = time + 0.5; // prevent spamming
- }
- }
- if(self.BUTTON_ATCK2)
- {
- entity e = self.cursor_trace_ent;
-
- if not(e)
- {
- entity t;
- for(t = world; (t = findflags(t, turrcaps_flags, TFL_TURRCAPS_ISTURRET)); )
- {
- if(vlen(self.cursor_trace_endpos - t.origin) < 80)
- {
- if(IsDifferentTeam(e, t))
- {
- e = t;
- break; // don't bother checking any other turrets
- }
- }
- }
- }
-
- if(e)
- if not(e.takedamage)
- e = world;
-
- if not(e)
- {
- wp = spawn();
- wp.classname = "monster_waypoint"; // set so we can kill this later
- wp.owner = self; // hmm...
- wp.think = rts_waypoint_think;
- wp.nextthink = time;
- WaypointSprite_Spawn("Here", 1, 0, wp, '0 0 10', world, self.team, wp, sprite, FALSE, RADARICON_DANGER, ((teamplay) ? Team_ColorRGB(self.team) : '1 0 0'));
- setorigin(wp, self.cursor_trace_endpos);
- }
-
- FOR_EACH_MONSTER(head)
- {
- if(head.owner != self) continue;
- if not(head.selected) continue;
-
- if(e)
- {
- float sheight = ((e.sprite_height) ? e.sprite_height + 20 : 80);
- if(IsDifferentTeam(e, self))
- {
- WaypointSprite_Spawn("Attacking", 1, 0, e, '0 0 1' * sheight, world, self.team, self, sprite, FALSE, RADARICON_DANGER, ((teamplay) ? Team_ColorRGB(self.team) : '1 0 0'));
- head.goalentity = world;
- head.enemy = e;
- }
- else if(e.flags & FL_MONSTER && e != head)
- {
- WaypointSprite_Spawn("Following", 1, 0, e, '0 0 1' * sheight, world, self.team, self, sprite, FALSE, RADARICON_DANGER, ((teamplay) ? Team_ColorRGB(self.team) : '1 0 0'));
- head.goalentity = e;
- }
- else // its not a monster or an enemy, so revert to waypoint
- {
- head.goalentity = wp;
- head.enemy = world;
- }
-
- }
- else
- {
- head.goalentity = wp;
- head.enemy = world;
- }
- }
- }
-
- return FALSE;
-}
-
-MUTATOR_HOOKFUNCTION(rts_MonsterSpawn)
-{
- // new monster
- if not(self.monster_respawned)
- {
- self.level = 0;
- self.speed = 1;
- }
-
- self.spawnflags = MONSTERFLAG_NORESPAWN;
-
- self.goalentity = world;
- self.enemy = world;
- self.moveto = self.origin;
-
- self.candrop = FALSE;
-
- self.respawntime = 10; // default to 10 seconds for now
- self.effects |= EF_SELECTABLE;
- self.monster_moveflags = MONSTER_MOVE_NOMOVE;
-
- WaypointSprite_Kill(self.sprite);
- self.sprite = world;
- self.heal_delay = -1; // this is reset when monster takes damage
-
- return FALSE;
-}
-
-MUTATOR_HOOKFUNCTION(rts_MonsterThink)
-{
- vector color = ((self.team) ? Team_ColorRGB(self.team) : '1 1 1');
-
- if(self.health >= self.max_health)
- self.heal_delay = -1;
- else if(time >= self.heal_delay)
- {
- self.health = min(self.health + 5, self.max_health);
- WaypointSprite_UpdateHealth(self.sprite, self.health);
- self.heal_delay = time + 2;
- }
-
- monster_speed_run = 150 * self.speed;
- monster_speed_walk = 150 * self.speed;
-
- if(IS_PLAYER(monster_target))
- monster_target = world; // shouldn't be able to find players...
-
- if not(IsDifferentTeam(monster_target, self))
- {
- // following a fellow teammate, so attack their enemy
- if(monster_target.deadflag != DEAD_NO || monster_target.health < 1)
- monster_target = world; // teammate died
-
- if(monster_target.enemy)
- {
- self.enemy = monster_target.enemy;
- monster_target = world; // don't follow anymore?
- }
- }
-
- if(self.selected)
- self.colormod = color * 10;
- else
- self.colormod = color;
-
- if(monster_target)
- self.enemy = world; // don't ignore our owner's commands
-
- if not(self.sprite)
- {
- WaypointSprite_Spawn(self.netname, 0, 0, self, '0 0 1' * self.sprite_height, world, self.team, self, sprite, FALSE, RADARICON_DANGER, ((teamplay) ? Team_ColorRGB(self.team) : '1 0 0'));
- WaypointSprite_UpdateMaxHealth(self.sprite, self.max_health);
- WaypointSprite_UpdateHealth(self.sprite, self.health);
- }
-
- if(self.owner)
- if not(self.selected)
- self.owner = world;
-
- if not(IsDifferentTeam(self, self.enemy))
- self.enemy = world; // no same team fighting
-
- self.last_trace = time; // realtime moving?
-
- return FALSE;
-}
-
-MUTATOR_HOOKFUNCTION(rts_MonsterDies)
-{
- entity e;
-
- if(IsDifferentTeam(frag_attacker, frag_target) && frag_attacker.team)
- TeamScore_AddToTeam(frag_attacker.team, ST_SCORE, 1);
-
- // need to keep the monster selected to get the points... hmm (TODO: realowners?)
- if(IS_PLAYER(frag_attacker.owner))
- {
- PlayerScore_Add(frag_attacker.owner, SP_SCORE, 5);
- PlayerScore_Add(frag_attacker.owner, SP_KILLS, 1);
- }
-
- for(e = world; (e = findentity(e, goalentity, self)); )
- {
- e.goalentity = world; // fix teammates if they still see us as a valid target
- }
-
- self.effects &~= EF_SELECTABLE;
- self.selected = FALSE;
-
- self.goalentity = world;
- self.enemy = world;
-
- return FALSE;
-}
-
-MUTATOR_HOOKFUNCTION(rts_MonsterRespawn)
-{
- if(other.team)
- return TRUE;
-
- return FALSE; // if no team is set, don't respawn
-}
-
-MUTATOR_HOOKFUNCTION(rts_MonsterTarget)
-{
- // don't search for enemies, they are given to us
- return TRUE;
-}
-
-MUTATOR_HOOKFUNCTION(rts_MonsterBossFlag)
-{
- // no minibosses in RTS
- return TRUE;
-}
-
-MUTATOR_HOOKFUNCTION(rts_PlayerDamage)
-{
- if(IS_PLAYER(frag_target))
- frag_damage = 0; // don't damage the invincible players...
-
- if((frag_target.flags & FL_MONSTER) && frag_target.goalentity)
- frag_target.enemy = world; // don't attack the attacker, we're probably pulling back
-
- if((frag_target.flags & FL_MONSTER) && !IsDifferentTeam(frag_target, frag_attacker))
- frag_damage = 0; // no team damage
-
- if((frag_target.flags & FL_MONSTER) && frag_damage > 0)
- frag_target.heal_delay = time + 2; // pause healing
-
- return FALSE;
-}
-
-MUTATOR_HOOKFUNCTION(rts_PlayerPhysics)
-{
- if not(IS_PLAYER(self))
- return FALSE;
-
- self.origin_z = self.oldorigin_z;
- self.stat_sv_maxspeed *= 4; // lol
-
- return FALSE;
-}
-
-MUTATOR_HOOKFUNCTION(rts_PlayerDies)
-{
- // prevent changing teams with selected monsters
- entity head;
- FOR_EACH_MONSTER(head)
- {
- if(head.owner != self) continue;
- if not(head.selected) continue;
-
- if(IsDifferentTeam(self, head))
- {
- head.selected = FALSE;
- head.owner = world;
- }
- }
-
- return FALSE;
-}
-
-void rts_ScoreRules()
-{
- ScoreRules_basics(2, SFL_SORT_PRIO_PRIMARY, 0, TRUE);
- ScoreRules_basics_end();
-}
-
-void rts_DelayedInit()
-{
- rts_ScoreRules();
-}
-
-void rts_Initialize()
-{
- InitializeEntity(world, rts_DelayedInit, INITPRIO_GAMETYPE);
-}
-
-MUTATOR_DEFINITION(gamemode_rts)
-{
- MUTATOR_HOOK(PlayerPhysics, rts_PlayerPhysics, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerSpawn, rts_PlayerSpawn, CBC_ORDER_ANY);
- MUTATOR_HOOK(SetStartItems, rts_SetStartItems, CBC_ORDER_ANY);
- MUTATOR_HOOK(FilterItem, rts_FilterItem, CBC_ORDER_ANY);
- MUTATOR_HOOK(MonsterSpawn, rts_MonsterSpawn, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerPreThink, rts_PlayerThink, CBC_ORDER_ANY);
- MUTATOR_HOOK(MonsterMove, rts_MonsterThink, CBC_ORDER_ANY);
- MUTATOR_HOOK(MonsterFindTarget, rts_MonsterTarget, CBC_ORDER_ANY);
- MUTATOR_HOOK(MonsterDies, rts_MonsterDies, CBC_ORDER_ANY);
- MUTATOR_HOOK(MonsterRespawn, rts_MonsterRespawn, CBC_ORDER_ANY);
- MUTATOR_HOOK(MonsterCheckBossFlag, rts_MonsterBossFlag, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerDamage_Calculate, rts_PlayerDamage, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerDies, rts_PlayerDies, 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");
-
- rts_Initialize();
- }
-
- MUTATOR_ONREMOVE
- {
- error("This is a game type and it cannot be removed at runtime.");
- }
-
- return FALSE;
-}
+++ /dev/null
-// Zombie Apocalypse mutator - small side project
-// Spawns a defined number of zombies at the start of a match
-
-float za_numspawns, totalzombies, roundcnt, numzoms;
-entity PickZombieSpawn()
-{
- entity sp;
-
- RandomSelection_Init();
-
- if(teamplay)
- {
- for(sp = world; (sp = find(sp, classname, "info_player_team1")); )
- {
- RandomSelection_Add(sp, 0, string_null, 1, 1);
- }
- }
- else
- {
- for(sp = world; (sp = find(sp, classname, "info_player_deathmatch")); )
- {
- RandomSelection_Add(sp, 0, string_null, 1, 1);
- }
- }
-
- return RandomSelection_chosen_ent;
-}
-
-void zombie_spawn_somewhere ()
-{
- if(gameover) { return; }
-
- entity mon, sp;
-
- if(MoveToRandomMapLocation(self, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, 10, 1024, 256))
- {
- mon = spawnmonster("zombie", self, self, self.origin, TRUE, 2); // double tap needed
- tracebox(mon.origin, mon.mins, mon.maxs, mon.origin, MOVE_NOMONSTERS, mon);
-
- if(trace_startsolid)
- {
- sp = PickZombieSpawn();
- if(sp)
- setorigin(mon, sp.origin);
- }
-
- za_numspawns += 1;
- }
- else
- zombie_spawn_somewhere();
-}
-
-void() spawn_zombies;
-void za_roundwon()
-{
- Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ZA_WIN);
-
- roundcnt += 1;
-
- numzoms = autocvar_g_za_monster_count;
-
- monsters_total += numzoms;
- totalzombies = numzoms;
-
- self.think = spawn_zombies;
- self.nextthink = time + 10;
-}
-
-void spawn_zombies ()
-{
- self.nextthink = time + 1;
-
- if(totalzombies <= 0)
- {
- self.think = za_roundwon;
- self.nextthink = time;
- return;
- }
-
- if(gameover || numzoms <= 0)
- return;
-
- entity e;
-
- dprint("Them zombies be spawnin'!\n");
-
- while(numzoms > 0)
- {
- e = spawn();
- e.think = zombie_spawn_somewhere;
- e.nextthink = time;
-
- numzoms -= 1;
- }
-}
-
-void za_init ()
-{
- entity e;
-
- roundcnt = 1;
-
- numzoms = autocvar_g_za_monster_count;
-
- monsters_total += numzoms;
- totalzombies = numzoms;
-
- e = spawn();
- e.think = spawn_zombies;
- e.nextthink = time + 3;
-}
-
-MUTATOR_HOOKFUNCTION(za_ZombieDies)
-{
- if(self.monster_respawned)
- return FALSE; // don't count zombies that respawned
-
- if(frag_attacker.classname == "player")
- PlayerScore_Add(frag_attacker, SP_SCORE, 1);
-
- totalzombies -= 1;
- monsters_killed += 1;
- return FALSE;
-}
-
-MUTATOR_HOOKFUNCTION(za_BuildMutatorsString)
-{
- ret_string = strcat(ret_string, ":Zombies");
- return 0;
-}
-
-MUTATOR_HOOKFUNCTION(za_BuildMutatorsPrettyString)
-{
- ret_string = strcat(ret_string, ", Zombies");
- return 0;
-}
-
-MUTATOR_DEFINITION(mutator_zombie_apocalypse)
-{
- MUTATOR_HOOK(MonsterDies, za_ZombieDies, CBC_ORDER_ANY);
- MUTATOR_HOOK(BuildMutatorsString, za_BuildMutatorsString, CBC_ORDER_ANY);
- MUTATOR_HOOK(BuildMutatorsPrettyString, za_BuildMutatorsPrettyString, CBC_ORDER_ANY);
-
- MUTATOR_ONADD
- {
- za_init();
- }
-
- return 0;
-}