/****************************************
* MapType for Athletics Game Mode *
* Author: steeffeen *
* Contact: schteffens@gmail.com *
****************************************/
#RequireContext CSmMapType
#Include "TextLib" as TextLib
#Include "Libs/Nadeo/Anchor.Script.txt" as Anchor
#Const Version "0.6 (2013-04-25)"
#Const C_LobbyName "Lobby"
#Const C_DisciplineTypes [1 => "LongJump", 2 => "HighJump", 3 => "Run", 4 => "Rounds"]
declare Integer[Text] G_Disciplines;
declare Integer[Text] G_Rounds;
// Initializes all anchors to default
Void InitAnchors() {
foreach (Anchor in AnchorData) {
Anchor.Tag = Anchor.DefaultTag;
Anchor.Order = Anchor.DefaultOrder;
}
}
// Check validity of discipline name
Boolean CheckDisciplineNameIsValid(Text _Name) {
// Check name length
if (TextLib::Length(_Name) <= 0) {
return False;
}
// Check for invalid chars
for (Index, 0, TextLib::Length(_Name)-1) {
switch (TextLib::SubString(_Name, Index, 1)) {
case ":": {
return False;
}
case "\\": {
return False;
}
case "\"": {
return False;
}
}
}
return True;
}
// Extracts discipline of a goal tag
Text GetDisciplineFromGoalTag(Text _Tag) {
for (Index, 0, TextLib::Length(_Tag)-1) {
if (TextLib::SubString(_Tag, Index, 1) == ":") {
return TextLib::SubString(_Tag, 0, Index);
}
}
return "";
}
// Extracts goal type of a tag
Text GetGoalTypeFromTag(Text _Tag) {
for (Index, 0, TextLib::Length(_Tag)-1) {
if (TextLib::SubString(_Tag, Index, 1) == ":") {
return TextLib::SubString(_Tag, Index+2, TextLib::Length(_Tag)-2-Index);
}
}
return "";
}
// Assigns order for extra information to all goal anchors of a discipline
Void AssignExtraOrder(Text _Discipline, Integer _Order) {
foreach (Anchor in AnchorData) {
if ((Anchor.DefaultTag == "Goal" || Anchor.DefaultTag == "Checkpoint") && _Discipline == GetDisciplineFromGoalTag(Anchor.Tag)) {
if ("Goal" == GetGoalTypeFromTag(Anchor.Tag)) {
Anchor.Order = _Order;
} else {
Anchor.Order = 0;
}
}
}
}
// Get created disciplines of the map
Void GatherDisciplines() {
G_Disciplines.clear(); // Clear old disciplines
foreach (Anchor in AnchorData) {
switch (Anchor.DefaultTag) {
// Disciplines are defined by spawns
case "Spawn": {
// Ignore default spawns and check name validity
if (Anchor.Tag != "Spawn" && Anchor.Tag != C_LobbyName && CheckDisciplineNameIsValid(Anchor.Tag)) {
if (!G_Disciplines.existskey(Anchor.Tag)) {
// New discipline found - Save name and type
G_Disciplines[Anchor.Tag] = Anchor.Order;
}
}
}
}
}
}
// Counts goals of a discipline
Integer NumberOfDisciplineGoals(Text _Discipline, Text _GoalType) {
declare NbGoals = 0;
foreach (Anchor in AnchorData) {
if (Anchor.DefaultTag == "Goal" || Anchor.DefaultTag == "Checkpoint") {
// Only check goals
if (TextLib::SubString(Anchor.Tag, 0, TextLib::Length(_Discipline)) == _Discipline) {
// Goal belongs to the discipline
if (TextLib::SubString(Anchor.Tag, TextLib::Length(Anchor.Tag)-4, 4) == _GoalType) {
// Goal is a discipline goal
NbGoals += 1;
}
}
}
}
return NbGoals;
}
// Check if the map is valid
Void UpdateValidability() {
ValidationStatus = CSmMapType::ValidationStatus::NotValidable;
GatherDisciplines();
Anchor::UpdateAnchorCounts();
// Check for unused spawns
if (Anchor::HasAtLeastOneAnchor("Spawn", 0, "")) {
ValidabilityRequirementsMessage = "You have at least one unused Spawn!";
ValidationStatus = CSmMapType::ValidationStatus::NotValidable;
return;
}
// Check for unused goals
if (Anchor::HasAtLeastOneAnchor("Goal", 0, "")) {
ValidabilityRequirementsMessage = "You have at least one unused Goal!";
ValidationStatus = CSmMapType::ValidationStatus::NotValidable;
return;
}
// Check lobby
if (!Anchor::HasExactlyOneAnchor(C_LobbyName, 0, """You must place exactly one {{{C_LobbyName}}}!""")) return;
// Check disciplines
foreach (Name => Type in G_Disciplines) {
// Check for ports
if (NumberOfDisciplineGoals(Name, "Port") != 1) {
// Missing port
ValidabilityRequirementsMessage = """You must place at exactly one {{{Name}}} port!""";
ValidationStatus = CSmMapType::ValidationStatus::NotValidable;
return;
}
// Check for goals
switch (Type) {
case 3: {
// Run
if (NumberOfDisciplineGoals(Name, "Goal") < 1) {
// Missing finish
ValidabilityRequirementsMessage = """You must place at least one {{{Name}}} goal!""";
ValidationStatus = CSmMapType::ValidationStatus::NotValidable;
return;
}
}
case 4: {
// Rounds
if (NumberOfDisciplineGoals(Name, "Goal") < 2) {
// Missing checkpoints
ValidabilityRequirementsMessage = """You must place at least two {{{Name}}} checkpoints (goals)!""";
ValidationStatus = CSmMapType::ValidationStatus::NotValidable;
return;
}
// Check if rounds count is set
declare RoundsSet = True;
foreach (Anchor in AnchorData) {
if (Name == GetDisciplineFromGoalTag(Anchor.Tag) && "Spawn" != Anchor.DefaultTag && "Goal" == GetGoalTypeFromTag(Anchor.Tag)) {
if (Anchor.Order <= 0) {
RoundsSet = False;
}
}
}
if (!RoundsSet) {
// Rounds are not set!
ValidabilityRequirementsMessage = """You must set the amount of rounds for {{{Name}}}!""";
ValidationStatus = CSmMapType::ValidationStatus::NotValidable;
return;
}
}
}
}
ValidabilityRequirementsMessage = "";
ValidationStatus = CSmMapType::ValidationStatus::Validated;
}
// Return the manialink for spawn anchor edition
Text EditSpawnAnchorManialink(Ident _AnchorId) {
declare Manialink = """
""";
Index = 0;
foreach (Type => Name in C_DisciplineTypes) {
if (Index % 2 == 0) {
Manialink ^= """
""";
} else {
Manialink ^= """
""";
}
Index += 1;
}
Manialink ^= """
""";
return Manialink;
}
// Return the manialink for goal anchor edition
Text EditGoalAnchorManialink(Ident _AnchorId) {
declare Manialink = """
""";
Index = 0;
foreach (Name => Type in G_Disciplines) {
if (Index % 2 == 0) {
Manialink ^= """
""";
} else {
Manialink ^= """
""";
}
Index += 1;
}
Manialink ^= """
""";
return Manialink;
}
// Show the anchor edition manialink
Void EditAnchorData(Ident _EditedAnchorDataId) {
declare Integer AnchorOrder for ManialinkPage;
declare Text AnchorTag for ManialinkPage;
declare Text ExtraText for ManialinkPage;
declare Boolean Finish for ManialinkPage;
Finish = False;
AnchorOrder = AnchorData[_EditedAnchorDataId].Order;
AnchorTag = AnchorData[_EditedAnchorDataId].Tag;
if (G_Disciplines.existskey(AnchorTag) && G_Disciplines[AnchorTag] == 4) {
if (G_Rounds.existskey(AnchorTag)) {
ExtraText = ""^G_Rounds[AnchorTag];
} else {
ExtraText = ""^2;
}
} else {
ExtraText = "";
}
switch (AnchorData[_EditedAnchorDataId].DefaultTag) {
case "Spawn": {
ManialinkText = EditSpawnAnchorManialink(_EditedAnchorDataId);
}
case "Goal": {
if (G_Disciplines.count > 0) {
ManialinkText = EditGoalAnchorManialink(_EditedAnchorDataId);
} else {
Finish = True;
}
}
case "Checkpoint": {
if (G_Disciplines.count > 0) {
ManialinkText = EditGoalAnchorManialink(_EditedAnchorDataId);
} else {
Finish = True;
}
}
}
while (!Finish) {
yield;
}
switch (AnchorData[_EditedAnchorDataId].DefaultTag) {
case "Spawn": {
if (CheckDisciplineNameIsValid(AnchorTag)) {
AnchorData[_EditedAnchorDataId].Tag = AnchorTag;
AnchorData[_EditedAnchorDataId].Order = AnchorOrder;
if (AnchorOrder == C_DisciplineTypes.keyof("Rounds") && TextLib::ToInteger(ExtraText) > 0) {
G_Rounds[AnchorTag] = TextLib::ToInteger(ExtraText);
AssignExtraOrder(AnchorTag, G_Rounds[AnchorTag]);
}
}
}
case "Goal": {
AnchorData[_EditedAnchorDataId].Tag = AnchorTag;
if ("Port" == GetGoalTypeFromTag(AnchorTag)) {
AnchorData[_EditedAnchorDataId].Order = 0;
} else {
declare Discipline = GetDisciplineFromGoalTag(AnchorTag);
if (G_Rounds.existskey(Discipline)) {
AssignExtraOrder(Discipline, G_Rounds[Discipline]);
}
}
}
case "Checkpoint": {
AnchorData[_EditedAnchorDataId].Tag = AnchorTag;
if ("Port" == GetGoalTypeFromTag(AnchorTag)) {
AnchorData[_EditedAnchorDataId].Order = 0;
} else {
declare Discipline = GetDisciplineFromGoalTag(AnchorTag);
if (G_Rounds.existskey(Discipline)) {
AssignExtraOrder(Discipline, G_Rounds[Discipline]);
}
}
}
}
ManialinkText = "";
}
// Main
main() {
log("AthleticsArena.Script.txt loaded!");
log("Version: "^Version);
CustomEditAnchorData = True;
declare metadata Text ScriptVersion for Map;
ScriptVersion = Version;
GatherDisciplines();
UpdateValidability();
while (True) {
yield;
foreach (Index => Event in PendingEvents) {
switch (Event.Type) {
case CPluginEvent::Type::MapModified: {
UpdateValidability();
}
case CPluginEvent::Type::EditAnchor: {
EditAnchorData(Event.EditedAnchorDataId);
UpdateValidability();
}
case CPluginEvent::Type::StartValidation: {
StartTestMapWithMode("Athletics.Script.txt");
}
}
}
}
}