X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fmutators%2Fgamemode_invasion.qc;h=56df8c1e35589a1ac3fabaf5f5d0722fb25185f4;hb=54715714c337f55d217c63bd6b11be3bf7a01d68;hp=90d18d4fc9df02275395e80488e6b718b4c55b66;hpb=da570c60f96cdc1f1f70a682414eb73c1b051117;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/mutators/gamemode_invasion.qc b/qcsrc/server/mutators/gamemode_invasion.qc index 90d18d4fc..56df8c1e3 100644 --- a/qcsrc/server/mutators/gamemode_invasion.qc +++ b/qcsrc/server/mutators/gamemode_invasion.qc @@ -1,7 +1,7 @@ void invasion_spawnpoint() { - if not(g_invasion) { remove(self); return; } - + if(!g_invasion) { remove(self); return; } + self.classname = "invasion_spawnpoint"; } @@ -12,52 +12,55 @@ float invasion_PickMonster(float supermonster_count) float i; entity mon; - + RandomSelection_Init(); - + for(i = MON_FIRST; i <= MON_LAST; ++i) { mon = get_monsterinfo(i); - if((mon.spawnflags & MONSTER_TYPE_FLY) || (mon.spawnflags & MONSTER_TYPE_SWIM) || (mon.spawnflags & MON_FLAG_SUPERMONSTER && supermonster_count >= 1)) + if((mon.spawnflags & MONSTER_TYPE_FLY) || (mon.spawnflags & MONSTER_TYPE_SWIM) || ((mon.spawnflags & MON_FLAG_SUPERMONSTER) && supermonster_count >= 1)) continue; // flying/swimming monsters not yet supported - + RandomSelection_Add(world, i, "", 1, 1); } - + return RandomSelection_chosen_float; } entity invasion_PickSpawn() { entity e; - + RandomSelection_Init(); - + for(e = world;(e = find(e, classname, "invasion_spawnpoint")); ) RandomSelection_Add(e, 0, string_null, 1, 1); - + return RandomSelection_chosen_ent; } void invasion_SpawnChosenMonster(float mon) { entity spawn_point, monster; - + spawn_point = invasion_PickSpawn(); - + if(spawn_point == world) { dprint("Warning: couldn't find any invasion_spawnpoint spawnpoints, no monsters will spawn!\n"); return; } - + monster = spawnmonster("", mon, spawn_point, spawn_point, spawn_point.origin, FALSE, 2); + + if(inv_roundcnt >= inv_maxrounds) + monster.spawnflags |= MONSTERFLAG_MINIBOSS; // last round spawns minibosses } void invasion_SpawnMonsters(float supermonster_count) { float chosen_monster = invasion_PickMonster(supermonster_count); - + invasion_SpawnChosenMonster(chosen_monster); } @@ -67,27 +70,22 @@ float Invasion_CheckWinner() if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0) { FOR_EACH_MONSTER(head) - { - WaypointSprite_Kill(head.sprite); - if(head.weaponentity) remove(head.weaponentity); - if(head.iceblock) remove(head.iceblock); - remove(head); - } - - if(roundcnt >= maxrounds) + monster_remove(head); + + if(inv_roundcnt >= inv_maxrounds) { NextLevel(); return 1; } - + Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_OVER); Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_OVER); round_handler_Init(5, autocvar_g_invasion_warmup, autocvar_g_invasion_round_timelimit); return 1; } - + float total_alive_monsters = 0, supermonster_count = 0; - + FOR_EACH_MONSTER(head) if(head.health > 0) { if((get_monsterinfo(head.monsterid)).spawnflags & MON_FLAG_SUPERMONSTER) @@ -95,29 +93,29 @@ float Invasion_CheckWinner() ++total_alive_monsters; } - if((total_alive_monsters + numkilled) < maxspawned && maxcurrent < 10) // 10 at a time should be plenty + if((total_alive_monsters + inv_numkilled) < inv_maxspawned && inv_maxcurrent < 10) // 10 at a time should be plenty { - if(time >= last_check) + if(time >= inv_lastcheck) { invasion_SpawnMonsters(supermonster_count); - last_check = time + 2; + inv_lastcheck = time + autocvar_g_invasion_spawn_delay; } - + return 0; } - - if(numspawned < 1 || numkilled < maxspawned) + + if(inv_numspawned < 1 || inv_numkilled < inv_maxspawned) return 0; // nothing has spawned yet, or there are still alive monsters - - if(roundcnt >= maxrounds) + + if(inv_roundcnt >= inv_maxrounds) { NextLevel(); return 1; } - + entity winner = world; float winning_score = 0; - + FOR_EACH_PLAYER(head) { float cs = PlayerScore_Add(head, SP_KILLS, 0); @@ -128,12 +126,15 @@ float Invasion_CheckWinner() } } + FOR_EACH_MONSTER(head) + monster_remove(head); + if(winner) { Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_PLAYER_WIN, winner.netname); Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_PLAYER_WIN, winner.netname); } - + round_handler_Init(5, autocvar_g_invasion_warmup, autocvar_g_invasion_round_timelimit); return 1; @@ -153,59 +154,70 @@ void Invasion_RoundStart() e.player_blocked = 0; ++numplayers; } - - roundcnt += 1; - - maxcurrent = 0; - numspawned = 0; - numkilled = 0; - - if(roundcnt > 1) - maxspawned = rint(autocvar_g_invasion_monster_count * (roundcnt * 0.5)); - else - maxspawned = autocvar_g_invasion_monster_count; - - monster_skill += 0.1 * numplayers; + + inv_roundcnt += 1; + + inv_monsterskill = inv_roundcnt + (numplayers * 0.3); + + inv_maxcurrent = 0; + inv_numspawned = 0; + inv_numkilled = 0; + + inv_maxspawned = rint(min(autocvar_g_invasion_monster_count, autocvar_g_invasion_monster_count * (inv_roundcnt * 0.5))); } MUTATOR_HOOKFUNCTION(invasion_MonsterDies) { - numkilled += 1; - maxcurrent -= 1; - - if(IS_PLAYER(frag_attacker)) - PlayerScore_Add(frag_attacker, SP_KILLS, +1); - + if(!(self.spawnflags & MONSTERFLAG_RESPAWNED)) + { + inv_numkilled += 1; + inv_maxcurrent -= 1; + + if(IS_PLAYER(frag_attacker)) + PlayerScore_Add(frag_attacker, SP_KILLS, +1); + } + return FALSE; } MUTATOR_HOOKFUNCTION(invasion_MonsterSpawn) { - if(self.realowner == world) + if(!(self.spawnflags & MONSTERFLAG_SPAWNED)) { - WaypointSprite_Kill(self.sprite); - if(self.weaponentity) remove(self.weaponentity); - if(self.iceblock) remove(self.iceblock); - remove(self); + monster_remove(self); return FALSE; } - - numspawned += 1; - maxcurrent += 1; - + + if(!(self.spawnflags & MONSTERFLAG_RESPAWNED)) + { + inv_numspawned += 1; + inv_maxcurrent += 1; + } + + self.monster_skill = inv_monsterskill; + + if((get_monsterinfo(self.monsterid)).spawnflags & MON_FLAG_SUPERMONSTER) + Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_INVASION_SUPERMONSTER, M_NAME(self.monsterid)); + self.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_BOTCLIP | DPCONTENTS_MONSTERCLIP; - + return FALSE; } MUTATOR_HOOKFUNCTION(invasion_PlayerThink) { - monsters_total = maxspawned; // TODO: make sure numspawned never exceeds maxspawned - monsters_killed = numkilled; - + monsters_total = inv_maxspawned; // TODO: make sure numspawned never exceeds maxspawned + monsters_killed = inv_numkilled; + return FALSE; } +MUTATOR_HOOKFUNCTION(invasion_PlayerRegen) +{ + // no regeneration in invasion + return TRUE; +} + MUTATOR_HOOKFUNCTION(invasion_PlayerSpawn) { self.bot_attack = FALSE; @@ -219,10 +231,7 @@ MUTATOR_HOOKFUNCTION(invasion_PlayerDamage) frag_damage = 0; frag_force = '0 0 0'; } - - if(frag_attacker.flags & FL_MONSTER && frag_target.flags & FL_MONSTER && frag_attacker != frag_target) - frag_damage = 0; - + return FALSE; } @@ -230,30 +239,44 @@ MUTATOR_HOOKFUNCTION(invasion_PlayerCommand) { if(MUTATOR_RETURNVALUE) // command was already handled? return FALSE; - + if(cmd_name == "debuginvasion") { - sprint(self, strcat("maxspawned = ", ftos(maxspawned), "\n")); - sprint(self, strcat("numspawned = ", ftos(numspawned), "\n")); - sprint(self, strcat("numkilled = ", ftos(numkilled), "\n")); - sprint(self, strcat("roundcnt = ", ftos(roundcnt), "\n")); + sprint(self, strcat("inv_maxspawned = ", ftos(inv_maxspawned), "\n")); + sprint(self, strcat("inv_numspawned = ", ftos(inv_numspawned), "\n")); + sprint(self, strcat("inv_numkilled = ", ftos(inv_numkilled), "\n")); + sprint(self, strcat("inv_roundcnt = ", ftos(inv_roundcnt), "\n")); sprint(self, strcat("monsters_total = ", ftos(monsters_total), "\n")); sprint(self, strcat("monsters_killed = ", ftos(monsters_killed), "\n")); - sprint(self, strcat("monster_skill = ", ftos(monster_skill), "\n")); - + sprint(self, strcat("inv_monsterskill = ", ftos(inv_monsterskill), "\n")); + return TRUE; } - + return FALSE; } MUTATOR_HOOKFUNCTION(invasion_SetStartItems) { - start_armorvalue = 100; - + start_health = 200; + start_armorvalue = 200; + return FALSE; } +MUTATOR_HOOKFUNCTION(invasion_AccuracyTargetValid) +{ + if(frag_target.flags & FL_MONSTER) + return MUT_ACCADD_INVALID; + return MUT_ACCADD_INDIFFERENT; +} + +MUTATOR_HOOKFUNCTION(invasion_AllowMobSpawning) +{ + // monster spawning disabled during an invasion + return TRUE; +} + void invasion_ScoreRules() { ScoreRules_basics(0, 0, 0, FALSE); @@ -266,17 +289,13 @@ void invasion_Initialize() independent_players = 1; // to disable extra useless scores invasion_ScoreRules(); - + independent_players = 0; round_handler_Spawn(Invasion_CheckPlayers, Invasion_CheckWinner, Invasion_RoundStart); round_handler_Init(5, autocvar_g_invasion_warmup, autocvar_g_invasion_round_timelimit); - - allowed_to_spawn = TRUE; - - monster_skill = 0.5; - - roundcnt = 0; + + inv_roundcnt = 0; } MUTATOR_DEFINITION(gamemode_invasion) @@ -284,17 +303,20 @@ MUTATOR_DEFINITION(gamemode_invasion) MUTATOR_HOOK(MonsterDies, invasion_MonsterDies, CBC_ORDER_ANY); MUTATOR_HOOK(MonsterSpawn, invasion_MonsterSpawn, CBC_ORDER_ANY); MUTATOR_HOOK(PlayerPreThink, invasion_PlayerThink, CBC_ORDER_ANY); + MUTATOR_HOOK(PlayerRegen, invasion_PlayerRegen, CBC_ORDER_ANY); MUTATOR_HOOK(PlayerSpawn, invasion_PlayerSpawn, CBC_ORDER_ANY); MUTATOR_HOOK(PlayerDamage_Calculate, invasion_PlayerDamage, CBC_ORDER_ANY); MUTATOR_HOOK(SV_ParseClientCommand, invasion_PlayerCommand, CBC_ORDER_ANY); MUTATOR_HOOK(SetStartItems, invasion_SetStartItems, CBC_ORDER_ANY); - + MUTATOR_HOOK(AccuracyTargetValid, invasion_AccuracyTargetValid, CBC_ORDER_ANY); + MUTATOR_HOOK(AllowMobSpawning, invasion_AllowMobSpawning, 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."); invasion_Initialize(); - + cvar_settemp("g_monsters", "1"); }