SplitScreen Stunt Mode Script V0.8

You can talk about ManiaScript for ManiaPlanet here

Moderator: English Moderator

User avatar
BragonHightake
Posts: 250
Joined: 17 Aug 2011, 00:22

Re: SplitScreen Stunt Mode Script V0.5

Post by BragonHightake »

kapsubm wrote:the script so far (works perfectly in splitscreen, single and multiplayermode)
(issues: Scoretable on end of round)
the Difference to your script is, that u can respan, the time limit is taken in account,
in this time all players can do stunts as long as the time limit is not null
(scoring 1 minute due to nadeo restriction)
if we can sort out the table sort and maybe ladderranks, it should be ready for release.

Code: Select all

// *********************** ** ** *   *
// *    Multiplayer Stunt competition
// ******************* ** ** *   *

#RequireContext CTmMode

#Include "TextLib" as TextLib
#Include "MathLib" as MathLib


#Include "Libs/Nadeo/Mode.Script.txt"
#Include "Libs/Nadeo/TrackMania/TM.Script.txt" as TM

// ******** Match Mode Settings *********
#Setting MatchMode 0               //0 = Match mode off; 1 = Points mode; 2 = Nr of rounds mode; 3 = Map playlist mode
#Setting PointsLimit 30            //Nr of Points needed to win match.  (Only used when MatchMode is set to 1)
#Setting NrOfRoundsLimit 5            //Nr of rounds to play before match ends. (Only used when MatchMode is set to 2)
#Setting CanMatchEndInTie False     //True = The match can end in a tie; False = Extra round(s) are played if winning score is tied at end of match

//********* GameMode Settings ********
#Setting GameMode 2                  // 0 = Rounds (Not working) 1 = TimeAttack (Not working see separate script); 2 = StuntMode; 3 = Platform(Not working)

// ******** TimeAttack Settings **********
#Setting TimeLimitSeconds 300         //Time limit for round in seconds
#Setting AlwaysRespawnToStart False   //True = Respawn to start; False = Respawn to latest checkpoint, but respawn twice within 1 sec to respawn to start.

// ******** Various Settings ******
#Setting RandomMapOrder False         //True = Random Map Order; False = Map Order of PlayList
#Setting ShowGoldTime False           //True = Show the map's gold time in upper left corner; False = Don't show gold time
#Setting ForceStuntFigrueText False   //True = Show StuntFigureText regardless of game type; False = Show StuntFigureText depending on game type.

//***** Constants ******
#Const RoundPoints [10,6,4,3,2,1]
#Const GAME_MODE_ROUNDS         0
#Const GAME_MODE_TIME_ATTACK   1
#Const GAME_MODE_STUNTS         2
#Const GAME_MODE_PLATFORM      3

#Const MATCH_MODE_OFF             0   //In this mode there is no match, just plain old time attack.
#Const MATCH_MODE_POINTS          1   //In this mode the match ends when a player reaches the point limit.
#Const MATCH_MODE_NR_OF_ROUNDS  2   //In this mode the match ends after a certain number of rounds have been played.
#Const MATCH_MODE_PLAYLIST       3   //In this mode the match ends after all maps in playlist have been played.

#Const DOUBLE_CLICK_THRESHOLD    1000 //
#Const STUNT_TEXT_TIMEOUT       1000
#Const STUNT_MODE_COUNT_DOWN    60000 // Not configurable/working in ManiaPlanet 1.2e beta so setting it as a constant

//My StuntUIStates
#Const REGULAR_SCORE 0               //Makes UI display CurRace.StuntsScore
#Const COUNT_DOWN_SCORE -1            //Makes UI display CurRace.StuntsScore - countdown penalty
#Const SKIP_REDRAW -2               //Used to optimize drawing of ui somewhat
#Const HAS_FINISHED -3               //Makes UI display CurRace.StuntsScore at end of race
//StuntUIStates > 0 = time when to redraw regular score. (Last time a stunt was performed + STUNT_TEXT_TIMEOUT

//#Const SORT_ASCENDING = 0
//#Const SORT_DECENDING = 0

declare Integer[Ident] RoundArrivalOrder;
declare Integer[Ident] StuntUIState;
declare Integer[] MapOrder;
declare Boolean IsSkipThisRound;
declare Text[CTmModeEvent::EStuntFigure] StuntFigureDictionary;
declare CTmResult::ETmRaceResultCriteria ResultCriteria;
declare Boolean ShowStuntFigureText;


Void InitializeGlobalVars() {
   switch(GameMode) {
      case GAME_MODE_ROUNDS: {
         ShowStuntFigureText = ForceStuntFigrueText;
         ResultCriteria = CTmResult::ETmRaceResultCriteria::Stunts;
      }
      case GAME_MODE_TIME_ATTACK: {
         ShowStuntFigureText = ForceStuntFigrueText;
         ResultCriteria = CTmResult::ETmRaceResultCriteria::Stunts;
      }
      case GAME_MODE_STUNTS: {
         ShowStuntFigureText = True;
         //ShowStuntUI = True;
         ResultCriteria = CTmResult::ETmRaceResultCriteria::Stunts;
      }
      case GAME_MODE_PLATFORM: {
         ShowStuntFigureText = ForceStuntFigrueText;
         ResultCriteria = CTmResult::ETmRaceResultCriteria::Stunts;
      }
   }
}


