/** * Annihilation (Round version) mode - PvE Co-op GameMode * Author : lethan * Contact : lethanov@gmail.com */ // ---------------------------------- // // Requirements // ---------------------------------- // #Extends "Modes/ShootMania/ModeBase.Script.txt" #Const CompatibleMapTypes "AnnihilationArena" #Const Version "2016-02-14" #Const ScriptName "Annihilation.Script.txt" #Include "MathLib" as MathLib #Include "TextLib" as TextLib #Include "Libs/Nadeo/Message.Script.txt" as Message #Include "Libs/Nadeo/Interface.Script.txt" as Interface #Include "Libs/Nadeo/ShootMania/SM.Script.txt" as SM #Include "Libs/Nadeo/ShootMania/Score.Script.txt" as Score #Include "Libs/Nadeo/ShootMania/SpawnScreen.Script.txt" as SpawnScreen // ---------------------------------- // // Settings // ---------------------------------- // //#Setting S_GameMode 0 as _("GameMode : 0 - Rounds, 1 - Survival, 2 - Custom (Enable option below)") // #Const Description _("TYPE: PvE Co-Op\nOBJECTIVE: Eliminate all bots in the map before time lmit !\nINFOS\nGreen bots : Rocket\nRed bots : Nucleus\nBlue bots : Laser\nYellow bots : Arrow") #Const UITickPeriod 200 #Const MaxRounds 6 // ---------------------------------- // // Global var // ---------------------------------- // declare CUILayer SoundLayerFirst; declare CUILayer SoundLayerSecond; declare CUILayer MatchInfo; declare Integer LastHit; declare Integer KillStreak; declare Integer Score; declare Integer TimeLimit; declare Integer Round; declare Text GamePhase; declare Boolean CanPlay; declare Integer _LatestUITickLayerTeam; declare CUILayer _LayerTeam; declare Text[Ident] _PlayerManialinkLines; // ---------------------------------- // // Set rules // ---------------------------------- // ***Rules*** *** declare ModeName = "Annihilation"; declare ModeRules = TextLib::Compose(_("Eliminate all bots in the map before the time is running out !\nGreen bots : Rocket\nRed bots : Nucleus\nBlue bots : Laser\nYellow bots : Arrow"), "$"^SpawnScreen::GetModeColor()); SpawnScreen::ResetRulesSection(); SpawnScreen::AddSubsection(_("Annihilation - PvE Co-Op Gamemode"), ModeRules, 20.); SpawnScreen::CreatePrettyRules(ModeName); ModeStatusMessage = _("TYPE: PvE Co-Op\nOBJECTIVE: Eliminate all bots in the map before the time is running out !\nINFOS\nGreen bots : Rocket\nRed bots : Nucleus\nBlue bots : Laser\nYellow bots : Arrow"); *** // ---------------------------------- // // Server start // ---------------------------------- // ***StartServer*** *** SoundLayerFirst = UIManager.UILayerCreate(); UIManager.UIAll.UILayers.add(SoundLayerFirst); SoundLayerFirst.ManialinkPage = """ """; SoundLayerSecond = UIManager.UILayerCreate(); UIManager.UIAll.UILayers.add(SoundLayerSecond); SoundLayerSecond.ManialinkPage = """ """; MatchInfo = UIManager.UILayerCreate(); UIManager.UIAll.UILayers.add(MatchInfo); MatchInfo.ManialinkPage = """ """; //Layer Team _LayerTeam = UIManager.UILayerCreate(); UIManager.UIAll.UILayers.add(_LayerTeam); _LayerTeam.ManialinkPage = """ """; // ---------------------------------- // // Set mode options UseClans = True; UseAllies = True; // ---------------------------------- // // Create the rules ---Rules--- // ---------------------------------- // // Initialize UI SpawnScreen::CreateScores("Score.RoundPoints"); SpawnScreen::CreateMapInfo(); //Interface::CreateRank(); // ---------------------------------- // // Create the scores table ST2::SetStyle("LibST_SMBaseSolo"); ST2::SetStyle("LibST_SMBasePoints"); MB_SetScoresTableStyleFromXml(S_ScoresTableStylePath); ST2::Build("SM"); *** // ---------------------------------- // // Map start // ---------------------------------- // ***StartMap*** *** LastHit = Now; KillStreak = 0; Score = 0; Round = 1; GamePhase = "checking"; Score::MatchBegin(); SM::SetupDefaultVisibility(); // ---------------------------------- // // Init bases foreach (Base in MapBases) { Base.Clan = 1; Base.IsActive = True; } // ---------------------------------- // // New map sound UIManager.UIAll.UISequence = CUIConfig::EUISequence::Intro; *** // ---------------------------------- // // Play loop // ---------------------------------- // ***PlayLoop*** *** if(GamePhase == "checking"){ CheckSettings(); EndTime = 0; } if(GamePhase == "newRound"){ PlaySound("newRoundIn", -1); declare Msg = ""; Msg = TextLib::Compose(_("Round %1/%2"), TextLib::ToText(Round), TextLib::ToText(MaxRounds)); Message::SendBigMessage(Msg, 2000, 3, CUIConfig::EUISound::PhaseChange, 0); sleep(2000); CreateBots(); SpawnPlayers(); UIManager.UIAll.UISequence = CUIConfig::EUISequence::Playing; StartTime = Now; TimeLimit = 45 - 5 * Players.count; if (TimeLimit > 0) EndTime = StartTime + (TimeLimit * 1000) + 2500; else EndTime = -1; Score = 0; sleep(1000); PlaySound("play", 0); Msg = TextLib::Compose(_("3"), TextLib::ToText(Round)); Message::SendBigMessage(Msg, 2000, 3, CUIConfig::EUISound::Silence, 0); sleep(500); Msg = TextLib::Compose(_("2"), TextLib::ToText(Round)); Message::SendBigMessage(Msg, 2000, 3, CUIConfig::EUISound::Silence, 0); sleep(500); Msg = TextLib::Compose(_("1"), TextLib::ToText(Round)); Message::SendBigMessage(Msg, 2000, 3, CUIConfig::EUISound::Silence, 0); sleep(500); Msg = TextLib::Compose(_("Play !"), TextLib::ToText(Round)); Message::SendBigMessage(Msg, 2000, 3, CUIConfig::EUISound::Silence, 0); MatchInfo(True); GamePhase = "play"; } else if(GamePhase == "play"){ ShowLayerTeam(True); foreach (Event, PendingEvents) { // ---------------------------------- // // On armor empty if (Event.Type == CSmModeEvent::EType::OnArmorEmpty) { if(Event.Victim.IsFakePlayer){ Score += 1; declare Msg = ""; declare Gap = BotPlayers.count - Score; declare Variant = 3 - Gap; if (Gap > 0 && Gap <= 3) { if (Gap > 1) { Msg = TextLib::Compose(_("%1 bots left !"), TextLib::ToText(Gap)); } else { Msg = TextLib::Compose(_("Eliminate the last one!")); } Message::SendStatusMessage(Msg, 2000, 3, CUIConfig::EUISound::TieBreakPoint, Variant); } else if (Gap <= 0) { Msg = TextLib::Compose(_("All bots are annihilated !")); Message::SendStatusMessage(Msg, 2000, 3, CUIConfig::EUISound::VictoryPoint, 0); EndTime = 0; GamePhase = "roundEnd"; } else { Message::SendStatusMessage(TextLib::Compose("%1 : %2 / %3", _("Eliminations"), TextLib::ToText(Score), TextLib::ToText(BotPlayers.count)), 2000, 3, CUIConfig::EUISound::ScoreProgress, MathLib::Rand(0,3)); } MatchInfo(True); XmlRpc::OnArmorEmpty(Event); PassOn(Event); } else{ declare statusMsg = TextLib::Compose(_("%1 $m$a00has been eliminated !"), Event.Victim.Name); ChangePlayerState(Event.Victim, False); Message::SendStatusMessage(statusMsg, 2000, 3, CUIConfig::EUISound::EndMatch, 0); XmlRpc::OnArmorEmpty(Event); PassOn(Event); } } // ---------------------------------- // // On hit else if (Event.Type == CSmModeEvent::EType::OnHit) { if (Event.Victim == Null || Event.Shooter == Event.Victim) { Discard(Event); } else { if(Event.Shooter.IsFakePlayer && !Event.Victim.IsFakePlayer){ //Bots shoots Players Event.Damage = 100; XmlRpc::OnHit(Event); PassOn(Event); } else if(!Event.Shooter.IsFakePlayer && Event.Victim.IsFakePlayer){ //Players shoots Bots declare Points = 1; Score::AddPoints(Event.Shooter, Points); Event.ShooterPoints = Points; declare Distance = SendHitDistanceMessage(Event); SetPlayerAmmo(Event.Shooter, CSmMode::EWeapon::Laser, 1); declare HitInterval = 700; if(Now < LastHit + HitInterval){ KillStreak += 1; LastHit = Now; DoKillStreakAnnounce(); } else { KillStreak = 0; LastHit = Now; } declare lifeStealChance = MathLib::Rand(0,1); if(lifeStealChance == 1){ Event.Shooter.Armor += 100; declare UI <=> UIManager.GetUI(Event.Shooter); UI.SendNotice(TextLib::Compose(_("$0a0+1 armor point !")), CUIConfig::ENoticeLevel::Default, Null, CUIConfig::EAvatarVariant::Default, CUIConfig::EUISound::Silence, 0); } if(Event.Victim.Armor == 100){ declare bonusTime = 0; switch (Players.count){ case 1: bonusTime = MathLib::Rand(3,4); case 2: bonusTime = MathLib::Rand(2,4); case 3: bonusTime = MathLib::Rand(2,3); case 4: bonusTime = MathLib::Rand(1,2); default: bonusTime = MathLib::Rand(3,4); } EndTime += (bonusTime * 1000); if(KillStreak == 0){ if(bonusTime == 1){ Message::SendBigMessage(TextLib::Compose(_("+%1 second !"), TextLib::ToText(bonusTime)), 3000, 0); } else { Message::SendBigMessage(TextLib::Compose(_("+%1 seconds !"), TextLib::ToText(bonusTime)), 3000, 0); } } else { if(bonusTime == 1){ Message::SendBigMessage(TextLib::Compose(_("+%1 second ! ($0f0+%2!$fff)"), TextLib::ToText(bonusTime+1), TextLib::ToText(1)), 3000, 0); } else { Message::SendBigMessage(TextLib::Compose(_("+%1 seconds ! ($0f0+%2!$fff)"), TextLib::ToText(bonusTime+1), TextLib::ToText(1)), 3000, 0); } EndTime += 1000; } Event.Damage = 100; } XmlRpc::OnHit(Event); PassOn(Event); } else { Discard(Event); } } } // ---------------------------------- // // On player request respawn else if (Event.Type == CSmModeEvent::EType::OnPlayerRequestRespawn) { if(Event.Player.SpawnStatus == CSmPlayer::ESpawnStatus::Spawned) { declare statusMsg = TextLib::Compose(_("%1 $m$s$a00has been eliminated !"), Event.Player.Name); Message::SendStatusMessage(statusMsg, 2000, 3, CUIConfig::EUISound::EndMatch, 0); ChangePlayerState(Event.Player, False); } XmlRpc::OnPlayerRequestRespawn(Event); PassOn(Event); } else { Discard(Event); } } TimerSound(); if(EndTime < Now || Players.count == 0 || ClansNbPlayersAlive[1] == 0){ sleep(1000); GamePhase = "roundEnd"; } } else if (GamePhase == "roundEnd") { ShowLayerTeam(False); sleep(2000); MatchInfo.ManialinkPage = ""; DestroyAllBotPlayers(); MatchInfo(False); EndTime = 0; declare Msg = ""; if(Score == BotPlayers.count) { if(Round >= MaxRounds){ UnspawnPlayers(); Msg = TextLib::Compose(_("$0f0You have won the match !")); PlaySound("win", 0); Message::SendBigMessage(Msg, 2000, 3, CUIConfig::EUISound::EndRound, 0); UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::ForcedVisible; UIManager.UIAll.UISequence = CUIConfig::EUISequence::PlayersPresentation; sleep(3000); Message::CleanBigMessages(); Message::CleanStatusMessages(); Score::MatchEnd(True); Round = 1; PlaySound("nextMap", 0); MatchEndRequested = True; sleep(8000); } else { Msg = TextLib::Compose(_("Round %1 terminated !"), TextLib::ToText(Round)); Message::SendBigMessage(Msg, 2000, 3, CUIConfig::EUISound::EndRound, 0); Score::RoundEnd(); PlaySound("excellent", 0); Round += 1; sleep(1000); GamePhase = "checking"; } } else { UnspawnPlayers(); Msg = TextLib::Compose(_("$f00You have lost the match !")); Score::RoundEnd(); PlaySound("lost", 0); Message::SendBigMessage(Msg, 2000, 3, CUIConfig::EUISound::EndRound, 0); UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::ForcedVisible; UIManager.UIAll.UISequence = CUIConfig::EUISequence::PlayersPresentation; Round = 1; sleep(2000); Score::MatchEnd(); Score::MatchBegin(); } sleep(2000); GamePhase = "checking"; } Message::Loop(); *** // ---------------------------------- // // Map end // ---------------------------------- // /****EndMap*** *** ****/ // ---------------------------------- // // Server end // ---------------------------------- // ***EndServer*** *** UIManager.UILayerDestroyAll(); Interface::DestroyRank(); SpawnScreen::DestroyRules(); SpawnScreen::DestroyScores(); SpawnScreen::DestroyMapInfo(); *** // ---------------------------------- // // Functions // ---------------------------------- // Void ChangePlayerState(CSmPlayer Player, Boolean IsFree){ if(Player.CurrentClan==0) return; if(IsFree){ _PlayerManialinkLines[Player.Id] = """"""; }else{ _PlayerManialinkLines[Player.Id] = """"""; } } Void PlaySound(Text soundName, Integer variant){ SoundLayerFirst.ManialinkPage = """"""; if(soundName == "cd"){ SoundLayerFirst.ManialinkPage = """ """; } if(soundName == "30sec"){ SoundLayerFirst.ManialinkPage = """ """; } if(soundName == "excellent"){ SoundLayerFirst.ManialinkPage = """ """; } if(soundName == "play"){ SoundLayerFirst.ManialinkPage = """ """; } if(soundName == "lost"){ SoundLayerFirst.ManialinkPage = """ """; } if(soundName == "win"){ SoundLayerFirst.ManialinkPage = """ """; } if(soundName == "newRoundIn"){ SoundLayerFirst.ManialinkPage = """ """; } if(soundName == "nextMap"){ SoundLayerFirst.ManialinkPage = """ """; } } Void CreateAnniBot(Text _Type, CSmMapLandmark _Spawn){ declare newBot = CreateBotPlayer(NullId, 0); switch(_Type){ case "Laser":{ SetPlayerWeapon(newBot, CSmMode::EWeapon::Laser, False); newBot.ForceColor = <0.0, 0.5, 0.5>;} case "Rocket":{ SetPlayerWeapon(newBot, CSmMode::EWeapon::Rocket, False); newBot.ForceColor = <0.0, 1.0, 0.0>;} case "Nucleus":{ SetPlayerWeapon(newBot, CSmMode::EWeapon::Nucleus, False); newBot.ForceColor = <0.5, 0.0, 0.5>;} case "Arrow":{ SetPlayerAmmoMax(newBot, CSmMode::EWeapon::Arrow, 2); SetPlayerWeapon(newBot, CSmMode::EWeapon::Arrow, False); newBot.ForceColor = <0.5, 0.5, 0.0>;} case "Special":{ SetPlayerWeapon(newBot, CSmMode::EWeapon::Rocket, False); newBot.ForceColor = <1.0, 0.5, 0.0>;} } newBot.Driver.AttackFilter = CSmPlayerDriver::ESmAttackFilter::OppositePlayers; if(_Type != "Special"){ newBot.Driver.Behaviour = CSmPlayerDriver::ESmDriverBehaviour::Saunter; newBot.Driver.Saunter_AnchorPoint = _Spawn.Position; newBot.Driver.Saunter_Radius = 10.; newBot.Driver.AggroRadius = 50.; newBot.Driver.DisengageDistance = 30.; newBot.Driver.Accuracy = 0.6; newBot.Driver.ShootPeriodMin = 500; } else { newBot.Driver.Behaviour = CSmPlayerDriver::ESmDriverBehaviour::Turret; newBot.Driver.AggroRadius = 100.; newBot.Driver.DisengageDistance = 0.; newBot.Driver.Accuracy = 1.0; newBot.Driver.ShootPeriodMax = 10; newBot.Driver.ShootPeriodMin = 10; newBot.Driver.RocketAnticipation = True; newBot.AmmoGain = 10.0; } newBot.Driver.Fov = 300.0; newBot.ArmorMax = 100; SpawnBotPlayer(newBot, 0, 100, _Spawn.BotPath, Now); } Void CreateBots(){ //Bots creation declare botCountId = 0; while(botCountId < 30) { declare Spawn <=> MapLandmarks_BotPath[MathLib::Rand(0, MapLandmarks_BotPath.count-1)]; declare botsWeapons = 0; if(Spawn.Tag == "BotPath"){ if(Round == 1){ botsWeapons = 1; } if(Round == 2){ botsWeapons = 2; } if(Round == 3){ botsWeapons = MathLib::Rand(2,3); } if(Round == 4){ botsWeapons = 3; } if(Round == 5){ botsWeapons = MathLib::Rand(3,4); } if(Round == 6){ botsWeapons = MathLib::Rand(1,4); } if(botsWeapons == 1){ CreateAnniBot("Laser",Spawn); } else if(botsWeapons == 2){ CreateAnniBot("Rocket",Spawn); } else if(botsWeapons == 3){ CreateAnniBot("Nucleus",Spawn); } else if(botsWeapons == 4){ CreateAnniBot("Arrow", Spawn); } botCountId += 1; } } foreach(BotPath, MapLandmarks_BotPath){ if(BotPath.Tag == "Special"){ if(Round == MaxRounds){ CreateAnniBot("Special", BotPath); } } } } Void SpawnPlayers() { foreach (Player in Players) { if(Player.SpawnStatus == CSmPlayer::ESpawnStatus::NotSpawned){ Player.ArmorMax = 400; Player.AmmoGain = 1.8; SetPlayerWeapon(Player, CSmMode::EWeapon::Laser, False); SetPlayerClan(Player, 1); ChangePlayerState(Player, True); SpawnPlayer(Player, 1, 400, MapLandmarks_PlayerSpawn[MathLib::Rand(0, MapLandmarks_PlayerSpawn.count-1)].PlayerSpawn, Now); } } } Void UnspawnPlayers(){ foreach (Player in Players) { if (Player.SpawnStatus == CSmPlayer::ESpawnStatus::Spawned) { UnspawnPlayer(Player); } } } Real SendHitDistanceMessage(CSmModeEvent _Event) { if (_Event.Type != CSmModeEvent::EType::OnHit) return -1.; // Wrong event type if (_Event.Shooter == Null || _Event.Victim == Null || _Event.Shooter == _Event.Victim) return -1.; // Invalid players // Get distance declare Distance = MathLib::Distance(_Event.Shooter.Position, _Event.Victim.Position); Distance = MathLib::NearestInteger(Distance * 10) / 10.0; // Save longest hit /* if (Distance > G_LongestHitDist) { G_LongestHitDist = Distance; G_LongestHitName = _Event.Shooter.Name; SetFooterStats(Null); } */ declare UI <=> UIManager.GetUI(_Event.Shooter); if (UI == Null) return -1.; // Send message UI.SendNotice(TextLib::Compose(_("%1m hit!"), TextLib::ToText(Distance)), CUIConfig::ENoticeLevel::Default, Null, CUIConfig::EAvatarVariant::Default, CUIConfig::EUISound::Silence, 0); return Distance; } Void DoKillStreakAnnounce(){ SoundLayerSecond.ManialinkPage = """"""; if(KillStreak == 1){ SoundLayerSecond.ManialinkPage = """ """; foreach(Player in Players){ declare UI <=> UIManager.GetUI(Player); UI.SendNotice(TextLib::Compose(_("$f00Double Kill!")), CUIConfig::ENoticeLevel::Default, Null, CUIConfig::EAvatarVariant::Default, CUIConfig::EUISound::Silence, 0); } } else if(KillStreak == 2){ SoundLayerSecond.ManialinkPage = """ """; foreach(Player in Players){ declare UI <=> UIManager.GetUI(Player); UI.SendNotice(TextLib::Compose(_("$f00Multi Kill!")), CUIConfig::ENoticeLevel::Default, Null, CUIConfig::EAvatarVariant::Default, CUIConfig::EUISound::Silence, 0); } } else if(KillStreak == 3){ SoundLayerSecond.ManialinkPage = """ """; foreach(Player in Players){ declare UI <=> UIManager.GetUI(Player); UI.SendNotice(TextLib::Compose(_("$f00Mega Kill!")), CUIConfig::ENoticeLevel::Default, Null, CUIConfig::EAvatarVariant::Default, CUIConfig::EUISound::Silence, 0); } } else if(KillStreak == 4){ SoundLayerSecond.ManialinkPage = """ """; foreach(Player in Players){ declare UI <=> UIManager.GetUI(Player); UI.SendNotice(TextLib::Compose(_("$f00Ultra Kill!")), CUIConfig::ENoticeLevel::Default, Null, CUIConfig::EAvatarVariant::Default, CUIConfig::EUISound::Silence, 0); } } else if(KillStreak > 5){ SoundLayerSecond.ManialinkPage = """ """; foreach(Player in Players){ declare UI <=> UIManager.GetUI(Player); UI.SendNotice(TextLib::Compose(_("$f00Monster Kill!")), CUIConfig::ENoticeLevel::Default, Null, CUIConfig::EAvatarVariant::Default, CUIConfig::EUISound::Silence, 0); } } } Void MatchInfo(Boolean show){ if(show){ MatchInfo.ManialinkPage = """