• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Diplomacy

Status
Not open for further replies.
Level 15
Joined
Nov 30, 2007
Messages
1,202
If I want to store the following information for 40 seconds. How do I go about it, the events would look this:

Player X offers Player Y either a or b.

There are 12 players in the map, and each can get have two pending offers at the same time from every player.

For player Y to accept player X offer, he reply by offering the same thing.

How would I temporarily store the above information to look for a pending offer of the same value between players?
 
Level 20
Joined
Jul 14, 2011
Messages
3,213
First, you need a system to make and take offers. I'd suggest a game text message like:

-offer PlayerX (Player number) YYY (Amount) Wood/Stone/Gold

Then you need to take the Substrings of the player, the amount, and the type of offer.

You need a Boolean array (or a Hash) to know if a player has received an offer of that type on the last 40 seconds, or if it already has too many offers pending to display a message like "Player has too many offers pending"

You basically need a Hashtable.

Let's asume that players goes on the parent Hash value (from 1 to 12), and you can offer Wood, Stone, and Gold (1, 2, 3) stored on child Hash value. BUT you also take offers, so you need 3 more child value slots, which can be Offer+3 (Offer made is stored in 1 -> Offers taken stored in 1+3 = 4).

- (Player 1) Offers (Player 6) 10 Wood
Save 10 (Ammount offered) as 1 (representing Wood Player offers) of 1 (The player 1) in Hash
Save 10 (Ammount offered) as 1 (representing Wood offered to this player) of 6 (The player 6) in Hash

Display a game text to involved players..

And so on.


It's hard to make a suggestion here because you have many things to determine and clarify in order for us (the Hiver's) to help you achieve what you want (or something similar or better)
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
First, you need a system to make and take offers. I'd suggest a game text message like:

-offer PlayerX (Player number) YYY (Amount) Wood/Stone/Gold

Then you need to take the Substrings of the player, the amount, and the type of offer.

You need a Boolean array (or a Hash) to know if a player has received an offer of that type on the last 40 seconds, or if it already has too many offers pending to display a message like "Player has too many offers pending"

You basically need a Hashtable.

Let's asume that players goes on the parent Hash value (from 1 to 12), and you can offer Wood, Stone, and Gold (1, 2, 3) stored on child Hash value. BUT you also take offers, so you need 3 more child value slots, which can be Offer+3 (Offer made is stored in 1 -> Offers taken stored in 1+3 = 4).

- (Player 1) Offers (Player 6) 10 Wood
Save 10 (Ammount offered) as 1 (representing Wood Player offers) of 1 (The player 1) in Hash
Save 10 (Ammount offered) as 1 (representing Wood offered to this player) of 6 (The player 6) in Hash

Display a game text to involved players..

And so on.


It's hard to make a suggestion here because you have many things to determine and clarify in order for us (the Hiver's) to help you achieve what you want (or something similar or better)

I applogize, the chat commands are down. I just don't want to create a variable for every player...

They are offering peace and alliance. ;)

Hashtables, it always returns to hashtables!


It would roughly work like this:

Event: Player A offers Player B ally or neutral.

IF player A already has a pending offer of (ally or neutral) to player B then
Remove the pending offer.

IF player B already has a pending offer on player A then
A accepts offer from B

ELSE
Display offer for B.
Set variable for Offer of type (ally or neutral) between A to B = TRUE.
WAIT 40 seconds
IF variable for Offer of type (ally or neutral) between A to B = TRUE then
Set variable for offer of type (ally or neutral) between A to B = FALSE

My trouble is containing the information in the "variable" in a way that's easy to access in a Boolean.

Information:
- Offer-type (alliance or neutrality)
- From player
- To player

Perhaps making a index of pending offers and then just loop through the index for a match, but making a index seems overly complicated for the task at hand.
 
Last edited:
Level 20
Joined
Jul 14, 2011
Messages
3,213
There are 12 players in the map, and each can get have two pending offers at the same time from every player.

12 (Players) x 12 = 144 indexes.