// === Scores ===
Integer GetResultScore(CTmResult _Result, CTmResult::ETmRaceResultCriteria _ResultCriteria) {
   declare Integer Score;
   switch (_ResultCriteria) {
      case CTmResult::ETmRaceResultCriteria::Time:
         Score = _Result.StuntsScore;
      case CTmResult::ETmRaceResultCriteria::Stunts:
         Score = _Result.StuntsScore;
      case CTmResult::ETmRaceResultCriteria::NbRespawns:
         Score = _Result.StuntsScore;
      default:
         assert(False); //Shouldn't be here! FIx it!
   }
   return Score;
}


//Doesn't work with negative Results!
Boolean IsResultBetter(CTmResult _Result1, CTmResult _Result2, CTmResult::ETmRaceResultCriteria _ResultCriteria)
{
   if (_Result1 != Null && _Result2 != Null)
      log("IsResultBetter: " ^GetResultScore(_Result1,_ResultCriteria)^" "^GetResultScore(_Result2,_ResultCriteria));
      
   declare Boolean IsBetter;
   if ( _Result1 == Null ) {
      log("Result1 was null");
      IsBetter =  False;
      
   }
   else if ( _Result2 == Null) {
      log("Result2 was null");
      IsBetter =  True;
   }
   else {
      declare Comp = _Result1.Compare(_Result2, _ResultCriteria);
      IsBetter =  Comp > 0;
   }
   return IsBetter;
}

Integer Result_Compare(Integer _Result1, Integer _Result2, CTmResult::ETmRaceResultCriteria ResultCriteria) {
   declare Integer Result;
   switch(ResultCriteria) {
      case CTmResult::ETmRaceResultCriteria::Time:
         Result = _Result2 - _Result1;
      case CTmResult::ETmRaceResultCriteria::Stunts:
         Result = _Result1 - _Result2;
      case CTmResult::ETmRaceResultCriteria::NbRespawns:
         Result = _Result2 - _Result1;
      default:
         assert(False); //Shouldn't reach this point.   
   }
   return Result;
}

Boolean IsResultBetter(Integer _Result1, Integer _Result2, CTmResult::ETmRaceResultCriteria ResultCriteria) {
   return Result_Compare(_Result1, _Result2, ResultCriteria) > 0;
}


Integer[Text] SortResultArray(Integer[Text] _ResultArray, CTmResult::ETmRaceResultCriteria ResultCriteria) {
   declare Integer[Text] SortedArray;
   switch(ResultCriteria) {
      case CTmResult::ETmRaceResultCriteria::Time:
         SortedArray = _ResultArray.sort();
      case CTmResult::ETmRaceResultCriteria::Stunts: {
         foreach (Name => Score in _ResultArray) {
            SortedArray[Name] = -Score;
         }
         SortedArray = SortedArray.sort();
         foreach (Name => Score in SortedArray){
            SortedArray[Name] = MathLib::Abs(Score);
         }
      }
      case CTmResult::ETmRaceResultCriteria::NbRespawns:
         SortedArray = _ResultArray.sort();
      default:
         assert(False); //Shouldn't reach this point.
   }
   return SortedArray;
}

Integer[Ident] SortRoundArrivalOrder(Integer[Ident] _RoundArrivalArray, CTmResult::ETmRaceResultCriteria ResultCriteria) {
   declare Integer[Ident] SortedArray;
   switch(ResultCriteria) {
      case CTmResult::ETmRaceResultCriteria::Time:
         SortedArray = _RoundArrivalArray.sort();
      case CTmResult::ETmRaceResultCriteria::Stunts: {
         foreach (Id => Score in _RoundArrivalArray) {
            SortedArray[Id] = -Score;
         }
         SortedArray = SortedArray.sort();
         foreach (Id => Score in SortedArray){
            SortedArray[Id] = MathLib::Abs(Score);
         }
      }
      case CTmResult::ETmRaceResultCriteria::NbRespawns:
         SortedArray = _RoundArrivalArray.sort();
      default:
         assert(False); //Shouldn't reach this point.
   }
   return SortedArray;
}


Integer GetEventScore(CTmModeEvent Event,  CTmResult::ETmRaceResultCriteria ResultCriteria) {
   declare Integer Result;
   switch (ResultCriteria) {
      case CTmResult::ETmRaceResultCriteria::Time:
         Result = Event.RaceTime;
      case CTmResult::ETmRaceResultCriteria::Stunts:
         Result = Event.StuntsScore;
      case CTmResult::ETmRaceResultCriteria::NbRespawns:
         Result = Event.NbRespawns;
      default:
         assert(False); //Shouldn't be here! FIx it!
   }
   return Result;
}


Void ClearScoreTimes() {
   foreach (Score in Scores) {
      Score.BestRace.Time = -1;
      Score.BestLap.Time = -1;
      Score.PrevRace.Time = -1;
      Score.TempResult.Time = -1;
      
      Score.BestRace.StuntsScore = 0;
      Score.BestLap.StuntsScore = 0;
      Score.PrevRace.StuntsScore = 0;
      Score.TempResult.StuntsScore = 0;
      
      Score.BestRace.NbRespawns = -1;
      Score.BestLap.NbRespawns = -1;
      Score.PrevRace.NbRespawns = -1;
      Score.TempResult.NbRespawns = -1;
   }
}

Boolean IsPointsTied() {
   if (Scores.count > 1)
      return Scores[0].Points == Scores[1].Points;

   return False;
}

Integer CalcStuntScoreAtCountDown(CTmPlayer Player, Integer Time) {
   declare StuntScore = Player.CurRace.StuntsScore;
   if (Player.RaceStartTime != 0 && Time > STUNT_MODE_COUNT_DOWN) {
      StuntScore = StuntScore - (Time - STUNT_MODE_COUNT_DOWN) / 200;
      if (StuntScore < 0)
         StuntScore = 0;
   }
   return StuntScore;
}

