//============================================================================= // // Santa's Grotto 1.2 - santas_grotto_v1_2 // // Who When What //----------------------------------------------------------------------------- // Mateos - Updated waypoint mapping // + Goals conversion/management + Routing // Mateos 21/04/2010 Added _goals.gm file // Routing to secure the Key Card // //============================================================================= /**************************************************** Path mapping updated and script by Mateos Correspondant WAY file size: 149 Ko (153 440 octets) Last update: 1st January 2019 ****************************************************/ global Spawns = { OLD_FISHING_HOUSE = 1, LANCASTER_BOMBER_DEPLOYMENT = 2, /** * Axis only, available after the First Gate is destroyed, * then is unavailable once the Key is secured at the Second Gate. */ WORKSHOP = 3, NORTH_POLE = 4, FACTORY = 5, GARAGE = 6, ELF_S_HUT = 7, GetAxisReinforceTime = function() { foreach ( id and bot in BotTable ) { if ( bot.GetTeam() == TEAM.AXIS ) { return bot.GetReinforceTime(); } } }, SetSpawn = function( team, spawn, selfkill ) { foreach ( bot in BotTable ) { if ( bot.GetTeam() == team ) { bot.ChangeSpawnPoint( spawn ); if ( selfkill ) { bot.ExecCommand( "kill" ); } } } }, }; global Map = { Debug = 0, // Please set to zero before distributing your script isFuseBoxBuilt = false, isSackStolen = false, northPoleTeam = TEAM.AXIS, // From alchemycastle_b3.gm by palota NavDoor = function( _this ) { wpinfo = _this.navigation.wpinfo; if ( wpinfo == null ) { wpinfo = Util.WpNameInfo( _this.CurrentNavigation ); _this.navigation.wpinfo = wpinfo; } pos = wpinfo.position; vec = wpinfo.facing.Normalize(); pos1 = pos - vec * 50; pos1 = Vector3( pos1.x, pos1.y, pos.z ); pos2 = pos + vec * 140; pos2 = Vector3( pos2.x, pos2.y, pos.z ); for ( i = 0; i < 4; i += 1 ) { if ( _this.Goto(pos) == EVENT.PATH_FAILED ) { return; } _this.AddAimRequest( Priority.High, "facing", wpinfo.facing ); tr = TraceLine( pos, pos2, null, TRACE.SOLID, 0, true ); if ( tr.fraction == 1 ) { _this.Bot.MoveTowards( pos2 ); sleep( 0.8 ); break; } sleep( 0.1 ); _this.Bot.PressButton( BTN.USE ); _this.Bot.MoveTowards( pos1 ); // Wait while door opens sleep( 1 ); } }, // Paththrough Navigational Navigation = { // One-way door cp_door = { navigate = function( _this ) { Map.NavDoor( _this ); }, }, jump = { navigate = function( _this ) { // Since this kind of navigation doesn't work well with waypoints wpTable = {}; Wp.GetWaypointByName( "top", wpTable ); // With a good jump while going forward to pass the 2 steps _this.AddAimRequest( Priority.High, "facing", wpTable.facing ); _this.Bot.HoldButton( BTN.FORWARD, 1 ); _this.Bot.HoldButton( BTN.JUMP, 0.5 ); }, }, jump_crouch = { navigate = function( _this ) { _this.AddAimRequest( Priority.High, "facing", Vec3( 0.2, 0.9, 0.4 ) ); sleep( 1 ); _this.Bot.HoldButton( BTN.JUMP, 1 ); sleep( 0.5 ); _this.AddAimRequest( Priority.High, "facing", Vec3( 0.1, 0.6, -0.8 ) ); _this.Bot.HoldButton( BTN.CROUCH, 1 ); sleep( 1 ); }, }, }, Roles = { AXIS = { // North Pole flag DEFENDER = { voice = "defend", // Signals voice chat to randomly announce numbots = 2, // Maximum of 2 bots }, }, ALLIES = { // North Pole flag ATTACKER = { voice = "attack", // Signals voice chat to randomly announce numbots = 2, // Maximum of 2 bots }, }, }, // *** TRIGGER CALLBACKS *** First_Gate_Destroyed = function( trigger ) { // blockwall flags refresh sleep( 2 ); Goals.First_Gate( false ); Cabinets.Garage( true ); Util.EnableGoal( "ATTACK_SG.*" ); SetAvailableMapGoals( TEAM.AXIS, true, ".*AxisBravo.*" ); SetAvailableMapGoals( TEAM.ALLIES, true, { "FLAG_gate_key", "CAPPOINT_Secondgate", }); Functions.Print( "First_Gate_Destroyed", true ); }, gate_key_Taken = function( trigger ) { Util.EnableGoal( "ATTACK_SFB.*" ); Util.DisableGoal( "ATTACK_SG.*" ); SetAvailableMapGoals( TEAM.AXIS, false, ".*AxisBravo.*" ); SetAvailableMapGoals( TEAM.AXIS, true, ".*AxisSecondGate.*" ); Util.MapDebugPrint( "gate_key_taken" ); }, gate_key_returned = function( trigger ) { Functions.AxisSuicideOnGateKeyReturned(); Util.EnableGoal( "ATTACK_SG.*" ); Util.DisableGoal( "ATTACK_SFB.*" ); SetAvailableMapGoals( TEAM.AXIS, false, ".*AxisSecondGate.*" ); SetAvailableMapGoals( TEAM.AXIS, true, ".*AxisBravo.*" ); Util.MapDebugPrint( "gate_key_returned" ); }, Secondgate_Captured = function( trigger ) { Functions.AxisSuicideOnGateKeySecured(); // Just for Axis mobile mortar Cabinets.Factory( true ); SetAvailableMapGoals( TEAM.AXIS, false, { ".*AxisSecondGate.*", "ATTACK_SFB.*", }); SetAvailableMapGoals( TEAM.AXIS, true, { ".*AxisCharlie.*", "CAMP_FuseBox.*", "CHECKPOINT_.*", "DEFEND_Flag.*", "DEFEND_FuseBox.*", }); // Disabled because the ceiling is f***ed SetAvailableMapGoals( TEAM.AXIS, false, "MOBILEMORTAR_AxisCharlie" ); SetAvailableMapGoals( TEAM.ALLIES, false, "CAPPOINT_Secondgate" ); Functions.Print( "Secondgate_Captured", true ); }, Second_Gate_Open = function( trigger ) { // blockwall flags refresh sleep( 1 ); Cabinets.Garage( false ); SetAvailableMapGoals( TEAM.ALLIES, false, "ATTACK_SFB.*" ); Goals.Second_Gate( true ); Util.MapDebugPrint( "Second_Gate_Open" ); }, north_pole_flag_Axis_Captured = function( trigger ) { Map.northPoleTeam = TEAM.AXIS; Util.MapDebugPrint( "north_pole_flag_Axis_Captured", true ); }, north_pole_flag_Allies_Captured = function( trigger ) { Map.northPoleTeam = TEAM.ALLIES; Util.MapDebugPrint( "north_pole_flag_Allies_Captured", true ); }, Fuse_Box_Built = function( trigger ) { Map.isFuseBoxBuilt = true; Wp.SetWaypointFlag( "3rd_door_1", "axis", false ); Wp.SetWaypointFlag( "3rd_door_2", "axis", false ); Goals.Second_Gate( false ); // They'll spawn at the Elf's Hut otherwise // Move there only if the Sack isn't in the nature // Also handle a few goals if ( !Map.isSackStolen ) { Spawns.SetSpawn( TEAM.AXIS, Spawns.FACTORY, false ); Goals.Factory( true ); } else { Goals.Santa_S_Grotto( true ); } SetAvailableMapGoals( TEAM.AXIS, false, ".*AxisCharlie.*" ); Functions.Print( "Fuse_Box_Built", true ); }, Third_Gate_Open = function( trigger ) { SetAvailableMapGoals( TEAM.ALLIES, true, { "CAPPOINT_sackdest", "FLAG_sack", }); Util.MapDebugPrint( "Third_Gate_Open" ); }, sack_Taken = function( trigger ) { Map.isSackStolen = true; // Move Axis to Elf's Hut spawn, // and selfkill if the spawn time is equal or below 5 seconds selfkill = Functions.CanAxisSelfkill( 5 ); Spawns.SetSpawn( TEAM.AXIS, Spawns.ELF_S_HUT, selfkill ); if ( Map.isFuseBoxBuilt ) { Goals.Factory( false ); Goals.Santa_S_Grotto( true ); } else { // If the Fuse Box isn't built when this event is triggered, // it means a human player bypassed the protected door to steal the objective... // Allied bots will keep their goals as is then (because reachability), but not Axis! SetAvailableMapGoals( TEAM.AXIS, false, ".*" ); SetAvailableMapGoals( TEAM.AXIS, true, "ATTACK_SD.*" ); } Util.MapDebugPrint( "sack_taken" ); }, sack_returned = function( trigger ) { Map.isSackStolen = false; Goals.Santa_S_Grotto( false ); // Consider that Allies can only bypass the Second Gate door, // since they're all covi-protected; // so it only depends on the Fuse Box status if ( Map.isFuseBoxBuilt ) { Spawns.SetSpawn( TEAM.AXIS, Spawns.FACTORY, false ); Goals.Factory( true ); } else { if ( Map.northPoleTeam == TEAM.AXIS ) { Spawns.SetSpawn( TEAM.AXIS, Spawns.NORTH_POLE, false ); } else { Spawns.SetSpawn( TEAM.AXIS, Spawns.FACTORY, false ); } // Just re-enable what was disabled for Axis Util.EnableGoal( "ATTACK_TG.*" ); Util.EnableGoal( "CHECKPOINT_.*" ); SetAvailableMapGoals( TEAM.AXIS, true, ".*AxisCharlie.*" ); // Disabled because the ceiling is f***ed SetAvailableMapGoals( TEAM.AXIS, false, "MOBILEMORTAR_AxisCharlie" ); Cabinets.North_Pole( true ); } Util.MapDebugPrint( "sack_returned" ); }, sack_secured = function( trigger ) { Functions.Print( "sack_secured", false ); }, }; global OnMapLoad = function() { Functions.timeLimitInMinutes = Ceil( GetGameTimeLeft() ) / 60; // *** TRIGGERS *** OnTrigger( "^1Allies have blown the First Gate!", Map.First_Gate_Destroyed ); OnTrigger( "^1Key for the Second Gate has been stolen by Allies!", Map.gate_key_Taken ); OnTrigger( "^1Key for the Second Gate has been returned to the House!", Map.gate_key_returned ); OnTrigger( "^1Second Gate Key has been secured, Second Gate opening!", Map.Secondgate_Captured ); OnTrigger( "^1Second Gate open!", Map.Second_Gate_Open ); OnTrigger( "^1Axis have captured the North Pole!", Map.north_pole_flag_Axis_Captured ); OnTrigger( "^1Allies have Captured the North Pole!", Map.north_pole_flag_Allies_Captured ); OnTrigger( "^1Fuse Box has been repaired", Map.Fuse_Box_Built ); OnTrigger( "^1Third Gate open!", Map.Third_Gate_Open ); OnTrigger( "^1Allies have got Santa's Sack!", Map.sack_Taken ); OnTrigger( "^1Santa's Sack has been taken back to the Factory!", Map.sack_returned ); OnTrigger( "^1Santa's Sack has been returned to Santa, Christmas can continue! :D", Map.sack_secured ); // *** CLEAR ALL GOALS FOR BOTH TEAMS *** Util.DisableGoal( ".*", true ); // All but Routes Goals.First_Gate( true ); SetAvailableMapGoals( TEAM.ALLIES, true, "PLANT_First_Gate" ); // *** GOALS PROPERTIES *** Wp.SetWaypointFlag( "3rd_door_1", "axis", true ); Wp.SetWaypointFlag( "3rd_door_2", "axis", true ); Util.ExcludeClass( "MOUNTMG42_.*", TEAM.AXIS, CLASS.MEDIC, CLASS.ENGINEER ); Util.ExcludeClass( "MOUNTMG42_.*", TEAM.ALLIES, CLASS.MEDIC, CLASS.ENGINEER ); Util.SetGoalOffset( 300, -20, -375, "PLANT_First_Gate" ); SetMapGoalProperties( "ATTACK_.*", { DisableCM = 1, MinCampTime = 20, MaxCampTime = 42 } ); SetMapGoalProperties( "CAMP_.*", { DisableCM = 1, MinCampTime = 20, MaxCampTime = 42 } ); SetMapGoalProperties( "DEFEND_.*", { DisableCM = 1, MinCampTime = 20, MaxCampTime = 42 } ); SetMapGoalProperties( "MOUNTMG42_.*", { MinCampTime = 15, MaxCampTime = 60 } ); // *** ROLES *** SetGoalRole( "CHECKPOINT_north_pole_flag", { ROLE.ATTACKER, ROLE.DEFENDER } ); SetGoalRole( "ATTACK_Flag.*", ROLE.ATTACKER ); SetGoalRole( "DEFEND_Flag.*", ROLE.DEFENDER ); Util.MapDebugPrint( "Omni-Bot 0.8x map script for Santa's Grotto 1.2 by Mateos executed." ); }; global OnBotJoin = function( bot ) { bot.MaxViewDistance = 1000.0; }; global Goals = { First_Gate = function( bAvailability ) { Cabinets.Old_Fishing_House( bAvailability ); if ( bAvailability ) { Util.EnableGoal( "CAMP_FirstGate.*" ); } else { Util.DisableGoal( "CAMP_FirstGate.*" ); } // *** AXIS GOALS *** SetAvailableMapGoals( TEAM.AXIS, bAvailability, { ".*AxisAlpha.*", "DEFEND_FirstGate.*", }); // *** ALLIED GOALS *** SetAvailableMapGoals( TEAM.ALLIES, bAvailability, { ".*AlliesAlpha.*", "ATTACK_FirstGate.*", }); }, Second_Gate = function( bAvailability ) { Cabinets.North_Pole( bAvailability ); if ( bAvailability ) { Util.EnableGoal( "CAMP_FuseBox.*" ); } else { Util.DisableGoal( "CAMP_FuseBox.*" ); } SetAvailableMapGoals( TEAM.AXIS, bAvailability, { "DEFEND_Flag.*", "DEFEND_FuseBox.*", }); SetAvailableMapGoals( TEAM.ALLIES, bAvailability, { "ATTACK_Flag.*", "ATTACK_FuseBox.*", "BUILD_Fuse_Box", }); }, Factory = function( bAvailability ) { Cabinets.Factory( bAvailability ); Cabinets.Command_Post( bAvailability ); if ( bAvailability ) { Util.EnableGoal( "ATTACK_Sack.*" ); Util.EnableGoal( "BUILD_Command_Post" ); Util.EnableGoal( "PLANT_Command_Post" ); } else { Util.DisableGoal( "ATTACK_Sack.*" ); Util.DisableGoal( "BUILD_Command_Post" ); Util.DisableGoal( "PLANT_Command_Post" ); } SetAvailableMapGoals( TEAM.AXIS, bAvailability, { ".*AxisDelta.*", "MOUNTMG42_Factory_MG", "REPAIRMG42_Factory_MG", }); }, Santa_S_Grotto = function( bAvailability ) { if ( bAvailability ) { Util.EnableGoal( "ATTACK_SD.*" ); } else { Util.DisableGoal( "ATTACK_SD.*" ); } SetAvailableMapGoals( TEAM.AXIS, bAvailability, ".*AxisEcho.*" ); }, }; global InitializeRoutes = function() { MapRoutes = { CAMP_FirstGate1 = { ROUTE_LancasterDeploymentSpawn = { ROUTE_EastSea1 = {}, ROUTE_MiddleSea1 = { ROUTE_MiddleSea2 = {}, }, }, }, CAPPOINT_sackdest = { ROUTE_Sack = { ROUTE_Sack_Back1 = { Weight = 4, // Prefer ROUTE_Sack_Back1 4 times more ROUTE_Sack_Back2 = { ROUTE_Sack_Junction1 = { ROUTE_Sack_Junction2 = {}, }, }, }, ROUTE_Sack_Low_Left = { Weight = 2, // Prefer ROUTE_Sack_Low_Left twice more ROUTE_Sack_Junction1 = { ROUTE_Sack_Junction2 = {}, }, }, ROUTE_Sack_Low_Right = { ROUTE_Sack_Junction1 = { ROUTE_Sack_Junction2 = {}, }, }, }, }, CAPPOINT_Secondgate = { ROUTE_GateKeyTaken = { ROUTE_KeyToSafe1 = { ROUTE_KeyToSafe2 = { ROUTE_KeyToSafe3 = { ROUTE_KeyToSafe4 = { ROUTE_KeyToSafe5 = { ROUTE_KeyToSafe6 = { ROUTE_KeyToSafe7 = { ROUTE_KeySecured = {}, }, }, }, }, }, }, }, }, }, FLAG_gate_key = { ROUTE_Old_Fishing_House = { ROUTE_ToGateKey = { ROUTE_ToGateKeyLeft = { Weight = 3 }, ROUTE_ToGateKeyMiddle = { Weight = 2 }, ROUTE_ToGateKeyRight = {}, }, }, }, PLANT_First_Gate = { ROUTE_LancasterDeploymentSpawn = { ROUTE_EastSea1 = {}, ROUTE_MiddleSea1 = { ROUTE_MiddleSea2 = {}, }, ROUTE_WestSea1 = { ROUTE_WestSea2 = {}, }, }, }, }; // Copy routes MapRoutes.ATTACK_FirstGate2 = MapRoutes.CAMP_FirstGate1; MapRoutes.ATTACK_FirstGate3 = MapRoutes.CAMP_FirstGate1; MapRoutes.CAMP_FirstGate2 = MapRoutes.CAMP_FirstGate1; MapRoutes.CAMP_FirstGate3 = MapRoutes.CAMP_FirstGate1; Util.Routes( MapRoutes ); }; global Cabinets = { Lancaster = function( bAvailability ) { SetAvailableMapGoals( TEAM.ALLIES, bAvailability, { "AMMOCAB_t6", "HEALTHCAB_t7", }); }, Old_Fishing_House = function( bAvailability ) { if ( bAvailability ) { Util.EnableGoal( "AMMOCAB_t2" ); Util.EnableGoal( "HEALTHCAB_t1" ); } else { Util.DisableGoal( "AMMOCAB_t2" ); Util.DisableGoal( "HEALTHCAB_t1" ); } }, Garage = function( bAvailability ) { if ( bAvailability ) { Util.EnableGoal( "AMMOCAB_t19" ); Util.EnableGoal( "HEALTHCAB_t20" ); } else { Util.DisableGoal( "AMMOCAB_t19" ); Util.DisableGoal( "HEALTHCAB_t20" ); } }, North_Pole = function( bAvailability ) { if ( bAvailability ) { Util.EnableGoal( "AMMOCAB_t22" ); Util.EnableGoal( "HEALTHCAB_t23" ); } else { Util.DisableGoal( "AMMOCAB_t22" ); Util.DisableGoal( "HEALTHCAB_t23" ); } }, Factory = function( bAvailability ) { if ( bAvailability ) { Util.EnableGoal( "AMMOCAB_t25" ); Util.EnableGoal( "HEALTHCAB_t26" ); } else { Util.DisableGoal( "AMMOCAB_t25" ); Util.DisableGoal( "HEALTHCAB_t26" ); } }, Command_Post = function( bAvailability ) { if ( bAvailability ) { Util.EnableGoal( "AMMOCAB_t66" ); Util.EnableGoal( "HEALTHCAB_t67" ); } else { Util.DisableGoal( "AMMOCAB_t66" ); Util.DisableGoal( "HEALTHCAB_t67" ); } }, }; global Functions = { /** * Map time limit. */ timeLimitInMinutes, /** * Prints a text with elapsed and left times. * @param text Text to print. * @param printActiveGoals Either print or not active goals. */ Print = function( text, printActiveGoals ) { Util.MapDebugPrint( text + Functions.GetFormattedElaspedTime() + Functions.GetFormattedTimeLeft(), !printActiveGoals ); }, /** * Builds and returns the elapsed time since the round has started. */ GetFormattedElaspedTime = function() { totalTimeInSeconds = Functions.timeLimitInMinutes * 60; gameTimeLeftInSeconds = Floor( GetGameTimeLeft() ); elapsedTimeInSeconds = totalTimeInSeconds - gameTimeLeftInSeconds; elapsedTimeMinutes = Floor( elapsedTimeInSeconds / 60 ); elapsedTimeSeconds = elapsedTimeInSeconds - elapsedTimeMinutes * 60; if ( elapsedTimeSeconds < 10 ) { elapsedTimeSeconds = "0" + elapsedTimeSeconds; } return " (" + elapsedTimeMinutes + ":" + elapsedTimeSeconds + " elapsed)"; }, /** * Builds and returns the game time left, formatted as mm:ss. */ GetFormattedTimeLeft = function() { gameTimeLeft = Floor( GetGameTimeLeft() ); minutes = Floor( gameTimeLeft / 60 ); seconds = gameTimeLeft - minutes * 60; if ( seconds < 10 ) { seconds = "0" + seconds; } return " (" + minutes + ":" + seconds + " left)"; }, /** * Upon Gate Key Returned event, * if an Axis bot is far away from the Key, * and its spawn time it close, just selfkill. * Note: The distance calculation is only done on XY plane (that's enough). */ AxisSuicideOnGateKeyReturned = function() { selfkill = Functions.CanAxisSelfkill( 5 ); if ( !selfkill ) { return; } keyPosition = GetGoal( "FLAG_gate_key" ).GetPosition(); foreach ( id and bot in BotTable ) { if ( bot.GetTeam() == TEAM.AXIS ) { botPosition = bot.GetPosition(); x = botPosition.x - keyPosition.x; y = botPosition.y - keyPosition.y; distance = Sqrt( x * x + y * y ); if ( distance > 1000. ) { bot.ExecCommand( "kill" ); Util.MapDebugPrint( bot.Name + "^b selfkilled because he was too far away (" + distance + ") from the key", true ); } } } }, /** * Upon Gate Key Secured event, * if an Axis bot is far away from the Second Gate, * and its spawn time is below 10 seconds, just selfkill. */ AxisSuicideOnGateKeySecured = function() { if ( !Functions.CanAxisSelfkill( 10 ) ) { return; } foreach ( id and bot in BotTable ) { if ( bot.GetTeam() == TEAM.AXIS ) { botPosition = bot.GetPosition(); if ( botPosition.x > 830. && botPosition.y > 3875. ) { bot.ExecCommand( "kill" ); Util.MapDebugPrint( bot.Name + "^b selfkilled because he was too far away", true ); } } } }, /** * Indicates if Axis can selfkill based on a given time left. * @param seconds Number of seconds below which reinforce time will allow selfkill. */ CanAxisSelfkill = function( seconds ) { axisReinforceTime = Spawns.GetAxisReinforceTime(); selfkill = axisReinforceTime <= seconds; Util.MapDebugPrint( "Axis reinforce time: " + axisReinforceTime + " => Suicide: " + selfkill, true ); return selfkill; }, };