PlayerA (Player1) = 1-12
Player B (Player2) = 13-24
Player C (Player3) = 25-36
...
Player L (Player12) = 133-144

Assumming PlayerC (Player3) makes an offer to PlayerA (Player1) You can store that offer on Index[3]
If the same Player C (Player3) makes an offer to player B (Player2) you store it instead on Index[15]

Formula is (OfferedPlayerNumber * 12) + (OfferingPlayerNumber - 12)

Assumming PlayerC (Player3) makes an offer to PlayerA (Player1) You can store that offer on Index[(1*12) + (3-12) = 12-9 = 3] = True
If the same Player C (Player3) makes an offer to player B (Player2) you store it instead on Index[(2*12) + (3-12) = 24 - 9 = 15] = True

Whenever a player(A) makes an offer to another(B), you first check if the player B has already made an offer to A in order to know if he's initiating and offer or responding to an already made offer.

You keep track of the amount of offers per player with a simple Integer Array. Every time a player makes/receives an offer you make PlayerOffers[PlayerNumber] = PlayerOffers[PlayerNumber]+1. If it's already 2, you display some message.

The tricky part comes with the 40 secs timer... You can use a Timer Array default size of 24 so you can use 1-12 for one pending offer, and 13-24 for the other pending offer. Same way as before, here the indexes for the players offers are 1 and 13 for player1, 2 and 14 for player 2, and so on. Basically PlayerNumber for offer 1, and Playernumber+12 for offer 2.

When the timer expires you set PlayerOffers[PlayerNumber] = PlayerOffers[PlayerNumber]-1 to adjust the amount of pending offers.
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
AH, I was trying to wrap my head around that, you put explained it to be so simple: Thanks!

JASS:
function OfferNeutral  takes string s returns boolean
    if s == "-neutral " then
        return true
    elseif s == "-na " then
        return true
    elseif s == "-peace " then
        return true
    endif
    return false
endfunction

function GetPlayerName takes string s returns integer 
    if (s == "red" or s == udg_DIPS_Faction[0] or s == udg_DIPS_Name[0]) then
        return Player(0)    
    // ...
    endif
    return null
endfunction

How would I check using the above functions combined to compare if a string is true.

Step 1) Detect if its an ally/neutral/war command. okey easy enough. But how do I split up the string to see if there is a match in the entered player name aswell - substring and how would I determine where to start the substring?

"-na red"
"-peace red"
"-war red"
"-unally red"
"-ally red"

Function GetCommandLength and then check the player after that. Dunno how to determine command length though... it would be by looping and check where the " " (spacing occurs) but can't get it to work.

  • Untitled Trigger 003
    • Events
      • Player - Player 3 (Teal) types a chat message containing -na deep as A substring
    • Conditions
      • (Substring((Entered chat string), 5, 999)) Equal to deep
    • Actions
      • Game - Display to (All players) the text: !!!
      • For each (Integer A) from 0 to 10, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Substring((Entered chat string), (Integer A), ((Integer A) + 1))) Equal to
            • Then - Actions
              • Game - Display to (All players) the text: (String((Integer A)))
            • Else - Actions
The above trigger should Print "4" but it doesn't, it only prints "!!!!" even though there is a spacing (" ") in the condition. ;(
 