Boolean IsEndOfMatchReached(Integer MatchRoundNr) {
   if (MatchMode == MATCH_MODE_POINTS && Scores.count > 0 && Scores[0].Points >= PointsLimit)
      return True;
   else if (MatchMode == MATCH_MODE_NR_OF_ROUNDS && MatchRoundNr >= NrOfRoundsLimit)
      return True;
   else if (MatchMode == MATCH_MODE_PLAYLIST && MatchRoundNr >= MapList.count)
      return True;
   return False;
}

Void UnSpawn(CTmPlayer Player) {
   TM::EndRaceSequence_Remove(Player);
   Player.RaceStartTime = 0;
}

Integer[] CreateMapOrder(Boolean shouldRandomize) {
   declare Integer[] newMapOrder;
   declare Integer maxMapNr = MapList.count-1;
   
   for(i,0,maxMapNr) {
      newMapOrder.add(i);
   }
   
   if (shouldRandomize) {
      declare Integer tmp;
      declare Integer rand;
      
      for (i, 0, maxMapNr) {
         rand = MathLib::Rand(0, maxMapNr);
         tmp = newMapOrder[i];
         newMapOrder[i] = newMapOrder[rand];
         newMapOrder[rand] = tmp;
      }
   }
   return newMapOrder;
}

Text GetRaceResultText(Integer Result, CTmResult::ETmRaceResultCriteria ResultCriteria) {
   declare Text RaceResultText;
   switch (ResultCriteria) {
      case CTmResult::ETmRaceResultCriteria::Time: {
         RaceResultText ^= TextLib::TimeToText(Result, True);
      }
      case CTmResult::ETmRaceResultCriteria::Stunts: {
         RaceResultText ^= Result ^" Points";
      }
      default:
         assert(False);  //Should not be here
   }
   return RaceResultText;
}

Text GetRaceResultText(CTmResult Result, CTmResult::ETmRaceResultCriteria ResultCriteria) {
   declare Text RaceResultText;
   RaceResultText = GetRaceResultText(GetResultScore(Result, ResultCriteria), ResultCriteria);
   return RaceResultText;
}





Text GetManiaLinkPage(Text text, Integer length, Integer height) {
return """<frame posn="0 60">
         <quad  posn="0 3 -1"   sizen="{{{length}}} {{{height}}}"   halign="center"   style="Bgs1InRace" substyle="BgTitle3"  />
         <label posn="0 0"                  halign="center" scale="1" text="{{{text}}}" />
         </frame>""";
}

Text GetManiaLinkPage(Text text) {
   return GetManiaLinkPage(text, 15, 2);
}

Void InitStuntFigureDictionary() {
   StuntFigureDictionary.clear();
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::None] =                "None???";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::StraightJump] =          "Jump";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::Flip] =                "Flip";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::BackFlip] =             "Back Flip";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::Spin] =                "Spin";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::Aerial] =             "Aerial";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::AlleyOop] =             "Alley Ooop";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::Roll] =                "Roll";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::Corkscrew] =             "Corkscrew";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::SpinOff] =             "Spin Off";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::Rodeo] =                "Rodeo";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::FlipFlap] =             "Flip Flap";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::Twister] =             "Twister";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::FreeStyle] =             "Free Style";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::SpinningMix] =          "Spinning Mix";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::FlippingChaos] =          "Flipping Chaos";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::RollingMadness] =       "Rolling Madness";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::WreckNone] =             "Wreck";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::WreckStraightJump] =       "Jump Wreck";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::WreckFlip] =             "Flip Wreck";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::WreckBackFlip] =          "Back Flip Wreck";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::WreckSpin] =             "Spin Wreck";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::WreckAerial] =          "Aerial Wreck";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::WreckAlleyOop] =          "Alley Ooop Wreck";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::WreckRoll] =             "Roll Wreck";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::WreckCorkscrew] =       "Corkscrew Wreck";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::WreckSpinOff] =          "Spin Off Wreck";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::WreckRodeo] =          "Rodeo Wreck";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::WreckFlipFlap] =          "Flip Flap Wreck";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::WreckTwister] =          "Twister Wreck";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::WreckFreeStyle] =       "Free Style Wreck";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::WreckSpinningMix] =       "Spinning Mix Wreck";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::WreckFlippingChaos] =    "Flipping Chaos Wreck";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::WreckRollingMadness] =   "Rolling Madness Wreck";
///
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::TimePenalty] =          "Time Penalty";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::Reset] =                "Reset";
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::RespawnPenalty] =       "Respawn Penalty";
///
   StuntFigureDictionary[CTmModeEvent::EStuntFigure::Grind] =                "Grind";
}

Text GetStuntText(CTmModeEvent Event) {
   declare Text StuntText = "";
   
   /*
   (Chained)(Master) (Straight) (Basic) xxx (Angle)(!!!)
      + 34
      50 Points
   */
   
   if (Event.Combo > 0) {
      if (Event.Combo > 1)
         StuntText ^= """{{{Event.Combo}}}X""";
      StuntText ^= " Chained";
   }
   
   if (Event.IsReverse)
	  StuntText ^= " Reverse";
   if (Event.IsMasterJump) 
      StuntText ^= " Master";
   if (Event.IsStraight)
      StuntText ^= " Straight";
   if (Event.Angle == 0)
      StuntText ^= " Basic";
   
   StuntText ^=""" {{{StuntFigureDictionary[Event.StuntFigure]}}}""";
   
   if (Event.Angle != 0) {
      StuntText ^= """ {{{Event.Angle}}}""";
      for (i, 1, Event.Angle/180)
         StuntText ^= "!";
   }
   return StuntText;
}



