//NEW: changed behaviour so that it prevents that previous spectators/observers suddenly spawn as players
if (self.classname == "player") {
//PlayerScore_Clear(self);
- if(g_lms)
- PlayerScore_Add(self, SP_LMS_LIVES, LMS_NewPlayerLives());
self.killcount = 0;
//stop the player from moving so that he stands still once he gets respawned
self.velocity = '0 0 0';
Spawnqueue_Insert(self);
}
}
- else if(g_lms)
- {
- // Only if the player cannot play at all
- if(PlayerScore_Add(self, SP_LMS_RANK, 0) == 666)
- self.frags = FRAGS_SPECTATOR;
- else
- self.frags = FRAGS_LMS_LOSER;
- }
else if(g_ca)
{
if(self.caplayer)
// reset player keys
self.itemkeys = 0;
- // player is dead and becomes observer
- // FIXME fix LMS scoring for new system
- if(g_lms)
- {
- if(PlayerScore_Add(self, SP_LMS_RANK, 0) > 0)
- self.classname = "observer";
- }
-
if((g_arena && !self.spawned) || (g_ca && !allowed_to_spawn))
self.classname = "observer";
JoinBestTeam(self, FALSE, FALSE); // if the team number is valid, keep it
- if((autocvar_sv_spectate == 1 && !g_lms) || autocvar_g_campaign || self.team_forced < 0) {
+ if(autocvar_g_campaign || self.team_forced < 0) {
self.classname = "observer";
} else {
if(teamplay)
stuffcmd(self, "cl_cmd settemp chase_active 1\n");
}
- if(g_lms)
- {
- if(PlayerScore_Add(self, SP_LMS_LIVES, LMS_NewPlayerLives()) <= 0)
- {
- PlayerScore_Add(self, SP_LMS_RANK, 666);
- self.frags = FRAGS_SPECTATOR;
- }
- }
-
if(!sv_foginterval && world.fog != "")
stuffcmd(self, strcat("\nfog ", world.fog, "\nr_fog_exp2 0\nr_drawfog 1\n"));
if(frametime)
player_anim();
button_pressed = (self.BUTTON_ATCK || self.BUTTON_JUMP || self.BUTTON_ATCK2 || self.BUTTON_HOOK || self.BUTTON_USE);
- force_respawn = (g_lms || g_ca || g_cts || autocvar_g_forced_respawn);
+ force_respawn = (g_ca || g_cts || autocvar_g_forced_respawn);
if (self.deadflag == DEAD_DYING)
{
if(force_respawn)
return 0;
if (g_weaponarena)
return 0;
- if (g_lms)
- return 0;
if (g_ca)
return 0;
if (g_cts)
float player_count;
float currentbots;
float bots_would_leave;
-float lms_lowest_lives;
-float lms_next_place;
-float LMS_NewPlayerLives();
void UpdateFrags(entity player, float f);
.float totalfrags;
{
f = RunematchHandleFrags(attacker, targ, f);
}
- else if(g_lms)
- {
- // remove a life
- float tl;
- tl = PlayerScore_Add(targ, SP_LMS_LIVES, -1);
- if(tl < lms_lowest_lives)
- lms_lowest_lives = tl;
- if(tl <= 0)
- {
- if(!lms_next_place)
- lms_next_place = player_count;
- else
- lms_next_place = min(lms_next_place, player_count);
- PlayerScore_Add(targ, SP_LMS_RANK, lms_next_place); // won't ever spawn again
- --lms_next_place;
- }
- f = 0;
- }
}
attacker.totalfrags += f;
return WINNING_NO;
}
-float LMS_NewPlayerLives()
-{
- float fl;
- fl = autocvar_fraglimit;
- if(fl == 0)
- fl = 999;
-
- // first player has left the game for dying too much? Nobody else can get in.
- if(lms_lowest_lives < 1)
- return 0;
-
- if(!autocvar_g_lms_join_anytime)
- if(lms_lowest_lives < fl - autocvar_g_lms_last_join)
- return 0;
-
- return bound(1, lms_lowest_lives, fl);
-}
-
// Assault winning condition: If the attackers triggered a round end (by fulfilling all objectives)
// they win. Otherwise the defending team wins once the timelimit passes.
void assault_new_round();
g_pinata = 0; // incompatible
g_weapon_stay = 0; // incompatible
WEPSET_COPY_AA(start_weapons, g_weaponarena_weapons);
- if(!(g_lms || g_ca))
+ if(!g_ca)
start_items |= IT_UNLIMITED_AMMO;
}
else if (g_minstagib)
}
else
{
- if(g_lms || g_ca)
+ if(g_ca)
{
start_ammo_shells = cvar("g_lms_start_ammo_shells");
start_ammo_nails = cvar("g_lms_start_ammo_nails");
}
}
- if (g_lms || g_ca)
+ if (g_ca)
{
start_health = cvar("g_lms_start_health");
start_armorvalue = cvar("g_lms_start_armor");
entity frag_target;
// INPUT, OUTPUT:
float frag_score;
+
+MUTATOR_HOOKABLE(PlayerClearScore);
+ // called when a player's scores are going to be cleared
+ // returning TRUE prevents score clearing
MUTATOR_HOOKABLE(MatchEnd);
// called when the match ends
--- /dev/null
+// main functions
+float LMS_NewPlayerLives()
+{
+ float fl;
+ fl = autocvar_fraglimit;
+ if(fl == 0)
+ fl = 999;
+
+ // first player has left the game for dying too much? Nobody else can get in.
+ if(lms_lowest_lives < 1)
+ return 0;
+
+ if(!autocvar_g_lms_join_anytime)
+ if(lms_lowest_lives < fl - autocvar_g_lms_last_join)
+ return 0;
+
+ return bound(1, lms_lowest_lives, fl);
+}
+
+// mutator hooks
+MUTATOR_HOOKFUNCTION(lms_RemovePlayer)
+{
+ // Only if the player cannot play at all
+ if(PlayerScore_Add(self, SP_LMS_RANK, 0) == 666)
+ self.frags = FRAGS_SPECTATOR;
+ else
+ self.frags = FRAGS_LMS_LOSER;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(lms_PlayerSpawn)
+{
+ PlayerScore_Add(self, SP_LMS_LIVES, LMS_NewPlayerLives());
+
+ // player is dead and becomes observer
+ // FIXME fix LMS scoring for new system
+ if(PlayerScore_Add(self, SP_LMS_RANK, 0) > 0)
+ self.classname = "observer";
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(lms_ClientConnect)
+{
+ self.classname = "player";
+ campaign_bots_may_start = 1;
+
+ if(PlayerScore_Add(self, SP_LMS_LIVES, LMS_NewPlayerLives()) <= 0)
+ {
+ PlayerScore_Add(self, SP_LMS_RANK, 666);
+ self.frags = FRAGS_SPECTATOR;
+ }
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(lms_PlayerThink)
+{
+ if(self.deadflag == DEAD_DYING)
+ self.deadflag = DEAD_RESPAWNING;
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(lms_ForbidThrowing)
+{
+ // forbode!
+ return TRUE;
+}
+
+MUTATOR_HOOKFUNCTION(lms_GiveFragsForKill)
+{
+ // remove a life
+ float tl;
+ tl = PlayerScore_Add(frag_target, SP_LMS_LIVES, -1);
+ if(tl < lms_lowest_lives)
+ lms_lowest_lives = tl;
+ if(tl <= 0)
+ {
+ if(!lms_next_place)
+ lms_next_place = player_count;
+ else
+ lms_next_place = min(lms_next_place, player_count);
+ PlayerScore_Add(frag_target, SP_LMS_RANK, lms_next_place); // won't ever spawn again
+ --lms_next_place;
+ }
+ frag_score = 0;
+
+ return TRUE;
+}
+
+MUTATOR_HOOKFUNCTION(lms_SetStartItems)
+{
+ start_items &~= IT_UNLIMITED_AMMO;
+ start_ammo_shells = cvar("g_lms_start_ammo_shells");
+ start_ammo_nails = cvar("g_lms_start_ammo_nails");
+ start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
+ start_ammo_cells = cvar("g_lms_start_ammo_cells");
+ start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
+ start_health = cvar("g_lms_start_health");
+ start_armorvalue = cvar("g_lms_start_armor");
+
+ return FALSE;
+}
+
+MUTATOR_HOOKFUNCTION(lms_KeepScore)
+{
+ // don't clear player score
+ return TRUE;
+}
+
+MUTATOR_HOOKFUNCTION(lms_FilterItem)
+{
+ // no items in LMS
+ return TRUE;
+}
+
+// scoreboard stuff
+void lms_ScoreRules()
+{
+ ScoreRules_basics(0, 0, 0, FALSE);
+ ScoreInfo_SetLabel_PlayerScore(SP_LMS_LIVES, "lives", SFL_SORT_PRIO_SECONDARY);
+ ScoreInfo_SetLabel_PlayerScore(SP_LMS_RANK, "rank", SFL_LOWER_IS_BETTER | SFL_RANK | SFL_SORT_PRIO_PRIMARY | SFL_ALLOW_HIDE);
+ ScoreRules_basics_end();
+}
+
+void lms_Initialize()
+{
+ lms_lowest_lives = 9999;
+ lms_next_place = 0;
+
+ lms_ScoreRules();
+}
+
+MUTATOR_DEFINITION(gamemode_lms)
+{
+ MUTATOR_HOOK(MakePlayerObserver, lms_RemovePlayer, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerSpawn, lms_PlayerSpawn, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ClientConnect, lms_ClientConnect, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerPreThink, lms_PlayerThink, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ForbidThrowCurrentWeapon, lms_ForbidThrowing, CBC_ORDER_ANY);
+ MUTATOR_HOOK(GiveFragsForKill, lms_GiveFragsForKill, CBC_ORDER_ANY);
+ MUTATOR_HOOK(SetStartItems, lms_SetStartItems, CBC_ORDER_ANY);
+ MUTATOR_HOOK(PlayerClearScore, lms_KeepScore, CBC_ORDER_ANY);
+ MUTATOR_HOOK(FilterItem, lms_FilterItem, 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.");
+ lms_Initialize();
+ }
+
+ MUTATOR_ONROLLBACK_OR_REMOVE
+ {
+ // we actually cannot roll back lms_Initialize here
+ // BUT: we don't need to! If this gets called, adding always
+ // succeeds.
+ }
+
+ MUTATOR_ONREMOVE
+ {
+ print("This is a game type and it cannot be removed at runtime.");
+ return -1;
+ }
+
+ return 0;
+}
--- /dev/null
+// scoreboard stuff
+#define SP_LMS_LIVES 4
+#define SP_LMS_RANK 5
+
+// lives related defs
+float lms_lowest_lives;
+float lms_next_place;
+float LMS_NewPlayerLives();
\ No newline at end of file
MUTATOR_DECLARATION(gamemode_nexball);
MUTATOR_DECLARATION(gamemode_onslaught);
MUTATOR_DECLARATION(gamemode_domination);
+MUTATOR_DECLARATION(gamemode_lms);
MUTATOR_DECLARATION(mutator_dodging);
MUTATOR_DECLARATION(mutator_invincibleprojectiles);
mutators/gamemode_keyhunt.qh // TODO fix this
mutators/gamemode_keepaway.qh
mutators/gamemode_nexball.qh
+mutators/gamemode_lms.qh
mutators/mutator_dodging.qh
//// tZork Turrets ////
mutators/gamemode_keepaway.qc
mutators/gamemode_nexball.qc
mutators/gamemode_onslaught.qc
+mutators/gamemode_lms.qc
mutators/mutator_invincibleproj.qc
mutators/mutator_new_toys.qc
mutators/mutator_nix.qc
if(teamscores_entities_count)
return 0;
- if(g_lms) return 0;
+ if(MUTATOR_CALLHOOK(PlayerClearScore)) return 0;
if(g_arena || g_ca) return 0;
if(g_cts) return 0; // in CTS, you don't lose score by observing
if(g_race && g_race_qualifying) return 0; // in qualifying, you don't lose score by observing
ScoreRules_basics_end();
}
-// LMS stuff
-#define SP_LMS_LIVES 4
-#define SP_LMS_RANK 5
-void ScoreRules_lms()
-{
- ScoreRules_basics(0, 0, 0, FALSE);
- ScoreInfo_SetLabel_PlayerScore(SP_LMS_LIVES, "lives", SFL_SORT_PRIO_SECONDARY);
- ScoreInfo_SetLabel_PlayerScore(SP_LMS_RANK, "rank", SFL_LOWER_IS_BETTER | SFL_RANK | SFL_SORT_PRIO_PRIMARY | SFL_ALLOW_HIDE);
- ScoreRules_basics_end();
-}
-
// Key hunt stuff
#define ST_KH_CAPS 1
#define SP_KH_CAPS 4
return TRUE;
if(autocvar_g_powerups == 0)
return FALSE;
- if(g_lms)
- return FALSE;
if(g_ca)
return FALSE;
if(g_arena)
return TRUE;
if(autocvar_g_pickup_items == 0)
return FALSE;
- if(g_lms)
- return FALSE;
if(g_ca)
return FALSE;
if(g_weaponarena)
leadlimit_override = 0; // not supported by LMS
if(fraglimit_override == 0)
fraglimit_override = -1;
- lms_lowest_lives = 9999;
- lms_next_place = 0;
- ScoreRules_lms();
+ MUTATOR_ADD(gamemode_lms);
}
if(g_arena)