Ticket #4386: relics_poc.patch

File relics_poc.patch, 11.5 KB (added by Sandarac, 7 years ago)
  • binaries/data/mods/public/maps/scripts/Relics.js

     
     1Trigger.prototype.CheckRelicsVictory = function(data)
     2{
     3    let cmpIdentity = Engine.QueryInterface(data.entity, IID_Identity);
     4    if (!cmpIdentity || !cmpIdentity.HasClass("Relic") || data.from == -1)
     5        return;
     6
     7    if (data.from != 0)
     8        --this.playerRelicsCount[data.from];
     9
     10    ++this.playerRelicsCount[data.to];
     11
     12    this.CheckCountdown();
     13};
     14
     15/**
     16 * Check if an individual player or a team has acquired all the relics
     17 * Also check if the countdown needs to be stopped if a player/team no longer has all the relics
     18 */
     19Trigger.prototype.CheckCountdown = function()
     20{
     21    for (let playerID = 1; playerID < TriggerHelper.GetNumberOfPlayers(); ++playerID)
     22    {
     23        let playerAndAllies = QueryPlayerIDInterface(playerID).GetMutualAllies();
     24        let teamRelicsOwned = 0;
     25
     26        for (let ally of playerAndAllies)
     27            teamRelicsOwned += this.playerRelicsCount[ally];
     28
     29        if (teamRelicsOwned == this.relics.length - 1)
     30        {
     31            let data = { "entity": this.relics[playerID], "to": playerAndAllies };
     32            this.StartCountdown(data, playerAndAllies.length > 1);
     33            return;
     34        }
     35    }
     36
     37    this.DeleteRelicsVictoryMessages();
     38};
     39
     40Trigger.prototype.DeleteRelicsVictoryMessages = function()
     41{
     42    let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     43    let cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     44
     45    for (let ent in this.relicsVictoryMessages)
     46    {
     47        cmpGuiInterface.DeleteTimeNotification(this.relicsVictoryMessages[ent].ownMessage);
     48        cmpGuiInterface.DeleteTimeNotification(this.relicsVictoryMessages[ent].otherMessage);
     49        cmpTimer.CancelTimer(this.relicsVictoryTimers[ent]);
     50    }
     51};
     52
     53Trigger.prototype.StartCountdown = function(data, isTeam)
     54{
     55    let timer = this.relicsVictoryTimers[data.entity];
     56    let messages = this.relicsVictoryMessages[data.entity] || {};
     57
     58    let cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     59    let cmpGuiInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface);
     60
     61    if (timer)
     62    {
     63        cmpTimer.CancelTimer(timer);
     64        cmpGuiInterface.DeleteTimeNotification(messages.ownMessage);
     65        cmpGuiInterface.DeleteTimeNotification(messages.otherMessage);
     66    }
     67
     68    let players = [-1];
     69    for (let playerID = 1; playerID < TriggerHelper.GetNumberOfPlayers(); ++playerID)
     70    {
     71        let cmpPlayer = QueryPlayerIDInterface(playerID);
     72        if (cmpPlayer.GetState() == "won")
     73            return;
     74        if (data.to.indexOf(playerID) == -1)
     75            players.push(playerID);
     76    }
     77
     78    let cmpPlayer = QueryOwnerInterface(data.entity, IID_Player);
     79    messages.otherMessage = cmpGuiInterface.AddTimeNotification({
     80        "message": isTeam ? markForTranslation("%(player)s's team has captured all of the relics. They will have won in %(time)s") :
     81                            markForTranslation("%(player)s has captured all of the relics. They will have won in %(time)s"),
     82        "players": players,
     83        "parameters": {
     84            "player": cmpPlayer.GetName()
     85        },
     86        "translateMessage": true,
     87        "translateParameters": [],
     88    }, 10 * 60 * 1000); // 10 min
     89
     90    messages.ownMessage = cmpGuiInterface.AddTimeNotification({
     91        "message": isTeam ? markForTranslation("Your team has captured all of the relics. You will have won in %(time)s") :
     92                            markForTranslation("You have captured all of the relics. You will have won in %(time)s"),
     93        "players": data.to,
     94        "translateMessage": true,
     95    }, 10 * 60 * 1000);
     96
     97    timer = cmpTimer.SetTimeout(SYSTEM_ENTITY, IID_EndGameManager,
     98        "MarkPlayerAsWon", 10 * 60 * 1000, data.to[0]);
     99
     100    this.relicsVictoryTimers[data.entity] = timer;
     101    this.relicsVictoryMessages[data.entity] = messages;
     102};
     103
     104Trigger.prototype.InitRelicsGame = function()
     105{
     106    // Attempt to spawn one relic per player randomly in neutral territory
     107    let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     108    let cmpWaterManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_WaterManager);
     109    let cmpTerritoryManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TerritoryManager);
     110
     111    let validSpawnPoint = entity => {
     112
     113        let cmpIdentity = Engine.QueryInterface(entity, IID_Identity);
     114        let cmpPosition = Engine.QueryInterface(entity, IID_Position);
     115
     116        if (!cmpIdentity || !cmpPosition || !cmpPosition.IsInWorld())
     117            return false;
     118
     119        let pos = cmpPosition.GetPosition();
     120
     121        // do not spawn relics underwater
     122        if (cmpIdentity.HasClass("SeaCreature") || pos.y <= cmpWaterManager.GetWaterLevel(pos.x, pos.z) ||
     123            cmpTerritoryManager.GetOwner(cmpPosition.GetPosition2D().x, cmpPosition.GetPosition2D().y) != 0)
     124            return false;
     125
     126        return true;
     127    };
     128
     129    let gaiaEntities = cmpRangeManager.GetEntitiesByPlayer(0).filter(entity => validSpawnPoint(entity));
     130
     131    if (!gaiaEntities.length)
     132    {
     133        error("No relic spawn points on map");
     134        return;
     135    }
     136
     137    for (let i = 1; i < TriggerHelper.GetNumberOfPlayers(); ++i)
     138    {
     139        this.relics[i] = TriggerHelper.SpawnUnits(gaiaEntities[Math.floor(Math.random() * gaiaEntities.length)],
     140            "special_units/special_relic", 1, 0)[0];
     141        this.playerRelicsCount[i] = 0;
     142
     143        let cmpHealth = Engine.QueryInterface(this.relics[i], IID_Health);
     144        cmpHealth.SetUndeletable(true);
     145
     146        let cmpDamageReceiver = Engine.QueryInterface(this.relics[i], IID_DamageReceiver);
     147        cmpDamageReceiver.SetInvulnerability(true);
     148    }
     149};
     150
     151let cmpTrigger = Engine.QueryInterface(SYSTEM_ENTITY, IID_Trigger);
     152cmpTrigger.relics = [];
     153cmpTrigger.playerRelicsCount = [];
     154cmpTrigger.relicsVictoryTimers = {};
     155cmpTrigger.relicsVictoryMessages = {};
     156
     157cmpTrigger.DoAfterDelay(0, "InitRelicsGame", {});
     158cmpTrigger.RegisterTrigger("OnOwnershipChanged", "CheckRelicsVictory", { "enabled": true });
     159cmpTrigger.RegisterTrigger("OnDiplomacyChanged", "CheckCountdown", { "enabled": true });
  • binaries/data/mods/public/simulation/components/Identity.js

    Property changes on: binaries/data/mods/public/maps/scripts/Relics.js
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
     
    5454        "</element>" +
    5555    "</optional>" +
    5656    "<optional>" +
    57         "<element name='Classes' a:help='Optional list of space-separated classes applying to this entity. Choices include: Animal, Apadana, ArmyCamp, Ashoka, BarterMarket, Celt, CitizenSoldier, CivCentre, Colony, ConquestCritical, Defensive, Domestic, DropsiteFood, DropsiteMetal, DropsiteStone, DropsiteWood, Elephant, Female, FishingBoat, ForestPlant, Fortress, GarrisonFortress, GarrisonTower, Gates, Human, Iberian, Immortal, Italian, Juggernaut, Kennel, Lighthouse, LongWall, MercenaryCamp, Naval, NavalMarket, Organic, Palace, Palisade, Player, PtolemyIV, SeaCreature, SiegeWall, SpecialBuilding, StoneWall, Structure, Syssiton, Theater, Tower, Unit, WoodenTower'>" +
     57        "<element name='Classes' a:help='Optional list of space-separated classes applying to this entity. Choices include: Animal, Apadana, ArmyCamp, Ashoka, BarterMarket, Celt, CitizenSoldier, CivCentre, Colony, ConquestCritical, Defensive, Domestic, DropsiteFood, DropsiteMetal, DropsiteStone, DropsiteWood, Elephant, Female, FishingBoat, ForestPlant, Fortress, GarrisonFortress, GarrisonTower, Gates, Human, Iberian, Immortal, Italian, Juggernaut, Kennel, Lighthouse, LongWall, MercenaryCamp, Naval, NavalMarket, Organic, Palace, Palisade, Player, PtolemyIV, Relic, SeaCreature, SiegeWall, SpecialBuilding, StoneWall, Structure, Syssiton, Theater, Tower, Unit, WoodenTower'>" +
    5858            "<attribute name='datatype'>" +
    5959                "<value>tokens</value>" +
    6060            "</attribute>" +
  • binaries/data/mods/public/simulation/components/Trigger.js

     
    1111    "CinemaPathEnded",
    1212    "CinemaQueueEnded",
    1313    "ConstructionStarted",
     14    "DiplomacyChanged",
    1415    "Interval",
    1516    "OwnershipChanged",
    1617    "PlayerCommand",
     
    265266    this.CallEvent("PlayerWon", msg);
    266267};
    267268
     269Trigger.prototype.OnGlobalDiplomacyChanged = function(msg)
     270{
     271    this.CallEvent("DiplomacyChanged", msg);
     272};
     273
    268274/**
    269275 * Execute a function after a certain delay.
    270276 *
  • binaries/data/mods/public/simulation/data/settings/victory_conditions/relics.json

     
     1{
     2    "TranslatedKeys": ["Title", "Description"],
     3    "Data":
     4    {
     5        "Title": "Relics",
     6        "Description": "Collect all of the relics spread across the map and keep them for a certain time to win the game.",
     7        "Scripts":
     8        [
     9            "scripts/TriggerHelper.js",
     10            "scripts/ConquestCommon.js",
     11            "scripts/Conquest.js",
     12            "scripts/Relics.js"
     13        ]
     14    }
     15}
  • binaries/data/mods/public/simulation/templates/special_units/special_relic.xml

    Property changes on: binaries/data/mods/public/simulation/data/settings/victory_conditions/relics.json
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
     
     1<?xml version="1.0" encoding="utf-8"?>
     2<Entity parent="template_unit">
     3  <Capturable>
     4    <CapturePoints>100</CapturePoints>
     5    <RegenRate>1</RegenRate>
     6    <GarrisonRegenRate>10</GarrisonRegenRate>
     7  </Capturable>
     8  <Cost>
     9    <Population>0</Population>
     10  </Cost>
     11  <Footprint replace="">
     12    <Square width="5.0" depth="12.0"/>
     13    <Height>2.0</Height>
     14  </Footprint>
     15  <Identity>
     16    <Civ>gaia</Civ>
     17    <Classes datatype="tokens">Relic</Classes>
     18    <GenericName>Relic</GenericName>
     19    <Icon>technologies/metal_pot.png</Icon>
     20    <Tooltip>Special unit for Relics games.</Tooltip>
     21  </Identity>
     22  <Selectable>
     23    <Overlay>
     24      <Texture>
     25        <MainTexture>circle/256x256.png</MainTexture>
     26        <MainTextureMask>circle/256x256_mask.png</MainTextureMask>
     27      </Texture>
     28    </Overlay>
     29  </Selectable>
     30  <UnitMotion>
     31    <WalkSpeed>6</WalkSpeed>
     32    <Run>
     33      <Speed>12.0</Speed>
     34    </Run>
     35  </UnitMotion>
     36  <VisualActor>
     37    <Actor>units/athenians/siege_spear_packed.xml</Actor>
     38  </VisualActor>
     39</Entity>
  • source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Map/Map.cpp

    Property changes on: binaries/data/mods/public/simulation/templates/special_units/special_relic.xml
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
     
    149149    gameTypes.Add(_T("wonder"));
    150150    gameTypes.Add(_T("endless"));
    151151    gameTypes.Add(_T("regicide"));
     152    gameTypes.Add(_T("relics"));
    152153
    153154    wxFlexGridSizer* gridSizer = new wxFlexGridSizer(2, 5, 5);
    154155    gridSizer->AddGrowableCol(1);