Void UpdateStuntScoreUI(CTmPlayer Player, Text StuntFigureText, Integer StuntPoint, Integer Score) {
   declare UI <=> UIManager.GetUI(Player);
   
   if (UI != Null) {
      declare Text PointIncrText;
	  declare Text plusminus;
	  plusminus="-";
      if (StuntPoint > 0) {
	  	if (StuntFigureText != " Basic Respawn Penalty") {
		plusminus="+";
	}
         PointIncrText = plusminus^"""{{{StuntPoint}}}""";
      }
      
      UI.StatusMessage = """{{{StuntFigureText}}}
{{{PointIncrText}}}
{{{Score}}} Points""";
   }
}

Void UpdateStuntScoreUI(CTmPlayer Player, Text StuntFigureText, Integer StuntPoint) {
	  UpdateStuntScoreUI(Player, StuntFigureText, StuntPoint, Player.CurRace.StuntsScore);
}
/* Not used. (Need to rewrite it in order to improve stunt mode ui.)
Void doUI(CPlayer _Player) {
   
   declare UI <=> UIManager.GetUI(_Player);
   declare CUILayer UILayerTmp;
   
   if ( UI != Null ) {
      UI.UILayers.add(UILayerTmp);
      //frame pos 80 -45 = lower right quadrant
      UILayerTmp.ManialinkPage = """<frame posn="0 0" >
         <!-- <quad  posn="0 0 -1" valign="center" halign="center"  sizen="160 90"    style="Bgs1InRace" substyle="BgTitle3"  /> -->
         <label posn="0 0"    valign="center"          halign="center"     scale="2" text="Stunt: " />
         </frame>""";
      
   }   
}
*/

Void logUI(CUIConfig UI, Text _text) {
   log(_text ^" UIStatus: " ^UI.UIStatus);
   log("Number of layers: "^UI.UILayers.count);
   //log("IsHidden: "^UI.OverlayHideNotices ^ UI.OverlayHideMapInfo^UI.OverlayHideOpponentsInfo^UI.OverlayHideChat^UI.OverlayHideCheckPointList^UI.OverlayHideRoundScores^UI.OverlayHideAll^UI.OverlayHideScoresOnAltMenu^UI.NoticesFilter_HidePlayerInfo^UI.NoticesFilter_HidePlayerWarning^UI.NoticesFilter_HidePlayerInfoIfNotMe^UI.NoticesFilter_HidePlayerWarningIfNotMe^UI.NoticesFilter_HideMapInfo^UI.NoticesFilter_HideMapWarning^UI.NoticesFilter_HideMatchInfo^UI.NoticesFilter_HideMatchWarning);
   log("ScoreTableVisibility: "^UI.ScoreTableVisibility^" SmallScoreTableVisibility: "^UI.SmallScoreTableVisibility^"    AlliesLabelsVisibility: "^UI.AlliesLabelsVisibility^" EnemiesLabelsVisibility: "^UI.EnemiesLabelsVisibility^" EnemiesLabelsShowGauges: "^UI.EnemiesLabelsShowGauges);
   log("ManiaLinkPage :"^ UI.ManialinkPage);
}

//Best times shown in upper left corner 
Text GetFrameMapResults(CTmResult::ETmRaceResultCriteria ResultCriteria)
{
   declare Integer[Text] Results;
   if (ShowGoldTime && ResultCriteria == CTmResult::ETmRaceResultCriteria::Time) {
      Results["Gold"] = Map.TMObjective_GoldTime;
   }
   foreach (Score in Scores) {
      switch (ResultCriteria) {
         case CTmResult::ETmRaceResultCriteria::Time: {
            if (Score.BestRace.Time != -1)
               Results[Score.User.Name] = Score.BestRace.Time;
         }
         case CTmResult::ETmRaceResultCriteria::Stunts: {
            if (Score.BestRace.StuntsScore != -1)
               Results[Score.User.Name] = Score.BestRace.StuntsScore;
         }
         default:
            assert(False); //Should not reach this point
      }
   }
   
   Results = SortResultArray(Results, ResultCriteria);
   declare Text Legend;
   switch (ResultCriteria) {
      case CTmResult::ETmRaceResultCriteria::Time:
         Legend = ("$oBest times:");
      case CTmResult::ETmRaceResultCriteria::Stunts:
         Legend = ("$oBest scores:");
      default:
         assert(False); //Shouldn't reach this point
   }
   
   declare Frame = """   <frame posn="-160 76">
                  <label posn="1 3"    style="TextRaceStaticSmall" sizen="50 2" halign="left" text="{{{Legend}}}"  />""";
   declare Line = 0;
   foreach (Name => Result in Results) {
      Frame ^= """<label posn="2 {{{-3*Line}}}"    style="TextPlayerCardName"  sizen="25 3" halign="left" text="{{{Name}}}"  />
                  <label posn="30 {{{-3*Line}}}"    style="TextRaceStaticSmall" sizen="25 3" halign="left" text="$0F0{{{GetRaceResultText(Result, ResultCriteria)}}}"  />""";
      Line += 1;
   }
   
   Frame ^=  """</frame>""" ;
   
   return Frame;
}

declare CUILayer UILayerScores;
declare CUILayer UILayerInfo;