Last edited:
Level 15
Joined
Nov 30, 2007
Messages
1,202
If using "-na", substring(4,length)
If using "-peace", substring(8,length)
etc
(using GUI. In jass, you'd probably subtract 1 from each of those if the first position is 0 and not 1)

You'll need to check each case based on which command was used.

I was thinking it would loop through the string and search for a spacing instead of adding a return value for each string yourself. But alas, it doesn't work for me.

How to find the space and store them into two separate Strings?

JASS:
    // How? 
function GetCommandLength takes string s returns integer
    local integer i = 0
    loop
        if (*************) then         // Look for first spacing " " in string. 
            return i
        endif
    exitwhen i == StringLength(s) 
    endloop
    return 0
endfunction





JASS:
function GetPlayer takes string s returns player
    if (s == "red" or s == udg_DIPS_Faction[0] or s == udg_DIPS_Name[0]) then
        return Player(0)
    elseif (s == "blue" or s == udg_DIPS_Faction[1] or s == udg_DIPS_Name[1]) then
        return Player(1)
    elseif (s == "teal" or s == udg_DIPS_Faction[2] or s == udg_DIPS_Name[2]) then
        return Player(2)
    elseif (s == "purple" or s == udg_DIPS_Faction[3] or s == udg_DIPS_Name[3]) then
        return Player(3)
    elseif (s == "yellow" or s == udg_DIPS_Faction[4] or s == udg_DIPS_Name[4]) then
        return Player(4)
    elseif (s == "orange" or s == udg_DIPS_Faction[5] or s == udg_DIPS_Name[5]) then
        return Player(5)
    elseif (s == "green" or s == udg_DIPS_Faction[6] or s == udg_DIPS_Name[6]) then
        return Player(6)
    elseif (s == "pink" or s == udg_DIPS_Faction[7] or s == udg_DIPS_Name[7]) then
        return Player(7)
    elseif (s == "gray" or s == "grey" or s == udg_DIPS_Faction[8] or s == udg_DIPS_Name[8]) then
        return Player(8)
    elseif (s == "light blue" or s == "lightblue" or s == "lb" or s == udg_DIPS_Faction[9] or s == udg_DIPS_Name[9]) then
        return Player(9)
    elseif (s == "dark green" or s == "darkgreen" or s == "dg" or s == udg_DIPS_Faction[10] or s == udg_DIPS_Name[10]) then
        return Player(10)
    elseif (s == "brown" or s == udg_DIPS_Faction[11] or s == udg_DIPS_Name[11]) then
        return Player(11)
    endif
    return null
endfunction

function AllyCommand takes string s returns boolean
    if (s == "-ally") then
        return true
    endif
    return false
endfunction

function NeutralCommand takes string s returns boolean
    if (s == "-neutral" or s == "-na" or s == "-peace") then
        return true
    endif
    return false
endfunction

function WarCommand takes string s returns boolean
    if (s == "-war" or s == "-unally") then
        return true
    endif
    return false
endfunction

    // How? 
function GetSpacing takes string s returns integer
    local integer i = 0
    loop
        if (1 == 1) then
            return i
        endif
    exitwhen i == StringLength(s) 
    endloop
    return 0
endfunction


function Commands_Actions takes nothing returns boolean
    local integer i = GetSpacing(GetEventPlayerChatString())
    local string s1 = "First part of the substring 0-where the devide is."
    local string s2 = "Second part of the subtring after the devide"
    local player p = GetPlayer(s2)
    local trigger t

    if (p != null) then

        if (AllyCommand(s1) == true) then
            set t = gg_trg_Ally
            set udg_DIPS_PlayerGiving = GetTriggerPlayer()
            set udg_DIPS_PlayerRecieving = p
            call ConditionalTriggerExecute(t)

        elseif (NeutralCommand(s1) == true) then
            set t = gg_trg_Neutral
            set udg_DIPS_PlayerGiving = GetTriggerPlayer()
            set udg_DIPS_PlayerRecieving = p
            call ConditionalTriggerExecute(t)

        elseif (WarCommand(s1) == true) then
            set t = gg_trg_War
            set udg_DIPS_PlayerGiving = GetTriggerPlayer()
            set udg_DIPS_PlayerRecieving = p
            call ConditionalTriggerExecute(t)
        endif
    endif 
    
    set t = null
    set p = null
    return false
endfunction


//===========================================================================
function InitTrig_Commands takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterPlayerChatEvent( t, Player(0), "-", false )
    call TriggerRegisterPlayerChatEvent( t, Player(1), "-", false )
    call TriggerRegisterPlayerChatEvent( t, Player(2), "-", false )
    call TriggerRegisterPlayerChatEvent( t, Player(3), "-", false )
    call TriggerRegisterPlayerChatEvent( t, Player(4), "-", false )
    call TriggerRegisterPlayerChatEvent( t, Player(5), "-", false )
    call TriggerRegisterPlayerChatEvent( t, Player(6), "-", false )
    call TriggerRegisterPlayerChatEvent( t, Player(7), "-", false )
    call TriggerRegisterPlayerChatEvent( t, Player(8), "-", false )
    call TriggerRegisterPlayerChatEvent( t, Player(9), "-", false )
    call TriggerRegisterPlayerChatEvent( t, Player(10), "-", false )
    call TriggerRegisterPlayerChatEvent( t, Player(11), "-", false )
    call TriggerAddCondition( t, Condition( function Commands_Actions ))
    set t = null
endfunction
 
Last edited:
Level 15
Joined
Nov 30, 2007
Messages
1,202
  • (Substring((Entered chat string), 5, 999)) Equal to deep
wat. Seriously? 999?

You are right. It should be:

  • (Substring((Entered chat string), 5, 666)) Equal to deep
But in JASS now. How do I split a string into two by looping trough the characters to find the spacing.

Entered Chat String: Hi Bob! (Spacing between 2 and 3 i.e. return 2.)
set s1 = Substring(0,1)
set s2 = Substring(3,6)
 
Level 25
Joined
Jul 10, 2006
Messages
3,315
  • dsfdsaf
    • Events
    • Conditions
    • Actions
      • -------- find the space --------
      • Set search = True
      • For each (Integer A) from 1 to 10, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Substring((Entered chat string), (Integer A), (Integer A))) Equal to
              • search Equal to True
            • Then - Actions
              • -------- save the space position --------
              • Set spacePos = (Integer A)
              • -------- stop searching for another space --------
              • Set search = False
            • Else - Actions
      • Set playerString = (Substring((Entered chat string), (spacePos + 1), (Length of (Entered chat string))))
      • Set commandString = (Substring((Entered chat string), 1, (spacePos - 1)))
