How to implement turn based MP

Nefliqus

Prince
Joined
Sep 16, 2010
Messages
400
Location
Poland
I think that it is possible to implement sequential turn in MP using current SDK and modding 2 system file on local PCs. Below you can find description of this idea and sample code.
Ok, let;s start with basic plan, requirements and assumption:
1) I want to implement "Player Units Moving Turn" during standard simultaneous turn.
2) I want to implement all change transparently to single player games and all others MODs. Basically by adding ScripData by map script and checking it in system function that I have to change.
3) At the beginning of all turns I want to set zero movements points for all units. So nobody can move their units before turn sequence but players can change setting and e.g cities...
4) I want to active Moving Player sequential from Player[0] to Player[21]
5) I want to set movements points to max for all units of Moving Player at the beginning o his Moving Turn.
6) I want change again moving point to zero after finishing Moving Turn by relevant player who has ended his Moving Turn.

Ok, now description how i want to do it.
Step #1:
First thing it is to change to zero movement points of all players and active first Moving Player. I will use for this Events.ActivePlayerTurnStart
Sample code (I plan use ScripData to mark current Moving Player):
Spoiler :

Code:
Events.ActivePlayerTurnStart.Add(function()
    for iPlayer_ID = 0, GameDefines.MAX_MAJOR_CIVS - 1 do
        if iPlayer_ID ~= 0 then
            local pPlayer = Players[iPlayer_ID];
            if ( pPlayer ~= nil and pPlayer:GetStartingPlot() ~= nil and pPlayer:IsAlive() == true) then --if valid
                if (pPlayer:IsHuman() == true and pPlayer:IsBarbarian() == false) then
                    local sInfoText = nil;
                    for u in pPlayer:Units() do
                        u:SetName("Waiting!");
                        u:SetMoves(0);
                    end
                    local SetScriptDataTxt = tostring(0);
                    pPlayer:SetScriptData(SetScriptDataTxt);
                end
            end
        else
            local pPlayer = Players[iPlayer_ID];
            for u in pPlayer:Units() do
                u:SetMoves(u:MaxMoves());
                u:SetName("Idle!");
            end
        end
    end


end);

Step #2:
Next step it is to change Moving Player to next one. First we need function that will change movements points (old Moving Player points to zero and new Moving Player to maximum). It is example of such function:


Spoiler :

Code:
function DoNextPlr()
    local iActPlayer_ID = nil;
    for i = 0,  GameDefines.MAX_MAJOR_CIVS - 1  do
        local YourTurn = Players[i]:GetScriptData();
        if tonumber(YourTurn) == 1 then
            iActPlayer_ID = i;
            break
        end
    end    
    
    if iActPlayer_ID  ~= nil then
        if iActPlayer_ID ~=  Game.GetActivePlayer() then
            local labelText = "This is " .. Players[iActPlayer_ID]:GetName() .. " turn! Pls try later!"
            Controls.NextPlrLabel:LocalizeAndSetText(labelText);
            Controls.Grid:DoAutoSize();
            return
        end
    else
        ContextPtr:SetHide( true );
        return
    end
    
    if Game.GetGameTurn() > 5 then
        local pActPlayer = Players[iActPlayer_ID];
        ----
        --deactive player
        ----
        if (pActPlayer:IsHuman() == true and pActPlayer:IsBarbarian() == false) then
            for u in pActPlayer:Units() do
                local sInfoText = nil;
                u:SetName("End!");
                u:SetMoves(0); 
            end
            local SetScriptDataTxt = tostring(0);
            pActPlayer:SetScriptData(SetScriptDataTxt);
        end
        ----
        --active next player                    
        ----
        for nextPlr_ID = 0, GameDefines.MAX_MAJOR_CIVS - 1  do
            local nextPlr = Players[nextPlr_ID];
            if ( nextPlr ~= nil and nextPlr:GetStartingPlot() ~= nil and nextPlr:IsAlive() == true) then --if valid
                if (nextPlr:IsHuman() == true and nextPlr:IsBarbarian() == false and nextPlr_ID > iActPlayer_ID ) then --if next human
                    local YourTurn = Players[nextPlr_ID]:GetScriptData();
                    if (tonumber(YourTurn) == 0 or tonumber(YourTurn) == nil) then --if not active (to be sure)
                        for u in nextPlr:Units() do
                           u:SetMoves(u:MaxMoves());
                           u:SetName("Idle!");
                        end
                        Players[nextPlr_ID]:AddNotification(NotificationTypes.NOTIFICATION_GENERIC, "Your turn, you can move your units now." , "Your turn.");
                        local labelText = Players[nextPlr_ID]:GetName() .. " is moving.";
                        Controls.NextPlrLabel:LocalizeAndSetText(labelText);
                        Controls.Grid:DoAutoSize();
                        local SetScriptDataTxt = tostring(1);
                        Players[nextPlr_ID]:SetScriptData(SetScriptDataTxt);
                        break
                    end
                end
            end -- valid end
        end --for end
    end --end game turn if
end



Step #3 is to trigger local function DoNextPlr() on all PCs when we want to change Moving Player. I plan to do it by:
a) adding context window with name of current moving player and button "Next Player" that will launch DoNextPlr() --> local player can activate Moving Turn change by pressing "Next Player" button
b) adding to players list update function trigger that will monitor pPlayer:HasReceivedNetTurnComplete() status and launch DoNextPlr() when Moving Player finish his turn on remote PCs --> automatic activation Moving Turn change on remote PC

Step #3a:

Adding contest window is ease. We need xml file e.g NextPlr.xml


Spoiler :

Code:
<Context ColorSet="Beige_Black_Alpha" Font="TwCenMT16" FontStyle="Shadow">
    <Grid ID="Grid" Offset="0,-10" Anchor="C,T" Size="300,60" Color="White.256" Style="Grid9DetailSix140" Padding="70,60" ConsumeMouse="1">
         <Label Anchor="L,C" Offset="30,-5" Font="TwCenMT20" ColorSet="Beige_Black_Alpha" FontStyle="Shadow" ID="NextPlrLabel">
          <GridButton Offset="10,-10" Font="TwCenMT16" Anchor="R,B" AnchorSide="o,i" Size="100,27" Style="SmallButton" String="Next Player" ID="NextPlr"/>
        </Label>
     </Grid>
</Context>


and add it to core system file: InGame.xml (first system file that we have to change). Just add such line:
Spoiler :

Code:
<Container Size="F,F" ID="BulkUI" >


[B]<LuaContext FileName="Assets/UI/InGame/NextPlr" ID="NextPlr" Hidden="True"/>[/B]



/Container>

It will add window defined in InGame.xml and include InGame.lue where you can past DoNextPlr() and Events.ActivePlayerTurnStart.Add

Step #3b is ease also. You have to change "if" from line 180 in MPlist.lua (second system file that we have to change)
Spoiler :

Code:
    -- turn finished
    if( pPlayer:HasReceivedNetTurnComplete() or not pPlayer:IsAlive() ) then
        controlTable.Name:SetAlpha( 0.5 );
        controlTable.IconBox:SetAlpha( 0.2 );

[B]        ---- change
            DoNextPlr();
        ----[/B]
        
    else
        controlTable.Name:SetAlpha( 1 );
        controlTable.IconBox:SetAlpha( 1 );
    end

and this is it.

If you see any logical problem according this procedure pls let me know.
 
I have made mod based of above idea.
To test it just copy file from attached rar file into your civ5 folder.
C:\Program Files\Steam\steamapps\common\sid meier's civilization v\
You have to overwrite two game files and restart civ5

Its works only with human players and games built by MirrorArenaPro_v8_6 map script. It is transparent to other SP games.
Sequential units movements start after 5th turn

Of course all players have to install it.

I have tested it only on Duel map.
Spoiler :

mini_Nefliqus_phpoAQg1z_turnbased.jpg


Its works but it is unstable and needs some more work. Without MP debugger I can fix it. Maybe someone can continue my work and can finish this mod.
 

Attachments

  • turnbased.jpg
    turnbased.jpg
    103.9 KB · Views: 139
hi :)

could you please explain in more detail about installing and launching this mod of yours?
Thanks,

Bala
 
hi :)

could you please explain in more detail about installing and launching this mod of yours?
Thanks,

Bala

1) DOWNLOAD install program from http://forum.civilization.org.pl/download.php?id=1346
2) run install program
3) Restart civ5
3) configure game on MirrorArena map
4) check sequential turn option (I think that it is the last one)
5) launch the game

It works only in duel (2 players only). I dont have 3 civ5 account to test it and fix it.
 
Thanks for the guide.

Maybe I could somehow help you test your mod for real multiplayer, more than just 2 players? If you are on Steam - contact "balamutas".

Btw, I am from Lithuania :)

Bala
 
Thanks for the guide.

Maybe I could somehow help you test your mod for real multiplayer, more than just 2 players? If you are on Steam - contact "balamutas".

Btw, I am from Lithuania :)

Bala

I have to see monitors to test it.
I don't plan to do any new change to this mods, I don't want to waste any more time on civ5 moding. You are welcome to continue my work.
 
Back
Top Bottom