//  ============ Intro Sequence:
Void PlayIntroSequence(Text InfoText){
   sleep(0);   // flush loading lag.
   UILayerScores.ManialinkPage = GetFrameMapResults(ResultCriteria);
   UIManager.UIAll.UILayers.clear();
   UIManager.UIAll.UILayers.add(UILayerScores);
   
   UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::ForcedVisible;
   UIManager.UIAll.UISequence = CUIConfig::EUISequence::Intro;
   
   //sleep(4000);   // HACK; should be "wait(sequences over)"
   wait(UIManager.UIAll.UISequenceIsCompleted);
   
   if (InfoText == "")
      UILayerInfo.ManialinkPage = "";
   else {
      UILayerInfo.ManialinkPage = GetManiaLinkPage(InfoText);
   }
   UIManager.UIAll.UILayers.add(UILayerInfo);
   
   UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::Normal;
   UIManager.UIAll.UISequence = CUIConfig::EUISequence::Playing;
   foreach(Player, Players) {
      declare UI <=> UIManager.UI[Player];
      Player.RaceStartTime = Now + 100000;         // spawn the cars.
   }
   sleep(3000);
   
   //Remove UILayerInfo
   UIManager.UIAll.UILayers.clear();
   UIManager.UIAll.UILayers.add(UILayerScores);
   
   UIManager.UIAll.BigMessage = "";
   UIManager.UIAll.StatusMessage = "";
   foreach(Player, Players) {
      declare UI <=> UIManager.UI[Player];
      UI.BigMessage = "";
      UI.BigMessageAvatarLogin = "";
      UI.StatusMessage = "";
   }
}


// === Race rounds ==
Void DoTimeAttackRace()
{
   UiRounds = False;
   
   
   if (GameMode == GAME_MODE_STUNTS) {  //Should be stuntmodeui= true
      UiStuntsMode = True;
      UiRaceChrono = CTmMode::ETmRaceChronoBehaviour::CountDown;
      UiDisplayStuntsNames = True; //Nadeo hasn't got it working yet. Extracted own stunt name  own StuntUI Layer.
      ResultCriteria = CTmResult::ETmRaceResultCriteria::Stunts;
   } else { //StuntMode Off
      ResultCriteria = CTmResult::ETmRaceResultCriteria::Time;
   }
   UIManager.UIAll.UISequence = CUIConfig::EUISequence::Playing;
   
   TM::Players_SpawnAll(Now + 2000);
   foreach(Score, Scores) {
      Score.PrevRaceDeltaPoints = 0;
   }
   sleep(500);   
   Synchro_DoBarrier();

   RoundArrivalOrder = Integer[Ident];
   declare RoundArrivalOrderDirty = True; 
   declare LastRespawnTime = Integer[Ident];
   declare CheckpointCount = Integer[Ident];
   foreach (Player, Players) {
      LastRespawnTime[Player.Id] = Now;
   }
   declare Integer MatchBestResult for Map = -1;
   
   
   foreach(Player, Players) {
      declare Integer StuntUIState for Player;
      Player.CurRace.StuntsScore = 0;
//      StuntsScore[Player.Id] = 0;
      StuntUIState = REGULAR_SCORE;  //Is this one needed?
   }
   
   
   UILayerScores.ManialinkPage = GetFrameMapResults(ResultCriteria);
   
   CutOffTimeLimit = Now + TimeLimitSeconds * 1000 +2500;
   
   //=== Loop until all players finished racing
   declare NbContestants = Players.count;
   while(  Now < CutOffTimeLimit ) {
      TM::RunGame();
      TM::EndRaceSequence_Update();
      
      if (MatchEndRequested)
         return;

      // Process events queue
      foreach(Event, PendingEvents) {         
         PassOn(Event);
		 declare Text stunttext = "";
         declare Player <=> Event.Player;
         declare Integer StuntUIState for Player;
         stunttext=GetStuntText(Event);
         if (Event.Type == CTmModeEvent::EType::Stunt) {
		XmlRpc.SendCallback("playerStunt", "playerLogin:"^Player.User.Login^";stuntScore:"^Player.CurRace.StuntsScore^";eventScore:"^Event.Points^";Stunt:"^stunttext^":");
			if ( stunttext == " Basic Respawn Penalty" ) {
			Player.CurRace.StuntsScore -= Event.Points; }
		 else {
            Player.CurRace.StuntsScore += Event.Points;
			 }
			
            
			UpdateStuntScoreUI(Event.Player, GetStuntText(Event), Event.Points);         
            StuntUIState = Now + STUNT_TEXT_TIMEOUT;
         }
         
           else if (Event.Type == CTmModeEvent::EType::StartLine) {
            CheckpointCount[Player.Id] = 0;
            StuntUIState = REGULAR_SCORE; //Displays stuntui when respawned
            Player.CurRace.StuntsScore = 0;
         } else if (Event.Type == CTmModeEvent::EType::WayPoint) {
            CheckpointCount[Player.Id] +=1;
		//xmlrpc
		declare Text Stuntdata= "playerLogin:"^Player.User.Login^";stuntScore:"^Player.CurRace.StuntsScore;
		XmlRpc.SendCallback("playerCheckpoint", Stuntdata);
            if (Event.IsEndRace) {
               assert(Player.CurRace.Time == Event.RaceTime);
               Player.CurRace.StuntsScore = CalcStuntScoreAtCountDown(Player, Event.RaceTime);
               StuntUIState = HAS_FINISHED; //Stops the countdown in StuntUI and displays the final score.
          
               Player.Score.PrevRace = Player.CurRace;
			   declare Text ResultText = "$00F" ^ GetRaceResultText(Player.CurRace, ResultCriteria);
			   declare NbRespawns = Player.CurRace.NbRespawns;
		//xmlrpc					
		XmlRpc.SendCallback("playerFinish", "playerLogin:"^Player.User.Login^";stuntScore:"^Player.CurRace.StuntsScore^";CPCount:"^NbRespawns);             
               if (IsResultBetter(Player.CurRace, Player.Score.BestRace, ResultCriteria)) {
                  Player.Score.BestRace = Player.CurRace;
				  
                  if (IsResultBetter(GetResultScore(Player.CurRace, ResultCriteria), MatchBestResult, ResultCriteria)) {
                     MatchBestResult = GetResultScore(Player.CurRace, ResultCriteria);
                     TM::EndRaceSequence_Add(Player, TextLib::Compose(_("New match record! %1"), ResultText));
                  } else {
                     TM::EndRaceSequence_Add(Player, TextLib::Compose(_("Personal record! %1"), ResultText));
                  }
                  RoundArrivalOrder[Player.Id] = GetEventScore(Event, ResultCriteria);
                  RoundArrivalOrderDirty = True;
               } else {
                  if (GameMode != GAME_MODE_STUNTS)
                     ResultText = "";
                  TM::EndRaceSequence_Add(Player, ResultText);
               }
            }
         }
      }
      
      //Not fully optimized, could have a proper Dirty flag...
      foreach(Player, Players) {
         declare Integer StuntUIState for Player;
      
         //assert (Player.Id!= prevPlayerId);
         if ((StuntUIState > 0 && Now > StuntUIState)
               || StuntUIState == REGULAR_SCORE) {
            UpdateStuntScoreUI(Player, "", 0);
            StuntUIState = SKIP_REDRAW;
            
         } else if (StuntUIState == HAS_FINISHED) {
            //UpdateStuntScoreUI(Player, "", 0);
         }
         
         
         declare CurRaceTime = Now - Player.RaceStartTime;
         if (Player.RaceStartTime > 0 && CurRaceTime > STUNT_MODE_COUNT_DOWN
                && StuntUIState != HAS_FINISHED) {
            UpdateStuntScoreUI(Player, "$f00Finish Now!", 0, CalcStuntScoreAtCountDown(Player, CurRaceTime));
         }
         //prevPlayerId = Player.Id;
      }

      // Refresh score table.      
      if (RoundArrivalOrderDirty) {
         RoundArrivalOrderDirty = False;
         RoundArrivalOrder = SortRoundArrivalOrder(RoundArrivalOrder, ResultCriteria);
                  
         UILayerScores.ManialinkPage = GetFrameMapResults(ResultCriteria);      // refresh scores...
      }
      
      // Respawn unspawned players
      if (PlayersWaiting.count > 0) {
         TM::Players_SpawnWaiting(0);
      }
   }
   TM::Players_UnspawnAll();
   
   Synchro_DoBarrier();

   // endround sequence
   sleep(1000);
}

