Advertisement
Guest User

Untitled

a guest
Nov 25th, 2015
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 128.43 KB | None | 0 0
  1. /**
  2. * Mode Battle & Battle Waves
  3. */
  4.  
  5. #Extends "Modes/ShootMania/ModeMatchmaking.Script.txt"
  6.  
  7. #Const CompatibleMapTypes "BattleArena"
  8. #Const Version "2014-11-26"
  9. #Const ScriptName "Battle.Script.txt"
  10.  
  11. #Include "MathLib" as MathLib
  12. #Include "TextLib" as TextLib
  13. #Include "Libs/Nadeo/Victory.Script.txt" as Victory
  14. #Include "Libs/Nadeo/Interface.Script.txt" as Interface
  15. #Include "Libs/Nadeo/TabsServer.Script.txt" as Tabs
  16. #Include "Libs/Nadeo/Top2.Script.txt" as Top
  17. #Include "Libs/Nadeo/ShootMania/SM.Script.txt" as SM
  18. #Include "Libs/Nadeo/ShootMania/Map.Script.txt" as Map
  19. #Include "Libs/Nadeo/ShootMania/Score.Script.txt" as Score
  20. #Include "Libs/Nadeo/ShootMania/BalancedWeapons.Script.txt" as BalancedWeapons
  21. #Include "Libs/Nadeo/ShootMania/BeginnersWelcome.Script.txt" as Beginners
  22. #Include "Libs/Nadeo/ShootMania/WarmUp2.Script.txt" as WarmUp2
  23.  
  24. // ---------------------------------- //
  25. // Settings
  26. // ---------------------------------- //
  27. #Setting S_RespawnTime 6001 as "<hidden>" //_("Respawn time") ///< Time before respawn
  28. #Setting S_RoundsToWin 2 as _("Rounds to win") ///< Number of rounds to win a map
  29. #Setting S_RoundGapToWin 1 as _("Round gap to win") ///< Minimum gap between the two leaders to win a map
  30. #Setting S_RoundsLimit 3 as _("Rounds limit") ///< Point limit on map
  31. #Setting S_TimeLimit 300 as "<hidden>" //_("Time limit (seconds)")///< Time limit (seconds)
  32. #Setting S_UseOvertime True as _("Use overtime") ///< Activate the overtime system
  33. #Setting S_CaptureMaxValue 30000 as _("Capture time (milliseconds)") ///< Pole capture time (milliseconds)
  34. #Setting S_AlternativePoints False as "<hidden>" //_("Use atk and def points as score")
  35. #Setting S_AllowBeginners False as "<hidden>" //_("Is a Beginners Welcome server")
  36. //#Setting S_AutoManageAFK True as _("Switch inactive players to spectators")
  37. #Setting S_ArmorPoints 2 as _("Armor points")
  38. #Setting S_WarmUpDuration 0 as _("Warm up duration (sec.)") ///< Duration of the warm up round (0 = no warmup)
  39. #Setting S_NbPlayersPerTeamMax 0 as "<hidden>" //_("Maximum number of players per team (0: no max)") ///< Do not spawn players beyond this limit, 0=no limit
  40. #Setting S_NbPlayersPerTeamMin 1 as "<hidden>" //_("Minumum number of players per team") ///< Wait until this minimum is reach
  41. // Waves Settings
  42. #Setting S_BattleWaves True as "<hidden>" //_("Use Waves Mode")
  43. #Setting S_TimeLimitForFirstCapture 300 as _("Time limit for first capture") // en s
  44. #Setting S_TimeLimitAfterFirstCapture 600 as _("Time limit after first capture") // en s
  45. #Setting S_WaveDuration 15 as _("Wave duration") // en s
  46. #Setting S_StayInAttackOnCapture True as _("Reset timer when a pole is beeing captured")
  47. #Setting S_GladiatorMode False as "<hidden>" ///< Give bonus on hit
  48. // Clublinks settings
  49. #Setting S_UsePlayerClublinks True as "<hidden>" //_("Use players clublinks") ///< Use the players clublinks, or otherwise use the default teams
  50. #Setting S_ForceClublinkTeam1 "" as "<hidden>" ///< Force the Clublink of team 1 (format: http://www.example.com/MyTeam.Club.xml)
  51. #Setting S_ForceClublinkTeam2 "" as "<hidden>" ///< Force the Clublink of team 2 (format: http://www.example.com/MyTeam.Club.xml)
  52. // UI setting
  53. #Setting S_DisplayTopsRound True as _("Display the tops at the end of the round")
  54. #Setting S_DisplayTopsMap True as _("Display the tops at the end of the map")
  55. #Setting S_DisplayTopsOnlyShooter False as "<hidden>" //_("Only display the shooter top")
  56. #Setting S_DisplayPoleRecords True as _("Display pole running time record")
  57. // Auto balance
  58. #Setting S_AutoBalance True as _("Use map autobalance") ///< Use auto balance at the start of the map
  59. #Setting S_AutoBalanceRound True as _("Use round autobalance") ///< Use auto balance at the end of the round
  60. #Setting S_AutoBalanceDelta 2 as _("Maximum clan players number difference") ///< Maximum difference of players number before autobalance
  61.  
  62. // Score Constants (used to be settings)
  63. #Const S_HotSpotsRadius 20.
  64. #Const S_AtkHotSpotsRadius 4.
  65. #Const S_ScoreDefense_HitOnPole 3
  66. #Const S_ScoreDefense_HitNearPole 3
  67. #Const S_ScoreAttack_HitNearPole 2
  68. #Const S_ScoreAttack_ClassicHit 1
  69. #Const S_PointsPerPole 10.
  70. #Const S_DefPointOnDenyForOnePole 20.
  71. #Const S_ScoreDefense_CaptureJiT 1 //as _("Defense points granted for a Just In Time capture")
  72. #Const S_PointsOnEngage 1 //as _("Attack points granted for the engage pole")
  73.  
  74. // round phases for UI
  75. #Const C_RoundPhase_Playing 1
  76. #Const C_RoundPhase_EndRound 2
  77.  
  78. #Const S_ResetTimeOnCapturedPole False
  79. #Const C_ImgBaseDir "file://Media/Manialinks/Shootmania/Common/"
  80. #Const UITickPeriod 200
  81. #Const C_JustInTimeLimit 3000 //milli sec.
  82. #Const C_NoCollisionsDuration 6000 ///< No collision duration at the beginning of the round
  83. #Const C_Top5SequenceDuration 10000 ///< Duration of the top 5 sequence at the end of the round and the map
  84. #Const C_MinimumExtendedTime 30000 ///< Minimum duration of the extended time
  85.  
  86. #Const C_PoleCaptureState_Neutral 0
  87. #Const C_PoleCaptureState_Capturing 1
  88. #Const C_PoleCaptureState_Captured 2
  89. #Const C_PoleCaptureState_Protected 3
  90. #Const C_PoleCaptureState_Locked 4
  91. #Const C_PoleCaptureState_Denied 5
  92.  
  93. #Const C_TopId_Hit "HIT"
  94. #Const C_TopId_Capture "CAPTURE"
  95. #Const C_TopId_Defense "DEFENSE"
  96. #Const C_TopId_Attack "ATTACK"
  97. #Const C_TopId_Combo "COMBO"
  98.  
  99. #Const C_SlideId_Attack 0
  100. #Const C_SlideId_Defense 1
  101. #Const C_SlideId_Combo 3
  102.  
  103. #Const Description _("TYPE: Team versus Team\nOBJECTIVE:\nCapture all the poles of the opposing team before the end of the time limit.\nIn Waves mode you can only capture when your team is in attack.\nThe team with the more poles at the end of the round scores 1 point. If
  104.  
  105. this team reaches the points limit she wins the map.")
  106.  
  107. #Const C_DisplayRulesReminder True
  108. #Const C_Battle_BlueBots 0
  109. #Const C_Battle_RedBots 0
  110.  
  111. declare Text G_ScoreTeam1;
  112. declare Text G_ScoreTeam2;
  113. declare Integer[Ident] G_PolesIndice;
  114. declare Ident G_EngagePoleId;
  115.  
  116. declare Ident G_LayerRoundInfoId;
  117. declare Ident G_TimeLeftLayerId;
  118.  
  119. declare Integer G_CurrentRoundIndex;
  120. declare Integer G_CaptureMaxValue;
  121.  
  122. declare CSmMapLandmark[Integer] G_ClanSpawnAnchors;
  123.  
  124. declare Boolean G_OvertimeActivated;
  125. declare Integer G_OvertimeAdvantage;
  126.  
  127. ***LogVersion***
  128. ***
  129. MB_LogVersion(ScriptName, Version);
  130. MB_LogVersion(SM::GetScriptName(), SM::GetScriptVersion());
  131. MB_LogVersion(Top::GetScriptName(), Top::GetScriptVersion());
  132. MB_LogVersion(Score::GetScriptName(), Score::GetScriptVersion());
  133. MB_LogVersion(Layers::GetScriptName(), Layers::GetScriptVersion());
  134. MB_LogVersion(Victory::GetScriptName(), Victory::GetScriptVersion());
  135. MB_LogVersion(WarmUp2::GetScriptName(), WarmUp2::GetScriptVersion());
  136. MB_LogVersion(Interface::GetScriptName(), Interface::GetScriptVersion());
  137. MB_LogVersion(Tabs::GetScriptName(), Tabs::GetScriptVersion());
  138. MB_LogVersion(SpawnScreen::GetScriptName(), SpawnScreen::GetScriptVersion());
  139. MB_LogVersion(BalancedWeapons::GetScriptName(), BalancedWeapons::GetScriptVersion());
  140. MB_LogVersion(Beginners::GetScriptName(), Beginners::GetScriptVersion());
  141. ***
  142.  
  143. ***LobbyStartServer***
  144. ***
  145. MM_SetFormat([S_NbPlayersPerTeamMax, S_NbPlayersPerTeamMax]);
  146. if (S_NbPlayersPerTeamMax > S_NbPlayersPerTeamMin) {
  147. declare Formats = Integer[][];
  148. for (I, S_NbPlayersPerTeamMin, S_NbPlayersPerTeamMax-1) {
  149. if (I > 0) Formats.add([I, I]);
  150. }
  151. MM_SetProgressiveFormats(Formats);
  152. }
  153. ***
  154.  
  155. ***InitServer***
  156. ***
  157. declare IsRematch = False; ///< Do the players want a rematch ?
  158. declare RematchNb = 0; ///< Number of consecutive rematch
  159. ***
  160.  
  161. ***Reinit***
  162. ***
  163. //MB_UseLogging = True;
  164. ---LoadBeginnersLib---
  165.  
  166. // Set mode options
  167. UseClans = True;
  168. MB_UseSectionRound = True;
  169. MB_UsePlayerClublinks = S_UsePlayerClublinks;
  170.  
  171. // Set UIAll settings
  172. UIManager.UIAll.ScreenIn3dHideScoreSummary=True;
  173. UIManager.UIAll.AltMenuNoCustomScores = True;
  174. UIManager.UIAll.AltMenuNoDefaultScores = True;
  175.  
  176. // Init variables
  177. G_CurrentRoundIndex = 0;
  178.  
  179. // Create various layers for the UI :
  180. // * ScoresTable - the custom scores table
  181. // * Tops - the tops (in a sperate tab)
  182. // * LayerRoundInfo - infos about the game always shown in the UI (e.g. captured poles, capture state, etc.).
  183. // * LayerMarkers - markers above poles
  184. // * TabsLayer - A layer for the tabs and tabs management
  185.  
  186. // /////////
  187. // Tops
  188.  
  189. Top::Load();
  190. declare Real TopXPosition = -76.;
  191. declare Real TopYPosition = 31.;
  192. declare Real TopXOffset = 38.;
  193. declare Integer NbPlayersPerTop = 12;
  194. declare Text TopBGImg = C_ImgBaseDir^"topsBg.dds";
  195. Top::SetTopWidth(37.);
  196. Top::SetDefaultTitle();
  197. Top::Create(C_TopId_Hit, _("Hit"), NbPlayersPerTop, <TopXPosition, TopYPosition>);
  198. TopXPosition += TopXOffset;
  199. Top::Create(C_TopId_Capture, _("Capture"), NbPlayersPerTop, <TopXPosition, TopYPosition>);
  200. TopXPosition += TopXOffset;
  201. Top::Create(C_TopId_Defense, _("Defense"), NbPlayersPerTop, <TopXPosition, TopYPosition>);
  202. TopXPosition += TopXOffset;
  203. Top::Create(C_TopId_Attack, _("|Substantive|Attack"), NbPlayersPerTop, <TopXPosition, TopYPosition>);
  204. TopXPosition += TopXOffset;
  205. Top::Create(C_TopId_Combo, "Combo", NbPlayersPerTop, <TopXPosition, TopYPosition>);
  206. Top::SetCommonBackgroundImage(TopBGImg, <0.05, 95.75>, <207., 175.75>);
  207. Top::SetLayerType(CUILayer::EUILayerType::AltMenu);
  208.  
  209.  
  210. // /////////
  211. // Round info
  212. declare LayerRoundInfo <=> UIManager.UILayerCreate();
  213. G_LayerRoundInfoId = LayerRoundInfo.Id;
  214. // This layer is added at the beginning of each round
  215.  
  216.  
  217. // /////////
  218. // Markers
  219. declare LayerMarkers <=> UIManager.UILayerCreate();
  220. LayerMarkers.Type = CUILayer::EUILayerType::Markers;
  221. UIManager.UIAll.UILayers.add(LayerMarkers);
  222.  
  223. // /////////
  224. // Tabs
  225. Tabs::Load();
  226. /*
  227. declare TabsLayer <=> Tabs::CreateTabPaneLayer(
  228. [
  229. "TopTab" => "Buddies",
  230. "ScoresTab" => "Rankings"
  231. ], 7, -1, False);
  232. */
  233. declare TabsLayer <=> Tabs::CreateTabPaneLayer(
  234. [
  235. "TopTab" => "Buddies",
  236. "ScoresTab" => "Rankings"
  237. ], 29, -5, False);
  238.  
  239. TabsLayer.Type = CUILayer::EUILayerType::AltMenu;
  240. UIManager.UIAll.UILayers.add(TabsLayer);
  241.  
  242. declare CUILayer TimeLeftLayer;
  243. declare Ident G_TimeLeftLayerId;
  244. if(S_BattleWaves) {
  245. TimeLeftLayer <=> UIManager.UILayerCreate();
  246. G_TimeLeftLayerId = TimeLeftLayer.Id;
  247. }
  248.  
  249. CreateRulesReminderLayer();
  250. ***
  251.  
  252. ***StartServer***
  253. ***
  254. WarmUp2::Load();
  255.  
  256. // ---------------------------------- //
  257. // Matchmaking mode
  258. if (MM_IsMatchServer()) {
  259. MM_Init([S_NbPlayersPerTeamMax, S_NbPlayersPerTeamMax]);
  260. }
  261.  
  262. +++Reinit+++
  263. ---ScoresTable---
  264.  
  265. AFK::SetIdleTimeLimit(30000);
  266.  
  267. // ---------------------------------- //
  268. // Create layers
  269. Layers::Create("Top5", GetMLTop5());
  270. Layers::Attach("Top5");
  271. Layers::Hide("Top5");
  272. ***
  273.  
  274. ***ScoresTable***
  275. ***
  276. ST2::SetStyle("LibST_SMBaseTeams");
  277. ST2::SetStyle("LibST_SMBasePoints");
  278. ST2::SetStyle("LibST_SMWithLegends");
  279. ST2::CreateCol("Capture", _("|Capture,Substantive|Cap"), "0", 3., 60.);
  280. ST2::CreateCol("Attack", _("|Attack,Substantive|Atk"), "0", 3., 70.);
  281. ST2::CreateCol("Defense", _("|Defense|Def"), "0", 3., 80.);
  282. ST2::SetColLegend("LibST_SMRoundPoints", _("|Substantive|Hit"));
  283. ST2::SetColLegend("LibST_SMPoints", _("Score"));
  284. MM_SetScoresTableStyleFromXml(S_ScoresTableStylePath);
  285. ST2::GetLayer().Type = CUILayer::EUILayerType::Normal;
  286. ST2::Build("SM");
  287. ***
  288.  
  289.  
  290. ***LoadBeginnersLib***
  291. ***
  292. // TODO : sperate beginners for Battle/waves ?
  293. if(S_BattleWaves) {
  294. Beginners::Load("Nadeo_Battle");
  295. Beginners::CreateWelcomeWindow(TextLib::Compose(_("Welcome to Battle!")), TextLib::Compose(_("Capture the $<$0f0poles$> to win.\nYou cannot capture during $<$0f0defense$> phases."), TextLib::ToText(S_WaveDuration), TextLib::ToText(S_RoundsToWin)));
  296. } else {
  297. Beginners::Load("Nadeo_Battle");
  298. Beginners::CreateWelcomeWindow(TextLib::Compose(_("Welcome to Battle!")), TextLib::Compose(_("Capture the $<$0f0poles$> to win.")));
  299. }
  300. ***
  301.  
  302.  
  303. // ---------------------------------- //
  304. // Match begin
  305. // ---------------------------------- //
  306. ***StartMatch***
  307. ***
  308. // Init libs
  309. Score::MatchBegin(False);
  310. BalancedWeapons::MatchBegin();
  311. Victory::MatchBegin();
  312.  
  313. Mode::Ladder_OpenMatch_All();
  314. G_PolesIndice = Integer[Ident];
  315. +++MatchBegin+++
  316. // Reset clan scores
  317. ClanScores[1] = 0;
  318. ClanScores[2] = 0;
  319. ***
  320.  
  321.  
  322. // ---------------------------------- //
  323. // Map begin
  324. // ---------------------------------- //
  325. ***InitMap***
  326. ***
  327. if (MM_IsMatchServer()) MB_UseIntro = False;
  328. else MB_UseIntro = True;
  329. ***
  330.  
  331. ***StartMap***
  332. ***
  333. MM_SetScores([ClanScores[1], ClanScores[2]]);
  334.  
  335. G_CurrentRoundIndex = 0;
  336. Users_SetNbFakeUsers(C_Battle_BlueBots, C_Battle_RedBots); // add bots for debug purpose
  337.  
  338. ComputeCaptureMaxValue();
  339. ResetMapRunnersRanking();
  340.  
  341. foreach (Score in Scores) {
  342. Score.Clear();
  343.  
  344. declare Integer Battle_ScoreDefenseBonus for Score;
  345. declare Integer Battle_ScoreAttackBonus for Score;
  346. declare Integer Battle_ScoreAlternative for Score;
  347. declare Integer Battle_ScoreHit for Score;
  348. declare Integer Battle_TotalCaptureTime for Score;
  349. declare Integer Battle_TotalDenyTime for Score;
  350. Battle_ScoreDefenseBonus = 0;
  351. Battle_ScoreAttackBonus = 0;
  352. Battle_ScoreAlternative = 0;
  353. Battle_ScoreHit = 0;
  354. Battle_TotalCaptureTime = 0;
  355. Battle_TotalDenyTime = 0;
  356.  
  357. Score.Points = 0;
  358. Score.RoundPoints = 0;
  359. }
  360.  
  361. foreach (Player in AllPlayers) {
  362. declare Integer MapHit for Player = 0;
  363. declare Integer MapCombo for Player = 0;
  364. declare Integer MapCapture for Player = 0;
  365. declare Integer MapDefense for Player = 0;
  366. declare Integer MapAttack for Player = 0;
  367. MapHit = 0;
  368. MapCombo = 0;
  369. MapCapture = 0;
  370. MapDefense = 0;
  371. MapAttack = 0;
  372.  
  373. declare Integer Battle_RoundIndex for Player.Score = -1;
  374. Battle_RoundIndex = 0;
  375.  
  376. declare Integer RoundCombo for Player = 0;
  377. RoundCombo = 0;
  378.  
  379. declare Integer Battle_ScoreCapture for Player;
  380. declare Integer Battle_ScoreDefense for Player;
  381. declare Integer Battle_ScoreAttack for Player;
  382. Battle_ScoreCapture = 0;
  383. Battle_ScoreDefense = 0;
  384. Battle_ScoreAttack = 0;
  385.  
  386. declare Battle_BalanceClan for Player = -1;
  387. Battle_BalanceClan = -1;
  388.  
  389. InitializePlayer(Player, "");
  390. }
  391.  
  392. SpawnScreen::CreateMapInfo();
  393. SpawnScreen::SetModeName("Battle");
  394. SpawnScreen::CreateScores("Score.Points + Score.RoundPoints");
  395. Top::ResetAll();
  396.  
  397. InitWarmUp();
  398.  
  399. // ---------------------------------- //
  400. // Wait players when using matchmaking
  401. // ---------------------------------- //
  402. // Wait players when using matchmaking
  403. if (MM_IsMatchServer()) {
  404. if (!IsRematch) {
  405. MM_MatchWait();
  406. MM_VoteForNextMap(True);
  407. } else {
  408. MM_WaitPlayers(15000);
  409. }
  410. } else if (S_WarmUpDuration > 0 && S_NbPlayersPerTeamMax > 0) {
  411. MB_CurrentSection = "WarmUp";
  412. DoWarmUp();
  413. MB_CurrentSection = "StartMap";
  414. } else {
  415. MB_CurrentSection = "WarmUp";
  416. WaitForPlayers(S_NbPlayersPerTeamMin, S_WarmUpDuration);
  417. MB_CurrentSection = "StartMap";
  418.  
  419. // Team balance
  420. if (S_AutoBalance && !MM_IsMatchmakingServer()) Mode::AutoTeamBalance();
  421. }
  422. IsRematch = False;
  423.  
  424. // ---------------------------------- //
  425. // Matchmaking : allow substitutes
  426. if (MM_IsMatchServer()) MM_AllowSubstitutes(True);
  427. MM_SetScores([ClanScores[1], ClanScores[2]]);
  428.  
  429. // ---------------------------------- //
  430. // Create tops slider
  431. Interface::CreateSlider();
  432. Interface::SetSliderAnimation(<-208., 40.>, <-160., 40.>);
  433. //Interface::AddSlide(C_SlideId_Attack, "Top", _("|Battle Top5 Attack|Top Attack"), C_TopId_Attack);
  434. //Interface::AddSlide(C_SlideId_Defense, "Top", _("|Battle Top5 Defense|Top Defense"), C_TopId_Defense);
  435. Interface::AddSlide(C_SlideId_Combo, "Top", _("|Top5 hits combo|Top Combo"), C_TopId_Combo);
  436. ***
  437.  
  438. // ---------------------------------- //
  439. // Round initalization
  440. // ---------------------------------- //
  441. ***InitRound***
  442. ***
  443. declare Boolean RoundBattleWaves = S_BattleWaves;
  444. declare CaptureOngoing = False;
  445. declare TouchdownUserId = NullId;
  446. declare FinalCaptureUserId = NullId;
  447. declare OvertimeCaptureUserId = NullId;
  448. declare ExtendedTimeRatio = 0.5;
  449. SetOvertime(False);
  450. SetOvertimeAdvantage(-1);
  451.  
  452. declare UpdateLayerScoresTable = False; ///< The scores table UI need an update
  453. declare ClanPoles = [1=>CSmMapLandmark[], 2=>CSmMapLandmark[]];
  454.  
  455. declare MapSidesIndices = [1=>(MB_SectionRoundNb % 2)+1, 2=>2-(MB_SectionRoundNb % 2)];
  456. G_ClanSpawnAnchors = [
  457. 1=>Map::GetLandmarkPlayerSpawn("Spawn", MapSidesIndices[1]),
  458. 2=>Map::GetLandmarkPlayerSpawn("Spawn", MapSidesIndices[2])
  459. ];
  460. declare LastestCapturedGoalId = NullId;
  461. declare FirstClanToStartCapture = 0;
  462. declare LatestUITick = Now;
  463.  
  464. ComputeCaptureMaxValue();
  465.  
  466. G_EngagePoleId = NullId;
  467. for (Clan, 1, 2) {
  468. foreach (Pole in MapLandmarks_Gauge) {
  469. if((Pole.Tag == "Goal") || (Pole.Tag == "Checkpoint")) { // for retro-compatibility
  470. if((Pole.Order == 3) && (G_EngagePoleId == NullId)) { // Engage Pole
  471. G_EngagePoleId = Pole.Id;
  472. Pole.Gauge.Clan = 0;
  473. } else {
  474. if (Pole.Order != MapSidesIndices[Clan]) continue;
  475. ClanPoles[Clan].add(Pole);
  476. Pole.Gauge.Value = 0;
  477. Pole.Gauge.Max = G_CaptureMaxValue;
  478. Pole.Gauge.Clan = 3-Clan;
  479. }
  480. }
  481. }
  482. }
  483. declare Integer NbPolesByClan = ClanPoles[1].count;
  484.  
  485. // ////////////////////////////
  486. // INITIALIZE MARKERS
  487. // build Markers list
  488. declare Text PoleMarkers = "";
  489. foreach(Pole in MapLandmarks_Gauge) {
  490. if (Pole.Tag != "Goal" && Pole.Tag != "Checkpoint") continue;
  491.  
  492. declare Vec3 Pos = Pole.Position + <0., 25., 0.>;
  493. if(Pole.Gauge.Clan == 0) {
  494. Pos.Y = Pole.Position.Y + 5.; // only 5 meters for the engage checkpoint
  495. }
  496. PoleMarkers ^= """<marker pos="{{{Pos.X}}} {{{Pos.Y}}} {{{Pos.Z}}}" manialinkframeid="PoleMarker{{{Pole.Id}}}"/>
  497. """;
  498. }
  499.  
  500. // build Pole indice
  501. for (Clan, 1, 2) {
  502. declare Integer PoleIndex = 0;
  503. foreach (Pole in ClanPoles[Clan])
  504. {
  505. PoleIndex += 1;
  506. G_PolesIndice[Pole.Id] = PoleIndex;
  507. }
  508. }
  509.  
  510. // ////////////////////////////
  511.  
  512. declare NumberOfCapturedPoles = [1 => 0,2 => 0];
  513. declare TotalCaptureValue = [1 => 0,2 => 0];
  514.  
  515. declare Real SqDistanceToScoreNearPole = S_HotSpotsRadius * S_HotSpotsRadius;
  516. declare Real SqDistanceAtkNearPole = S_AtkHotSpotsRadius * S_AtkHotSpotsRadius;
  517.  
  518. declare Boolean DoUpdateScore = True;
  519. declare Boolean[Ident] PoleTakers = Boolean[Ident]; // Emulates a Set (collection of unique elements - the boolean value is never read)
  520. declare Boolean[Ident] PoleDeniers = Boolean[Ident];
  521.  
  522. // for Waves Mode
  523. declare FirstWaveClanAttack = 0;
  524. declare DurationBeforePivot = 0;
  525. declare CurrentAckClan = 0;
  526. declare FirstWaveStartTime = -1;
  527.  
  528. declare WavesDuration = S_WaveDuration; // Waves durations can only be changed between rounds.
  529. declare Boolean AllowBeginners = S_AllowBeginners;
  530. declare Integer NoCollisionsEndTime;
  531. ***
  532.  
  533.  
  534. // ---------------------------------- //
  535. // Round begin
  536. // ---------------------------------- //
  537. ***StartRound***
  538. ***
  539. G_CurrentRoundIndex += 1;
  540.  
  541. UIManager.UIAll.UISequence = CUIConfig::EUISequence::Playing;
  542. UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::Normal;
  543.  
  544. Score::RoundBegin();
  545. BalancedWeapons::RoundBegin();
  546. Victory::RoundBegin();
  547. +++RoundBegin+++
  548.  
  549. SM::SetupDefaultVisibility();
  550.  
  551. // the countdown
  552. //UIManager.UIAll.CountdownCoord.Y = C_CountdownY;
  553. //UIManager.UIAll.CountdownCoord.X = 0.;
  554.  
  555. StartTime = Now + S_RespawnTime;
  556. ---EndTime---
  557.  
  558. // No collisions at the beginning of the round
  559. NoCollisionsEndTime = StartTime + C_NoCollisionsDuration;
  560. UsePvPCollisions = False;
  561.  
  562. UpdateBasesColors();
  563.  
  564. // ---------------------------------- //
  565. // Init capture time records
  566. declare Text EngageLogin for This;
  567. EngageLogin = "";
  568. declare netwrite Integer[Text] Net_RoundTop_CaptureTimeRecords for Teams[0];
  569. declare netwrite Integer Net_RoundTop_CaptureTimeRecordsUpdate for Teams[0];
  570. Net_RoundTop_CaptureTimeRecords.clear();
  571. Net_RoundTop_CaptureTimeRecordsUpdate = Now;
  572. foreach (Score in Scores) {
  573. declare Integer[Ident] RoundTop_CaptureTime for Score;
  574. RoundTop_CaptureTime.clear();
  575.  
  576. declare Integer Battle_ScoreCombo for Score;
  577. Battle_ScoreCombo = 0;
  578. }
  579.  
  580. foreach (Player in AllPlayers) {
  581. declare Integer RoundCombo for Player = 0;
  582. RoundCombo = 0;
  583.  
  584. InitializePlayer(Player, PoleMarkers);
  585. }
  586.  
  587. // ---------------------------------- //
  588. // Update the players clublinks
  589. if (S_ForceClublinkTeam1 == "" && S_ForceClublinkTeam2 == "") Clublink::DefineTeamAuto();
  590. else Clublink::DefineTeamFromUrl(S_ForceClublinkTeam1, S_ForceClublinkTeam2);
  591. Clublink::SyncUpdate();
  592.  
  593. MM_Sleep(1);
  594. CreateRoundInfoUI(LayerRoundInfo, ClanPoles);
  595. UIManager.UIAll.UILayers.add(LayerRoundInfo);
  596.  
  597. // Set markers layer
  598. LayerMarkers.ManialinkPage = CreateMarkersManialinkPage(ClanPoles);
  599. LayerMarkers.IsVisible = True;
  600.  
  601. // Update the rules now, if a change occured in the settings
  602. ---Rules---
  603. SpawnScreen::CreateRules(ModeName, ModeRules);
  604.  
  605.  
  606. // +++UpdateScore+++
  607. ---UpdateTotalCapture---
  608. ---UpdateTeamsScoresUI---
  609.  
  610. if(S_BattleWaves) {
  611. if(TimeLeftLayer == Null) TimeLeftLayer <=> UIManager.UILayerCreate();
  612. TimeLeftLayer.ManialinkPage = BuildTimeLeftManialink(WavesDuration);
  613. UIManager.UIAll.UILayers.add(TimeLeftLayer);
  614. }
  615.  
  616. ST2::SetFooterText(TextLib::Compose("%1 "^S_RoundsToWin, _("Points limit : ")));
  617. ***
  618.  
  619. ***OnNewPlayer***
  620. ***
  621. InitializePlayer(Player, PoleMarkers);
  622. // Show welcome window to beginners
  623. if(S_AllowBeginners) {
  624. Beginners::NotifyNewPlayer(Player);
  625. }
  626. if (Now > StartTime + 10) UpdateLayerScoresTable = True;
  627.  
  628. Interface::ShowSlider(Player, 0);
  629. ***
  630.  
  631. ***OnNewSpectator***
  632. ***
  633. InitializePlayer(Spectator, PoleMarkers);
  634. if (Now > StartTime + 10) UpdateLayerScoresTable = True;
  635.  
  636. Interface::ShowSlider(Spectator, 0);
  637. ***
  638.  
  639. ***Yield***
  640. ***
  641. Top::Loop();
  642. Message::Loop();
  643. Tabs::XmlRpcLoop();
  644. ***
  645.  
  646. // ---------------------------------- //
  647. // Play loop
  648. // ---------------------------------- //
  649. ***PlayLoop***
  650. ***
  651. if(S_BattleWaves != RoundBattleWaves) {
  652. MB_StopMatch = True;
  653. ResetAllUIs();
  654. +++Reinit+++
  655. break;
  656. }
  657.  
  658. if(AllowBeginners != S_AllowBeginners) {
  659. Beginners::ResetPlayers();
  660. MB_StopMatch = True;
  661. }
  662.  
  663. CaptureOngoing = False;
  664. OvertimeCaptureUserId = NullId;
  665.  
  666. // No collisions
  667. if (NoCollisionsEndTime > 0 && NoCollisionsEndTime <= Now) {
  668. NoCollisionsEndTime = -1;
  669. UsePvPCollisions = True;
  670. }
  671.  
  672. // for each players
  673. foreach (Player in Players) {
  674. if (Player.CurrentClan == CurrentAckClan)
  675. if (Player.CurWeapon != 1) SetPlayerWeapon(Player, CSmMode::EWeapon::Laser, False);
  676. if (Player.CurrentClan != CurrentAckClan)
  677. if (Player.CurWeapon != 2 && Player.IsOnTeachWeapon) SetPlayerWeapon(Player, CSmMode::EWeapon::Rocket, True);
  678. }
  679.  
  680. foreach (Event in PendingEvents) {
  681. if (Event.Type == CSmModeEvent::EType::OnHit) {
  682. if (Event.Shooter == Null || Event.Victim == Null || Event.Shooter == Event.Victim) {
  683. Discard(Event);
  684. } else if (UseClans && Event.Shooter.CurrentClan == Event.Victim.CurrentClan) {
  685. Discard(Event);
  686. } else {
  687. if(S_AllowBeginners) {
  688. Event.Damage = Beginners::GetDamage(Event.Shooter, Event.Victim, Event.Damage);
  689. }
  690.  
  691. if (Event.Damage > 0) {
  692. declare CSmPlayer Victim <=> Event.Victim;
  693. declare CSmPlayer Shooter <=> Event.Shooter;
  694.  
  695. if(S_AllowBeginners) Beginners::NotifyHit(Shooter);
  696. declare Boolean GivePoints = (!S_AllowBeginners) || Beginners::ShouldGivePoints(Shooter, Victim);
  697. if(! GivePoints) {
  698. Event.ShooterPoints = 0;
  699. XmlRpc::OnHit(Event);
  700. PassOn(Event);
  701. continue;
  702. }
  703.  
  704.  
  705. // declare Boolean GiveExraPointsForDefenseActions = True;
  706. declare Integer PointsGivenToTheShooter = 1;
  707. declare Integer Battle_ScoreHit for Shooter.Score;
  708. declare CustomScorePlayer <=> Shooter;
  709. ---OnHit---
  710. // Score::AddPoints(Shooter, PointsGivenToTheShooter);
  711.  
  712. declare Integer Battle_ScoreDefenseBonus for Shooter.Score;
  713. declare Integer Battle_ScoreAttackBonus for Shooter.Score;
  714.  
  715. Battle_ScoreHit += PointsGivenToTheShooter;
  716.  
  717. // Combo
  718. declare Integer Battle_ScoreCombo as ComboShooter for Shooter.Score;
  719. declare Integer Battle_ScoreCombo as ComboVictim for Victim.Score;
  720. declare Integer MapCombo for Shooter;
  721. declare Integer RoundCombo for Shooter;
  722. ComboShooter += 1;
  723. ComboVictim = 0;
  724. if (ComboShooter > MapCombo) MapCombo = ComboShooter;
  725. if (ComboShooter > RoundCombo) RoundCombo = ComboShooter;
  726.  
  727. declare Boolean BonusGranted = False;
  728. // 1. Check if the victim is currently taking a pole
  729. if( Victim.CapturedLandmark != Null && Victim.CapturedLandmark.Gauge != Null) {
  730. declare CSmMapLandmark Pole <=> Victim.CapturedLandmark;
  731. declare Boolean IsPoleActive = ! Pole.Gauge.Captured;
  732. ---IsPoleActive---
  733. if((IsPoleActive) && (Victim.CapturedLandmark.Gauge.Clan == Victim.CurrentClan)) {
  734. // Defensive move : the victim has been shot while taking a pole
  735. Battle_ScoreDefenseBonus += S_ScoreDefense_HitOnPole;
  736. BonusGranted = True;
  737. }
  738. }
  739.  
  740. // 2. Check if the victim or the shooter is in a hot spot
  741. if (! BonusGranted) {
  742. foreach(Pole in MapLandmarks_Gauge) {
  743. if (Pole.Tag != "Goal" && Pole.Tag != "Checkpoint") continue;
  744.  
  745. declare Boolean IsPoleActive = ! Pole.Gauge.Captured;
  746.  
  747. ---IsPoleActive---
  748. if(IsPoleActive) {
  749. declare Boolean ShooterInDefHotSpot = SqCloserThan(Pole.Position, Shooter.Position, SqDistanceToScoreNearPole);
  750. declare Boolean VictimInDefHotSpot = SqCloserThan(Pole.Position, Victim.Position , SqDistanceToScoreNearPole);
  751. if(ShooterInDefHotSpot || VictimInDefHotSpot) {
  752. if(Pole.Gauge.Clan == 3-Shooter.CurrentClan) {
  753. // Defensive Move : the shooter is close to a pole of his/her clan
  754. Battle_ScoreDefenseBonus += S_ScoreDefense_HitNearPole;
  755. declare CustomScorePlayer <=> Shooter;
  756. BonusGranted = True;
  757. break;
  758. }
  759. }
  760.  
  761. declare Boolean ShooterInAtkHotSpot = SqCloserThan(Pole.Position, Shooter.Position, SqDistanceAtkNearPole);
  762. declare Boolean VictimInAtkHotSpot = SqCloserThan(Pole.Position, Victim.Position , SqDistanceAtkNearPole);
  763. if(ShooterInAtkHotSpot || VictimInAtkHotSpot) {
  764. if(Pole.Gauge.Clan == Shooter.CurrentClan) {
  765. // Offensive Move : the victim is close to a pole of his/her clan
  766. Battle_ScoreAttackBonus += S_ScoreAttack_HitNearPole;
  767. declare CustomScorePlayer <=> Shooter;
  768. BonusGranted = True;
  769. break;
  770. }
  771. }
  772. }
  773. }
  774.  
  775. if (! BonusGranted) {
  776. // 1 "classic" hit => Attack Points
  777. Battle_ScoreAttackBonus += S_ScoreAttack_ClassicHit;
  778. }
  779. }
  780.  
  781. // Gladiator mode
  782. if (S_GladiatorMode) {
  783. if (Event.Shooter.Armor < Event.Shooter.ArmorMax) {
  784. Event.Shooter.Armor += 100;
  785. if (Event.Shooter.Armor > Event.Shooter.ArmorMax) {
  786. Event.Shooter.Armor = Event.Shooter.ArmorMax;
  787. }
  788. }
  789. }
  790.  
  791. +++SetCustomScoreHit+++
  792. }
  793. XmlRpc::OnHit(Event);
  794. PassOn(Event);
  795. }
  796. } else if (Event.Type == CSmModeEvent::EType::OnArmorEmpty) {
  797. BalancedWeapons::OnOut(Event.Shooter, Event.Victim);
  798. XmlRpc::OnArmorEmpty(Event);
  799. Interface::ShowSlider(Event.Victim, 0);
  800. PassOn(Event);
  801. } else if (Event.Type == CSmModeEvent::EType::OnCapture) {
  802. if (Event.Landmark.Tag == "Goal") {
  803. UpdateBasesColors();
  804. LastestCapturedGoalId = Event.Landmark.Id;
  805. XmlRpc::OnCapture(Event);
  806.  
  807. // Get last capturer user id
  808. foreach(PlayerId in Event.Landmark.Sector.PlayersIds) {
  809. if (!Players.existskey(PlayerId)) continue;
  810. declare Player <=> Players[PlayerId];
  811. if (Player.CurrentClan != Event.Landmark.Gauge.Clan) continue;
  812. FinalCaptureUserId = Player.User.Id;
  813. break;
  814. }
  815. }
  816.  
  817. PassOn(Event);
  818. } else if (Event.Type == CSmModeEvent::EType::OnPlayerRequestRespawn) {
  819. Interface::ShowSlider(Event.Player, 0);
  820. PassOn(Event);
  821. } else {
  822. PassOn(Event);
  823. }
  824. }
  825.  
  826. if(S_BattleWaves) {
  827. // Update atk countdown and switch atk side when it reaches 0
  828. if (FirstWaveClanAttack != 0) {
  829. DurationBeforePivot -= Period;
  830. if (DurationBeforePivot <= 0) {
  831. CurrentAckClan = 3-CurrentAckClan;
  832. DurationBeforePivot = WavesDuration * 1000; // redemarre la jauge.;
  833. UIManager.UIAll.SendNotice("", CUIConfig::ENoticeLevel::PlayerInfo, Null, CUIConfig::EAvatarVariant::Default,
  834. CUIConfig::EUISound::PhaseChange, 0);
  835. // G_UpdateMarkers = True;
  836. }
  837. }
  838.  
  839. // Check engagement pole
  840. if(G_EngagePoleId != NullId && (CurrentAckClan==0)) {
  841. declare CSmMapLandmark EngagePole <=> MapLandmarks_Gauge[G_EngagePoleId];
  842. if(EngagePole != Null && ! EngagePole.Gauge.Captured) {
  843. declare EngageClan = -1;
  844. declare EngageName = "";
  845. declare Text EngageLogin for This;
  846. foreach(PlayerId in EngagePole.Sector.PlayersIds) {
  847. if (!Players.existskey(PlayerId)) continue;
  848. declare Player <=> Players[PlayerId];
  849. declare PlayerClan = Player.CurrentClan;
  850. if (EngageClan < 0) {
  851. EngageClan = PlayerClan;
  852. EngageName = Player.User.Name;
  853. EngageLogin = Player.User.Login;
  854. } else if (EngageClan != PlayerClan) {
  855. // 2 diff clans on the pole : no capture
  856. EngageClan = -1;
  857. EngageName = "";
  858. EngageLogin = "";
  859. break;
  860. }
  861. }
  862.  
  863. if (EngageClan > 0) {
  864. EngagePole.Gauge.Max = 1;
  865. EngagePole.Gauge.Value = 1;
  866. EngagePole.Gauge.Captured = True;
  867. EngagePole.Gauge.Clan = 0;
  868.  
  869. FirstClanToStartCapture = EngageClan;
  870. CurrentAckClan = EngageClan;
  871. FirstWaveClanAttack = EngageClan;
  872.  
  873. FirstWaveStartTime = Now;
  874. EndTime = Now + S_TimeLimitAfterFirstCapture*1000;
  875. DurationBeforePivot = WavesDuration * 1000;
  876.  
  877. //G_UpdateMarkers = True;
  878. UIManager.UIAll.SendNotice("", CUIConfig::ENoticeLevel::PlayerInfo, Null, CUIConfig::EAvatarVariant::Default,
  879. CUIConfig::EUISound::PhaseChange, 0);
  880.  
  881. if (EngageName != "") Message::SendBigMessage(TL::Compose(_("$<%1$> captured the pole."), EngageName), 3000, 1);
  882.  
  883. foreach(PlayerId in EngagePole.Sector.PlayersIds) {
  884. if (!Players.existskey(PlayerId)) continue;
  885. declare Player <=> Players[PlayerId];
  886. declare Integer Battle_ScoreAttackBonus for Player.Score;
  887. Battle_ScoreAttackBonus += S_PointsOnEngage;
  888. PoleTakers[PlayerId] = True;
  889. DoUpdateScore = True;
  890. }
  891. }
  892. }
  893. }
  894. }
  895.  
  896. // Spawning players
  897. foreach (Player in Players) {
  898. if (Player.SpawnStatus == CSmPlayer::ESpawnStatus::NotSpawned && !Player.User.RequestsSpectate) {
  899. // Skip invalid player in matchmaking
  900. if (MM_IsMatchServer() && !MM_PlayerIsValid(Player)) continue;
  901.  
  902. // Set player clan
  903. SetPlayerClan(Player, Battle_GetRequestedClan(Player));
  904. if (SpawnIsLimited()) {
  905. WarmUp2::Clean();
  906. if (Player.CurrentClan == 1) WarmUp2::SetPlayerGroup(Player, "Clan1");
  907. else if (Player.CurrentClan == 2) WarmUp2::SetPlayerGroup(Player, "Clan2");
  908. WarmUp2::Fill();
  909. }
  910. if (!IsSpawnable(Player)) continue;
  911.  
  912. //declare Integer ClublinkClan for Player;
  913. //if (ClublinkClan == 0) continue;
  914. BalancedWeapons::SetPlayerWeapon(Player, True);
  915.  
  916. Player.ArmorMax = 200;
  917. declare Integer BaseArmor = 200;
  918. if(S_AllowBeginners) {
  919. Beginners::UpdateBeginnerStatus(Player);
  920.  
  921. declare CUIConfig PlayerUI <=> UIManager.GetUI(Player);
  922. if(PlayerUI != Null) {
  923. declare netwrite Boolean Battle_IsBeginner for PlayerUI;
  924. Battle_IsBeginner = Beginners::IsBeginner(Player);
  925. }
  926. }
  927. // 1. get the difference between beginners and regular players
  928. declare Integer BeginnerExtraArmor = (Player.ArmorMax - BaseArmor) / 100;
  929. if(BeginnerExtraArmor <= 0) BeginnerExtraArmor = 0;
  930.  
  931. // 2. get the armor setting in correct boundaries
  932. declare Integer ArmorSetting = S_ArmorPoints;
  933. if(ArmorSetting <= 0) ArmorSetting = 1;
  934. else if (ArmorSetting > 9) ArmorSetting = 9;
  935.  
  936. // 3. compute armor for beginners-or-not
  937. declare Integer TotalArmorFactor = ArmorSetting + BeginnerExtraArmor;
  938. if(TotalArmorFactor > 9) TotalArmorFactor = 9;
  939.  
  940. // 4. set it
  941. declare Integer TotalArmor = 100 * TotalArmorFactor;
  942. Player.ArmorMax = TotalArmor;
  943. Player.Armor = TotalArmor;
  944.  
  945. // Reset combo
  946. declare Integer Battle_ScoreCombo for Player.Score;
  947. Battle_ScoreCombo = 0;
  948.  
  949. // Reset touched poles
  950. declare Ident[] RoundTop_TouchedPoles for Player;
  951. RoundTop_TouchedPoles.clear();
  952.  
  953. //If the player is in the clan who attack, apply a attackweapon
  954. if (Player.CurrentClan == CurrentAckClan)
  955. { SetPlayerWeapon(Player, CSmMode::EWeapon::Laser, False); Player.AmmoGain = 1.20; }
  956. else { SetPlayerWeapon(Player, CSmMode::EWeapon::Rocket, True); Player.AmmoGain = 1.; }
  957.  
  958. SM::SpawnPlayer(Player, Player.CurrentClan, G_ClanSpawnAnchors[Player.CurrentClan].PlayerSpawn, Now + S_RespawnTime);
  959.  
  960. Interface::HideSlider(Player, 5000);
  961.  
  962. if(S_AllowBeginners) {
  963. Beginners::HighlightPlayer(Player);
  964. }
  965.  
  966. declare AutoBalance_ReloadSpeedBonus for Player.User = 1.;
  967. Player.AmmoGain = AutoBalance_ReloadSpeedBonus;
  968. }
  969. }
  970.  
  971.  
  972. // Capturing points
  973. // set default state to neutral
  974. foreach (Player in Players) {
  975. declare UI <=> UIManager.GetUI(Player);
  976. if (UI != Null) {
  977. declare netwrite Integer Battle_PoleCaptureState for UI;
  978. Battle_PoleCaptureState = C_PoleCaptureState_Neutral;
  979. }
  980. }
  981.  
  982. // check if a pole is beeing captured
  983. for (Clan, 1, 2) {
  984. // ---ContinueToSkipClan---
  985. declare Integer PoleIndex = -1;
  986. declare PolesOfClan = ClanPoles[Clan];
  987. foreach (Pole in PolesOfClan) {
  988. PoleIndex += 1;
  989.  
  990. // This section is useful only if you want to give points to pole denial.
  991. declare IsGoalThreatened = False; // Is an attacker on the pole ?
  992. foreach (PlayerId in Pole.Sector.PlayersIds) {
  993. if (!Players.existskey(PlayerId)) continue;
  994. declare Player <=> Players[PlayerId];
  995. if (Player.CurrentClan != Clan) {
  996. IsGoalThreatened = True;
  997. break;
  998. }
  999. }
  1000. if(!IsGoalThreatened) {
  1001. Pole.Gauge.Speed = 0;
  1002. continue;
  1003. }
  1004.  
  1005. declare IsGoalDenied = False;
  1006. foreach (PlayerId in Pole.Sector.PlayersIds) {
  1007. if (!Players.existskey(PlayerId)) continue;
  1008. declare Player <=> Players[PlayerId];
  1009. if (Player.CurrentClan == Clan) { // GoalClan
  1010. IsGoalDenied = True;
  1011. // Was
  1012. //break;
  1013. PoleDeniers[PlayerId] = True;
  1014. declare Integer Battle_TotalDenyTime for Player.Score;
  1015. Battle_TotalDenyTime += Period;
  1016. DoUpdateScore = True; // fuu
  1017. }
  1018. }
  1019.  
  1020. // Capture time record
  1021. if (S_DisplayPoleRecords && Pole.Sector.PlayersIds.count > 0) {
  1022. foreach (PlayerId in Pole.Sector.PlayersIds) {
  1023. if (!Players.existskey(PlayerId)) continue;
  1024. declare Player <=> Players[PlayerId];
  1025.  
  1026. // We can only touch the poles of the opponent
  1027. if (Player.CurrentClan == Clan) continue;
  1028.  
  1029. declare Ident[] RoundTop_TouchedPoles for Player;
  1030. if (RoundTop_TouchedPoles.exists(Pole.Id)) continue;
  1031. RoundTop_TouchedPoles.add(Pole.Id);
  1032.  
  1033. // Personnal best
  1034. declare Integer[Ident] RoundTop_CaptureTime for Player.Score;
  1035. declare CaptureTime = Now - Player.StartTime;
  1036. if (RoundTop_CaptureTime.existskey(Pole.Id)) {
  1037. if (CaptureTime < RoundTop_CaptureTime[Pole.Id]) {
  1038. RoundTop_CaptureTime[Pole.Id] = CaptureTime;
  1039. SendCaptureTime(Player);
  1040. }
  1041. } else {
  1042. RoundTop_CaptureTime[Pole.Id] = CaptureTime;
  1043. SendCaptureTime(Player);
  1044. }
  1045.  
  1046. // Round best
  1047. declare netwrite Integer[Text] Net_RoundTop_CaptureTimeRecords for Teams[0];
  1048. declare netwrite Integer Net_RoundTop_CaptureTimeRecordsUpdate for Teams[0];
  1049. if (Net_RoundTop_CaptureTimeRecords.existskey(""^Pole.Id)) {
  1050. if (CaptureTime < Net_RoundTop_CaptureTimeRecords[""^Pole.Id]) {
  1051. Net_RoundTop_CaptureTimeRecords[""^Pole.Id] = CaptureTime;
  1052. Net_RoundTop_CaptureTimeRecordsUpdate = Now;
  1053. }
  1054. } else {
  1055. Net_RoundTop_CaptureTimeRecords[""^Pole.Id] = CaptureTime;
  1056. Net_RoundTop_CaptureTimeRecordsUpdate = Now;
  1057. }
  1058. }
  1059. }
  1060.  
  1061. ---IsCapturePossible---
  1062. if (IsCapturePossible && (Pole.Sector.PlayersIds.count > 0)) {
  1063. declare Integer PoleGlobalIndex = ((Clan-1)*NbPolesByClan) + PoleIndex;
  1064.  
  1065. declare NumberOfPlayerCapturing = 0;
  1066. foreach (PlayerId in Pole.Sector.PlayersIds) {
  1067. if (!Players.existskey(PlayerId)) continue;
  1068. declare Player <=> Players[PlayerId];
  1069. if (Player.CurrentClan == Clan) continue; // Opponent team only
  1070.  
  1071. declare UI <=> UIManager.GetUI(Player);
  1072. NumberOfPlayerCapturing += 1;
  1073. OvertimeCaptureUserId = Player.User.Id;
  1074. if (FirstClanToStartCapture == 0) {
  1075. FirstClanToStartCapture = Player.CurrentClan;
  1076. if(S_BattleWaves) {
  1077. if(G_EngagePoleId == NullId) {
  1078. CurrentAckClan = Player.CurrentClan;
  1079. declare Integer Battle_ScoreAttackBonus for Player.Score;
  1080. Battle_ScoreAttackBonus += S_PointsOnEngage;
  1081. // it is ok to give points only to this player.
  1082. // the case where more than 1 player take the pole at the same time is unlikely and invisible.
  1083. // it is just bad luck for the other guys...
  1084. }
  1085. }
  1086. }
  1087.  
  1088. PoleTakers[PlayerId] = True;
  1089.  
  1090. if (Pole.Gauge.Value < G_CaptureMaxValue) {
  1091. declare Integer Battle_TotalCaptureTime for Player.Score;
  1092. Battle_TotalCaptureTime += Period;
  1093.  
  1094. if (UI != Null) {
  1095. declare netwrite Integer Battle_PoleCaptureState for UI;
  1096. declare netwrite Integer Battle_PoleCaptureRate for UI;
  1097.  
  1098. Battle_PoleCaptureState = C_PoleCaptureState_Capturing;
  1099. Battle_PoleCaptureRate = (100 * Pole.Gauge.Value) / G_CaptureMaxValue;
  1100. }
  1101. } else {
  1102. if (UI != Null) {
  1103. declare netwrite Integer Battle_PoleCaptureState for UI;
  1104. Battle_PoleCaptureState = C_PoleCaptureState_Captured;
  1105. }
  1106. }
  1107. }
  1108.  
  1109. +++Capturing+++
  1110. Pole.Gauge.Speed = NumberOfPlayerCapturing;
  1111.  
  1112.  
  1113. if (NumberOfPlayerCapturing > 0) {
  1114. DoUpdateScore = True;
  1115.  
  1116. if (!Pole.Gauge.Captured) {
  1117. CaptureOngoing = True;
  1118. }
  1119. }
  1120.  
  1121. } else {
  1122. Pole.Gauge.Speed = 0;
  1123. ---OnCaptureDenied---
  1124. }
  1125. }
  1126. }
  1127.  
  1128. // Overtime, disadvantaged clan touch an active pole, stop countdown decrease
  1129. if (GetOvertimeAdvantage() != CurrentAckClan) {
  1130. if (CaptureOngoing) {
  1131. DurationBeforePivot += Period;
  1132. }
  1133. }
  1134.  
  1135. if (Now >= EndTime) DoUpdateScore = True;
  1136.  
  1137. // Update UI
  1138. if (Now > LatestUITick + UITickPeriod)
  1139. {
  1140. LatestUITick = Now;
  1141.  
  1142. // Clublink::DefineTeamAuto();
  1143. ---UpdateTeamsScoresUI---
  1144.  
  1145. foreach (Player in Players) {
  1146. declare UI <=> UIManager.GetUI(Player);
  1147. if (UI==Null) continue;
  1148. +++UIPlayer+++
  1149. }
  1150.  
  1151. foreach (Spectator in Spectators) {
  1152. declare UI <=> UIManager.GetUI(Spectator);
  1153. if (UI==Null) continue;
  1154. declare netwrite Integer Battle_PoleCaptureState for UI;
  1155. Battle_PoleCaptureState = C_PoleCaptureState_Neutral;
  1156. }
  1157.  
  1158. +++UIAll+++
  1159.  
  1160. if (DoUpdateScore) {
  1161. DoUpdateScore = False;
  1162. ---UpdateTotalCapture---
  1163.  
  1164. foreach(PlayerId => PoleTaken in PoleTakers) {
  1165. if(! Players.existskey(PlayerId)) continue;
  1166. declare CustomScorePlayer <=> Players[PlayerId];
  1167. +++SetCustomScorePole+++
  1168. }
  1169. PoleTakers.clear();
  1170. foreach(PlayerId => PoleDenied in PoleDeniers) {
  1171. if(! Players.existskey(PlayerId)) continue;
  1172. declare CustomScorePlayer <=> Players[PlayerId];
  1173. +++SetCustomScoreDefenseAction+++
  1174. }
  1175. PoleDeniers.clear();
  1176. }
  1177. }
  1178.  
  1179. // Update the status message
  1180. UpdateModeStatusMessage();
  1181.  
  1182. // Stop match if there's not enough players left in matchmaking
  1183. if (MM_IsMatchServer()) {
  1184. if (MM_RestartMatchmaking || ClansNbPlayers[1] <= 0 || ClansNbPlayers[2] <= 0) {
  1185. MB_StopMatch = True;
  1186. }
  1187. }
  1188. ***
  1189.  
  1190.  
  1191. ***IsPoleActive***
  1192. ***
  1193. if(S_BattleWaves) {
  1194. IsPoleActive = IsPoleActive
  1195. && (Pole.Gauge.Clan > 0)
  1196. && (Pole.Gauge.Clan == CurrentAckClan);
  1197. }
  1198. ***
  1199.  
  1200. ***Capturing***
  1201. ***
  1202. if(S_BattleWaves) {
  1203. // is this parameter is set to false, attack phase is not reset when an attacker captures a pole
  1204. if (NumberOfPlayerCapturing > 0) {
  1205. if(S_StayInAttackOnCapture) {
  1206. if((Pole.Gauge.Value < G_CaptureMaxValue) || S_ResetTimeOnCapturedPole) {
  1207. // Add def points for a "just in time" capture
  1208. if((DurationBeforePivot > 0) && (DurationBeforePivot <= C_JustInTimeLimit)) {
  1209. foreach (PlayerId in Pole.Sector.PlayersIds) {
  1210. if (!Players.existskey(PlayerId)) continue;
  1211. declare CustomScorePlayer <=> Players[PlayerId];
  1212. if (CustomScorePlayer.CurrentClan == Clan) continue; // Opponent team only
  1213. else {
  1214. declare Integer Battle_ScoreDefenseBonus for CustomScorePlayer.Score;
  1215. Battle_ScoreDefenseBonus += S_ScoreDefense_CaptureJiT;
  1216. +++SetCustomScoreDefenseAction+++
  1217. }
  1218. }
  1219. }
  1220.  
  1221. if (!GetOvertime()) {
  1222. // Display the name of the player who did the pivot
  1223. if (DurationBeforePivot <= (WavesDuration * 1000) / 5) {
  1224. foreach (PlayerId in Pole.Sector.PlayersIds) {
  1225. if (!Players.existskey(PlayerId)) continue;
  1226. declare Player <=> Players[PlayerId];
  1227. if (Player.CurrentClan != Clan) {
  1228. declare TimeSplit = TL::Split(".", TL::ToText(DurationBeforePivot / 1000.));
  1229. declare Time = "0";
  1230. if (TimeSplit.existskey(0)) Time = TimeSplit[0];
  1231. if (TimeSplit.existskey(1)) Time ^= "."^TL::SubText(TimeSplit[1], 0, 1);
  1232. declare Message = TL::Compose(_("|Battle: 1=Player name, 2=Time in seconds|$<%1$> restarts attack countdown (%2s)"), Player.Name, Time);
  1233. Message::SendBigMessage(Message, 3000, 1);
  1234. break;
  1235. }
  1236.  
  1237. }
  1238. }
  1239. DurationBeforePivot = WavesDuration * 1000; //< Reset the atk countdown
  1240. }
  1241. }
  1242. }
  1243.  
  1244. if (FirstWaveStartTime == -1) {
  1245. FirstWaveStartTime = Now;
  1246. FirstWaveClanAttack = 3-Clan;
  1247. EndTime = Now + S_TimeLimitAfterFirstCapture*1000;
  1248. }
  1249. }
  1250. }
  1251. ***
  1252.  
  1253. ***SetCustomScorePole***
  1254. ***
  1255. if(True) // Create a context
  1256. {
  1257. UpdatePlayerScore(CustomScorePlayer, G_CaptureMaxValue);
  1258.  
  1259. declare Integer Battle_ScoreCapture for CustomScorePlayer;
  1260. declare Integer Battle_ScoreAttack for CustomScorePlayer;
  1261.  
  1262. ST2::SetColValue("Attack", CustomScorePlayer.Score, TextLib::ToText(Battle_ScoreAttack));
  1263. ST2::SetColValue("Capture", CustomScorePlayer.Score, TextLib::ToText(Battle_ScoreCapture));
  1264.  
  1265. // update tops
  1266. declare Integer MapCapture for CustomScorePlayer = 0;
  1267. declare Integer MapAttack for CustomScorePlayer = 0;
  1268.  
  1269. Top::SetRecord(CustomScorePlayer, C_TopId_Capture , ""^(MapCapture + Battle_ScoreCapture) , -(MapCapture + Battle_ScoreCapture));
  1270. Top::SetRecord(CustomScorePlayer, C_TopId_Attack , ""^(MapAttack + Battle_ScoreAttack) , -(MapAttack + Battle_ScoreAttack));
  1271. }
  1272. ***
  1273.  
  1274. ***SetCustomScoreHit***
  1275. ***
  1276. if(True) // Create a context
  1277. {
  1278. UpdatePlayerScore(CustomScorePlayer, G_CaptureMaxValue);
  1279.  
  1280. declare Integer Battle_ScoreDefense for CustomScorePlayer;
  1281. declare Integer Battle_ScoreAttack for CustomScorePlayer;
  1282. declare Integer Battle_ScoreHit for CustomScorePlayer.Score;
  1283.  
  1284. ST2::SetColValue("Attack", CustomScorePlayer.Score, TextLib::ToText(Battle_ScoreAttack));
  1285. ST2::SetColValue("Defense", CustomScorePlayer.Score, TextLib::ToText(Battle_ScoreDefense));
  1286.  
  1287. // update tops
  1288. declare Integer MapHit for CustomScorePlayer = 0;
  1289. declare Integer MapCombo for CustomScorePlayer = 0;
  1290. declare Integer MapDefense for CustomScorePlayer = 0;
  1291. declare Integer MapAttack for CustomScorePlayer = 0;
  1292.  
  1293. declare Integer RoundCombo for CustomScorePlayer = 0;
  1294.  
  1295. Top::SetRecord(CustomScorePlayer, C_TopId_Hit , ""^(MapHit + Battle_ScoreHit) , -(MapHit + Battle_ScoreHit));
  1296. Top::SetRecord(CustomScorePlayer, C_TopId_Combo , ""^(RoundCombo) , -RoundCombo);
  1297. Top::SetRecord(CustomScorePlayer, C_TopId_Defense , ""^(MapDefense + Battle_ScoreDefense) , -(MapDefense + Battle_ScoreDefense));
  1298. Top::SetRecord(CustomScorePlayer, C_TopId_Attack , ""^(MapAttack + Battle_ScoreAttack) , -(MapAttack + Battle_ScoreAttack));
  1299. }
  1300. ***
  1301.  
  1302. ***SetCustomScoreDefenseAction***
  1303. ***
  1304. if(True) // Create a context
  1305. {
  1306. UpdatePlayerScore(CustomScorePlayer, G_CaptureMaxValue);
  1307.  
  1308. declare Integer Battle_ScoreDefense for CustomScorePlayer;
  1309. ST2::SetColValue("Defense", CustomScorePlayer.Score, TextLib::ToText(Battle_ScoreDefense));
  1310.  
  1311. // update tops
  1312. declare Integer MapDefense for CustomScorePlayer = 0;
  1313. Top::SetRecord(CustomScorePlayer, C_TopId_Defense , ""^(MapDefense + Battle_ScoreDefense) , -(MapDefense + Battle_ScoreDefense));
  1314. }
  1315. ***
  1316.  
  1317. ***SetCustomScoreAll***
  1318. ***
  1319. if(True) // Create a context
  1320. {
  1321. UpdatePlayerScore(CustomScorePlayer, G_CaptureMaxValue);
  1322.  
  1323. declare Integer Battle_ScoreCapture for CustomScorePlayer;
  1324. declare Integer Battle_ScoreDefense for CustomScorePlayer;
  1325. declare Integer Battle_ScoreAttack for CustomScorePlayer;
  1326. declare Integer Battle_ScoreHit for CustomScorePlayer.Score;
  1327. ST2::SetColValue("Capture", CustomScorePlayer.Score, TextLib::ToText(Battle_ScoreCapture));
  1328. ST2::SetColValue("Attack", CustomScorePlayer.Score, TextLib::ToText(Battle_ScoreAttack));
  1329. ST2::SetColValue("Defense", CustomScorePlayer.Score, TextLib::ToText(Battle_ScoreDefense));
  1330.  
  1331. // update tops
  1332. declare Integer MapHit for CustomScorePlayer = 0;
  1333. declare Integer MapCombo for CustomScorePlayer = 0;
  1334. declare Integer MapCapture for CustomScorePlayer = 0;
  1335. declare Integer MapDefense for CustomScorePlayer = 0;
  1336. declare Integer MapAttack for CustomScorePlayer = 0;
  1337.  
  1338. declare Integer RoundCombo for CustomScorePlayer = 0;
  1339.  
  1340. Top::SetRecord(CustomScorePlayer, C_TopId_Hit , ""^(MapHit + Battle_ScoreHit) , -(MapHit + Battle_ScoreHit));
  1341. Top::SetRecord(CustomScorePlayer, C_TopId_Combo , ""^(RoundCombo) , -(RoundCombo));
  1342. Top::SetRecord(CustomScorePlayer, C_TopId_Capture , ""^(MapCapture + Battle_ScoreCapture) , -(MapCapture + Battle_ScoreCapture));
  1343. Top::SetRecord(CustomScorePlayer, C_TopId_Defense , ""^(MapDefense + Battle_ScoreDefense) , -(MapDefense + Battle_ScoreDefense));
  1344. Top::SetRecord(CustomScorePlayer, C_TopId_Attack , ""^(MapAttack + Battle_ScoreAttack) , -(MapAttack + Battle_ScoreAttack));
  1345.  
  1346. }
  1347. ***
  1348.  
  1349. ***OnCaptureDenied***
  1350. ***
  1351. if(S_BattleWaves) {
  1352. declare Integer PoleClan = Pole.Gauge.Clan;
  1353. foreach (PlayerId in Pole.Sector.PlayersIds) {
  1354. if (!Players.existskey(PlayerId)) continue;
  1355. declare Player <=> Players[PlayerId];
  1356. declare UI <=> UIManager.GetUI(Player);
  1357. if (UI != Null) {
  1358. declare Integer PlayerClan = Player.CurrentClan;
  1359. declare netwrite Integer Battle_PoleCaptureState for UI;
  1360.  
  1361. declare Integer OldState = Battle_PoleCaptureState;
  1362.  
  1363. if(PoleClan == PlayerClan) { // A pole current player must capture
  1364. if (Pole.Gauge.Value < G_CaptureMaxValue) { // not captured yet
  1365. if((PlayerClan != CurrentAckClan) || (CurrentAckClan==0)) { // pole locked if player is not attacking
  1366. Battle_PoleCaptureState = C_PoleCaptureState_Locked;
  1367. } else {
  1368. Battle_PoleCaptureState = C_PoleCaptureState_Denied;
  1369. }
  1370. } else { // already captured
  1371. Battle_PoleCaptureState = C_PoleCaptureState_Captured;
  1372. }
  1373. } else { // A pole current player must defend
  1374. if (Pole.Gauge.Value < G_CaptureMaxValue) { // pole protected
  1375. Battle_PoleCaptureState = C_PoleCaptureState_Protected;
  1376. } else { // already captured
  1377. Battle_PoleCaptureState = C_PoleCaptureState_Neutral;
  1378. }
  1379. }
  1380. }
  1381. }
  1382. } else {
  1383. declare Integer PoleClan = Pole.Gauge.Clan;
  1384. foreach (PlayerId in Pole.Sector.PlayersIds) {
  1385. if (!Players.existskey(PlayerId)) continue;
  1386. declare Player <=> Players[PlayerId];
  1387.  
  1388. declare UI <=> UIManager.GetUI(Player);
  1389. if (UI != Null) {
  1390. declare netwrite Integer Battle_PoleCaptureState for UI;
  1391. if (Pole.Gauge.Value < G_CaptureMaxValue) {
  1392. if(Player.CurrentClan == PoleClan) {
  1393. Battle_PoleCaptureState = C_PoleCaptureState_Denied;
  1394. } else {
  1395. Battle_PoleCaptureState = C_PoleCaptureState_Protected;
  1396. }
  1397. } else if(PoleClan == Player.CurrentClan) {
  1398. Battle_PoleCaptureState = C_PoleCaptureState_Captured;
  1399. } else {
  1400. //Battle_PoleCaptureState = C_PoleCaptureState_Lost;
  1401. Battle_PoleCaptureState = C_PoleCaptureState_Neutral;
  1402. }
  1403. }
  1404. }
  1405. }
  1406. ***
  1407.  
  1408. // ---------------------------------- //
  1409. // Round end
  1410. // ---------------------------------- //
  1411. ***EndRound***
  1412. ***
  1413. Message::CleanAllMessages();
  1414.  
  1415. foreach(Player in Players) {
  1416. if(Player.Score == Null) continue;
  1417.  
  1418. declare Integer Battle_ScoreHit for Player.Score;
  1419. declare Real AutoBalance_ReloadSpeedBonus for Player.User = 1.;
  1420.  
  1421.  
  1422. if(S_AllowBeginners && Beginners::IsBeginner(Player)) {
  1423. Beginners::BalanceBeginner(Player, Battle_ScoreHit);
  1424. } else {
  1425. if(Battle_ScoreHit <= 1) {
  1426. if (AutoBalance_ReloadSpeedBonus < 1.3) AutoBalance_ReloadSpeedBonus += .1;
  1427. } else {
  1428. AutoBalance_ReloadSpeedBonus = 1.;
  1429. }
  1430. }
  1431. }
  1432.  
  1433. foreach(Player in AllPlayers) {
  1434. Interface::HideSlider(Player, 0);
  1435. declare UI <=> UIManager.GetUI(Player);
  1436. if(UI == Null) continue;
  1437.  
  1438. declare netwrite Integer Battle_UIRoundPhase for UI;
  1439. Battle_UIRoundPhase = C_RoundPhase_EndRound;
  1440. }
  1441.  
  1442. ResetAllUIs();
  1443. // LayerMarkers.ManialinkPage = "";
  1444. LayerMarkers.IsVisible = False;
  1445.  
  1446. // update map tops
  1447. foreach(Player in Players) {
  1448. declare Integer MapHit for Player = 0;
  1449. declare Integer MapCapture for Player = 0;
  1450. declare Integer MapDefense for Player = 0;
  1451. declare Integer MapAttack for Player = 0;
  1452.  
  1453. declare Integer Battle_ScoreCapture for Player;
  1454. declare Integer Battle_ScoreDefense for Player;
  1455. declare Integer Battle_ScoreAttack for Player;
  1456. declare Integer Battle_ScoreHit for Player.Score;
  1457.  
  1458. MapHit += Battle_ScoreHit;
  1459. MapCapture += Battle_ScoreCapture;
  1460. MapDefense += Battle_ScoreDefense;
  1461. MapAttack += Battle_ScoreAttack;
  1462. }
  1463. UpdateMapRunnersRanking();
  1464. UpdatePlayersScores(G_CaptureMaxValue);
  1465.  
  1466. StartTime = -1;
  1467. EndTime = -1;
  1468. UIManager.UIAll.OverlayHideCountdown = False;
  1469. for (Clan, 1, 2) {
  1470. foreach (Pole in ClanPoles[Clan]) {
  1471. Pole.Gauge.Speed = 0;
  1472. }
  1473. }
  1474.  
  1475. MM_Sleep(1700);
  1476.  
  1477. UIManager.UIAll.BigMessageSound = CUIConfig::EUISound::EndRound;
  1478. if (TouchdownUserId != NullId && Users.existskey(TouchdownUserId)) {
  1479. UIManager.UIAll.StatusMessage = TL::Compose(_("$<%1$> touched the pole."), Users[TouchdownUserId].Name);
  1480. } else if (FinalCaptureUserId != NullId && Users.existskey(FinalCaptureUserId)) {
  1481. UIManager.UIAll.StatusMessage = TL::Compose(_("$<%1$> captured the last pole."), Users[FinalCaptureUserId].Name);
  1482. }
  1483. if (Victory::IsRoundWinner(1)) {
  1484. UIManager.UIAll.BigMessage = TextLib::Compose(_("$<%1$> wins the round!"), Teams[0].ColorizedName);
  1485. ClanScores[1] += 1;
  1486. } else if (Victory::IsRoundWinner(2)) {
  1487. UIManager.UIAll.BigMessage = TextLib::Compose(_("$<%1$> wins the round!"), Teams[1].ColorizedName);
  1488. ClanScores[2] += 1;
  1489. } else {
  1490. UIManager.UIAll.BigMessage = _("Draw round");
  1491. }
  1492. MM_SetScores([ClanScores[1], ClanScores[2]]);
  1493. // UIManager.UIAll.ScoreSummary_Points1 = Clan1Score;
  1494. // UIManager.UIAll.ScoreSummary_Points2 = Clan2Score;
  1495. ---UpdateTeamsScoresUI---
  1496.  
  1497. ST2::SetFooterText(TextLib::Compose("%1 "^S_RoundsToWin, _("Points limit : ")));
  1498. Victory::SetMatchWinnerFromScore(S_RoundsToWin, S_RoundGapToWin, S_RoundsLimit);
  1499.  
  1500. foreach (Player in Players) {
  1501. UnspawnPlayer(Player);
  1502. }
  1503.  
  1504. UIManager.UIAll.UISequence = CUIConfig::EUISequence::EndRound;
  1505. if (S_DisplayTopsRound) {
  1506. UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::ForcedVisible;
  1507. MM_Sleep(5000);
  1508. UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::Normal;
  1509. LaunchTop5Sequence("round");
  1510. } else {
  1511. UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::ForcedVisible;
  1512. MM_Sleep(7*1000);
  1513. }
  1514.  
  1515. +++RoundEnd+++
  1516. if (S_AlternativePoints) {
  1517. foreach (Score in Scores) {
  1518. declare Integer Battle_ScoreAlternative for Score;
  1519. Score.RoundPoints = Battle_ScoreAlternative;
  1520. }
  1521. }
  1522. Victory::RoundEnd();
  1523.  
  1524. // Match / Map win
  1525. if (!Victory::NoMatchWinner() || MatchEndRequested) {
  1526. MB_StopMatch = True;
  1527. } else {
  1528. // Autoround balance
  1529. if (S_AutoBalanceRound && !MM_IsMatchmakingServer()) {
  1530. AutoTeamBalanceRound();
  1531. }
  1532. }
  1533.  
  1534. Score::RoundEnd();
  1535. BalancedWeapons::RoundEnd();
  1536.  
  1537. UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::Normal;
  1538. ResetAllUIs();
  1539. // LayerMarkers.ManialinkPage = ""; // Crash.
  1540.  
  1541. if(S_BattleWaves) {
  1542. // once again, to ensure an update of the UI in case of early endround (e.g. vote for next map)
  1543. +++OnRoundStop+++
  1544.  
  1545. if(G_EngagePoleId != NullId) {
  1546. declare CSmMapLandmark EngagePole <=> MapLandmarks_Gauge[G_EngagePoleId];
  1547. if(EngagePole != Null) {
  1548. EngagePole.Gauge.Captured = False;
  1549. EngagePole.Gauge.Value = 0;
  1550. }
  1551. }
  1552. }
  1553. ***
  1554.  
  1555. // ---------------------------------- //
  1556. // Map end
  1557. // ---------------------------------- //
  1558. ***EndMap***
  1559. ***
  1560. ResetAllUIs();
  1561. LayerMarkers.IsVisible = False;
  1562.  
  1563. declare WinnerClan = -1;
  1564. if (Victory::IsMatchWinner(1)) {
  1565. UIManager.UIAll.BigMessage = TextLib::Compose(_("$<%1$> wins the match!"), Teams[0].ColorizedName);
  1566. WinnerClan = 1;
  1567. } else if (Victory::IsMatchWinner(2)) {
  1568. UIManager.UIAll.BigMessage = TextLib::Compose(_("$<%1$> wins the match!"), Teams[1].ColorizedName);
  1569. WinnerClan = 2;
  1570. } else {
  1571. UIManager.UIAll.BigMessage = _("Draw match");
  1572. }
  1573.  
  1574. declare MasterLogin = "";
  1575. declare MasterPoints = 0;
  1576.  
  1577. if (MM_IsMatchServer() && (ClansNbPlayers[1] == 0 || ClansNbPlayers[2] == 0 || MM_RestartMatchmaking) && ClanScores[1] == 0 && ClanScores[2] == 0) {
  1578. MM_SetLadderMatchId();
  1579. Mode::Ladder_CancelMatch();
  1580. MB_Log("Cancel match and don't give LP because one of the team left the match.");
  1581. } else {
  1582. if (MM_IsMatchServer()) {
  1583. MM_SetLadderMatchId();
  1584. }
  1585.  
  1586. if (WinnerClan != -1) {
  1587. foreach(Score in Scores) {
  1588. Score.LadderRankSortValue = - 1 - Score.Points;
  1589. if (Score.Points > MasterPoints) {
  1590. MasterPoints = Score.Points;
  1591. MasterLogin = Score.User.Login;
  1592. }
  1593. }
  1594.  
  1595. Mode::Ladder_CloseMatch();
  1596. } else {
  1597. Mode::Ladder_CancelMatch();
  1598. }
  1599. }
  1600.  
  1601. BalancedWeapons::MatchEnd();
  1602.  
  1603. if (S_DisplayTopsMap) {
  1604. UIManager.UIAll.UISequence = CUIConfig::EUISequence::Podium;
  1605. } else {
  1606. UIManager.UIAll.UISequence = CUIConfig::EUISequence::EndRound;
  1607. }
  1608. UIManager.UIAll.BigMessageSound = CUIConfig::EUISound::EndRound;
  1609. UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::ForcedVisible;
  1610. MM_Sleep(6*1000);
  1611. if (S_DisplayTopsMap) {
  1612. UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::Normal;
  1613. LaunchTop5Sequence("map");
  1614. } else {
  1615. UIManager.UIAll.UISequence = CUIConfig::EUISequence::Podium;
  1616. MM_Sleep(10*1000);
  1617. }
  1618.  
  1619. UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::Normal;
  1620. ResetAllUIs();
  1621.  
  1622. Interface::DestroySlider();
  1623.  
  1624. // ---------------------------------- //
  1625. // Send match result and transfert players back to the lobby
  1626. if (MM_IsMatchServer()) {
  1627. if (!MM_RestartMatchmaking && ClansNbPlayers[1] > 0 && ClansNbPlayers[2] > 0) {
  1628. if (MB_StopMatch) {
  1629. if (RematchNb < S_MatchmakingRematchNbMax) {
  1630. IsRematch = MM_VoteForRematch();
  1631. RematchNb += 1;
  1632. }
  1633.  
  1634. if (!IsRematch) {
  1635. RematchNb = 0;
  1636. MM_MatchEnd(MasterLogin);
  1637. MM_MatchToLobby();
  1638. } else {
  1639. MM_VoteForNextMap(False);
  1640. }
  1641. } else {
  1642. MM_VoteForNextMap(False);
  1643. }
  1644. } else {
  1645. RematchNb = 0;
  1646. MM_MatchEnd(MasterLogin);
  1647. MM_MatchToLobby();
  1648. }
  1649. }
  1650. ***
  1651.  
  1652.  
  1653. // ---------------------------------- //
  1654. // Match end
  1655. // ---------------------------------- //
  1656. ***EndMatch***
  1657. ***
  1658. +++MatchEnd+++
  1659. Victory::MatchEnd();
  1660. ***
  1661.  
  1662. // ---------------------------------- //
  1663. // Server end
  1664. // ---------------------------------- //
  1665. ***EndServer***
  1666. ***
  1667. // Destroy layers
  1668. Layers::Detach("Top5");
  1669. Layers::Destroy("Top5");
  1670. UIManager.UILayerDestroy(LayerRoundInfo);
  1671. WarmUp2::Unload();
  1672. ***
  1673.  
  1674.  
  1675. // ---------------------------------- //
  1676. // Set the EndTime of the round
  1677. ***EndTime***
  1678. ***
  1679. if(S_BattleWaves) {
  1680. EndTime = StartTime + S_TimeLimitForFirstCapture*1000;
  1681. } else {
  1682. EndTime = StartTime + S_TimeLimit*1000;
  1683. }
  1684. ***
  1685.  
  1686. // ---------------------------------- //
  1687. // Define when a capture is possible
  1688. ***IsCapturePossible***
  1689. ***
  1690. declare Boolean IsCapturePossible;
  1691. if(S_BattleWaves) {
  1692. declare IsGoalClanAttacking = (CurrentAckClan != 0) && (Clan == CurrentAckClan);
  1693. IsCapturePossible = !IsGoalDenied && !IsGoalClanAttacking;
  1694. if((G_EngagePoleId != NullId) && CurrentAckClan == 0) {
  1695. IsCapturePossible = False;
  1696. }
  1697. } else {
  1698. IsCapturePossible = !IsGoalDenied;
  1699. }
  1700. ***
  1701.  
  1702. // ---------------------------------- //
  1703. // Set the rules in the SpawnScreen
  1704. ***Rules***
  1705. ***
  1706. declare Text ModeName = "Battle";
  1707. declare Text ModeRules;
  1708.  
  1709. SpawnScreen::ResetRulesSection();
  1710. SpawnScreen::AddSubsection(_("Type"), _("Team versus Team"), 0.);
  1711. SpawnScreen::AddSubsection(
  1712. _("Objectives"),
  1713. TextLib::Compose(_("$<%11. $>Capture the poles during Attack phases.\n$<%12. $>If the time limit is reached, only 100%% captured poles count. The first team to win %2 rounds wins the match."), "$"^SpawnScreen::GetModeColor() , ""^S_RoundsToWin),
  1714. 25.);
  1715.  
  1716. if(S_BattleWaves) {
  1717. SpawnScreen::AddSubsection(
  1718. _("Conditions"),
  1719. TextLib::Compose(_("$<%11. $>Touch the engagement point to be the first team to Attack.\n$<%12. $>If a team does not touch any pole during %2 seconds, the other team Attacks."), "$"^SpawnScreen::GetModeColor(), ""^S_WaveDuration),
  1720. 60.);
  1721. }
  1722.  
  1723. UpdateModeStatusMessage();
  1724. SpawnScreen::CreatePrettyRules(ModeName);
  1725. ***
  1726. // ---------------------------------- //
  1727. /** Get the requested clan of a player
  1728. *
  1729. * @param _Player The player to check
  1730. *
  1731. * @return The requested clan of the player
  1732. */
  1733. Integer Battle_GetRequestedClan(CSmPlayer _Player) {
  1734. if (MM_IsMatchServer()) {
  1735. return MM_GetRequestedClan(_Player);
  1736. } else {
  1737. if (_Player == Null) return 0;
  1738.  
  1739. declare Battle_BalanceClan for _Player = -1;
  1740. if (S_AutoBalanceRound && (Battle_BalanceClan == 1 || Battle_BalanceClan == 2)) {
  1741. return Battle_BalanceClan;
  1742. } else {
  1743. return _Player.User.RequestedClan;
  1744. }
  1745. }
  1746.  
  1747. return 0;
  1748. }
  1749.  
  1750. // ---------------------------------- //
  1751. /** Turn on/off the overtime
  1752. *
  1753. * @param _Activate If True activate overtime
  1754. */
  1755. Void SetOvertime(Boolean _Activate) {
  1756. G_OvertimeActivated = _Activate;
  1757.  
  1758. declare netwrite Boolean Net_OvertimeActivated for Teams[0];
  1759. Net_OvertimeActivated = G_OvertimeActivated;
  1760. }
  1761.  
  1762. // ---------------------------------- //
  1763. /** Get the current status of the overtime
  1764. *
  1765. * @return True if the overtime is activated, False otherwise
  1766. */
  1767. Boolean GetOvertime() {
  1768. return G_OvertimeActivated;
  1769. }
  1770.  
  1771. // ---------------------------------- //
  1772. /** Set the overtime advantage
  1773. *
  1774. * @param _Advantage The clan who has the advantage
  1775. */
  1776. Void SetOvertimeAdvantage(Integer _Advantage) {
  1777. G_OvertimeAdvantage = _Advantage;
  1778.  
  1779. declare netwrite Integer Net_OvertimeAdvantage for Teams[0];
  1780. Net_OvertimeAdvantage = G_OvertimeAdvantage;
  1781. }
  1782.  
  1783. // ---------------------------------- //
  1784. /** Get the current overtime advantage
  1785. *
  1786. * @return The clan that has the advantage
  1787. */
  1788. Integer GetOvertimeAdvantage() {
  1789. return G_OvertimeAdvantage;
  1790. }
  1791.  
  1792. Void UpdateScoreTeamsUI(CSmPlayer Player) {
  1793. declare UI <=> UIManager.GetUI(Player);
  1794. if (UI == Null) return;
  1795.  
  1796. declare netwrite Text Battle_ScoreTeam1 for UI;
  1797. declare netwrite Text Battle_ScoreTeam2 for UI;
  1798.  
  1799. Battle_ScoreTeam1 = G_ScoreTeam1;
  1800. Battle_ScoreTeam2 = G_ScoreTeam2;
  1801. }
  1802.  
  1803. /**
  1804. * Convert Integers from 1 to 9 into letters from A to I
  1805. */
  1806. Text GetLetterFromNumber(Integer N) {
  1807. declare Suffix = "";
  1808. if (N > 26) Suffix = TextLib::ToText(((N - 1) / 26) + 1);
  1809.  
  1810. switch(N) {
  1811. case 1 : return "A"^Suffix;
  1812. case 2 : return "B"^Suffix;
  1813. case 3 : return "C"^Suffix;
  1814. case 4 : return "D"^Suffix;
  1815. case 5 : return "E"^Suffix;
  1816. case 6 : return "F"^Suffix;
  1817. case 7 : return "G"^Suffix;
  1818. case 8 : return "H"^Suffix;
  1819. case 9 : return "I"^Suffix;
  1820. case 10: return "J"^Suffix;
  1821. case 11: return "K"^Suffix;
  1822. case 12: return "L"^Suffix;
  1823. case 13: return "M"^Suffix;
  1824. case 14: return "N"^Suffix;
  1825. case 15: return "O"^Suffix;
  1826. case 16: return "P"^Suffix;
  1827. case 17: return "Q"^Suffix;
  1828. case 18: return "R"^Suffix;
  1829. case 19: return "S"^Suffix;
  1830. case 20: return "T"^Suffix;
  1831. case 21: return "U"^Suffix;
  1832. case 22: return "V"^Suffix;
  1833. case 23: return "W"^Suffix;
  1834. case 24: return "X"^Suffix;
  1835. case 25: return "Y"^Suffix;
  1836. case 26: return "Z"^Suffix;
  1837. }
  1838.  
  1839. return "?"^Suffix;
  1840. }
  1841.  
  1842. // ---------------------------------- //
  1843. /// End map timer for MatchMaking
  1844. Void UpdateBasesColors() {
  1845. foreach (Base in MapBases) {
  1846. Base.Clan = 0;
  1847. Base.IsActive = True;
  1848. }
  1849.  
  1850. declare UpdatedBases = Ident[];
  1851.  
  1852. foreach (Clan => Spawn in G_ClanSpawnAnchors) {
  1853. if (Spawn.Base == Null) continue;
  1854.  
  1855. Spawn.Base.Clan = Clan;
  1856. Spawn.Base.IsActive = True;
  1857. UpdatedBases.add(Spawn.Base.Id);
  1858. }
  1859.  
  1860. foreach (Pole in MapLandmarks_Gauge) {
  1861. declare Clan = 0;
  1862. if (Pole.Gauge.Clan == 1 || Pole.Gauge.Clan == 2) {
  1863. if (Pole.Gauge.Value < Pole.Gauge.Max) Clan = 3 - Pole.Gauge.Clan;
  1864. else Clan = Pole.Gauge.Clan;
  1865. }
  1866.  
  1867. if (Pole.Base != Null) {
  1868. if (!UpdatedBases.exists(Pole.Base.Id)) {
  1869. Pole.Base.Clan = Clan;
  1870. UpdatedBases.add(Pole.Base.Id);
  1871. } else if (Pole.Base.Clan != Clan) {
  1872. Pole.Base.Clan = 0;
  1873. }
  1874. }
  1875. }
  1876. }
  1877.  
  1878. Void UpdatePlayerScore(CSmPlayer Player, Integer CaptureMaxValue) {
  1879. if(Player.Score == Null) return;
  1880.  
  1881. declare Real ScoreCaptureFactor = 1.;
  1882. declare Real ScoreDenyFactor = 1.;
  1883. if (CaptureMaxValue != 0) {
  1884. ScoreCaptureFactor = S_PointsPerPole / CaptureMaxValue;
  1885. ScoreDenyFactor = S_DefPointOnDenyForOnePole / CaptureMaxValue;
  1886. }
  1887.  
  1888. declare Integer Battle_ScoreDefenseBonus for Player.Score;
  1889. declare Integer Battle_ScoreAttackBonus for Player.Score;
  1890. declare Integer Battle_ScoreAlternative for Player.Score;
  1891. declare Integer Battle_ScoreHit for Player.Score;
  1892. declare Integer Battle_TotalCaptureTime for Player.Score;
  1893. declare Integer Battle_TotalDenyTime for Player.Score;
  1894.  
  1895. declare Real ScoreCapture = ScoreCaptureFactor * Battle_TotalCaptureTime;
  1896. declare Real ScoreDeny = ScoreDenyFactor * Battle_TotalDenyTime;
  1897.  
  1898. declare Integer Battle_ScoreCapture for Player;
  1899. declare Integer Battle_ScoreDefense for Player;
  1900. declare Integer Battle_ScoreAttack for Player;
  1901. Battle_ScoreCapture = MathLib::NearestInteger(ScoreCapture);
  1902. Battle_ScoreAttack = Battle_ScoreAttackBonus + Battle_ScoreCapture; // etc.
  1903. Battle_ScoreDefense = Battle_ScoreDefenseBonus + MathLib::NearestInteger(ScoreDeny); // etc.
  1904. Battle_ScoreAlternative = Battle_ScoreAttack + Battle_ScoreDefense;
  1905.  
  1906. Player.Score.RoundPoints = Battle_ScoreHit;
  1907. }
  1908.  
  1909. Void UpdatePlayersScores(Integer CaptureMaxValue)
  1910. {
  1911. foreach(Player in Players) {
  1912. UpdatePlayerScore(Player, CaptureMaxValue);
  1913. }
  1914. }
  1915.  
  1916. Void SendCaptureTime(CSmPlayer _Player) {
  1917. declare UI <=> UIManager.GetUI(_Player);
  1918. if (UI == Null) return;
  1919.  
  1920. declare Integer[Ident] RoundTop_CaptureTime for _Player.Score;
  1921. declare netwrite Integer[Text] Net_RoundTop_CaptureTime for UI;
  1922. declare netwrite Integer Net_RoundTop_CaptureTimeUpdate for UI;
  1923. Net_RoundTop_CaptureTime.clear();
  1924. foreach (PoleId => CaptureTime in RoundTop_CaptureTime) {
  1925. Net_RoundTop_CaptureTime[""^PoleId] = CaptureTime;
  1926. }
  1927. Net_RoundTop_CaptureTimeUpdate = Now;
  1928. }
  1929.  
  1930. Void InitializePlayer(CSmPlayer Player, Text PoleMarkers) {
  1931. SetPlayerClan(Player, Battle_GetRequestedClan(Player));
  1932.  
  1933. if(Player.Score == Null) return;
  1934.  
  1935. declare Integer Battle_TotalCaptureTime for Player.Score;
  1936. declare Integer Battle_TotalDenyTime for Player.Score;
  1937. declare Integer Battle_ScoreDefenseBonus for Player.Score;
  1938. declare Integer Battle_ScoreAttackBonus for Player.Score;
  1939. declare Integer Battle_ScoreAlternative for Player.Score;
  1940. declare Integer Battle_ScoreHit for Player.Score;
  1941.  
  1942. declare Integer Battle_RoundIndex for Player.Score = -1;
  1943.  
  1944. if(Battle_RoundIndex != G_CurrentRoundIndex) {
  1945. // reinit the score
  1946. Battle_RoundIndex = G_CurrentRoundIndex;
  1947.  
  1948. Battle_TotalCaptureTime = 0;
  1949. Battle_TotalDenyTime = 0;
  1950. Battle_ScoreDefenseBonus = 0;
  1951. Battle_ScoreAttackBonus = 0;
  1952. Battle_ScoreAlternative = 0;
  1953. Battle_ScoreHit = Player.Score.RoundPoints; // keep trace of previous score if the player disconnects.
  1954. }
  1955.  
  1956. declare CustomScorePlayer <=> Player;
  1957. +++SetCustomScoreAll+++
  1958.  
  1959. // update tops
  1960. declare Integer MapHit for Player = 0;
  1961. declare Integer MapCombo for Player = 0;
  1962. declare Integer MapCapture for Player = 0;
  1963. declare Integer MapDefense for Player = 0;
  1964. declare Integer MapAttack for Player = 0;
  1965. //MapHit = 0;
  1966. //MapCombo = 0;
  1967. //MapCapture = 0;
  1968. //MapDefense = 0;
  1969. //MapAttack = 0;
  1970.  
  1971. declare UI <=> UIManager.GetUI(Player);
  1972. if (UI == Null) return;
  1973.  
  1974. declare netwrite Integer Battle_PoleCaptureState for UI;
  1975. declare netwrite Integer Battle_PoleCaptureRate for UI;
  1976. declare netwrite Boolean Battle_ServToUIShowFrame for UI = False;
  1977. declare netwrite Integer Battle_UIRoundPhase for UI;
  1978.  
  1979. Battle_PoleCaptureState = C_PoleCaptureState_Neutral;
  1980. Battle_PoleCaptureRate = 0;
  1981. Battle_ServToUIShowFrame = ! Battle_ServToUIShowFrame;
  1982. Battle_UIRoundPhase = C_RoundPhase_Playing;
  1983.  
  1984. UI.MarkersXML = PoleMarkers;
  1985. Tabs::UseTabs(UI, "ScoresTab");
  1986. UpdateScoreTeamsUI(Player);
  1987. SendCaptureTime(Player);
  1988. }
  1989.  
  1990. Void UpdateModeStatusMessage() {
  1991. declare Text BaseRules = _("Team vs Team: Capture all the poles of the opposing team.");
  1992. declare Text WavesRules;
  1993. if(S_BattleWaves) {
  1994. WavesRules = _("Waves mode: On");
  1995. } else {
  1996. WavesRules = _("Waves mode: Off");
  1997. }
  1998. declare Text RoundsToWinSetting = ""^S_RoundsToWin;
  1999. declare Text MatchScore = ClanScores[1] ^ " - " ^ ClanScores[2];
  2000. declare Text RoundScore;
  2001. if((G_ScoreTeam1 == "") && (G_ScoreTeam2 == "")) {
  2002. RoundScore = "0% - 0%";
  2003. } else {
  2004. RoundScore = G_ScoreTeam1 ^ " - " ^G_ScoreTeam2;
  2005. }
  2006.  
  2007. ModeStatusMessage = TextLib::Compose("%1\n%2, Rounds to win: %3\nMatch Score: %4, Round Score: %5", BaseRules, WavesRules, RoundsToWinSetting, MatchScore, RoundScore);
  2008. }
  2009.  
  2010. Text GetMLColor(Text DollarColor) {
  2011. return TextLib::SubString(DollarColor, 1, 3)^"f";
  2012. }
  2013.  
  2014.  
  2015. Void CreateRoundInfoUI(CUILayer LayerRoundInfo, CSmMapLandmark[][Integer] ClanPoles)
  2016. {
  2017. declare Integer GaugesXPos = 93; //50
  2018. declare Integer GaugesYPos = 71; //57
  2019. declare Integer PolesXPos = 0;
  2020. declare Integer PolesYPos = 0;
  2021.  
  2022.  
  2023.  
  2024. declare Text ImgGoalCaptured = C_ImgBaseDir^"c_goal_captured.dds";
  2025. declare Text ImgGoalCapture = C_ImgBaseDir^"c_goal_capture.dds";
  2026. declare Text ImgGoalProtected = C_ImgBaseDir^"c_goal_shield.dds";
  2027. declare Text ImgGoalDenied = C_ImgBaseDir^"c_goal_shield_block.dds";
  2028. declare Text ImgGoalLocked = C_ImgBaseDir^"c_goal_lock.dds";
  2029. declare Text ImgGoalBg = C_ImgBaseDir^"goal.dds";
  2030.  
  2031. declare Team0Color = GetMLColor(Teams[0].ColorText);
  2032. declare Team1Color = GetMLColor(Teams[1].ColorText);
  2033.  
  2034. declare Text MLPage = """
  2035. <script><!--
  2036. #Include "MathLib" as MathLib
  2037. #Include "TextLib" as TextLib
  2038.  
  2039. Text TimeToText(Integer _Time) {
  2040. if (_Time < 0) {
  2041. return "???";
  2042. }
  2043.  
  2044. declare MilliSeconds = _Time % 1000;
  2045. declare CentiSeconds = (_Time / 10) % 100;
  2046. declare Seconds = (_Time / 1000) % 60;
  2047. declare Minutes = (_Time / 60000) % 60;
  2048. declare Hours = (_Time / 3600000) % 24;
  2049.  
  2050. declare Time = TextLib::FormatInteger(Seconds, 2)^"."^TextLib::FormatInteger(CentiSeconds, 2);
  2051. if (Minutes > 0) Time = TextLib::FormatInteger(Minutes, 2)^":"^Time;
  2052. if (Hours > 0) Time = Hours^":"^Time;
  2053. return Time;
  2054. }
  2055.  
  2056. Void UpdateCaptureTime(Boolean _IsRoundRecord, Integer[Text] _CaptureTime) {
  2057. foreach (PoleId => CaptureTime in _CaptureTime) {
  2058. declare Frame_Pole <=> (Page.GetFirstChild("PoleId_"^PoleId) as CMlFrame);
  2059. if (Frame_Pole == Null) continue;
  2060.  
  2061. if (_IsRoundRecord) {
  2062. declare Label_RB <=> (Frame_Pole.GetFirstChild("Label_RB") as CMlLabel);
  2063. Label_RB.Value = TimeToText(CaptureTime);
  2064. } else {
  2065. declare Label_PB <=> (Frame_Pole.GetFirstChild("Label_PB") as CMlLabel);
  2066. Label_PB.Value = TimeToText(CaptureTime);
  2067. }
  2068. }
  2069. }
  2070.  
  2071. main() {
  2072.  
  2073. while(InputPlayer == Null) yield;
  2074.  
  2075. declare netread Text Battle_ScoreTeam1 for UI;
  2076. declare netread Text Battle_ScoreTeam2 for UI;
  2077. declare netread Integer Battle_PoleCaptureState for UI;
  2078. declare netread Integer Battle_PoleCaptureRate for UI;
  2079.  
  2080. declare netread Integer[Text] Net_RoundTop_CaptureTimeRecords for Teams[0];
  2081. declare netread Integer Net_RoundTop_CaptureTimeRecordsUpdate for Teams[0];
  2082. declare netread Integer[Text] Net_RoundTop_CaptureTime for UI;
  2083. declare netread Integer Net_RoundTop_CaptureTimeUpdate for UI;
  2084.  
  2085. declare LabelScoreTeam1 <=> (Page.GetFirstChild("LabelScoreTeam1") as CMlLabel);
  2086. declare LabelScoreTeam2 <=> (Page.GetFirstChild("LabelScoreTeam2") as CMlLabel);
  2087. declare FrameSmallPoleText <=> (Page.GetFirstChild("FrameSmallPoleText") as CMlFrame);
  2088. declare LabelCaptureMessage <=> (Page.GetFirstChild("LabelCaptureMessage") as CMlLabel);
  2089. declare QuadCaptureMessage <=> (Page.GetFirstChild("QuadCaptureMessage") as CMlQuad);
  2090. declare Frame_Clan1 <=> (Page.GetFirstChild("Frame_Clan1") as CMlFrame);
  2091. declare Frame_Clan2 <=> (Page.GetFirstChild("Frame_Clan2") as CMlFrame);
  2092.  
  2093. declare CMlQuad[] QuadGaugesTeam1;
  2094. declare CMlQuad[] QuadGaugesTeam2;
  2095. declare CMlFrame[][Integer] PoleFrame;
  2096. declare CMlFrame[][Integer] PoleCapturedFrame;
  2097. declare CMlGauge[][Integer] PoleGauges;
  2098.  
  2099. declare CMlGauge CaptureGauge <=> (Page.GetFirstChild("CaptureGauge") as CMlGauge);
  2100.  
  2101. declare Real[Integer][Integer] CurrentClanPoles;
  2102. declare Integer[Integer][Integer] HighlightTimer;
  2103.  
  2104. for(ClanIndex, 1, 2) {
  2105. CurrentClanPoles[ClanIndex] = Real[Integer];
  2106. PoleFrame[ClanIndex] = CMlFrame[];
  2107. PoleCapturedFrame[ClanIndex] = CMlFrame[];
  2108. HighlightTimer[ClanIndex] = Integer[Integer];
  2109. PoleGauges[ClanIndex] = CMlGauge[];
  2110. }
  2111.  
  2112. declare Clan1PoleIndex = -1;
  2113. declare Clan2PoleIndex = -1;
  2114. foreach(Pole in MapLandmarks_Gauge) {
  2115. if (Pole.Tag != "Goal" && Pole.Tag != "Checkpoint") continue;
  2116.  
  2117. declare Integer PoleClan = Pole.Gauge.Clan;
  2118. declare Integer PoleIndex = -1;
  2119.  
  2120. if(PoleClan == 1) {
  2121. Clan1PoleIndex += 1;
  2122. PoleIndex = Clan1PoleIndex;
  2123. } else if (PoleClan == 2) {
  2124. Clan2PoleIndex += 1;
  2125. PoleIndex = Clan2PoleIndex;
  2126. }
  2127.  
  2128. if(PoleIndex >= 0) {
  2129. CurrentClanPoles[PoleClan][PoleIndex] = Pole.Gauge.ValueReal; // presumably 0.
  2130. PoleFrame[PoleClan].add((Page.GetFirstChild("PoleFrame"^PoleIndex^"_"^PoleClan) as CMlFrame));
  2131. PoleCapturedFrame[PoleClan].add((Page.GetFirstChild("PoleCapturedFrame"^PoleIndex^"_"^PoleClan) as CMlFrame));
  2132. PoleGauges[PoleClan].add((Page.GetFirstChild("PoleUIGauge"^PoleIndex^"_"^PoleClan) as CMlGauge));
  2133. HighlightTimer[PoleClan][PoleIndex] = Now;
  2134. }
  2135. }
  2136.  
  2137. declare Blinker = 0;
  2138. declare BlinkDelay = 4;
  2139. declare PreviousState = -1;
  2140. declare PrevClan = -1;
  2141. declare PrevCaptureTimeUpdate = -1;
  2142. declare PrevCaptureTimeRecordsUpdate = -1;
  2143.  
  2144. while(True) {
  2145.  
  2146. // yield;
  2147. sleep(200);
  2148.  
  2149. if (!PageIsVisible) continue;
  2150. if (InputPlayer == Null) continue;
  2151.  
  2152. if (PrevClan != InputPlayer.CurrentClan) {
  2153. PrevClan = InputPlayer.CurrentClan;
  2154.  
  2155. Page.GetClassChildren("ClanSpecific", Page.MainFrame, True);
  2156. foreach (Control in Page.GetClassChildren_Result) {
  2157. if (Control.HasClass("Clan1")) {
  2158. if (InputPlayer.CurrentClan == 1 || IsSpectatorMode) Control.Visible = True;
  2159. else Control.Visible = False;
  2160. } else if (Control.HasClass("Clan2")) {
  2161. if (InputPlayer.CurrentClan == 2 || IsSpectatorMode) Control.Visible = True;
  2162. else Control.Visible = False;
  2163. }
  2164. }
  2165. }
  2166.  
  2167. if (PrevCaptureTimeRecordsUpdate != Net_RoundTop_CaptureTimeRecordsUpdate) {
  2168. PrevCaptureTimeRecordsUpdate = Net_RoundTop_CaptureTimeRecordsUpdate;
  2169. UpdateCaptureTime(True, Net_RoundTop_CaptureTimeRecords);
  2170. }
  2171.  
  2172. if (PrevCaptureTimeUpdate != Net_RoundTop_CaptureTimeUpdate) {
  2173. PrevCaptureTimeUpdate = Net_RoundTop_CaptureTimeUpdate;
  2174. UpdateCaptureTime(False, Net_RoundTop_CaptureTime);
  2175. }
  2176.  
  2177. LabelScoreTeam1.SetText("$s$fff"^Battle_ScoreTeam1);
  2178. LabelScoreTeam2.SetText("$s$fff"^Battle_ScoreTeam2);
  2179.  
  2180. if(PreviousState != Battle_PoleCaptureState) {
  2181. PreviousState = Battle_PoleCaptureState;
  2182. switch(Battle_PoleCaptureState) {
  2183. case {{{C_PoleCaptureState_Neutral}}} : {
  2184. CaptureGauge.Hide();
  2185. FrameSmallPoleText.Hide();
  2186. }
  2187. case {{{C_PoleCaptureState_Capturing}}} : {
  2188. QuadCaptureMessage.ImageUrl = "{{{ImgGoalCapture}}}";
  2189. CaptureGauge.Show();
  2190. FrameSmallPoleText.Show();
  2191. }
  2192. case {{{C_PoleCaptureState_Captured}}} : {
  2193. LabelCaptureMessage.SetText(TextLib::Compose("$s%1", _("Pole captured")));
  2194. QuadCaptureMessage.ImageUrl = "{{{ImgGoalCaptured}}}";
  2195. CaptureGauge.Hide();
  2196. FrameSmallPoleText.Show();
  2197. }
  2198. case {{{C_PoleCaptureState_Protected}}} : {
  2199. LabelCaptureMessage.SetText(TextLib::Compose("$s%1", _("Pole protected")));
  2200. QuadCaptureMessage.ImageUrl = "{{{ImgGoalProtected}}}";
  2201. CaptureGauge.Hide();
  2202. FrameSmallPoleText.Show();
  2203. }
  2204. case {{{C_PoleCaptureState_Denied}}} : {
  2205. LabelCaptureMessage.SetText(TextLib::Compose("$s%1", _("Pole denied")));
  2206. QuadCaptureMessage.ImageUrl = "{{{ImgGoalDenied}}}";
  2207. CaptureGauge.Hide();
  2208. FrameSmallPoleText.Show();
  2209. }
  2210. case {{{C_PoleCaptureState_Locked}}} : {
  2211. LabelCaptureMessage.SetText(TextLib::Compose("$s%1", _("Pole locked")));
  2212. QuadCaptureMessage.ImageUrl = "{{{ImgGoalLocked}}}";
  2213. CaptureGauge.Hide();
  2214. FrameSmallPoleText.Show();
  2215. }
  2216. }
  2217. }
  2218.  
  2219. if(Battle_PoleCaptureState == {{{C_PoleCaptureState_Capturing}}}) {
  2220. LabelCaptureMessage.SetText(TextLib::Compose("$s%1 (%2%%)", _("Capturing"), ""^Battle_PoleCaptureRate));
  2221. CaptureGauge.SetRatio(Battle_PoleCaptureRate/100.);
  2222. }
  2223.  
  2224.  
  2225. declare Clan1PoleIndex = -1;
  2226. declare Clan2PoleIndex = -1;
  2227. foreach(Pole in MapLandmarks_Gauge) {
  2228. if (Pole.Tag != "Goal" && Pole.Tag != "Checkpoint") continue;
  2229.  
  2230. declare Integer PoleClan = Pole.Gauge.Clan;
  2231. if(PoleClan == 0) continue; // inconsistent data.
  2232. if(CurrentClanPoles[PoleClan].count <= 0) continue; // inconsistent data.
  2233.  
  2234. declare Integer PoleIndex = -1;
  2235. if(PoleClan == 1) {
  2236. Clan1PoleIndex += 1;
  2237. PoleIndex = Clan1PoleIndex;
  2238. } else if (PoleClan == 2) {
  2239. Clan2PoleIndex += 1;
  2240. PoleIndex = Clan2PoleIndex;
  2241. }
  2242.  
  2243. if(PoleIndex >= 0) {
  2244. declare Integer OpposingClan = 3-PoleClan;
  2245. declare PoleFrameOppClan = PoleFrame[PoleClan];
  2246.  
  2247. declare Real ServerCapture = Pole.Gauge.ValueReal;
  2248. // Blink timer
  2249. if(ServerCapture != CurrentClanPoles[PoleClan][PoleIndex]) {
  2250. CurrentClanPoles[PoleClan][PoleIndex] = ServerCapture;
  2251. HighlightTimer[PoleClan][PoleIndex] = Now + 500;
  2252. }
  2253.  
  2254. declare Real FakeValue = (MathLib::Sqrt(ServerCapture) + ServerCapture) / 2;
  2255. //PoleGauges[PoleClan][PoleIndex].SetRatio(ServerCapture);
  2256. PoleGauges[PoleClan][PoleIndex].SetRatio(FakeValue);
  2257.  
  2258. if(ServerCapture >= 1.) {
  2259. PoleFrame[PoleClan][PoleIndex].Hide();
  2260. PoleCapturedFrame[PoleClan][PoleIndex].Show();
  2261. } else if(HighlightTimer[PoleClan][PoleIndex] > Now) {
  2262. if((Blinker % BlinkDelay) == 0) {
  2263. //PoleFrameOppClan[PoleIndex].Show();
  2264. PoleCapturedFrame[PoleClan][PoleIndex].Show();
  2265. } else if((Blinker % BlinkDelay) == (BlinkDelay/2)) {
  2266. //PoleFrameOppClan[PoleIndex].Hide();
  2267. PoleCapturedFrame[PoleClan][PoleIndex].Hide();
  2268. }
  2269. } else {
  2270. PoleFrame[PoleClan][PoleIndex].Show();
  2271. PoleCapturedFrame[PoleClan][PoleIndex].Hide();
  2272. }
  2273. }
  2274. }
  2275. Blinker += 1;
  2276. } // end while
  2277. }
  2278. --></script>
  2279. <frame>
  2280. <frame posn="0 76 257">
  2281. <label id="LabelScoreTeam1" valign="bottom" posn="-37 0 0" halign="right" scale="1" />
  2282. <label id="LabelScoreTeam2" valign="bottom" posn=" 37 0 0" halign="left" scale="1" />
  2283. </frame>
  2284. <frame id="FrameSmallPoleText" hidden="1" posn="0 -56 3">
  2285. <label id="LabelCaptureMessage" valign="center" halign="center" posn="0 0 1" textsize="5" />
  2286. <quad id="QuadCaptureMessage" valign="center" halign="center" sizen="18 18" />
  2287. <gauge posn="-30 -5" sizen="60 6" halign="left" style="EnergyBar" id="CaptureGauge" />
  2288. </frame>
  2289. """;
  2290.  
  2291. declare Real ScoresXPos = 93.;//22.;//30;//28;//95; //138
  2292. declare Real ScoresYPos = 90.;//68.5; //71
  2293. declare Real ScoresZPos = 200.; //4
  2294. declare CommonAttribs = """ valign="center" halign="center" """;
  2295. declare PolesByClan = ClanPoles[1].count-1;
  2296.  
  2297. declare Width = 80.;
  2298. declare Margin = 0.5;
  2299. declare ItemNb = 9;
  2300. declare ItemWidth = (Width / ItemNb) - Margin;
  2301. declare ItemHeight = ItemWidth;
  2302. declare LabelTextSize = 1.5;
  2303. declare LeftPosX = -160. + Width - ((ItemWidth + Margin) / 2.);
  2304. declare RightPosX = LeftPosX * -1;
  2305. declare RecordsHidden = "0";
  2306. if (!S_DisplayPoleRecords) RecordsHidden = "1";
  2307.  
  2308. declare Clan1TextColor = Teams[0].ColorText;
  2309. declare Clan2TextColor = Teams[1].ColorText;
  2310. declare Clan1Color = Teams[0].ColorPrimary;
  2311. declare Clan2Color = Teams[1].ColorPrimary;
  2312. declare Text Clan1ColorTextVector = """{{{Clan1Color.X}}} {{{Clan1Color.Y}}} {{{Clan1Color.Z}}} 1.""";
  2313. declare Text Clan2ColorTextVector = """{{{Clan2Color.X}}} {{{Clan2Color.Y}}} {{{Clan2Color.Z}}} 1.""";
  2314.  
  2315. MLPage ^= """<frame posn="{{{LeftPosX}}} {{{ScoresYPos}}} {{{ScoresZPos}}}" id="Frame_Clan1" >""";
  2316.  
  2317. for (I, 0, PolesByClan) {
  2318. declare PoleId = "";
  2319. if (ClanPoles[2].existskey(I)) {
  2320. PoleId = ""^ClanPoles[2][I].Id;
  2321. }
  2322. MLPage ^= """
  2323. <frame posn="{{{-I*(ItemWidth + Margin)}}} 0 0" id="PoleId_{{{PoleId}}}">
  2324. <frame id="PoleFrame{{{I}}}_1" >
  2325. <label posn="0 {{{-ItemHeight*0.3}}} 0" halign="center" valign="center" text="{{{GetLetterFromNumber(I+1)}}}" textsize="{{{LabelTextSize}}}" />
  2326. <quad sizen="{{{ItemWidth}}} {{{ItemHeight}}}" halign="center" image="{{{ImgGoalBg}}}" colorize="000" />
  2327. </frame>
  2328. <frame hidden="1" id="PoleCapturedFrame{{{I}}}_1" >
  2329. <label posn="0 {{{-ItemHeight*0.3}}} 0" halign="center" valign="center" text="{{{Clan1TextColor}}}{{{GetLetterFromNumber(I+1)}}}" textsize="{{{LabelTextSize}}}"/>
  2330. <quad sizen="{{{ItemWidth}}} {{{ItemHeight}}}" halign="center" image="{{{ImgGoalBg}}}" colorize="{{{Clan1ColorTextVector}}}"/>
  2331. </frame>
  2332. <gauge posn="{{{ItemWidth*0.4}}} {{{-ItemHeight*0.9}}}" sizen="{{{ItemHeight*1.5}}} 6." color="{{{Clan1ColorTextVector}}}" style="EnergyBar" drawbg="false" rotation="-90" drawblockbg="false" id="PoleUIGauge{{{I}}}_1" />
  2333. <frame hidden="{{{RecordsHidden}}}">
  2334. <frame posn="0 -{{{ItemHeight + Margin}}}" class="ClanSpecific Clan1">
  2335. <quad posn="{{{-ItemWidth/2.}}} 0" sizen="3 3" style="Icons64x64_1" substyle="First" />
  2336. <label posn="{{{(-ItemWidth/2.)+3}}} 0" sizen="{{{ItemWidth-3}}} 3" textsize="1" text="--.--" id="Label_RB" />
  2337. <quad posn="{{{-ItemWidth/2.}}} -3" sizen="3 3" style="UIConstruction_Buttons" substyle="Author" />
  2338. <label posn="{{{(-ItemWidth/2.)+3}}} -3" sizen="{{{ItemWidth-3}}} 3" textsize="1" text="--.--" id="Label_PB" />
  2339. </frame>
  2340. </frame>
  2341. </frame>
  2342. """;
  2343. }
  2344.  
  2345. MLPage ^= """</frame><frame posn="{{{RightPosX}}} {{{ScoresYPos}}} {{{ScoresZPos}}}" id="Frame_Clan2" >""";
  2346.  
  2347. for (I, 0, PolesByClan) {
  2348. declare PoleId = "";
  2349. if (ClanPoles[1].existskey(I)) {
  2350. PoleId = ""^ClanPoles[1][I].Id;
  2351. }
  2352. MLPage ^= """
  2353. <frame posn="{{{I*(ItemWidth + Margin)}}} 0 0" id="PoleId_{{{PoleId}}}">
  2354. <frame id="PoleFrame{{{I}}}_2" >
  2355. <label posn="0 {{{-ItemHeight*0.3}}} 0" halign="center" valign="center" text="{{{GetLetterFromNumber(I+1)}}}" textsize="{{{LabelTextSize}}}" />
  2356. <quad sizen="{{{ItemWidth}}} {{{ItemHeight}}}" halign="center" image="{{{ImgGoalBg}}}" colorize="000" />
  2357. </frame>
  2358. <frame hidden="1" id="PoleCapturedFrame{{{I}}}_2" >
  2359. <label posn="0 {{{-ItemHeight*0.3}}} 0" halign="center" valign="center" text="{{{Clan2TextColor}}}{{{GetLetterFromNumber(I+1)}}}" textsize="{{{LabelTextSize}}}"/>
  2360. <quad sizen="{{{ItemWidth}}} {{{ItemHeight}}}" halign="center" image="{{{ImgGoalBg}}}" colorize="{{{Clan2ColorTextVector}}}"/>
  2361. </frame>
  2362. <gauge posn="{{{ItemWidth*0.4}}} {{{-ItemHeight*0.9}}}" sizen="{{{ItemHeight*1.5}}} 6." color="{{{Clan2ColorTextVector}}}" style="EnergyBar" drawbg="false" rotation="-90" drawblockbg="false" id="PoleUIGauge{{{I}}}_2" />
  2363. <frame hidden="{{{RecordsHidden}}}">
  2364. <frame posn="0 -{{{ItemHeight + Margin}}}" hidden="{{{RecordsHidden}}}" class="ClanSpecific Clan2">
  2365. <quad posn="{{{-ItemWidth/2.}}} 0" sizen="3 3" style="Icons64x64_1" substyle="First" />
  2366. <label posn="{{{(-ItemWidth/2.)+3}}} 0" sizen="{{{ItemWidth-3}}} 3" textsize="1" text="--.--" id="Label_RB" />
  2367. <quad posn="{{{-ItemWidth/2.}}} -3" sizen="3 3" style="UIConstruction_Buttons" substyle="Author" />
  2368. <label posn="{{{(-ItemWidth/2.)+3}}} -3" sizen="{{{ItemWidth-3}}} 3" textsize="1" text="--.--" id="Label_PB" />
  2369. </frame>
  2370. </frame>
  2371. </frame>
  2372. """;
  2373. }
  2374.  
  2375. MLPage ^= """</frame>""";
  2376. MLPage ^= """</frame>""";
  2377.  
  2378. LayerRoundInfo.ManialinkPage = MLPage;
  2379. }
  2380.  
  2381. ***UpdateTotalCapture***
  2382. ***
  2383. // Victory
  2384. for (Clan, 1, 2) {
  2385. TotalCaptureValue[Clan] = 0;
  2386. NumberOfCapturedPoles[Clan] = 0;
  2387. foreach (Pole in ClanPoles[3-Clan]) {
  2388. TotalCaptureValue[Clan] += Pole.Gauge.Value;
  2389. if (Pole.Gauge.Captured) {
  2390. NumberOfCapturedPoles[Clan] += 1;
  2391. }
  2392. }
  2393. if (NumberOfCapturedPoles[Clan] == ClanPoles[3-Clan].count) Victory::SetRoundWinnerIfNoWinner(Clan);
  2394. }
  2395.  
  2396. if (Now >= EndTime) {
  2397. // Overtime
  2398. if (S_UseOvertime && S_BattleWaves && FirstWaveStartTime >= 0) {
  2399. if (EndTime >= 0) {
  2400. UIManager.UIAll.OverlayHideCountdown = True;
  2401. EndTime = -1;
  2402. Message::CleanAllMessages();
  2403. Message::SendBigMessage(_("Overtime"), 3000, 1, CUIConfig::EUISound::PhaseChange, 0);
  2404. }
  2405. SetOvertime(True);
  2406.  
  2407. if (CurrentAckClan == 1 || CurrentAckClan == 2) {
  2408. if (GetOvertimeAdvantage() < 0) {
  2409. if (TotalCaptureValue[CurrentAckClan] > TotalCaptureValue[3 - CurrentAckClan]) {
  2410. SetOvertimeAdvantage(CurrentAckClan);
  2411. }
  2412. // Attacking clan has less points
  2413. else {
  2414. SetOvertimeAdvantage(3 - CurrentAckClan);
  2415. }
  2416. }
  2417.  
  2418. // Advantaged clan is attacking
  2419. if (GetOvertimeAdvantage() == CurrentAckClan) {
  2420. // Advantaged clan touch an active pole, win of this clan
  2421. if (CaptureOngoing) {
  2422. SetOvertime(False);
  2423. Victory::SetRoundWinnerIfNoWinner(GetOvertimeAdvantage());
  2424. TouchdownUserId = OvertimeCaptureUserId;
  2425. }
  2426. }
  2427. // Disadvantaged clan is attacking
  2428. else {
  2429. // Disadvantaged clan catch back, extended time
  2430. if (TotalCaptureValue[3 - GetOvertimeAdvantage()] >= TotalCaptureValue[GetOvertimeAdvantage()]) {
  2431. SetOvertime(False);
  2432. declare ExtendedTime = MathLib::NearestInteger(S_TimeLimitAfterFirstCapture * ExtendedTimeRatio * 1000.);
  2433. if (ExtendedTime < C_MinimumExtendedTime) {
  2434. ExtendedTime = C_MinimumExtendedTime;
  2435. } else {
  2436. ExtendedTimeRatio *= 0.5;
  2437. }
  2438. EndTime = Now + ExtendedTime;
  2439. UIManager.UIAll.OverlayHideCountdown = False;
  2440. Message::CleanAllMessages();
  2441. Message::SendBigMessage(_("Extended time"), 5000, 1, CUIConfig::EUISound::PhaseChange, 0);
  2442.  
  2443. declare TeamA = GetOvertimeAdvantage() - 1;
  2444. declare TeamB = 3 - GetOvertimeAdvantage() - 1;
  2445. if (Teams.existskey(TeamA) && Teams.existskey(TeamB)) {
  2446. Message::SendStatusMessage(
  2447. TextLib::Compose(
  2448. _("|%1 and %2 are teams names|$<%1$> has equaled $<%2$> score, the round continues."),
  2449. Teams[TeamB].ColorizedName,
  2450. Teams[TeamA].ColorizedName
  2451. ),
  2452. 5000,
  2453. 1
  2454. );
  2455. }
  2456.  
  2457. SetOvertimeAdvantage(-1);
  2458. }
  2459. }
  2460. }
  2461. } else {
  2462. // First Criteria : Current Score
  2463. if (NumberOfCapturedPoles[1] > NumberOfCapturedPoles[2]) Victory::SetRoundWinnerIfNoWinner(1);
  2464. if (NumberOfCapturedPoles[2] > NumberOfCapturedPoles[1]) Victory::SetRoundWinnerIfNoWinner(2);
  2465. // 2nd Criteria : most captured
  2466. if (TotalCaptureValue[1] > TotalCaptureValue[2]) Victory::SetRoundWinnerIfNoWinner(1);
  2467. if (TotalCaptureValue[2] > TotalCaptureValue[1]) Victory::SetRoundWinnerIfNoWinner(2);
  2468. // 3rd Criteria : First capture
  2469. if (FirstClanToStartCapture != 0) Victory::SetRoundWinnerIfNoWinner(FirstClanToStartCapture);
  2470. // 4rth Criteria : Draw
  2471. Victory::SetRoundDrawIfNoWinner();
  2472.  
  2473. FinalCaptureUserId = NullId;
  2474. SetOvertime(False);
  2475. SetOvertimeAdvantage(-1);
  2476. }
  2477. } else {
  2478. SetOvertime(False);
  2479. SetOvertimeAdvantage(-1);
  2480. }
  2481.  
  2482. if(!Victory::NoRoundWinner()) {
  2483. MB_StopRound = True;
  2484. if(S_BattleWaves) {
  2485. +++OnRoundStop+++
  2486. }
  2487. }
  2488. ***
  2489.  
  2490. ***OnRoundStop***
  2491. ***
  2492. // Update the UI before starting the "end round" business
  2493. CurrentAckClan = 0;
  2494. if(UIManager.UIAll.UILayers.existskey(G_TimeLeftLayerId)) {
  2495. declare Removed = UIManager.UIAll.UILayers.removekey(G_TimeLeftLayerId);
  2496. }
  2497.  
  2498. if(S_BattleWaves) {
  2499. +++UIAll+++
  2500. }
  2501. ***
  2502.  
  2503. ***UIAll***
  2504. ***
  2505. declare Integer DurationInSeconds = (DurationBeforePivot/1000) + 1;
  2506.  
  2507. foreach(Player in Players) {
  2508. UpdateTimeLeftUI(Player, CurrentAckClan, DurationInSeconds);
  2509. }
  2510. foreach(Spectator in Spectators) {
  2511. UpdateTimeLeftUI(Spectator, CurrentAckClan, DurationInSeconds);
  2512. }
  2513. ***
  2514.  
  2515. ***UpdateTeamsScoresUI***
  2516. ***
  2517. // Update UI
  2518. declare ClanTotalRatios1 = 100 * TotalCaptureValue[1] / (G_CaptureMaxValue * NbPolesByClan);
  2519. declare ClanTotalRatios2 = 100 * TotalCaptureValue[2] / (G_CaptureMaxValue * NbPolesByClan);
  2520.  
  2521. // Show a precise score if needed
  2522. if(ClanTotalRatios1 == ClanTotalRatios2) {
  2523. if(ClanTotalRatios1 == 0) {
  2524. G_ScoreTeam1 = "";
  2525. G_ScoreTeam2 = "";
  2526. } else {
  2527. declare Real RealRatio1 = TotalCaptureValue[1] / (1.0* (G_CaptureMaxValue * ClanPoles[1].count));
  2528. declare Real RealRatio2 = TotalCaptureValue[2] / (1.0* (G_CaptureMaxValue * ClanPoles[2].count));
  2529. declare Coma1 = MathLib::NearestInteger(1000.*RealRatio1) % 10;
  2530. declare Coma2 = MathLib::NearestInteger(1000.*RealRatio2) % 10;
  2531.  
  2532. G_ScoreTeam1 = ClanTotalRatios1^"."^Coma1^"%";
  2533. G_ScoreTeam2 = ClanTotalRatios2^"."^Coma2^"%";
  2534. }
  2535. } else {
  2536. G_ScoreTeam1 = ClanTotalRatios1^"%";
  2537. G_ScoreTeam2 = ClanTotalRatios2^"%";
  2538. }
  2539.  
  2540.  
  2541. foreach(Player in Players) {
  2542. UpdateScoreTeamsUI(Player);
  2543. }
  2544. foreach(Spectator in Spectators) {
  2545. UpdateScoreTeamsUI(Spectator);
  2546. }
  2547.  
  2548. // Update OverlayScoreSummary
  2549. declare PlayerClan1Id = NullId;
  2550. declare PlayerClan2Id = NullId;
  2551. foreach (Player in Players) {
  2552. if ((PlayerClan1Id == NullId) && (Player.CurrentClan == 1)) PlayerClan1Id = Player.Id;
  2553. if ((PlayerClan2Id == NullId) && (Player.CurrentClan == 2)) PlayerClan2Id = Player.Id;
  2554.  
  2555. if (PlayerClan1Id != NullId && PlayerClan2Id != NullId) break;
  2556. }
  2557.  
  2558. if (PlayerClan1Id != NullId && PlayerClan2Id != NullId) {
  2559. UIManager.UIAll.OverlayScoreSummary = True;
  2560. UIManager.UIAll.ScoreSummary_Player1 = PlayerClan1Id;
  2561. UIManager.UIAll.ScoreSummary_Points1 = ClanScores[1];
  2562. UIManager.UIAll.ScoreSummary_Gauge1 = ClanTotalRatios1/100.;
  2563. UIManager.UIAll.ScoreSummary_MatchPoints1 = -1;
  2564. UIManager.UIAll.ScoreSummary_Player2 = PlayerClan2Id;
  2565. UIManager.UIAll.ScoreSummary_Points2 = ClanScores[2];
  2566. UIManager.UIAll.ScoreSummary_Gauge2 = ClanTotalRatios2/100.;
  2567. UIManager.UIAll.ScoreSummary_MatchPoints2 = -1;
  2568. } else {
  2569. UIManager.UIAll.OverlayScoreSummary = False;
  2570. }
  2571. ***
  2572.  
  2573. ***MarkersML_ScriptInit***
  2574. ***
  2575. if(S_BattleWaves) {
  2576. MLPage ^= """
  2577. declare netread Integer BattleWaves_AtkClan for UI;
  2578. declare Integer CurrentStateOfAckClanVariable = -1;
  2579. """;
  2580.  
  2581. if(G_EngagePoleId != NullId) {
  2582. MLPage ^= """
  2583. declare CMlFrame EngagePoleFrame = (Page.GetFirstChild("EngagePoleFrame") as CMlFrame);""";
  2584. }
  2585. }
  2586. ***
  2587.  
  2588. ***MarkersML_ScriptLoop***
  2589. ***
  2590. if(S_BattleWaves) {
  2591. MLPage ^= """
  2592. if(CurrentStateOfAckClanVariable != BattleWaves_AtkClan) {
  2593. CurrentStateOfAckClanVariable = BattleWaves_AtkClan;
  2594. if(BattleWaves_AtkClan > 0) {""";
  2595.  
  2596. if(G_EngagePoleId != NullId) {
  2597. MLPage ^= """
  2598. EngagePoleFrame.Hide();""";
  2599. }
  2600.  
  2601. MLPage ^= """
  2602. for (I, 0, PolesByClan-1) {
  2603. PoleFrame[BattleWaves_AtkClan][I].Hide();
  2604. PoleFrame[3-BattleWaves_AtkClan][I].Show();
  2605. }
  2606. } else {""";
  2607. if(G_EngagePoleId != NullId) {
  2608. MLPage ^= """
  2609. EngagePoleFrame.Show();
  2610. for(ClanIndex, 1, 2) {
  2611. for (I, 0, PolesByClan-1) {
  2612. PoleFrame[ClanIndex][I].Hide();
  2613. }
  2614. }
  2615. """;
  2616. } else {
  2617. MLPage ^= """
  2618. declare Integer PlayerClan;
  2619. if(InputPlayer != Null) {
  2620. if((InputPlayer.CurrentClan == 1) || (InputPlayer.CurrentClan == 2)) {
  2621. PlayerClan = InputPlayer.CurrentClan;
  2622. } else {
  2623. PlayerClan = 1;
  2624. }
  2625. } else {
  2626. // arbitrary
  2627. PlayerClan = 1;
  2628. }
  2629.  
  2630. /*
  2631. // sometimes, GUIPlayer does not exist.
  2632. if(GUIPlayer != Null) {
  2633. PlayerClan = GUIPlayer.CurrentClan;
  2634. } else {
  2635. PlayerClan = InputPlayer.CurrentClan;
  2636. }
  2637. */
  2638.  
  2639. for (I, 0, PolesByClan-1) {
  2640. PoleFrame[3-PlayerClan][I].Show();
  2641. PoleFrame[ PlayerClan][I].Hide();
  2642. }
  2643. """;
  2644. }
  2645.  
  2646.  
  2647. MLPage ^= """
  2648.  
  2649. }
  2650. }
  2651. """;
  2652. }
  2653. ***
  2654.  
  2655. ***MarkersML_Markups***
  2656. ***
  2657. if(S_BattleWaves) {
  2658. if(G_EngagePoleId != NullId) {
  2659. declare Vec3 Clan1Color = Teams[1].ColorPrimary; // inverted to avoid the "blue/white/red" effect with default teams ;)
  2660. declare Vec3 Clan2Color = Teams[0].ColorPrimary;
  2661.  
  2662. declare Text ImgPoleEngageLeft = C_ImgBaseDir^"shield_left.dds";
  2663. declare Text ImgPoleEngageRight = C_ImgBaseDir^"shield_right.dds";
  2664.  
  2665. declare Vec3 EngageColor = <.5, .5, .5>;
  2666. declare Real EngagePoleImgSize = 10.;
  2667. declare Pole <=> MapLandmarks_Gauge[G_EngagePoleId];
  2668. MLPage ^= """
  2669. <frame id="PoleMarker{{{Pole.Id}}}" >
  2670. <frame id="EngagePoleFrame">
  2671. <quad posn="-0.1 0." halign="center" valign="center" sizen="{{{WidthFactor*EngagePoleImgSize}}} {{{EngagePoleImgSize}}}" image="{{{
  2672. ImgPoleEngageLeft}}}" colorize="{{{Clan1Color.X}}} {{{Clan1Color.Y}}} {{{Clan1Color.Z}}}" autoscale="False" />
  2673. <quad posn="0.1 0." halign="center" valign="center" sizen="{{{WidthFactor*EngagePoleImgSize}}} {{{EngagePoleImgSize}}}" image="{{{
  2674. ImgPoleEngageRight}}}" colorize="{{{Clan2Color.X}}} {{{Clan2Color.Y}}} {{{Clan2Color.Z}}}" autoscale="False" />
  2675. </frame>
  2676. </frame>""";
  2677. }
  2678. }
  2679. ***
  2680.  
  2681. Text CreateMarkersManialinkPage(CSmMapLandmark[][Integer] ClanPoles)
  2682. {
  2683. declare Text ImgPole = C_ImgBaseDir^"goal.dds";
  2684. declare Text ImgPoleCapture = C_ImgBaseDir^"goal_cap.dds";
  2685. declare Integer ServerPolesByClan = ClanPoles[1].count;
  2686.  
  2687. declare Text MLPage = """
  2688. <script><!--
  2689.  
  2690.  
  2691. #Include "MathLib" as MathLib
  2692.  
  2693. main() {
  2694. while(InputPlayer == Null) yield;
  2695.  
  2696. declare CMlFrame[][Integer] PoleFrame;
  2697. declare CMlQuad [][Integer] PoleQuad;
  2698. declare CMlGauge[][Integer] PoleGauge;
  2699.  
  2700. declare Real[Integer][Integer] CurrentClanPoles;
  2701. declare Integer[Integer][Integer] HighlightTimer;
  2702.  
  2703. declare Integer PolesByClan = 0;
  2704. foreach (Pole in MapLandmarks_Gauge) {
  2705. if (Pole.Tag != "Goal") continue;
  2706. PolesByClan += 1;
  2707. }
  2708. PolesByClan /= 2;
  2709.  
  2710.  
  2711. // Wait data on map change.
  2712. declare Boolean WaitData = True;
  2713. while(WaitData) {
  2714. yield;
  2715. WaitData = False;
  2716. for(ClanIndex, 1, 2) {
  2717. CurrentClanPoles[ClanIndex] = Real[Integer];
  2718. PoleFrame[ClanIndex] = CMlFrame[];
  2719. PoleQuad[ClanIndex] = CMlQuad[];
  2720. PoleGauge[ClanIndex] = CMlGauge[];
  2721. HighlightTimer[ClanIndex] = Integer[Integer];
  2722. for (I, 0, PolesByClan - 1) {
  2723. CurrentClanPoles[ClanIndex][I] = 0.;
  2724. declare CMlFrame TheFrame <=> (Page.GetFirstChild("PoleFrame"^I^"_"^ClanIndex) as CMlFrame);
  2725. if(TheFrame == Null) {
  2726. WaitData = True;
  2727. continue;
  2728. }
  2729. PoleFrame[ClanIndex].add(TheFrame);
  2730. PoleQuad[ClanIndex].add((Page.GetFirstChild("PoleQuad"^I^"_"^ClanIndex) as CMlQuad));
  2731. PoleGauge[ClanIndex].add((Page.GetFirstChild("PoleGauge"^I^"_"^ClanIndex) as CMlGauge));
  2732. HighlightTimer[ClanIndex][I] = Now;
  2733. }
  2734. }
  2735. }
  2736.  
  2737. """;
  2738.  
  2739. +++MarkersML_ScriptInit+++
  2740. MLPage ^= """
  2741. declare Text NeutralColor = "$o$888";
  2742.  
  2743. while(True) {
  2744. sleep(200);
  2745. if(!PageIsVisible) continue;
  2746.  
  2747. declare Clan1PoleIndex = -1;
  2748. declare Clan2PoleIndex = -1;
  2749. foreach(Pole in MapLandmarks_Gauge) {
  2750. if (Pole.Tag != "Goal" && Pole.Tag != "Checkpoint") continue;
  2751.  
  2752. declare Integer PoleClan = Pole.Gauge.Clan;
  2753. declare Integer PoleIndex = -1;
  2754. if(PoleClan == 1) {
  2755. Clan1PoleIndex += 1;
  2756. PoleIndex = Clan1PoleIndex;
  2757. } else if (PoleClan == 2) {
  2758. Clan2PoleIndex += 1;
  2759. PoleIndex = Clan2PoleIndex;
  2760. }
  2761.  
  2762. if(PoleIndex >= 0) {
  2763. declare Integer OpposingClan = 3-PoleClan;
  2764. declare Text ClanTextColor = Teams[2-PoleClan].ColorText;
  2765. declare Real ServerCapture = Pole.Gauge.ValueReal;
  2766.  
  2767. if(ServerCapture != CurrentClanPoles[OpposingClan][PoleIndex]) {
  2768. CurrentClanPoles[OpposingClan][PoleIndex] = ServerCapture;
  2769. HighlightTimer[OpposingClan][PoleIndex] = Now + 500;
  2770. }
  2771.  
  2772. if(ServerCapture >= 0.01) {
  2773. PoleGauge[OpposingClan][PoleIndex].Show();
  2774. }
  2775.  
  2776. if(ServerCapture >= 1.) {
  2777. PoleFrame[OpposingClan][PoleIndex].Hide();
  2778. } else if(HighlightTimer[OpposingClan][PoleIndex] > Now) {
  2779. PoleQuad[OpposingClan][PoleIndex].ImageUrl = "{{{ImgPoleCapture}}}";
  2780. } else {
  2781. PoleQuad[OpposingClan][PoleIndex].ImageUrl = "{{{ImgPole}}}";
  2782. }
  2783.  
  2784. declare Text CaptureLevel = MathLib::NearestInteger(ServerCapture*100)^"%";
  2785. declare Real FakeValue = (MathLib::Sqrt(ServerCapture) + ServerCapture) / 2;
  2786. PoleGauge[OpposingClan][PoleIndex].SetRatio(FakeValue);
  2787. }
  2788. }
  2789. """;
  2790. +++MarkersML_ScriptLoop+++
  2791. MLPage ^= """
  2792. }
  2793. }
  2794. --></script>""";
  2795.  
  2796. declare Real PoleIdLabelYOffset = 1.8;//1.5;//2.;
  2797. declare Real WidthFactor = 9./16.;
  2798. declare Real ImgSize = 9.;//8.;//10.;
  2799. declare Integer NbPoles = ClanPoles[1].count-1;
  2800.  
  2801. //<gauge id="PoleGauge{{{I}}}_{{{ClanIndex}}}" posn="-5 {{{ImgSize}}}" halign="left" sizen="{{{ImgSize}}} {{{ImgSize}}}" clan="{{{3-ClanIndex}}}" style="EnergyBar" drawbg="false" rotation="0"/>
  2802.  
  2803. for(ClanIndex, 1, 2) {
  2804. declare Vec3 ClanColor = Teams[2-ClanIndex].ColorPrimary;
  2805. declare Text ClanColorTextVector = """{{{ClanColor.X}}} {{{ClanColor.Y}}} {{{ClanColor.Z}}} 1.""";
  2806. declare Text ClanTextColor = Teams[2-ClanIndex].ColorText;
  2807. for (I, 0, NbPoles) {
  2808. declare PoleZIndice = (((ClanIndex-1)*NbPoles) + I);
  2809. declare Pole <=> ClanPoles[ClanIndex][I];
  2810. MLPage ^= """
  2811. <frame id="PoleMarker{{{Pole.Id}}}">
  2812. <frame id="PoleFrame{{{I}}}_{{{ClanIndex}}}" posn="0 0 {{{PoleZIndice}}}" >
  2813. <gauge id="PoleGauge{{{I}}}_{{{ClanIndex}}}" posn="2.5 -3. -1" sizen="{{{ImgSize*1.5}}} 6." color="{{{ClanColorTextVector}}}" style="EnergyBar" drawbg="false" rotation="-90" hidden="1" drawblockbg="false" />
  2814. <label posn="0 9" halign="center" id="PoleGaugeLabel{{{I}}}_{{{ClanIndex}}}" textsize="1" />
  2815. <quad halign="center" valign="center" sizen="{{{WidthFactor*ImgSize}}} {{{ImgSize}}}" image="{{{
  2816. ImgPole}}}" id="PoleQuad{{{I}}}_{{{ClanIndex}}}" colorize="{{{
  2817. ClanColor.X}}} {{{ClanColor.Y}}} {{{ClanColor.Z}}}" autoscale="False" />
  2818. <label id="PoleIndexLabel{{{I}}}_{{{ClanIndex}}}" halign="center" valign="center" posn="0 {{{PoleIdLabelYOffset}}}" text="{{{ClanTextColor}}}{{{GetLetterFromNumber(G_PolesIndice[Pole.Id])}}}" textsize="1" />
  2819. </frame>
  2820. </frame>""";
  2821. }
  2822. }
  2823.  
  2824.  
  2825. +++MarkersML_Markups+++
  2826. return MLPage;
  2827. }
  2828.  
  2829. Void ResetAllUIs()
  2830. {
  2831. UIManager.UIAll.BigMessage ="";
  2832. UIManager.UIAll.StatusMessage ="";
  2833.  
  2834. if( UIManager.UIAll.UILayers.existskey(G_LayerRoundInfoId) ) {
  2835. declare Removed = UIManager.UIAll.UILayers.removekey(G_LayerRoundInfoId);
  2836. }
  2837.  
  2838. // Remove markers
  2839. foreach (UI in UIManager.UI) {
  2840. UI.MarkersXML = "";
  2841. }
  2842. }
  2843.  
  2844. Void UpdateTimeLeftUI(CSmPlayer Player, Integer CurrentAckClan, Integer DurationInSeconds) {
  2845. declare UI <=> UIManager.GetUI(Player);
  2846. if (UI == Null) return;
  2847.  
  2848. declare netwrite Integer BattleWaves_TimeLeft for UI;
  2849. declare netwrite Integer BattleWaves_AtkClan for UI;
  2850.  
  2851. BattleWaves_AtkClan = CurrentAckClan;
  2852. BattleWaves_TimeLeft = DurationInSeconds;
  2853. }
  2854.  
  2855. Text BuildTimeLeftManialink(Integer _WavesDuration) {
  2856. // declare EmblemSize = 18;
  2857. declare ArrowsHeight = 18;
  2858. declare EmblemOffset = 24;
  2859.  
  2860. declare Text ImgActionLeft = C_ImgBaseDir^"action_left.dds";
  2861. declare Text ImgActionRight = C_ImgBaseDir^"action_right.dds";
  2862.  
  2863. declare Vec3 ColorClan1 = Teams[1].ColorPrimary;
  2864. declare Vec3 ColorClan2 = Teams[0].ColorPrimary;
  2865.  
  2866. declare MLText = """
  2867. <manialink version="1" name="Battle:TimeLeft">
  2868. <frame posn="0 63 40" halign="center" valign="center" hidden="1" id="FrameTimeLeft">
  2869. <frame posn="0 4">
  2870. <label posn="0 4" halign="center" valign="center" style="TextRaceMessageBig" textsize="4" id="LabelAttack" />
  2871. <label posn="0 -2" halign="center" valign="center" style="TextRaceMessageBig" textsize="4" id="Label_AdditionalRules" />
  2872. <label posn="0 -8" halign="center" valign="center" style="TextRaceMessageBig" textsize="4" id="LabelTimeLeft" />
  2873. </frame>
  2874. </frame>
  2875. <script><!--
  2876. #Include "MathLib" as MathLib
  2877. #Include "TextLib" as TextLib
  2878.  
  2879. main() {
  2880. declare netread Integer BattleWaves_TimeLeft for UI;
  2881. declare netread Integer BattleWaves_AtkClan for UI;
  2882. declare netread Boolean Battle_IsBeginner for UI;
  2883. declare netread Boolean Net_OvertimeActivated for Teams[0];
  2884. declare netread Integer Net_OvertimeAdvantage for Teams[0];
  2885.  
  2886. declare CMlFrame FrameTimeLeft <=> (Page.GetFirstChild("FrameTimeLeft") as CMlFrame);
  2887. declare CMlLabel LabelTimeLeft <=> (Page.GetFirstChild("LabelTimeLeft") as CMlLabel);
  2888. declare CMlLabel LabelAttack <=> (Page.GetFirstChild("LabelAttack") as CMlLabel);
  2889. declare CMlLabel Label_AdditionalRules <=> (Page.GetFirstChild("Label_AdditionalRules") as CMlLabel);
  2890.  
  2891. declare Clan1Color = Teams[0].ColorText;
  2892. declare Clan2Color = Teams[1].ColorText;
  2893.  
  2894. declare PrevAtkClan = -1;
  2895. declare CurrentPlayerClan = -1;
  2896. declare PrevPlayerClan = -1;
  2897. declare PrevOvertimeActivated = False;
  2898. declare PrevOvertimeAdvantage = -1;
  2899. declare PrevBigMessage = "";
  2900.  
  2901. while(True) {
  2902. sleep(100);
  2903.  
  2904. if (GUIPlayer != Null) CurrentPlayerClan = GUIPlayer.CurrentClan;
  2905. else if (InputPlayer != Null && !InputPlayer.RequestsSpectate) CurrentPlayerClan = InputPlayer.CurrentClan;
  2906. else CurrentPlayerClan = -1;
  2907.  
  2908. if (
  2909. PrevAtkClan != BattleWaves_AtkClan
  2910. || PrevPlayerClan != CurrentPlayerClan
  2911. || PrevOvertimeActivated != Net_OvertimeActivated
  2912. || PrevOvertimeAdvantage != Net_OvertimeAdvantage
  2913. || PrevBigMessage != UI.BigMessage
  2914. ) {
  2915. PrevAtkClan = BattleWaves_AtkClan;
  2916. PrevPlayerClan = CurrentPlayerClan;
  2917. PrevOvertimeActivated = Net_OvertimeActivated;
  2918. PrevOvertimeAdvantage = Net_OvertimeAdvantage;
  2919. PrevBigMessage = UI.BigMessage;
  2920.  
  2921. if (BattleWaves_AtkClan <= 0) {
  2922. FrameTimeLeft.Visible = False;
  2923. } else {
  2924. FrameTimeLeft.Visible = True;
  2925.  
  2926. if (CurrentPlayerClan == BattleWaves_AtkClan) {
  2927. LabelAttack.SetText(TextLib::Compose("$s%1", _("|Imperative|Attack")));
  2928. if (Battle_IsBeginner) {
  2929. Label_AdditionalRules.SetText(_("Capture the poles of the opposing team!"));
  2930. LabelTimeLeft.RelativePosition.Y = -8.;
  2931. } else if (Net_OvertimeActivated && UI.BigMessage == "") {
  2932. declare TeamA = Net_OvertimeAdvantage - 1;
  2933. declare TeamB = 3 - Net_OvertimeAdvantage - 1;
  2934. if (Teams.existskey(TeamA) && Teams.existskey(TeamB)) {
  2935. if (BattleWaves_AtkClan == Net_OvertimeAdvantage) {
  2936. Label_AdditionalRules.Value = TextLib::Compose(
  2937. "{{{_("|%1 is a team name|$<%1$> must attack a pole to win.")}}}",
  2938. Teams[TeamA].ColorizedName
  2939. );
  2940. } else {
  2941. Label_AdditionalRules.Value = TextLib::Compose(
  2942. "{{{_("|%1 and %2 are teams names|$<%1$> must equal $<%2$> score.")}}}",
  2943. Teams[TeamB].ColorizedName,
  2944. Teams[TeamA].ColorizedName
  2945. );
  2946. }
  2947. LabelTimeLeft.RelativePosition.Y = -8.;
  2948. } else {
  2949. Label_AdditionalRules.SetText("");
  2950. LabelTimeLeft.RelativePosition.Y = -2.;
  2951. }
  2952. } else {
  2953. Label_AdditionalRules.SetText("");
  2954. LabelTimeLeft.RelativePosition.Y = -2.;
  2955. }
  2956. } else if (CurrentPlayerClan == 3 - BattleWaves_AtkClan) {
  2957. LabelAttack.SetText(TextLib::Compose("$s%1", _("|Imperative|Defend")));
  2958. if (Battle_IsBeginner) {
  2959. Label_AdditionalRules.SetText(_("Prevent your poles from being captured!"));
  2960. LabelTimeLeft.RelativePosition.Y = -8.;
  2961. } else if (Net_OvertimeActivated && UI.BigMessage == "") {
  2962. declare TeamA = Net_OvertimeAdvantage - 1;
  2963. declare TeamB = 3 - Net_OvertimeAdvantage - 1;
  2964. if (Teams.existskey(TeamA) && Teams.existskey(TeamB)) {
  2965. if (BattleWaves_AtkClan == Net_OvertimeAdvantage) {
  2966. Label_AdditionalRules.Value = TextLib::Compose(
  2967. "{{{_("|%1 is a team name|$<%1$> must attack a pole to win.")}}}",
  2968. Teams[TeamA].ColorizedName
  2969. );
  2970. } else {
  2971. Label_AdditionalRules.Value = TextLib::Compose(
  2972. "{{{_("|%1 and %2 are teams names|$<%1$> must equal $<%2$> score.")}}}",
  2973. Teams[TeamB].ColorizedName,
  2974. Teams[TeamA].ColorizedName
  2975. );
  2976. }
  2977. LabelTimeLeft.RelativePosition.Y = -8.;
  2978. } else {
  2979. Label_AdditionalRules.SetText("");
  2980. LabelTimeLeft.RelativePosition.Y = -2.;
  2981. }
  2982. } else {
  2983. Label_AdditionalRules.SetText("");
  2984. LabelTimeLeft.RelativePosition.Y = -2.;
  2985. }
  2986. } else {
  2987. if (Teams.existskey(BattleWaves_AtkClan-1)) {
  2988. LabelAttack.SetText(TextLib::Compose("{{{_("|TeamName is attacking|$<%1$> is attacking")}}}", Teams[BattleWaves_AtkClan-1].ColorizedName));
  2989. if (Net_OvertimeActivated && UI.BigMessage == "") {
  2990. declare TeamA = Net_OvertimeAdvantage - 1;
  2991. declare TeamB = 3 - Net_OvertimeAdvantage - 1;
  2992. if (Teams.existskey(TeamA) && Teams.existskey(TeamB)) {
  2993. if (BattleWaves_AtkClan == Net_OvertimeAdvantage) {
  2994. Label_AdditionalRules.Value = TextLib::Compose(
  2995. "{{{_("|%1 is a team name|$<%1$> must attack a pole to win.")}}}",
  2996. Teams[TeamA].ColorizedName
  2997. );
  2998. } else {
  2999. Label_AdditionalRules.Value = TextLib::Compose(
  3000. "{{{_("|%1 and %2 are teams names|$<%1$> must equal $<%2$> score.")}}}",
  3001. Teams[TeamB].ColorizedName,
  3002. Teams[TeamA].ColorizedName
  3003. );
  3004. }
  3005. LabelTimeLeft.RelativePosition.Y = -8.;
  3006. } else {
  3007. Label_AdditionalRules.SetText("");
  3008. LabelTimeLeft.RelativePosition.Y = -2.;
  3009. }
  3010. } else {
  3011. Label_AdditionalRules.SetText("");
  3012. LabelTimeLeft.RelativePosition.Y = -2.;
  3013. }
  3014. } else {
  3015. LabelAttack.SetText("");
  3016. Label_AdditionalRules.SetText("");
  3017. LabelTimeLeft.RelativePosition.Y = -2.;
  3018. }
  3019. }
  3020. }
  3021. }
  3022.  
  3023. if(BattleWaves_TimeLeft <= {{{_WavesDuration}}}) {
  3024. LabelTimeLeft.SetText("$s"^BattleWaves_TimeLeft);
  3025. } else {
  3026. LabelTimeLeft.SetText("");
  3027. }
  3028. }
  3029. }
  3030. --></script>
  3031. </manialink>""";
  3032.  
  3033.  
  3034. return MLText;
  3035. }
  3036.  
  3037. Void CreateRulesReminderLayer() {
  3038. if(! C_DisplayRulesReminder) return;
  3039.  
  3040. declare Text WelcomeBgImage = C_ImgBaseDir^"WelcomeBg.dds";
  3041.  
  3042. declare Text TitleText = _("You are spectating the game");
  3043. declare Text ModeName = _("Battle Mode");
  3044. declare Text RulesReminder = _("Help your team capture the poles of the opposing team to win.\nYour contribution to victory is given by capture (Cap), attack (Atk) and defense (Def) scores.\nYour ranking depends on the number of hits you performed (Hits)
  3045.  
  3046. during the match.");
  3047. declare Text DoNotShowAgain = _("Do Not Show Again");
  3048. declare Text Close = _("Close");
  3049.  
  3050. declare Integer WindowWidth = 270;
  3051. declare Integer WindowHeight = 25;
  3052. declare Real WindowX = 0.;
  3053. declare Real WindowY = 30.;
  3054.  
  3055. declare Text MLText = """
  3056. <script><!--
  3057. // for the "do not show again" feature
  3058. declare persistent Boolean NadeoBattle_PersistentShowRulesReminder for This = True;
  3059.  
  3060. declare Boolean _TabsLib_ScoresLayerIsVisible for UI;
  3061. declare Boolean _TabsLib_AltLayerIsVisible for UI;
  3062.  
  3063.  
  3064. // NadeoBattle_PersistentShowRulesReminder = True; // Uncomment for testing purpose
  3065.  
  3066. declare netwrite Boolean Battle_UIToServShowRulesReminder for UI = True;
  3067. declare netread Boolean Battle_ServToUIShowFrame for UI;
  3068. declare netread Integer Battle_UIRoundPhase for UI;
  3069.  
  3070. Battle_UIToServShowRulesReminder = True;
  3071. if(! NadeoBattle_PersistentShowRulesReminder) {
  3072. Battle_UIToServShowRulesReminder = False;
  3073. return;
  3074. }
  3075.  
  3076. declare Button_DoNotShowAgain <=> (Page.GetFirstChild("Button_DoNotShowAgain") as CMlLabel);
  3077. declare Button_Close <=> (Page.GetFirstChild("Button_Close") as CMlLabel);
  3078. declare RulesReminderMainFrame <=> (Page.GetFirstChild("RulesReminderMainFrame") as CMlFrame);
  3079.  
  3080. declare Boolean ShowFrame = False;
  3081. declare Boolean SwitchShowFrame = False;
  3082. while(True) {
  3083. yield;
  3084.  
  3085. if(Battle_ServToUIShowFrame != SwitchShowFrame) {
  3086. SwitchShowFrame = Battle_ServToUIShowFrame;
  3087. ShowFrame = True;
  3088. }
  3089.  
  3090. if(
  3091. ! IsSpectatorMode ||
  3092. (_TabsLib_ScoresLayerIsVisible || _TabsLib_AltLayerIsVisible) ||
  3093. (Battle_UIRoundPhase != {{{C_RoundPhase_Playing}}}))
  3094. {
  3095. RulesReminderMainFrame.Hide();
  3096. continue;
  3097. }
  3098.  
  3099. if(ShowFrame) {
  3100. RulesReminderMainFrame.Show();
  3101. }
  3102.  
  3103. foreach(Event in PendingEvents) {
  3104. switch(Event.Type){
  3105. case CMlEvent::Type::MouseClick: {
  3106. if(Event.ControlId == "Button_DoNotShowAgain") {
  3107. NadeoBattle_PersistentShowRulesReminder = False;
  3108. Battle_UIToServShowRulesReminder = False;
  3109. RulesReminderMainFrame.Hide();
  3110. return; // End of this behavior
  3111. }
  3112. if(Event.ControlId == "Button_Close") {
  3113. RulesReminderMainFrame.Hide();
  3114. ShowFrame = False;
  3115. }
  3116. }
  3117. case CMlEvent::Type::KeyPress: {
  3118. if(Event.CharPressed == "2424832" ) { // F1
  3119. RulesReminderMainFrame.Hide();
  3120. ShowFrame = False;
  3121. }
  3122. }
  3123. }
  3124. }
  3125. }
  3126.  
  3127. --></script>
  3128. <frame id="RulesReminderMainFrame" hidden="true" posn="{{{WindowX}}} {{{WindowY}}} 100" >
  3129. <quad posn="0 -2" halign="center" valign="center" sizen="292 44" image="{{{WelcomeBgImage}}}" />
  3130. <label posn="0 {{{(WindowHeight/2)-3}}}" halign="center" valign="center" text="{{{TitleText}}}" textsize="5" />
  3131. <label posn="{{{-(WindowWidth/2)+2}}} {{{(WindowHeight/2)-8}}}" halign="left" valign="center" text="{{{ModeName}}}" textsize="3" textprefix="$0f0"/>
  3132. <label posn="{{{-(WindowWidth/2)+2}}} {{{(WindowHeight/2)-12}}}" halign="left" valign="center" text="{{{RulesReminder}}}" textsize="2"/>
  3133. <label posn="{{{(WindowWidth/2)-2}}} {{{-(WindowHeight/2)+2}}}" halign="right" valign="center" text="{{{DoNotShowAgain}}}" style="CardButtonSmall" ScriptEvents="true" id="Button_DoNotShowAgain" />
  3134. <label posn="{{{(WindowWidth/2)-42}}} {{{-(WindowHeight/2)+2}}}" halign="right" valign="center" text="{{{Close}}}" style="CardButtonSmall" ScriptEvents="true" id="Button_Close" />
  3135. <!--<label halign="center" valign="bottom" posn="0 {{{-(WindowHeight/2)}}}" text="{{{
  3136. _("Press $<$o$f00F1$> to close this window.")}}}" />-->
  3137. </frame>
  3138. """;
  3139.  
  3140. Layers::Create("RulesReminder", MLText);
  3141. Layers::Attach("RulesReminder");
  3142. }
  3143.  
  3144. // ---------------------------------- //
  3145. /// Initialize the warm up properties
  3146. Void InitWarmUp() {
  3147. if (S_NbPlayersPerTeamMax > 0) {
  3148. if (WarmUp2::GroupExists("Clan1")) WarmUp2::SetSlotsNb("Clan1", S_NbPlayersPerTeamMax);
  3149. else WarmUp2::CreateGroup("Clan1", S_NbPlayersPerTeamMax);
  3150. if (WarmUp2::GroupExists("Clan2")) WarmUp2::SetSlotsNb("Clan2", S_NbPlayersPerTeamMax);
  3151. else WarmUp2::CreateGroup("Clan2", S_NbPlayersPerTeamMax);
  3152. WarmUp2::DisplayClanSelection(True);
  3153. } else {
  3154. WarmUp2::DestroyGroup("Clan1");
  3155. WarmUp2::DestroyGroup("Clan2");
  3156. WarmUp2::DisplayClanSelection(False);
  3157. }
  3158. }
  3159.  
  3160. // ---------------------------------- //
  3161. /** Check if the spawns of the players are limited to a specific list
  3162. *
  3163. * @return True if the player spawns are limited, False otherwise
  3164. */
  3165. Boolean SpawnIsLimited() {
  3166. if (WarmUp2::GroupExists("Clan1") && WarmUp2::GroupExists("Clan2")) return True;
  3167. return False;
  3168. }
  3169.  
  3170. // ---------------------------------- //
  3171. /** Check if a player is spawnable
  3172. *
  3173. * @param _Player The player to check
  3174. *
  3175. * @return True if the player is spawnable, false otherwise
  3176. */
  3177. Boolean IsSpawnable(CSmPlayer _Player) {
  3178. if (_Player == Null) return False;
  3179. if (_Player.User.RequestsSpectate) return False;
  3180. if (!SpawnIsLimited()) return True;
  3181.  
  3182. if (WarmUp2::GetPlayerSlot(_Player) <= 0) return False;
  3183. if (_Player.CurrentClan == 1 && WarmUp2::GetPlayerGroup(_Player) == "Clan1") return True;
  3184. if (_Player.CurrentClan == 2 && WarmUp2::GetPlayerGroup(_Player) == "Clan2") return True;
  3185.  
  3186. return False;
  3187. }
  3188.  
  3189. Void ComputeCaptureMaxValue() {
  3190. G_CaptureMaxValue = S_CaptureMaxValue - 100; // small margin to ensure the pole is captured on time.
  3191. if(G_CaptureMaxValue < 500) G_CaptureMaxValue = 500; // 0.5 sec. min
  3192. }
  3193.  
  3194. /**
  3195. * @return True iff the squared distance between A and B is lower than _SqDistance.
  3196. * i.e. ||AB||² <= _SqDistance
  3197. */
  3198. Boolean SqCloserThan(Vec3 _A, Vec3 _B, Real _SqDistance) {
  3199. declare Vec3 VecDistance = _A - _B;
  3200. declare Real ABSqDistance = (VecDistance.X*VecDistance.X) + (VecDistance.Y*VecDistance.Y) + (VecDistance.Z*VecDistance.Z);
  3201.  
  3202. return ABSqDistance <= _SqDistance;
  3203. }
  3204.  
  3205. // ---------------------------------- //
  3206. /** Wait for enough players to play
  3207. *
  3208. * @param _Duration Duration of the warm up
  3209. * @param _MinimumNbPlayers The number of players to wait in each clan before starting the map if there's no duration
  3210. */
  3211. Void WaitForPlayers(Integer _MinimumNbPlayers, Integer _Duration) {
  3212. declare OldSequence = UIManager.UIAll.UISequence;
  3213. UIManager.UIAll.UISequence = CUIConfig::EUISequence::Playing;
  3214. UIManager.UIAll.BigMessageSound = CUIConfig::EUISound::Warning;
  3215. StartTime = Now;
  3216. if (_Duration > 0) {
  3217. UIManager.UIAll.CountdownEndTime = Now + (_Duration * 1000);
  3218. UIManager.UIAll.BigMessage = _("Warm up");
  3219. } else {
  3220. UIManager.UIAll.BigMessage = _("Waiting for players in each team...");
  3221. }
  3222.  
  3223. foreach (Player in AllPlayers) {
  3224. declare UI <=> UIManager.GetUI(Player);
  3225. if (UI != Null) Tabs::UseTabs(UI, "ScoresTab");
  3226. }
  3227.  
  3228. while (!ServerShutdownRequested && !MatchEndRequested) {
  3229. MM_Yield();
  3230.  
  3231. if (_Duration > 0) {
  3232. if (Now >= UIManager.UIAll.CountdownEndTime) break;
  3233. } else {
  3234. if (ClansNbPlayers[1] >= _MinimumNbPlayers && ClansNbPlayers[2] >= _MinimumNbPlayers) break;
  3235. }
  3236.  
  3237. SM::UnspawnPlayersChangingClan();
  3238. foreach(Player in Players) {
  3239. if (Player.SpawnStatus == CSmPlayer::ESpawnStatus::NotSpawned) {
  3240. declare Clan = Battle_GetRequestedClan(Player);
  3241. declare Spawn <=> Map::GetPlayerSpawn("Spawn", Clan);
  3242. if (Spawn != Null) SM::SpawnPlayer(Player, Clan, Spawn);
  3243. }
  3244. }
  3245.  
  3246. foreach (Event in PendingEvents) {
  3247. if (Event.Type == CSmModeEvent::EType::OnPlayerAdded) {
  3248. declare UI <=> UIManager.GetUI(Event.Player);
  3249. if (UI != Null) Tabs::UseTabs(UI, "ScoresTab");
  3250. }
  3251. }
  3252.  
  3253. WarmUp2::ManageEvents();
  3254. }
  3255.  
  3256. SM::UnspawnAllPlayers();
  3257. StartTime = -1;
  3258. UIManager.UIAll.CountdownEndTime = -1;
  3259. UIManager.UIAll.BigMessage = "";
  3260. UIManager.UIAll.UISequence = OldSequence;
  3261.  
  3262. // ---------------------------------- //
  3263. // Update the players clublinks
  3264. if (S_ForceClublinkTeam1 == "" && S_ForceClublinkTeam2 == "") Clublink::DefineTeamAuto();
  3265. else Clublink::DefineTeamFromUrl(S_ForceClublinkTeam1, S_ForceClublinkTeam2);
  3266. }
  3267.  
  3268. Void DoWarmUp() {
  3269. XmlRpc::BeginWarmUp();
  3270.  
  3271. // Shutdown the poles during warmup
  3272. foreach (Goal in MapLandmarks_Gauge) {
  3273. Goal.Gauge.Clan = 0;
  3274. Goal.Gauge.Speed = 0;
  3275. Goal.Gauge.Value = 0;
  3276. Goal.Gauge.Max = 1000;
  3277. Goal.Gauge.Captured = False;
  3278. }
  3279.  
  3280. UIManager.UIAll.UISequence = CUIConfig::EUISequence::Playing;
  3281. UIManager.UIAll.BigMessageSound = CUIConfig::EUISound::PhaseChange;
  3282. UIManager.UIAll.BigMessageSoundVariant = 0;
  3283. UIManager.UIAll.StatusMessage = _("Press F6 once you're ready.");
  3284. UIManager.UIAll.BigMessage = TL::Compose("$f90%1", _("Warm-up"));
  3285.  
  3286. // Wait players sycnhro
  3287. Mode::Synchro_DoBarrier();
  3288. SM::UnspawnAllPlayers();
  3289. foreach (Player in AllPlayers) {
  3290. SetPlayerClan(Player, Battle_GetRequestedClan(Player));
  3291. if (Player.CurrentClan == 1) WarmUp2::SetPlayerGroup(Player, "Clan1");
  3292. else if (Player.CurrentClan == 2) WarmUp2::SetPlayerGroup(Player, "Clan2");
  3293.  
  3294. declare UI <=> UIManager.GetUI(Player);
  3295. if (UI != Null) Tabs::UseTabs(UI, "ScoresTab");
  3296. }
  3297.  
  3298. WarmUp2::Clean();
  3299. WarmUp2::Begin();
  3300. WarmUp2::Fill();
  3301.  
  3302. declare PrevWarmUpDuration = S_WarmUpDuration-1;
  3303.  
  3304. while (!WarmUp2::Stop()) {
  3305. MM_Yield();
  3306.  
  3307. // Let the server sleep if there's no players on it
  3308. if (PlayersNbTotal <= 0) continue;
  3309.  
  3310. foreach (Player in Players) {
  3311. declare RequestedClan = Battle_GetRequestedClan(Player);
  3312. if (Player.CurrentClan != RequestedClan) {
  3313. UnspawnPlayer(Player);
  3314. SetPlayerClan(Player, RequestedClan);
  3315. if (Player.CurrentClan == 1) WarmUp2::SetPlayerGroup(Player, "Clan1");
  3316. else if (Player.CurrentClan == 2) WarmUp2::SetPlayerGroup(Player, "Clan2");
  3317. }
  3318. }
  3319.  
  3320. if (PrevWarmUpDuration != S_WarmUpDuration) {
  3321. PrevWarmUpDuration = S_WarmUpDuration;
  3322.  
  3323. declare LongTimer = S_WarmUpDuration*1000;
  3324. declare ShortTimer = 5000;
  3325. if (LongTimer <= 0) { LongTimer = 0; ShortTimer = 0; }
  3326.  
  3327. WarmUp2::SetGroupTimers("Clan1", [ShortTimer => [-1, S_NbPlayersPerTeamMin], LongTimer => [1, S_NbPlayersPerTeamMin]]);
  3328. WarmUp2::SetGroupTimers("Clan2", [ShortTimer => [-1, S_NbPlayersPerTeamMin], LongTimer => [1, S_NbPlayersPerTeamMin]]);
  3329. }
  3330.  
  3331. WarmUp2::Fill();
  3332. WarmUp2::Loop();
  3333.  
  3334. foreach(Player in Players) {
  3335. if (Player.SpawnStatus == CSmPlayer::ESpawnStatus::NotSpawned) {
  3336. declare Spawn <=> Map::GetPlayerSpawn("Spawn", Battle_GetRequestedClan(Player));
  3337. if (Spawn != Null) SM::SpawnPlayer(Player, Player.CurrentClan, Spawn);
  3338. }
  3339. }
  3340.  
  3341. foreach (Event in PendingEvents) {
  3342. if (Event.Type == CSmModeEvent::EType::OnPlayerAdded) {
  3343. declare UI <=> UIManager.GetUI(Event.Player);
  3344. if (UI != Null) Tabs::UseTabs(UI, "ScoresTab");
  3345. }
  3346. }
  3347.  
  3348. WarmUp2::ManageEvents();
  3349. }
  3350.  
  3351. WarmUp2::End();
  3352.  
  3353. UIManager.UIAll.UISequence = CUIConfig::EUISequence::EndRound;
  3354. UIManager.UIAll.StatusMessage = "";
  3355. UIManager.UIAll.BigMessage = "";
  3356. SM::UnspawnAllPlayers();
  3357.  
  3358. // ---------------------------------- //
  3359. // Update the players clublinks
  3360. if (S_ForceClublinkTeam1 == "" && S_ForceClublinkTeam2 == "") Clublink::DefineTeamAuto();
  3361. else Clublink::DefineTeamFromUrl(S_ForceClublinkTeam1, S_ForceClublinkTeam2);
  3362.  
  3363. XmlRpc::EndWarmUp();
  3364. }
  3365.  
  3366. // ---------------------------------- //
  3367. /** Transfert player for auto team balance
  3368. *
  3369. * @param _CountClan1 Number of players in clan 1
  3370. * @param _CountClan2 Number of players in clan 2
  3371. * @param _HitClan1 Number of hits in clan 1
  3372. * @param _HitClan2 Number of hits in clan 2
  3373. *
  3374. * @return True if a player was transfered, False otherwise
  3375. */
  3376. Boolean AutoTeamBalanceRound_Recursive(Integer _CountClan1, Integer _CountClan2, Integer _HitClan1, Integer _HitClan2) {
  3377. if (_CountClan1 > _CountClan2) {
  3378. declare Diff = (_HitClan1 - _HitClan2) / 2;
  3379. if (Diff < 0) Diff = 0;
  3380. declare MinDiff = -1;
  3381. declare CSmPlayer TransfertPlayer;
  3382.  
  3383. foreach (Player in Players) {
  3384. if (Player.Score == Null || Player.CurrentClan != 1) continue;
  3385. declare CurDiff = MathLib::Abs(Diff - Player.Score.RoundPoints);
  3386. if (MinDiff < 0 || CurDiff < MinDiff) {
  3387. MinDiff = CurDiff;
  3388. TransfertPlayer <=> Player;
  3389. if (MinDiff == 0) break;
  3390. }
  3391. }
  3392.  
  3393. if (TransfertPlayer != Null) {
  3394. declare Battle_BalanceClan for TransfertPlayer = -1;
  3395. Battle_BalanceClan = 2;
  3396.  
  3397. UnspawnPlayer(TransfertPlayer);
  3398. SetPlayerClan(TransfertPlayer, Battle_BalanceClan);
  3399.  
  3400. return True;
  3401. }
  3402. } else if (_CountClan2 > _CountClan1) {
  3403. declare Diff = (_HitClan2 - _HitClan1) / 2;
  3404. if (Diff < 0) Diff = 0;
  3405. declare MinDiff = -1;
  3406. declare CSmPlayer TransfertPlayer;
  3407.  
  3408. foreach (Player in Players) {
  3409. if (Player.Score == Null || Player.CurrentClan != 2) continue;
  3410. declare CurDiff = MathLib::Abs(Diff - Player.Score.RoundPoints);
  3411. if (MinDiff < 0 || CurDiff < MinDiff) {
  3412. MinDiff = CurDiff;
  3413. TransfertPlayer <=> Player;
  3414. if (MinDiff == 0) break;
  3415. }
  3416. }
  3417.  
  3418. if (TransfertPlayer != Null) {
  3419. declare Battle_BalanceClan for TransfertPlayer = -1;
  3420. Battle_BalanceClan = 1;
  3421.  
  3422. UnspawnPlayer(TransfertPlayer);
  3423. SetPlayerClan(TransfertPlayer, Battle_BalanceClan);
  3424.  
  3425. return True;
  3426. }
  3427. }
  3428.  
  3429. return False;
  3430. }
  3431.  
  3432. // ---------------------------------- //
  3433. /// Auto team balance depending on hit and players number
  3434. Void AutoTeamBalanceRound() {
  3435. declare IterationCount = 0;
  3436.  
  3437. // Set the player in the clan they requested before doing the balance
  3438. foreach (Player in Players) {
  3439. declare Battle_BalanceClan for Player = -1;
  3440. declare Battle_PrevClan for Player = -1;
  3441. Battle_BalanceClan = -1;
  3442. Battle_PrevClan = Player.CurrentClan;
  3443.  
  3444. UnspawnPlayer(Player);
  3445. SetPlayerClan(Player, Battle_GetRequestedClan(Player));
  3446. }
  3447.  
  3448. while (True) {
  3449. IterationCount += 1;
  3450. if (IterationCount > 128) break;
  3451.  
  3452. declare CountClan1 = 0;
  3453. declare CountClan2 = 0;
  3454. declare HitClan1 = 0;
  3455. declare HitClan2 = 0;
  3456.  
  3457. foreach (Player in Players) {
  3458. if (Player.CurrentClan == 1) {
  3459. CountClan1 += 1;
  3460. if (Player.Score != Null) HitClan1 += Player.Score.RoundPoints;
  3461. } else if (Player.CurrentClan == 2) {
  3462. CountClan2 += 1;
  3463. if (Player.Score != Null) HitClan2 += Player.Score.RoundPoints;
  3464. }
  3465. }
  3466.  
  3467. declare CountDiff = MathLib::Abs(CountClan1 - CountClan2);
  3468. if (CountDiff < S_AutoBalanceDelta || CountDiff < 2) break;
  3469.  
  3470. declare Transfered = AutoTeamBalanceRound_Recursive(CountClan1, CountClan2, HitClan1, HitClan2);
  3471. if (!Transfered) break;
  3472.  
  3473. MM_Yield();
  3474. }
  3475.  
  3476. foreach (Player in Players) {
  3477. declare Battle_PrevClan for Player = -1;
  3478. if (Battle_PrevClan >= 0 && Battle_PrevClan != Player.CurrentClan && (Player.CurrentClan == 1 || Player.CurrentClan == 2)) {
  3479. declare UI <=> UIManager.GetUI(Player);
  3480. if (UI != Null) UI.SendChat(TextLib::Compose(
  3481. _("|%1 is the name of the team|Auto team balance, you are transfered to the $<%1$> team."),
  3482. Teams[Player.CurrentClan-1].ColorizedName)
  3483. );
  3484. }
  3485. }
  3486. }
  3487.  
  3488. // ---------------------------------- //
  3489. /** Get the runners ranking
  3490. *
  3491. * @param _Level Can be "round" or "map"
  3492. *
  3493. * @return An array containing the ranking of the runners
  3494. */
  3495. Integer[Text] GetRunnersRanking(Text _Level) {
  3496. if (_Level == "map") {
  3497. declare Integer[Text] MapTop_CaptureTimePoints for This;
  3498. return MapTop_CaptureTimePoints;
  3499. }
  3500.  
  3501. declare Integer[Text] Ranking;
  3502. declare Integer[Text][Ident] CaptureTimeRanking;
  3503.  
  3504. foreach (Player in AllPlayers) {
  3505. declare Integer[Ident] RoundTop_CaptureTime for Player.Score;
  3506. foreach (PoleId => CaptureTime in RoundTop_CaptureTime) {
  3507. if (!CaptureTimeRanking.existskey(PoleId)) CaptureTimeRanking[PoleId] = Integer[Text];
  3508. CaptureTimeRanking[PoleId][Player.User.Login] = CaptureTime;
  3509. }
  3510. }
  3511.  
  3512. declare PointsRepartition = [10, 6, 4, 3, 2, 1];
  3513. foreach (PoleId => PoleRanking in CaptureTimeRanking) {
  3514. declare SortedRanking = PoleRanking.sort();
  3515. declare PointsKey = 0;
  3516. foreach (PlayerLogin => CaptureTime in SortedRanking) {
  3517. if (!Ranking.existskey(PlayerLogin)) Ranking[PlayerLogin] = 0;
  3518. declare Points = 0;
  3519. if (PointsRepartition.existskey(PointsKey)) Points = PointsRepartition[PointsKey];
  3520. Ranking[PlayerLogin] -= Points;
  3521. PointsKey += 1;
  3522. }
  3523. }
  3524.  
  3525. declare Text EngageLogin for This;
  3526. if (EngageLogin != "") {
  3527. if (!Ranking.existskey(EngageLogin)) Ranking[EngageLogin] = 0;
  3528. Ranking[EngageLogin] -= 10;
  3529. }
  3530.  
  3531. return Ranking;
  3532. }
  3533.  
  3534. // ---------------------------------- //
  3535. /// Add the round points to the map points
  3536. Void UpdateMapRunnersRanking() {
  3537. declare RoundRanking = GetRunnersRanking("round");
  3538. declare Integer[Text] MapTop_CaptureTimePoints for This;
  3539.  
  3540. foreach (Login => Points in RoundRanking) {
  3541. if (!MapTop_CaptureTimePoints.existskey(Login)) MapTop_CaptureTimePoints[Login] = 0;
  3542. MapTop_CaptureTimePoints[Login] += Points;
  3543. }
  3544. }
  3545.  
  3546. // ---------------------------------- //
  3547. /// Reset the runners map ranking
  3548. Void ResetMapRunnersRanking() {
  3549. declare Integer[Text] MapTop_CaptureTimePoints for This;
  3550. MapTop_CaptureTimePoints.clear();
  3551. }
  3552.  
  3553. // ---------------------------------- //
  3554. /** Set the top 5 name and ranking
  3555. *
  3556. * @param _Name Name of the top 5
  3557. * @param _Ranking Ranking of the top 5
  3558. */
  3559. Void UpdateTop5(Text _Name, Integer[Text] _Ranking) {
  3560. declare netwrite Integer Net_RoundTop_Update for Teams[0];
  3561. declare netwrite Integer[Text] Net_RoundTop_Ranking for Teams[0];
  3562. declare netwrite Text Net_RoundTop_Name for Teams[0];
  3563.  
  3564. Net_RoundTop_Ranking = _Ranking;
  3565. Net_RoundTop_Name = _Name;
  3566. Net_RoundTop_Update = Now;
  3567. }
  3568.  
  3569. // ---------------------------------- //
  3570. /** Launch the top 5 sequence
  3571. *
  3572. * @param _Level Can be "round" or "map"
  3573. */
  3574. Void LaunchTop5Sequence(Text _Level) {
  3575. if (ServerShutdownRequested || MatchEndRequested) return;
  3576.  
  3577. declare PrevUISequence = UIManager.UIAll.UISequence;
  3578. UIManager.UIAll.UISequence = CUIConfig::EUISequence::EndRound;
  3579. UIManager.UIAll.UISequence = CUIConfig::EUISequence::Podium;
  3580. UIManager.UIAll.BigMessageSound = CUIConfig::EUISound::Silence;
  3581. Layers::Show("Top5");
  3582.  
  3583. declare Tops = ["Runners", "Attack", "Defense", "Capture", "Hits"];
  3584. if (!S_DisplayPoleRecords) {
  3585. declare Removed = Tops.remove("Runners");
  3586. }
  3587. if (S_DisplayTopsOnlyShooter) Tops = ["Hits"];
  3588. foreach (Top in Tops) {
  3589. declare Integer[Text] Ranking;
  3590.  
  3591. switch (Top) {
  3592. case "Runners": {
  3593. Ranking = GetRunnersRanking(_Level);
  3594. if (_Level == "round") {
  3595. UIManager.UIAll.StatusMessage = _("Best runner of the round");
  3596. } else {
  3597. UIManager.UIAll.StatusMessage = _("Best runner of the map");
  3598. }
  3599. }
  3600. case "Attack": {
  3601. if (_Level == "round") {
  3602. foreach (Player in AllPlayers) {
  3603. declare Integer Battle_ScoreAttack for Player;
  3604. Ranking[Player.User.Login] = -Battle_ScoreAttack;
  3605. }
  3606. UIManager.UIAll.StatusMessage = _("Best attacker of the round");
  3607. } else {
  3608. foreach (Player in AllPlayers) {
  3609. declare Integer MapAttack for Player;
  3610. Ranking[Player.User.Login] = -MapAttack;
  3611. }
  3612. UIManager.UIAll.StatusMessage = _("Best attacker of the map");
  3613. }
  3614. }
  3615. case "Defense": {
  3616. if (_Level == "round") {
  3617. foreach (Player in AllPlayers) {
  3618. declare Integer Battle_ScoreDefense for Player;
  3619. Ranking[Player.User.Login] = -Battle_ScoreDefense;
  3620. }
  3621. UIManager.UIAll.StatusMessage = _("Best defender of the round");
  3622. } else {
  3623. foreach (Player in AllPlayers) {
  3624. declare Integer MapDefense for Player;
  3625. Ranking[Player.User.Login] = -MapDefense;
  3626. }
  3627. UIManager.UIAll.StatusMessage = _("Best defender of the map");
  3628. }
  3629. }
  3630. case "Capture": {
  3631. if (_Level == "round") {
  3632. foreach (Player in AllPlayers) {
  3633. declare Integer Battle_ScoreCapture for Player;
  3634. Ranking[Player.User.Login] = -Battle_ScoreCapture;
  3635. }
  3636. UIManager.UIAll.StatusMessage = _("Best capturer of the round");
  3637. } else {
  3638. foreach (Player in AllPlayers) {
  3639. declare Integer MapCapture for Player;
  3640. Ranking[Player.User.Login] = -MapCapture;
  3641. }
  3642. UIManager.UIAll.StatusMessage = _("Best capturer of the map");
  3643. }
  3644. }
  3645. case "Hits": {
  3646. if (_Level == "round") {
  3647. foreach (Player in AllPlayers) {
  3648. declare Integer Battle_ScoreHit for Player.Score;
  3649. Ranking[Player.User.Login] = -Battle_ScoreHit;
  3650. }
  3651. UIManager.UIAll.StatusMessage = _("Best shooter of the round");
  3652. } else {
  3653. foreach (Player in AllPlayers) {
  3654. declare Integer MapHit for Player;
  3655. Ranking[Player.User.Login] = -MapHit;
  3656. }
  3657. UIManager.UIAll.StatusMessage = _("Best shooter of the map");
  3658. }
  3659. }
  3660. }
  3661.  
  3662. declare InvertedRanking = Ranking.sort();
  3663. Ranking.clear();
  3664. UIManager.UIAll.UISequence_PodiumPlayersWin = "";
  3665. declare BestPlayerName = "";
  3666. declare Count = 0;
  3667. foreach (Login => Points in InvertedRanking) {
  3668. Count += 1;
  3669. Ranking[Login] = Points * -1;
  3670. if (BestPlayerName == "") {
  3671. declare User = SM::GetUser(Login);
  3672. if (User != Null) BestPlayerName = User.Name;
  3673. }
  3674. if (Count <= 3) {
  3675. if (UIManager.UIAll.UISequence_PodiumPlayersWin != "") UIManager.UIAll.UISequence_PodiumPlayersWin ^= ",";
  3676. UIManager.UIAll.UISequence_PodiumPlayersWin ^= Login;
  3677. }
  3678. }
  3679.  
  3680. UpdateTop5(Top, Ranking);
  3681. UIManager.UIAll.BigMessage = BestPlayerName;
  3682. Mode::PlaySound(CUIConfig::EUISound::Notice, 0);
  3683. MM_Sleep(C_Top5SequenceDuration / Tops.count);
  3684. }
  3685.  
  3686. Layers::Hide("Top5");
  3687. UIManager.UIAll.UISequence_PodiumPlayersWin = "";
  3688. UIManager.UIAll.UISequence = CUIConfig::EUISequence::EndRound;
  3689. UIManager.UIAll.UISequence = PrevUISequence;
  3690. UIManager.UIAll.StatusMessage = "";
  3691. UIManager.UIAll.BigMessage = "";
  3692. }
  3693.  
  3694. // ---------------------------------- //
  3695. /// Get the top 5 manialink
  3696. Text GetMLTop5() {
  3697. declare BgTop = C_ImgBaseDir^"topsbg2.dds";
  3698. declare BgLine = C_ImgBaseDir^"TopsLine.png";
  3699. declare BgTitle = "file://Media/Manialinks/Common/Lobbies/small-button-RED.dds";
  3700.  
  3701. declare CardSizeY = 6.;
  3702. declare RankSizeX = 5.;
  3703. declare NameSizeX = 30.;
  3704. declare RecordSizeX = 9.;
  3705. declare NamePosX = RankSizeX;
  3706. declare RecordPosX = NamePosX + NameSizeX + RecordSizeX;
  3707.  
  3708. return """
  3709. <manialink version="1" name="Battle:Top5">
  3710. <framemodel id="Framemodel_TopEntry">
  3711. <format style="TextCardSmallScores2" />
  3712. <label posn="{{{RankSizeX/2.}}} 0.3" sizen="{{{RankSizeX}}} {{{CardSizeY}}}" halign="center" valign="center" style="TextTitle3" textcolor="000" opacity="0.5" id="Label_Rank" />
  3713. <quad posn="{{{NamePosX+0.15}}} 3 2" sizen="{{{NameSizeX+RecordSizeX-0.1}}} {{{CardSizeY}}}" image="{{{BgLine}}}" opacity="0.8" />
  3714. <quad posn="{{{NamePosX+0.8}}} 1.6 3" sizen="3.5 3.5" image="file://Avatars/LoginDuJoueur/Default" id="Quad_Avatar"/>
  3715. <label posn="{{{NamePosX+4.8}}} 0.3 4" sizen="{{{NameSizeX-2.}}} {{{CardSizeY}}}" valign="center" id="Label_Name" />
  3716. <label posn="{{{RecordPosX-1.}}} 0.3 5" sizen="{{{RecordSizeX-5.}}} {{{CardSizeY}}}" halign="right" valign="center" id="Label_Value" />
  3717. </framemodel>
  3718. <frame posn="-160 31" id="Frame_Tops">
  3719. <quad posn="-5.70 5 -1" sizen="60 42" image="{{{BgTop}}}" />
  3720. <quad posn="3 3" sizen="43 6" image="{{{BgTitle}}}" id="Quad_ButtonRed" />
  3721. <label posn="25 -1.8" sizen="50 5" scale="0.8" halign="center" valign="bottom" style="TextButtonBig" textcolor="fff" textemboss="1" id="Label_Title"/>
  3722. <frame posn="2 -1" id="Frame_Top">
  3723. <frameinstance posn="0 -6" modelid="Framemodel_TopEntry" />
  3724. <frameinstance posn="0 -12" modelid="Framemodel_TopEntry" />
  3725. <frameinstance posn="0 -18" modelid="Framemodel_TopEntry" />
  3726. <frameinstance posn="0 -24" modelid="Framemodel_TopEntry" />
  3727. <frameinstance posn="0 -30" modelid="Framemodel_TopEntry" />
  3728. </frame>
  3729. </frame>
  3730. <frame posn="0 42" id="Frame_Message">
  3731. <label halign="center" textemboss="1" style="TextValueSmallSm" textcolor="fff" text="bla" id="Label_MyRank" />
  3732. </frame>
  3733. <script><!--
  3734. #Include "TextLib" as TL
  3735.  
  3736. Text GetNickname(Text _Login) {
  3737. foreach (Player in Players) {
  3738. if (Player.Login == _Login) return Player.Name;
  3739. }
  3740. return _Login;
  3741. }
  3742.  
  3743. Void UpdateRanking(Text _Name, Integer[Text] _Ranking) {
  3744. declare Label_Title <=> (Page.GetFirstChild("Label_Title") as CMlLabel);
  3745. Label_Title.Value = _Name;
  3746.  
  3747. declare Integer[] Points;
  3748. declare Text[] Logins;
  3749. declare MaxRank = 0;
  3750. declare MyRank = 0;
  3751. foreach (Login => Score in _Ranking) {
  3752. Logins.add(Login);
  3753. Points.add(Score);
  3754. MaxRank += 1;
  3755. if (Login == InputPlayer.Login) MyRank = MaxRank;
  3756. }
  3757.  
  3758. declare Label_MyRank <=> (Page.GetFirstChild("Label_MyRank") as CMlLabel);
  3759. if (MaxRank > 0 && MyRank > 0) {
  3760. Label_MyRank.Value = TL::Compose("{{{_("You are ranked %1/%2")}}}", TL::ToText(MyRank), TL::ToText(MaxRank));
  3761. Label_MyRank.Visible = True;
  3762. } else {
  3763. Label_MyRank.Visible = False;
  3764. }
  3765.  
  3766. declare Frame_Top <=> (Page.GetFirstChild("Frame_Top") as CMlFrame);
  3767. foreach (Key => Control in Frame_Top.Controls) {
  3768. declare Frame_TopEntry <=> (Control as CMlFrame);
  3769. declare Label_Rank <=> (Frame_TopEntry.GetFirstChild("Label_Rank") as CMlLabel);
  3770. declare Quad_Avatar <=> (Frame_TopEntry.GetFirstChild("Quad_Avatar") as CMlQuad);
  3771. declare Label_Name <=> (Frame_TopEntry.GetFirstChild("Label_Name") as CMlLabel);
  3772. declare Label_Value <=> (Frame_TopEntry.GetFirstChild("Label_Value") as CMlLabel);
  3773.  
  3774. Label_Rank.Value = TL::ToText(Key + 1);
  3775. if (Logins.existskey(Key)) {
  3776. declare Login = Logins[Key];
  3777. Quad_Avatar.Visible = True;
  3778. Quad_Avatar.ImageUrl = "file://Avatars/"^Login^"/Default";
  3779. Label_Name.Value = GetNickname(Login);
  3780. Label_Value.Value = TL::ToText(Points[Key]);
  3781. } else {
  3782. Quad_Avatar.Visible = False;
  3783. Label_Name.Value = "---";
  3784. Label_Value.Value = "---";
  3785. }
  3786. }
  3787. }
  3788.  
  3789. main() {
  3790. declare netread Integer Net_RoundTop_Update for Teams[0];
  3791. declare netread Integer[Text] Net_RoundTop_Ranking for Teams[0];
  3792. declare netread Text Net_RoundTop_Name for Teams[0];
  3793.  
  3794. declare PrevTopName = "";
  3795. declare PrevUpdate = -1;
  3796.  
  3797. while (True) {
  3798. yield;
  3799. if (!PageIsVisible || InputPlayer == Null) continue;
  3800.  
  3801. if (PrevUpdate != Net_RoundTop_Update) {
  3802. PrevUpdate = Net_RoundTop_Update;
  3803.  
  3804. UpdateRanking(Net_RoundTop_Name, Net_RoundTop_Ranking);
  3805. }
  3806. }
  3807. }
  3808. --></script>
  3809. </manialink>
  3810. """;
  3811. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement