Ticket #23: barter_2011_11_23.diff

File barter_2011_11_23.diff, 21.0 KB (added by fcxSanya, 12 years ago)
  • source/simulation2/Simulation2.cpp

     
    120120            componentManager.AddComponent(SYSTEM_ENTITY, cid, noParam)
    121121
    122122            LOAD_SCRIPTED_COMPONENT("AIInterface");
     123            LOAD_SCRIPTED_COMPONENT("Barter");
    123124            LOAD_SCRIPTED_COMPONENT("EndGameManager");
    124125            LOAD_SCRIPTED_COMPONENT("GuiInterface");
    125126            LOAD_SCRIPTED_COMPONENT("PlayerManager");
  • binaries/data/mods/public/gui/session/session.xml

     
    524524                    </object>
    525525                </object>
    526526
     527                <object name="unitBarterPanel" hidden="true"
     528                    size="5 5 100% 100%"
     529                >
     530                    <object ghost="true" style="resourceText" type="text" size="0 0 100% 18">Exchange resources:</object>
     531                    <object size="0 18 100% 64">
     532                        <repeat count="4">
     533                            <object name="unitBarterSellButton[n]" style="iconButton" type="button" size="0 0 46 46" tooltip_style="sessionToolTipBottomBold">
     534                                <object name="unitBarterSellIcon[n]" type="image" ghost="true" size="3 3 43 43"/>
     535                                <object name="unitBarterSellAmount[n]" ghost="true" style="resourceText" type="text" size="0 0 100% 50%"/>
     536                            </object>
     537                        </repeat>
     538                    </object>
     539                    <object size="0 64 100% 110">
     540                        <repeat count="4">
     541                            <object name="unitBarterBuyButton[n]" style="iconButton" type="button" size="0 0 46 46" tooltip_style="sessionToolTipBottomBold">
     542                                <object name="unitBarterBuyIcon[n]" type="image" ghost="true" size="3 3 43 43"/>
     543                                <object name="unitBarterBuyAmount[n]" ghost="true" style="resourceText" type="text" size="0 0 100% 50%"/>
     544                            </object>
     545                        </repeat>
     546                    </object>
     547                    <object name="PerformDealButton" type="button" style="StoneButton" size="2 112 100%-7 142">
     548                        <object ghost="true" style="statsText" type="text" size="0 0 100% 100%">Barter</object>
     549                    </object>
     550                </object>
     551
    527552                <!-- Stance Selection -->
    528553                <object name="unitStancePanel"
    529554                    style="TranslucentPanel"
  • binaries/data/mods/public/gui/session/input.js

     
    10081008    inputState = INPUT_BUILDING_PLACEMENT;
    10091009}
    10101010
     1011// Called by GUI when user clicks exchange resources button
     1012function exchangeResources(command)
     1013{
     1014    Engine.PostNetworkCommand({"type": "barter", "sell": command.sell, "buy": command.buy, "amount": command.amount});
     1015}
     1016
     1017
    10111018// Batch training:
    10121019// When the user shift-clicks, we set these variables and switch to INPUT_BATCHTRAINING
    10131020// When the user releases shift, or clicks on a different training button, we create the batched units
  • binaries/data/mods/public/gui/session/unit_commands.js

     
    1313const UNIT_PANEL_BASE = -52; // QUEUE: The offset above the main panel (will often be negative)
    1414const UNIT_PANEL_HEIGHT = 44; // QUEUE: The height needed for a row of buttons
    1515
     16// Barter constants
     17const BARTER_RESOURCE_AMOUNT_TO_SELL = 100;
     18const BARTER_BUNCH_MULTIPLIER = 5;
     19const BARTER_RESOURCES = ["food", "wood", "stone", "metal"];
     20const BARTER_ACTIONS = ["Sell", "Buy"];
     21
    1622// The number of currently visible buttons (used to optimise showing/hiding)
    17 var g_unitPanelButtons = {"Selection": 0, "Queue": 0, "Formation": 0, "Garrison": 0, "Training": 0, "Construction": 0, "Command": 0, "Stance": 0};
     23var g_unitPanelButtons = {"Selection": 0, "Queue": 0, "Formation": 0, "Garrison": 0, "Barter": 0, "Training": 0, "Construction": 0, "Command": 0, "Stance": 0};
    1824
    1925// Unit panels are panels with row(s) of buttons
    20 var g_unitPanels = ["Selection", "Queue", "Formation", "Garrison", "Training", "Construction", "Research", "Stance", "Command"];
     26var g_unitPanels = ["Selection", "Queue", "Formation", "Garrison", "Barter", "Training", "Construction", "Research", "Stance", "Command"];
    2127
     28// Indexes of resources to sell and buy on barter panel
     29var g_barterSell = 0;
     30var g_barterBuy = 1;
     31
    2232// Lay out a row of centered buttons (does not work inside a loop like the other function)
    2333function layoutButtonRowCentered(rowNumber, guiName, startIndex, endIndex, width)
    2434{
     
    108118    }
    109119}
    110120
     121function selectBarterResourceToSell(resourceIndex)
     122{
     123    g_barterSell = resourceIndex;
     124    // g_barterBuy should be set to different value in case if it is the same as g_barterSell
     125    // (it is no make sense to exchange resource to the same one).
     126    // We change it cyclic to next value.
     127    if (g_barterBuy == g_barterSell)
     128        g_barterBuy = (g_barterBuy + 1) % BARTER_RESOURCES.length;
     129}
     130
    111131// Sets up "unit panels" - the panels with rows of icons (Helper function for updateUnitDisplay)
    112132function setupUnitPanel(guiName, usedPanels, unitEntState, items, callback)
    113133{
     
    368388    g_unitPanelButtons[guiName] = numButtons;
    369389}
    370390
     391// Sets up "unit barter panel" - special case for setupUnitPanel
     392function setupUnitBarterPanel(unitEntState)
     393{
     394    // Amount of player's resource to exchange
     395    var amountToSell = BARTER_RESOURCE_AMOUNT_TO_SELL;
     396    if (Engine.HotkeyIsPressed("session.massbarter"))
     397        amountToSell *= BARTER_BUNCH_MULTIPLIER;
     398    // One pass for each resource
     399    for (var i = 0; i < BARTER_RESOURCES.length; i++)
     400    {
     401        var resource = BARTER_RESOURCES[i];
     402        // One pass for 'sell' row and another for 'buy'
     403        for (var j = 0; j < 2; j++)
     404        {
     405            var selectedResourceIndex = [g_barterSell, g_barterBuy][j];
     406            var action = BARTER_ACTIONS[j];
     407
     408            var imageNameSuffix = (i == selectedResourceIndex) ? "selected" : "inactive";
     409            var icon = getGUIObjectByName("unitBarter" + action + "Icon["+i+"]");
     410
     411            var button = getGUIObjectByName("unitBarter" + action + "Button["+i+"]");
     412            button.size = (i * 46) + " 0 " + ((i + 1) * 46) + " 46";
     413            var amountToBuy;
     414            // In 'buy' row show black icon in place corresponding to selected resource in 'sell' row
     415            if (j == 1 && i == g_barterSell)
     416            {
     417                button.enabled = false;
     418                button.tooltip = "";
     419                icon.sprite = "";
     420                amountToBuy = "";
     421            }
     422            else
     423            {
     424                button.enabled = true;
     425                button.tooltip = action + " " + resource;
     426                icon.sprite = "stretched:session/resources/" + resource + "_" + imageNameSuffix + ".png";
     427                var sellPrice = unitEntState.barterMarket.prices["sell"][BARTER_RESOURCES[g_barterSell]];
     428                var buyPrice = unitEntState.barterMarket.prices["buy"][resource];
     429                amountToBuy = "+" + Math.round(sellPrice / buyPrice * amountToSell);
     430            }
     431            var amount;
     432            if (j == 0)
     433            {
     434                button.onpress = (function(i){ return function() { selectBarterResourceToSell(i); } })(i);
     435                amount = (i == g_barterSell) ? "-" + amountToSell : "";
     436            }
     437            else
     438            {
     439                button.onpress = (function(i){ return function() { g_barterBuy = i; } })(i);
     440                amount = amountToBuy;
     441            }
     442            getGUIObjectByName("unitBarter" + action + "Amount["+i+"]").caption = amount;
     443        }
     444    }
     445    var performDealButton = getGUIObjectByName("PerformDealButton");
     446    var exchangeResourcesParameters = { "sell": BARTER_RESOURCES[g_barterSell], "buy": BARTER_RESOURCES[g_barterBuy], "amount": amountToSell };
     447    performDealButton.onpress = (function(exchangeResourcesParameters){ return function() { exchangeResources(exchangeResourcesParameters) } })(exchangeResourcesParameters);
     448}
     449
    371450// Updates right Unit Commands Panel - runs in the main session loop via updateSelectionDetails()
    372451function updateUnitCommands(entState, supplementalDetailsPanel, commandsPanel, selection)
    373452{
     
    424503                function (item) { performStance(entState.id, item); } );
    425504        }
    426505
     506        getGUIObjectByName("unitBarterPanel").hidden = !entState.barterMarket;
     507        if (entState.barterMarket)
     508        {
     509            usedPanels["Barter"] = 1;
     510            setupUnitBarterPanel(entState);
     511        }
     512
    427513        if (entState.buildEntities && entState.buildEntities.length)
    428514        {
    429515            setupUnitPanel("Construction", usedPanels, entState, entState.buildEntities, startBuildingPlacement);
  • binaries/data/mods/public/simulation/helpers/Commands.js

     
    392392        }
    393393        break;
    394394
     395    case "barter":
     396        var cmpBarter = Engine.QueryInterface(SYSTEM_ENTITY, IID_Barter);
     397        cmpBarter.ExchangeResources(playerEnt, cmd.sell, cmd.buy, cmd.amount);
     398        break;
     399
    395400    default:
    396401        error("Invalid command: unknown command type: "+uneval(cmd));
    397402    }
  • binaries/data/mods/public/simulation/components/GuiInterface.js

     
    254254        };
    255255    }
    256256
     257    if (!cmpFoundation && cmpIdentity.HasClass("BarterMarket"))
     258    {
     259        var cmpBarter = Engine.QueryInterface(SYSTEM_ENTITY, IID_Barter);
     260        ret.barterMarket = { "prices": cmpBarter.GetPrices() };
     261    }
     262
    257263    var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
    258264    ret.visibility = cmpRangeManager.GetLosVisibility(ent, player);
    259265
  • binaries/data/mods/public/simulation/components/interfaces/Barter.js

     
     1Engine.RegisterInterface("Barter");
  • binaries/data/mods/public/simulation/components/Barter.js

     
     1// True price of 100 units of resource (for case if some resource is more worth).
     2// With current bartering system only relative values makes sense
     3// so if for example stone is two times more expensive than wood,
     4// there will 2:1 exchange rate.
     5const TRUE_PRICES = { "food": 100, "wood": 100, "stone": 100, "metal": 100 };
     6
     7// Constant part of price difference between true price and buy/sell price.
     8// In percents.
     9// Buy price equal to true price plus constant difference.
     10// Sell price equal to true price minus constant difference.
     11const CONSTANT_DIFFERENCE = 10;
     12
     13// Additional difference of prices, added after each deal to specified resource price.
     14// In percents.
     15const DIFFERENCE_PER_DEAL = 5;
     16
     17// Price difference which restored each restore timer tick
     18// In percents.
     19const DIFFERENCE_RESTORE = 2;
     20
     21// Interval of timer which slowly restore prices after deals
     22const RESTORE_TIMER_INTERVAL = 5000;
     23
     24// Array of resource names
     25const RESOURCES = ["food", "wood", "stone", "metal"];
     26
     27function Barter() {}
     28
     29Barter.prototype.Schema =
     30    "<a:component type='system'/><empty/>";
     31
     32Barter.prototype.Init = function()
     33{
     34    this.priceDifferences = {};
     35    for each (var resource in RESOURCES)
     36        this.priceDifferences[resource] = 0;
     37    this.restoreTimer = undefined;
     38};
     39
     40Barter.prototype.GetPrices = function()
     41{
     42    var prices = { "buy": {}, "sell": {} };
     43    for each (var resource in RESOURCES)
     44    {
     45        prices["buy"][resource] = TRUE_PRICES[resource] * (100 + CONSTANT_DIFFERENCE + this.priceDifferences[resource]) / 100;
     46        prices["sell"][resource] = TRUE_PRICES[resource] * (100 - CONSTANT_DIFFERENCE + this.priceDifferences[resource]) / 100;
     47    }
     48    return prices;
     49};
     50
     51Barter.prototype.PlayerHasMarket = function(playerEntity)
     52{
     53    var cmpPlayer = Engine.QueryInterface(playerEntity, IID_Player);
     54    var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager);
     55    var entities = cmpRangeManager.GetEntitiesByPlayer(cmpPlayer.GetPlayerID());
     56    for each (var entity in entities)
     57    {
     58        var cmpFoundation = Engine.QueryInterface(entity, IID_Foundation);
     59        var cmpIdentity = Engine.QueryInterface(entity, IID_Identity);
     60        if (!cmpFoundation && cmpIdentity.HasClass("BarterMarket"))
     61            return true;
     62    }
     63    return false;
     64}
     65
     66Barter.prototype.ExchangeResources = function(playerEntity, resourceToSell, resourceToBuy, amount)
     67{
     68    // Data verification
     69    if (amount <= 0)
     70    {
     71        warn("ExchangeResources: incorrect amount: " + uneval(amount));
     72        return;
     73    }
     74    if (RESOURCES.indexOf(resourceToSell) == -1)
     75    {
     76        warn("ExchangeResources: incorrect resource to sell: " + uneval(resourceToSell));
     77        return;
     78    }
     79    if (RESOURCES.indexOf(resourceToBuy) == -1)
     80    {
     81        warn("ExchangeResources: incorrect resource to buy: " + uneval(resourceToBuy));
     82        return;
     83    }
     84    if (!this.PlayerHasMarket(playerEntity))
     85    {
     86        warn("ExchangeResources: player has no markets");
     87        return;
     88    }
     89
     90    var cmpPlayer = Engine.QueryInterface(playerEntity, IID_Player);
     91    var prices = this.GetPrices();
     92    var amountsToSubtract = {};
     93    amountsToSubtract[resourceToSell] = amount;
     94    if (cmpPlayer.TrySubtractResources(amountsToSubtract))
     95    {
     96        var amountToAdd = Math.round(prices["sell"][resourceToSell] / prices["buy"][resourceToBuy] * amount);
     97        cmpPlayer.AddResource(resourceToBuy, amountToAdd);
     98        var numberOfDeals = Math.round(amount / 100);
     99
     100        // Increase price difference for both exchange resources.
     101        // Overal price difference (constant + dynamic) can't exceed +-99%
     102        // so both buy/sell prices limited to [1%; 199%] interval.
     103        this.priceDifferences[resourceToSell] -= DIFFERENCE_PER_DEAL * numberOfDeals;
     104        this.priceDifferences[resourceToSell] = Math.min(99-CONSTANT_DIFFERENCE, Math.max(CONSTANT_DIFFERENCE-99, this.priceDifferences[resourceToSell]));
     105        this.priceDifferences[resourceToBuy] += DIFFERENCE_PER_DEAL * numberOfDeals;
     106        this.priceDifferences[resourceToBuy] = Math.min(99-CONSTANT_DIFFERENCE, Math.max(CONSTANT_DIFFERENCE-99, this.priceDifferences[resourceToBuy]));
     107    }
     108
     109    if (this.restoreTimer == undefined)
     110    {
     111        var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     112        this.restoreTimer = cmpTimer.SetInterval(this.entity, IID_Barter, "ProgressTimeout", RESTORE_TIMER_INTERVAL, RESTORE_TIMER_INTERVAL, {});
     113    }
     114};
     115
     116Barter.prototype.ProgressTimeout = function(data)
     117{
     118    var needRestore = false;
     119    for each (var resource in RESOURCES)
     120    {
     121        // Calculate value to restore, it should be limited to [-DIFFERENCE_RESTORE; DIFFERENCE_RESTORE] interval
     122        var differenceRestore = Math.min(DIFFERENCE_RESTORE, Math.max(-DIFFERENCE_RESTORE, this.priceDifferences[resource]));
     123        differenceRestore = -differenceRestore;
     124        this.priceDifferences[resource] += differenceRestore;
     125        // If price difference still exists then set flag to run timer again
     126        if (this.priceDifferences[resource] != 0)
     127            needRestore = true;
     128    }
     129
     130    if (!needRestore)
     131    {
     132        var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer);
     133        cmpTimer.CancelTimer(this.restoreTimer);
     134    }
     135}
     136
     137Engine.RegisterComponentType(IID_Barter, "Barter", Barter);
     138
  • binaries/data/mods/public/simulation/components/Identity.js

     
    8282                        "<value>CivCentre</value>" +
    8383                        "<value>Economic</value>" +
    8484                        "<value>Defensive</value>" +
     85                        "<value>BarterMarket</value>" +
    8586                        "<value>Village</value>" +
    8687                        "<value>Town</value>" +
    8788                        "<value>City</value>" +
  • binaries/data/mods/public/simulation/templates/template_structure_economic_market.xml

     
    2323  </Health>
    2424  <Identity>
    2525    <GenericName>Market</GenericName>
    26     <Tooltip>Create Trade units and Barter resources. (Currently a useless structure)</Tooltip>
    27     <Classes datatype="tokens">Town</Classes>
     26    <Tooltip>Create Trade units and Barter resources.</Tooltip>
     27    <Classes datatype="tokens">Town BarterMarket</Classes>
    2828    <Icon>structures/market.png</Icon>
    2929  </Identity>
    3030  <Obstruction>
  • binaries/data/config/default.cfg

    Cannot display: file marked as a binary type.
    svn:mime-type = application/octet-stream
    
    Property changes on: binaries/data/mods/public/art/textures/ui/session/resources/food_selected.png
    ___________________________________________________________________
    Added: svn:mime-type
       + application/octet-stream
    
    Cannot display: file marked as a binary type.
    svn:mime-type = application/octet-stream
    
    Property changes on: binaries/data/mods/public/art/textures/ui/session/resources/wood_selected.png
    ___________________________________________________________________
    Added: svn:mime-type
       + application/octet-stream
    
    Cannot display: file marked as a binary type.
    svn:mime-type = application/octet-stream
    
    Property changes on: binaries/data/mods/public/art/textures/ui/session/resources/stone_selected.png
    ___________________________________________________________________
    Added: svn:mime-type
       + application/octet-stream
    
    Cannot display: file marked as a binary type.
    svn:mime-type = application/octet-stream
    
    Property changes on: binaries/data/mods/public/art/textures/ui/session/resources/metal_inactive.png
    ___________________________________________________________________
    Added: svn:mime-type
       + application/octet-stream
    
    Cannot display: file marked as a binary type.
    svn:mime-type = application/octet-stream
    
    Property changes on: binaries/data/mods/public/art/textures/ui/session/resources/food_inactive.png
    ___________________________________________________________________
    Added: svn:mime-type
       + application/octet-stream
    
    Cannot display: file marked as a binary type.
    svn:mime-type = application/octet-stream
    
    Property changes on: binaries/data/mods/public/art/textures/ui/session/resources/wood_inactive.png
    ___________________________________________________________________
    Added: svn:mime-type
       + application/octet-stream
    
    Cannot display: file marked as a binary type.
    svn:mime-type = application/octet-stream
    
    Property changes on: binaries/data/mods/public/art/textures/ui/session/resources/stone_inactive.png
    ___________________________________________________________________
    Added: svn:mime-type
       + application/octet-stream
    
    Cannot display: file marked as a binary type.
    svn:mime-type = application/octet-stream
    
    Property changes on: binaries/data/mods/public/art/textures/ui/session/resources/metal_selected.png
    ___________________________________________________________________
    Added: svn:mime-type
       + application/octet-stream
    
     
    179179hotkey.session.garrison = Ctrl              ; Modifier to garrison when clicking on building
    180180hotkey.session.queue = Shift                ; Modifier to queue unit orders instead of replacing
    181181hotkey.session.batchtrain = Shift           ; Modifier to train units in batches
     182hotkey.session.massbarter = Shift           ; Modifier to barter bunch of resources
    182183hotkey.session.deselectgroup = Ctrl         ; Modifier to deselect units when clicking group icon, instead of selecting
    183184hotkey.session.rotate.cw = RightBracket     ; Rotate building placement preview clockwise
    184185hotkey.session.rotate.ccw = LeftBracket     ; Rotate building placement preview anticlockwise