Void PlayEndOfRoundSequence(Text InfoText, Integer MatchRoundNr) {
      UIManager.UIAll.UISequence = CUIConfig::EUISequence::EndRound;
   UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::ForcedVisible;
   
   sleep(6500);   //Showing race times End of round
   
   if (MatchMode != MATCH_MODE_OFF) {   //Display match point sequence
      UiRounds = False;
	  UiStuntsMode = True; 
      
      if (InfoText == "")
         UILayerInfo.ManialinkPage = "";
      else {
         UILayerInfo.ManialinkPage = GetManiaLinkPage(InfoText);
      }
      UIManager.UIAll.UILayers.add(UILayerInfo);

      declare Index = 0;
      declare Text Table;
      switch(ResultCriteria) {
         case CTmResult::ETmRaceResultCriteria::Time:
            Table = """<scoretable type="time">""";
         case CTmResult::ETmRaceResultCriteria::Stunts:
            Table = """<scoretable type="stunts">""";
         case CTmResult::ETmRaceResultCriteria::NbRespawns:
            assert(False); //Not implemented yet
         default:
            assert(False); //Shouldn't reach this point.
      }   
      declare Ident PrevPlayerId = NullId;
      declare ScoreInc = 0;
      foreach (PlayerId => Score in RoundArrivalOrder) {
         declare Player <=> Players[PlayerId];      // faut le PlayerInfo
         
         //Only update score of previous player if the times aren't identical
         declare Boolean IsSameTimeAsPrevPlayer = (PrevPlayerId != NullId && Score == RoundArrivalOrder[PrevPlayerId]);
         
         if (!IsSameTimeAsPrevPlayer) {
            if (Index < RoundPoints.count)
               ScoreInc = RoundPoints[Index];
            else
               ScoreInc = 1;
            
            if (Index == Players.count -1)      // last players gets no points.
               ScoreInc = 0;            
         }
         Index += 1;
         
         Table ^= """<score login="{{{Player.Login}}}" value="{{{Score}}}" inc="{{{ScoreInc}}}"/>""";      
         Player.Score.PrevRaceDeltaPoints = ScoreInc;
         PrevPlayerId = PlayerId;
      }
      Table ^= """</scoretable>""";
      UIManager.UIAll.SmallScoreTable = Table;

      sleep(12000);   //Showing DeltaPoints

      foreach(Score, Scores) {
         Score.Points += Score.PrevRaceDeltaPoints;
         Score.PrevRaceDeltaPoints = 0;
      }
      
      if (IsPointsTied() && IsEndOfMatchReached(MatchRoundNr))
         UILayerInfo.ManialinkPage = GetManiaLinkPage("Points are tied! Next round will be a tiebreaker!", 210, 14);
      
      sleep(2500); //Showing TotalPoints
      UILayerInfo.ManialinkPage = "";
   }
   
   UIManager.UIAll.SmallScoreTable = "";
   UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::Normal;
   
   sleep(500);   
   Synchro_DoBarrier();
}