Example input:
Code:
-	p	e	a	c	e	 	P	i	n	z	u
1	2	3	4	5	6	7	8	9	10	11	12
						^					
					-1		+1				len

The loop finds a space at 7, saves 7 and stops searching.
Command is set to substring(1, 7-1)
Player is set to substring(7+1, length) //length = 12
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
  • dsfdsaf
    • Events
    • Conditions
    • Actions
      • -------- find the space --------
      • Set search = True
      • For each (Integer A) from 1 to 10, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • (Substring((Entered chat string), (Integer A), (Integer A))) Equal to
              • search Equal to True
            • Then - Actions
              • -------- save the space position --------
              • Set spacePos = (Integer A)
              • -------- stop searching for another space --------
              • Set search = False
            • Else - Actions
      • Set playerString = (Substring((Entered chat string), (spacePos + 1), (Length of (Entered chat string))))
      • Set commandString = (Substring((Entered chat string), 1, (spacePos - 1)))
Example input:
Code:
-	p	e	a	c	e	 	P	i	n	z	u
1	2	3	4	5	6	7	8	9	10	11	12
						^					
					-1		+1				len

The loop finds a space at 7, saves 7 and stops searching.
Command is set to substring(1, 7-1)
Player is set to substring(7+1, length) //length = 12

Thanks, again!
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
The tricky part comes with the 40 secs timer... You can use a Timer Array default size of 24 so you can use 1-12 for one pending offer, and 13-24 for the other pending offer. Same way as before, here the indexes for the players offers are 1 and 13 for player1, 2 and 14 for player 2, and so on. Basically PlayerNumber for offer 1, and Playernumber+12 for offer 2.

When the timer expires you set PlayerOffers[PlayerNumber] = PlayerOffers[PlayerNumber]-1 to adjust the amount of pending offers.