//==== EndOfMatchSequence ====
Void EndOfMatchSequence() {
   TM::Players_UnspawnAll();
   UiRounds = True;
   
   if (Scores.count > 0 && Scores[0].Points > 0 && !ServerShutdownRequested) {
      UILayerScores.ManialinkPage = GetFrameMapResults(ResultCriteria);
      UIManager.UIAll.UISequence = CUIConfig::EUISequence::Podium;
      sleep(12500);
      
      declare Text WinnerNames = Scores[0].User.Name;
      declare TextBoxWidth = 130;
      
      for (i, 1, Scores.count -1) {
         if ( Scores[i].Points == Scores[0].Points) {
            WinnerNames ^= TextLib::MLEncode(" & ") ^Scores[i].User.Name;
            TextBoxWidth = 320;
         }
         else 
            break;
      }
      
      
      declare VictoryText = TextLib::Compose(_("$<%1$> wins the match!"), WinnerNames);
      UILayerScores.ManialinkPage = GetFrameMapResults(ResultCriteria);
      UILayerInfo.ManialinkPage = GetManiaLinkPage(VictoryText, TextBoxWidth, 14);
      

      UIManager.UIAll.UILayers.clear();
      UIManager.UIAll.UILayers.add(UILayerScores);
      UIManager.UIAll.UILayers.add(UILayerInfo);

      sleep(3000);
      UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::ForcedVisible;
      sleep(5000);
   }
   
   Synchro_DoBarrier();

   UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::Normal;
   UIManager.UIAll.UILayers.clear();

   Scores_Clear();
   
   MatchEndRequested = False;      // taken into account.
}

// === Main ===
main() 
{
   //Init
   UIManager.ResetAll();
   log("restart...");
   
   InitializeGlobalVars();
   
   
   IndependantLaps = True;
   
   RespawnBehaviour = ::ETMRespawnBehaviour::Normal;

   UILayerScores <=> UIManager.UILayerCreate();
   UILayerInfo <=> UIManager.UILayerCreate();
   
   InitStuntFigureDictionary();

   MapOrder = CreateMapOrder(RandomMapOrder);
   declare MapOrderIndex = 0;
   
   //Since the script needs to be pasted instead of loaded there is already a loaded map.
   //Need to unload it to enforce map order.
   //if (MapLoaded)
   //   UnloadMap();
   
   // loop until server interrupted
   while( !ServerShutdownRequested ) {
      declare MatchRoundNr = 1;
      declare IsTieBreakRound = False;
      
      declare IntroText = "";
      declare EndOfRoundText = "";
      
      //make sure new match start with first map in maplist in playlist mode. (Last match could've ended in tiebreak.)
      if (MatchMode == MATCH_MODE_PLAYLIST) {
         MapOrderIndex = 0;
      }
      
      // ============ Play the Time Attack races until the end of match condition is reached:
      while( !MatchEndRequested ) {
         IsSkipThisRound = False;
         
         //Display scoreTable before match in Rounds mode if a Match Mode is set
         if (MatchMode!= MATCH_MODE_OFF)
            UiRounds = True;
         UIManager.UIAll.ScoreTableVisibility = CUIConfig::EVisibility::ForcedVisible;
         UIManager.UIAll.UISequence = CUIConfig::EUISequence::Intro;

         NextMapIndex = MapOrder[MapOrderIndex];

         LoadMap();

         //ClearScoreTimes();  //Don't call "Scores_Clear" because we want to preserve the match points
         Scores_Clear();
         TM::Players_UnspawnAll();
         
         
         //Set texts according to settings and state
         if (IsTieBreakRound) {
            IntroText = "Tiebreaker round!";
            EndOfRoundText = "Player with most points wins!";
         } else if (MatchMode == MATCH_MODE_POINTS) {
            if (MatchRoundNr == 1)
               IntroText = "New match!";
            else
               IntroText = "";
            EndOfRoundText = """{{{PointsLimit}}} points to win!""";
         } else if (MatchMode == MATCH_MODE_NR_OF_ROUNDS) {
            IntroText = """Round {{{MatchRoundNr}}} of {{{NrOfRoundsLimit}}}""";
            EndOfRoundText = """Round {{{MatchRoundNr}}} of {{{NrOfRoundsLimit}}}""";
         } else if (MatchMode == MATCH_MODE_PLAYLIST) {
            IntroText = """Round {{{MatchRoundNr}}} of {{{MapList.count}}}""";
            EndOfRoundText = """Round {{{MatchRoundNr}}} of {{{MapList.count}}}""";
         }
         
         PlayIntroSequence(IntroText);
         DoTimeAttackRace();
         if (!IsSkipThisRound)
            PlayEndOfRoundSequence(EndOfRoundText, MatchRoundNr);
         
         if (IsEndOfMatchReached(MatchRoundNr)) {
            if (!CanMatchEndInTie && IsPointsTied())
               IsTieBreakRound = True;
            else {
               IsTieBreakRound = False;
               break;       // score limit reached.
            }
         }
         
         if (!IsSkipThisRound || MatchMode == MATCH_MODE_PLAYLIST)
            MatchRoundNr += 1;
         
         MapOrderIndex += 1;
         if (MapOrderIndex >= MapList.count) {
            MapOrderIndex = 0;
         }
         
         UnloadMap();
      }
      
      // ============ End of Match Sequence:
      if (MatchMode != MATCH_MODE_OFF)
         EndOfMatchSequence();
      
      UnloadMap();
   }
   
   // ====== Cleanup
   log("Cleanup! (Is this bit of code ever called???)");
   UIManager.UILayerDestroy(UILayerScores);
   UIManager.UILayerDestroy(UILayerInfo);
}
Sorry, wenn ich hier mal auf deutsch schreibe.
Wollten gestern mal einen Stuntserver zum laufen bringen,
hat leider noch nicht geklappt.
Verstehe das mit dem splitscreen auch nicht so ganz.
Kann man den mode auch normal laufen lassen?
User avatar
kapsubm
Posts: 238
Joined: 16 Aug 2011, 23:38
Location: Vienna, Austria
Contact:

Re: SplitScreen Stunt Mode Script V0.6

Post by kapsubm »

will release a serverversion this late evening, last test are running

known issues so far: skipmatch produces a crash. LP not Working yet
i ll open a own thread for Stuntmode Multiplayer.
Credits go to 90 % http://forum.maniaplanet.com/memberlist ... ile&u=6239 :pil
10 % are customizing and xmlrpc calls / removing unneeded stuff for multiplayer from me ;)

Script will be posted around 11 pm CET, with Instructions on how to start a multiplayer server.


Auf Deutsch:

Ich release das Multiplayer Script so gegen 23 Uhr.
inklusive Anleitung für Multiplayer server. , xmlrpc callback die von ServerControllern benutz werden können.
Bekannte Probleme: Skipmap produziert servercrash. (Votings abstellen!) es werden (noch) keine Ladderpunkte vergeben.

xmlrpc call activated:

playercheckpoint (login, score)
playerfinish (login, score, number CP´s)

for debugging: (disabled by default)
playerstunt (resource hungry!!!!! each stunt will be sent to controller) !! :arrow:
Join CSeSports Platform Server

[url=maniaplanet://:maniaplanet://#join=cs.esports@Platform@nadeolive]CS.eSportsPlatform 0-60K With Fox Control[/url]
[url=maniaplanet://:maniaplanet://#join=csesports2@SMStorm]CS.eSports SM Royal 0-60 k 40 players With Smart Servercontroller[/url]
[url=maniaplanet://:maniaplanet://#join=cs.esports1@TMCanyon]CS.eSports Stunts in Canyon with Smart Servercontroller[/url]
User avatar
kapsubm
Posts: 238
Joined: 16 Aug 2011, 23:38
Location: Vienna, Austria
Contact:

Re: SplitScreen Stunt Mode Script V0.6

Post by kapsubm »

i think i found a little bug (seems its harmless), but those 2 declaring should not be on that place
(Line501,502)
declare CUILayer UILayerScores;
declare CUILayer UILayerInfo;
arent those globals ?
Join CSeSports Platform Server

[url=maniaplanet://:maniaplanet://#join=cs.esports@Platform@nadeolive]CS.eSportsPlatform 0-60K With Fox Control[/url]
[url=maniaplanet://:maniaplanet://#join=csesports2@SMStorm]CS.eSports SM Royal 0-60 k 40 players With Smart Servercontroller[/url]
[url=maniaplanet://:maniaplanet://#join=cs.esports1@TMCanyon]CS.eSports Stunts in Canyon with Smart Servercontroller[/url]
supersmo
Posts: 64
Joined: 15 Sep 2011, 13:39
Location: Sweden

Re: SplitScreen Stunt Mode Script V0.6

Post by supersmo »

kapsubm wrote:i think i found a little bug (seems its harmless), but those 2 declaring should not be on that place
(Line501,502)
declare CUILayer UILayerScores;
declare CUILayer UILayerInfo;
arent those globals ?
No, not a bug just poor coding practice. ;)
Actually if you look at the original TMSplitScreen_Competition.Script.txt that comes with TM2 you will see that the global UILayerScores is from Nadeos script.

When I added UiLayerInfo I followed their poor example.
No excuse, just an explanation.

It's on the todo list for clean up code :)
Need to change some method signatures to pass the layers around instead of accessing them globally.
supersmo
Posts: 64
Joined: 15 Sep 2011, 13:39
Location: Sweden

Re: SplitScreen Stunt Mode Script V0.7

Post by supersmo »

SplitScreen Stunt Mode Script now reached version 0.7

Changelog
V0.7
  • Fixed respawn penalty and added setting to turn it off. (Thanx for the report kapsubm.)
  • Speeded up score countdown. (Feedback from kapsubm)
Todo:
Better looking stunt UI
Better performance for stunt UI
Implement option to have respawn penalty reset the score to what it was since last checkpoint.
Continue cleaning up code.
supersmo
Posts: 64
Joined: 15 Sep 2011, 13:39
Location: Sweden

Re: SplitScreen Stunt Mode Script V0.8

Post by supersmo »

SplitScreen Stunt Mode Script now reached version 0.8

Changelog
v0.8
  • Better looking stunt UI made with manialink frames.
  • Added "dirty" flags to optimize ui redraw.
Todo:
Maybe refactor the code into several scriptfiles so it is easier to maintain, improve and reuse if I want to make new game modes.
Fabinou38
Posts: 403
Joined: 09 Apr 2011, 18:13
Location: Europe / France / Auvergne-Rhône-Alpes / Isère

Re: SplitScreen Stunt Mode Script V0.8

Post by Fabinou38 »

Really good job! :thumbsup: I had tested this in 2013, I want to play it again bit I can't lauch again, because I can't open editor.. :(
MixterFab38 - Member of LAN Team - Moderator / Translator (FR) of TM²Galaxy - Project Helper of TMOne, of Stornium (by Guerro) and of ThomasFox's (aka Ziyx) projects :)
Here since ManiaPlanet 1 (TM² Canyon) :thx:
MP3 / MP4 beta tester
Post Reply

Return to “ManiaScript”

Who is online

Users browsing this forum: No registered users and 1 guest