Sadly you can offer everyone at the same time. ;(

So practically everyone could type in the start of the game -na all

JASS:
DIPS_OIdex[] = refers to your formula, i.e. PendingOffer[] 
DIPS_OIdexTime[] = time left
DIPS_OIdexCount = Current Range of Index

  • Pending Offers
    • Events
      • Time - Every 1.00 seconds of game time
    • Conditions
      • DIPS_IndexCount Greater than -1
    • Actions
      • For each (Integer A) from 0 to DIPS_IndexCount, do (Actions)
        • Loop - Actions
          • If (All Conditions are True) then do (Then Actions) else do (Else Actions)
            • If - Conditions
              • DIPS_Time[(Integer A)] Equal to 0
            • Then - Actions
              • -------- Remove Offer from Index --------
              • Set DIPS_PendingOffer[DIPS_Index[(Integer A)]] = False
              • Set DIPS_Index[(Integer A)] = DIPS_Index[DIPS_IndexCount]
              • Set DIPS_Time[(Integer A)] = DIPS_Time[DIPS_IndexCount]
              • Set DIPS_IndexCount = (DIPS_IndexCount - 1)
            • Else - Actions
              • Set DIPS_Time[(Integer A)] = (DIPS_Time[(Integer A)] - 1)
Might that work?

Should I turn off this trigger when the index is empty? (It might be over extended periods of time)
 
Last edited:
Level 20
Joined
Jul 14, 2011
Messages
3,213
That seems like could/should work. And yeah, turn on the trigger when someone offers, and turn off when index is empty. Thou a 1.00 periodic trigger is really light it's a good practice to keep stuff efficient.
 
Level 15
Joined
Nov 30, 2007
Messages
1,202
Okey I finnished the neutral command, however it breaks if I add multiple players and them remove. (I can't withdraw the offer when multiple players are pending) I don't know why that happens but it must be something with the index (PenDex). Can you see a obvios flaw with it? :>

JASS:
library Diplomacy initializer init 

globals
    private constant integer PENDING_TIME = 30
    boolean array PendingOffer
    integer array PenDexPointer
    integer array PenDexTime
    integer PenDexMax = -1
    string array Faction
    string array Name
endglobals

private function PlayerCommand takes string s returns integer 
     if (s == "red" or s == "sparta" or s == udg_DIPS_Name[0]) then
        return 0
    elseif (s == "blue" or s == "athens" or s == udg_DIPS_Name[1]) then
        return 1
    elseif (s == "teal" or s == "argos" or s == udg_DIPS_Name[2]) then
        return 2
    elseif (s == "purple" or s == "thebes" or s == udg_DIPS_Name[3]) then
        return 3
    elseif (s == "yellow" or s == "pirus"  or s == udg_DIPS_Name[4]) then
        return 4
    elseif (s == "orange" or s == "macedon" or s == udg_DIPS_Name[5]) then
        return 5
    elseif (s == "green" or s == "thessaly" or s == udg_DIPS_Name[6]) then
        return 6
    elseif (s == "pink" or s == "crete" or s == udg_DIPS_Name[7]) then
        return 7
    elseif (s == "gray" or s == "grey" or s == "persia" or s == udg_DIPS_Name[8]) then
        return 8
    elseif (s == "light blue" or s == "lightblue" or s == "thrace" or s == udg_DIPS_Name[9]) then
        return 9
    elseif (s == "dark green" or s == "darkgreen" or s == "dg" or s == "rhodes" or s == udg_DIPS_Name[10]) then
        return 10
    elseif (s == "brown" or s == "troy" or s == udg_DIPS_Name[11]) then
        return 11
   // elseif (s == "all") then
   //     return 12
    endif
    return 13
endfunction

private function NeutralCommand takes string s returns boolean
    if (s == "neutral" or s == "na" or s == "peace") then
        return true
    endif
    return false
endfunction

function AllyCommand takes string s returns boolean
    if (s == "ally") then
        return true
    endif
    return false
endfunction

private function convert takes integer formula returns integer 
    local integer i = 0
    loop
        exitwhen i > PenDexMax
        if (formula == PenDexPointer[i]) then
            return i 
        endif
    endloop
    return -1
endfunction

function RemovePenDex takes integer i returns nothing
    call BJDebugMsg(I2S(PenDexPointer[i]) + " was removed")
    set PendingOffer[PenDexPointer[i]] = false 
    set PenDexTime[i] = PenDexTime[PenDexMax]
    set PenDexPointer[i] = PenDexPointer[PenDexMax]
    set PenDexMax = PenDexMax - 1
endfunction

private function main takes nothing returns boolean 
    local string s = GetEventPlayerChatString()
    local integer sender = GetPlayerId(GetTriggerPlayer())
    local integer reciever 
    local string array word
    local integer cur = 0
    local integer i = 1
    local integer formula 

    loop
        exitwhen i > StringLength(s) 
        if (SubString(s,i, i+1) == " ") then
            set cur = cur + 1
        else
            set word[cur] = word[cur] + SubString(s,i,i+1) 
        endif
        set i = i + 1
    endloop
    set i = 0
    loop
        exitwhen word[i] == null
        set word[i] = StringCase(word[i], false) 
        set i = i + 1
    endloop
    
    set reciever = PlayerCommand(word[1])

    // + 144 for ally 
    
    
    if (NeutralCommand(word[0]) == true and reciever != 13) then 
    
        if (IsPlayerEnemy(Player(sender), Player(reciever)) == true) then
    
            if (PendingOffer[(reciever+1)*12+(sender+1)-12] == true) then
                // Accept Pending Offer
                set formula = (reciever+1)*12+(sender+1)-12
                call RemovePenDex(convert(formula))
                call BJDebugMsg(GetPlayerName(Player(reciever)) + " and " + GetPlayerName(Player(sender)) + " are now neutral!") 
                call SetPlayerAllianceStateBJ( Player(reciever), Player(sender), bj_ALLIANCE_NEUTRAL)
                call SetPlayerAllianceStateBJ( Player(sender), Player(reciever), bj_ALLIANCE_NEUTRAL)
        
            elseif (PendingOffer[(sender+1)*12+(reciever+1)-12] == false) then
                // Make Offer
                if (PenDexMax == -1) then
                    call EnableTrigger(PendingTimer)
                endif
                set formula = (sender+1)*12+(reciever+1)-12
                set PendingOffer[formula] = true 
                set PenDexMax = PenDexMax + 1
                set PenDexPointer[PenDexMax] = formula 
                set PenDexTime[PenDexMax] = PENDING_TIME
                call BJDebugMsg(GetPlayerName(Player(sender)) + " has offered " + GetPlayerName(Player(reciever)) + " neutrality!")
            else
                // Withdraw Offer
                set formula = (sender+1)*12+(reciever+1)-12 
                call RemovePenDex(convert(formula))
                call BJDebugMsg(GetPlayerName(Player(sender)) + " has withdrawn offer (neutrality) from " + GetPlayerName(Player(reciever)) + "!")
            endif
        else
            call BJDebugMsg("You are already allied/neutral")
        endif
        endif
    
    return false 
endfunction

private function init takes nothing returns nothing
    local trigger t = CreateTrigger() 
    local integer p = 0
    loop
        exitwhen p > 11
        call TriggerRegisterPlayerChatEvent(t, Player(p),"-", false) 
        set p = p + 1
    endloop
    call TriggerAddCondition( t, Condition( function main ))
    set t = null
endfunction

endlibrary
JASS:
library PendingOffers initializer init 
    
globals
    trigger PendingTimer
endglobals

private function main takes nothing returns boolean
    local integer i = 0
    if (PenDexMax == -1) then 
        call DisableTrigger(PendingTimer)
        call BJDebugMsg("Trigger OFF")
    endif
    loop
        exitwhen i > PenDexMax
        if (PenDexTime[i] == 0) then
            call RemovePenDex(i)
        else
            set PenDexTime[i] = PenDexTime[i] - 1
            call BJDebugMsg(I2S(PenDexTime[i]))
        endif
        set i = i + 1
    endloop
    return false 
endfunction

//===========================================================================
private function init takes nothing returns nothing
    set PendingTimer = CreateTrigger()
    call TriggerRegisterTimerEventPeriodic(PendingTimer, 1.00 )
    call TriggerAddAction(PendingTimer, function main )
endfunction

endlibrary
 
Last edited:
Status
Not open for further replies.
Top