| 05-14-2008, 06:19 AM | #1 |
Ok, this is the quest system i use in my UAV, somewhere within the code just caused the game to desync in multiplayer, i know the code is long, but it isnt really hard to understand (i think). The system code: JASS:library QuestSystem requires InitSupport, WaypointSystem, SubQuestStrings //**************************************************************************** //* * //* Quest System 1.0 * //* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ * //* This system contains all the foundemental functions for making quests * //* and such, another make-life-more-easier system. * //* * //**************************************************************************** globals private trigger QuestT private boolexpr fil private group PlayerHidedGroup private constant string update = "|cff00c400Quest Updated|r : " private constant string uprank = " |cff00c400Hero rank|r : " group QuestTempGroup boolexpr QuestTempBool quest MainQuest questitem MainQuestItem quest SubQuest questitem SubQuestItem integer SubQuestLimit = 40 string array SubQuestString boolean array SubQuestActivation endglobals //============================================================================================================ //Quest Updates //============================================================================================================ function UpdateQuest takes player p, string title, string descrip, string rank returns nothing local integer i = GetPlayerId(p) local string f = update+title if rank!=null and rank!="" then set f = f+uprank+rank set rank = "Rank: |cff00c400"+rank+"|r" endif if GetLocalPlayer() == p then call QuestSetDescription(MainQuest,descrip) call DisplayTimedTextToPlayer(p,0,0,6,f) if rank!=null and rank!="" then call QuestItemSetDescription(MainQuestItem,rank) endif call StartSound(bj_questDiscoveredSound) call KillSoundWhenDone(bj_questDiscoveredSound) endif endfunction function UpdateQuestAll takes string title, string descrip, string rank returns nothing local integer i = 0 local string s = update+title if rank!=null and rank!="" then set s = s+uprank+rank call QuestItemSetDescription(MainQuestItem,"Rank: |cff00c400"+rank+"|r") endif loop call DisplayTimedTextToPlayer(Player(i),0,0,6,s) set i=i+1 exitwhen i>5 endloop call StartSound(bj_questDiscoveredSound) call KillSoundWhenDone(bj_questDiscoveredSound) call QuestSetDescription(MainQuest,descrip) endfunction function UpdateSubQuest takes player p, string title, integer n, integer data returns nothing local integer i = GetPlayerId(p) local string e = "" if n==0 then call DisplayTimedTextToPlayer(p,0,0,6,"|cff00c400Optional Quest Discovered|r : "+title) set SubQuestActivation[data]=true elseif n==1 then call DisplayTimedTextToPlayer(p,0,0,6,"|cff00c400Optional Quest Updated|r : "+title) set SubQuestActivation[data]=true elseif n==2 then if title!=null and title!="" then call DisplayTimedTextToPlayer(p,0,0,6,"|cff00c400Optional Quest Completed|r : "+title) endif set SubQuestActivation[data]=false endif set n=0 loop if SubQuestActivation[n] then set e=e+SubQuestString[n] endif set n=n+1 exitwhen n>SubQuestLimit endloop if e=="" then set e="Currently you had not discovered any optional quests." endif if GetLocalPlayer() == p then call StartSound(bj_questDiscoveredSound) call KillSoundWhenDone(bj_questDiscoveredSound) call QuestSetDescription(SubQuest,e) endif endfunction //============================================================================================================ //Count living player (excluding leavers) //============================================================================================================ function CountPlayer takes nothing returns integer local player p local integer n=0 local integer r=0 loop set p = Player(n) if GetPlayerSlotState(p)==PLAYER_SLOT_STATE_PLAYING and GetPlayerController(p) == MAP_CONTROL_USER then set r=r+1 endif set n=n+1 exitwhen n>5 endloop set p=null return r endfunction //============================================================================================================ //enum n random units in a rect //============================================================================================================ globals private group gx = CreateGroup() endglobals private function enum_filter takes nothing returns boolean local unit u = GetFilterUnit() local boolean b if TempBool and IsUnitEnemy(u,Player(8)) then return false elseif not TempBool and not IsUnitEnemy(u,Player(8)) then return false endif set b = GetUnitAbilityLevel(u,'Aloc')==0 and GetWidgetLife(u)>0.405 and IsUnitInGroup(u,CreepGroup[GetUnitUserData(u)]) and not IsUnitType(u,UNIT_TYPE_STRUCTURE) set u=null return b endfunction function EnumUnitsInRect takes integer lim, rect r, boolean allies returns group local integer n = 0 call GroupClear(gx) set TempBool = allies call GroupEnumUnitsInRect(gx,r,fil) set bj_groupAddGroupDest=CreateGroup() loop set bj_groupRandomConsidered = 0 set bj_groupRandomCurrentPick = null call ForGroup(gx,function GroupPickRandomUnitEnum) exitwhen bj_groupRandomConsidered==0 if n<lim then call GroupAddUnit(bj_groupAddGroupDest,bj_groupRandomCurrentPick) call GroupRemoveUnit(gx,bj_groupRandomCurrentPick) set n=n+1 exitwhen n>=lim endif endloop call GroupClear(gx) return bj_groupAddGroupDest endfunction function CountUnitsInRect takes rect r, boolean allies returns integer local integer n = 0 call GroupClear(gx) set TempBool = allies call GroupEnumUnitsInRect(gx,r,fil) loop exitwhen FirstOfGroup(gx)==null call GroupRemoveUnit(gx,FirstOfGroup(gx)) set n=n+1 endloop return n endfunction //============================================================================================================ //Voting //============================================================================================================ private function EndVote takes nothing returns nothing local player p = GetTriggerPlayer() local force f = CreateForce() call ForceAddPlayer(f,p) call CinematicModeExBJ(true,f,0.5) call ForceRemovePlayer(f,p) call DestroyForce(f) call DisplayTextToPlayer(p,0,0,"Please wait for other players to cast their vote.") set p=null set f=null endfunction function VoteFor takes string title, string s1, string s2, string s3, string s4 returns integer local integer n = 0 local integer s local dialog d = DialogCreate() local trigger array trig local integer array count call CinematicModeExBJ(false,PlayerForce,0.2) call DialogSetMessage(d, title) set trig[0] = CreateTrigger() call TriggerRegisterDialogEvent(trig[0], d) call TriggerAddAction(trig[0],function EndVote) if s1!=null then set trig[1] = CreateTrigger() call TriggerRegisterDialogButtonEvent( trig[1], DialogAddButton(d,s1,1)) set s=1 endif if s2!=null then set trig[2] = CreateTrigger() call TriggerRegisterDialogButtonEvent( trig[2], DialogAddButton(d,s2,2)) set s=2 endif if s3!=null then set trig[3] = CreateTrigger() call TriggerRegisterDialogButtonEvent( trig[3], DialogAddButton(d,s3,3)) set s=3 endif if s4!=null then set trig[4] = CreateTrigger() call TriggerRegisterDialogButtonEvent( trig[4], DialogAddButton(d,s4,4)) set s=4 endif loop call DialogDisplay( Player(n), d, true) set n=n+1 exitwhen n>5 endloop set n=CountPlayer() loop exitwhen GetTriggerEvalCount(trig[0])>=n call TriggerSleepAction(0) endloop call DialogClear(d) call DialogDestroy(d) set d=null set n=0 loop set count[n] = GetTriggerEvalCount(trig[n]) call TriggerClearActions(trig[n]) call DestroyTrigger(trig[n]) set trig[n] = null set n=n+1 exitwhen n>s endloop //debug call DisplayTextToAll("Here's the vote result ! Count for first vote = "+I2S(count[1])+", Count for second vote = "+I2S(count[2])+", Count for third vote = "+I2S(count[3])+", Count for fourth vote = "+I2S(count[4]),5) set n=s set count[0]=s loop if count[count[0]]>count[n] then set n=count[0] endif set count[0]=count[0]-1 exitwhen count[0]<1 endloop if s==2 and count[1]==count[2] then call DisplayTextToAll("Looks like the votes is a tie, a random action is taken!",8) set n=GetRandomInt(1,2) elseif s==3 then if count[1]==count[2] and count[1]==count[3] then call DisplayTextToAll("Looks like the votes is a tie, a random action is taken!",8) set n=GetRandomInt(1,3) elseif count[1]==count[2] then call DisplayTextToAll("Looks like there is a few highest vote, a random action is taken!",8) set n=GetRandomInt(1,2) elseif count[1]==count[3] then call DisplayTextToAll("Looks like there is a few highest vote, a random action is taken!",8) set n=GetRandomInt(1,2) if n==2 then set n=3 endif elseif count[2]==count[3] then call DisplayTextToAll("Looks like there is a few highest vote, a random action is taken!",8) set n=GetRandomInt(2,3) endif elseif s==4 then if count[1]==count[2] then call DisplayTextToAll("Looks like there is a few highest vote, a random action is taken!",8) if count[1]==count[3] and count[1]==count[4] then set n=GetRandomInt(1,4) elseif count[1]==count[3] then set n=GetRandomInt(1,3) elseif count[1]==count[4] then set n=GetRandomInt(1,3) if n==3 then set n=4 endif else set n=GetRandomInt(1,2) endif elseif count[2]==count[3] then call DisplayTextToAll("Looks like there is a few highest vote, a random action is taken!",8) if count[2]==count[4] then set n=GetRandomInt(2,4) else set n=GetRandomInt(2,3) endif elseif count[1]==count[3] then call DisplayTextToAll("Looks like there is a few highest vote, a random action is taken!",8) if count[1]==count[4] then set n=GetRandomInt(2,4) if n==2 then set n=1 endif else set n=GetRandomInt(1,2) if n==2 then set n=3 endif endif elseif count[2]==count[4] then call DisplayTextToAll("Looks like there is a few highest vote, a random action is taken!",8) set n=GetRandomInt(2,3) if n==3 then set n=4 endif elseif count[1]==count[4] then call DisplayTextToAll("Looks like there is a few highest vote, a random action is taken!",8) set n=GetRandomInt(1,2) if n==2 then set n=4 endif elseif count[3]==count[4] then call DisplayTextToAll("Looks like there is a few highest vote, a random action is taken!",8) set n=GetRandomInt(3,4) endif endif return n endfunction //============================================================================================================ //UAV Cinematic Mode //============================================================================================================ function StartCinematic takes real x, real y returns nothing local integer n = 0 local group g = CreateGroup() set bj_pauseAllUnitsFlag = true set GameSwitch[0] = true loop if GetPlayerController(Player(n))==MAP_CONTROL_COMPUTER then call PauseCompAI(Player(n),true) endif if GetLocalPlayer() == Player(n) then call SetCameraBoundsToRect(GetWorldBounds()) call PanCameraToTimed(x,y,0) endif if n<6 then call SetUnitInvulnerable(PlayerHero[n],true) endif call GroupEnumUnitsOfPlayer(g,Player(n),null) call ForGroup(g,function PauseAllUnitsBJEnum) call GroupClear(g) set n=n+1 exitwhen n>15 endloop call CinematicModeExBJ(true,PlayerForce,0.5) call DestroyGroup(g) set g=null endfunction function EndCinematic takes nothing returns nothing local integer n = 0 local unit u local group g = CreateGroup() set GameSwitch[0] = false loop if GetWidgetLife(PlayerHero[n])>0.405 then set u=PlayerHero[n] else set u=PlayerGhost[n] endif if GetLocalPlayer()==Player(n) then call ResetToGameCamera(0) call SetCameraBoundsToRect(GetBigMap(GetUnitX(u),GetUnitY(u))) call PanCameraToTimed(GetUnitX(u),GetUnitY(u),0) endif call SetUnitInvulnerable(PlayerHero[n],false) set n=n+1 exitwhen n>5 endloop call CinematicModeExBJ(false,PlayerForce,0.5) set bj_pauseAllUnitsFlag = false set n=0 loop if GetPlayerController(Player(n))==MAP_CONTROL_COMPUTER then call PauseCompAI(Player(n),false) endif call GroupEnumUnitsOfPlayer(g,Player(n),null) call ForGroup(g,function PauseAllUnitsBJEnum) call GroupClear(g) set n=n+1 exitwhen n>15 endloop call DestroyGroup(g) set u=null set g=null endfunction //============================================================================================================ //Transmissions //============================================================================================================ function TransmissionToAllEx takes unit u, string d, string e, real t, boolean w returns nothing local real x = GetUnitX(u) local real y = GetUnitY(u) local string s = "|c00ff0303"+d+"|r : "+e call PingMinimap(GetUnitX(u),GetUnitY(u),t/2) call UnitAddIndicator(u,155,255,155,255) if GameSwitch[0] then call SetCinematicScene(GetUnitTypeId(u),GetPlayerColor(GetOwningPlayer(u)),d,e,t,t) else call SetCinematicScene(GetUnitTypeId(u),GetPlayerColor(GetOwningPlayer(u)),d,null,t,t) if (IsPlayerInForce(GetLocalPlayer(),PlayerForce)) then call DisplayTextToPlayer(GetLocalPlayer(),0,0,s) endif endif if w then call PolledWait(t) endif endfunction function TransmissionToAll takes unit u, string e, real t, boolean w returns nothing call TransmissionToAllEx(u,GetUnitName(u),e,t,w) endfunction //! define TransmissionToAll(u,e,t,w) TransmissionToAllEx(u,GetUnitName(u),e,t,w) function TransmissionToPlayerEx takes player p, unit u, string d, string e, real t, boolean w returns nothing local integer n = 0 local real x = GetUnitX(u) local real y = GetUnitY(u) local string s = "|c00ff0303"+d+"|r : "+e call UnitAddIndicator(u,125,125,255,255) if GetLocalPlayer()==p then call PingMinimap(GetUnitX(u),GetUnitY(u),t/2) if GameSwitch[0] then call SetCinematicScene(GetUnitTypeId(u),GetPlayerColor(GetOwningPlayer(u)),d,e,t,t) else call DisplayTextToPlayer(p,0,0,s) endif endif if w then call PolledWait(t) endif endfunction function TransmissionToPlayer takes player p, unit u, string e, real t, boolean w returns nothing call TransmissionToPlayerEx(p,u,GetUnitName(u),e,t,w) endfunction //! define TransmissionToPlayer(p,u,e,t,w) TransmissionToPlayerEx(p,u,GetUnitName(u),e,t,w) //============================================================================================================ //Register Quest Units //============================================================================================================ private struct QuestUnitData effect e texttag array tt[6] endstruct function UnregisterQuestUnit takes unit u returns nothing local QuestUnitData dat = GetAttachedInt(u,"QuestUnitData") local integer n=0 loop call DestroyTextTag(dat.tt[n]) set n=n+1 exitwhen n>5 endloop call DestroyEffect(dat.e) call AttachInt(u,"QuestUnitData",0) call AttachString(u,"UAVQuest",null) call dat.destroy() endfunction function RegisterQuestUnit takes unit u, string s, string e returns nothing local QuestUnitData dat = QuestUnitData.create() local integer n = 0 call TriggerRegisterUnitEvent(QuestT,u,EVENT_UNIT_SELECTED) set dat.e=AddSpecialEffectTarget("Abilities\\Spells\\Other\\TalkToMe\\TalkToMe.mdl",u,"overhead") loop set dat.tt[n]=CreateTextTag() call SetTextTagPos(dat.tt[n],GetUnitX(u)-100,GetUnitY(u),80) call SetTextTagColor(dat.tt[n],255,155,75,255) call SetTextTagText(dat.tt[n],e,0.025) if GetLocalPlayer()!=Player(n) then call SetTextTagVisibility(dat.tt[n],false) endif set n=n+1 exitwhen n>5 endloop call AttachInt(u,"QuestUnitData",dat) call AttachString(u,"UAVQuest",s) endfunction function RemoveQuestUnitText takes unit u, player p returns nothing local QuestUnitData dat = GetAttachedInt(u,"QuestUnitData") call SetTextTagVisibility(dat.tt[GetPlayerId(p)],false) endfunction function SetQuestUnitText takes unit u, player p, string s returns nothing local QuestUnitData dat = GetAttachedInt(u,"QuestUnitData") call SetTextTagText(dat.tt[GetPlayerId(p)],s,0.025) call SetTextTagVisibility(dat.tt[GetPlayerId(p)],true) endfunction function RemoveQuestUnitTextAll takes unit u returns nothing local QuestUnitData dat = GetAttachedInt(u,"QuestUnitData") local integer n = 0 loop call SetTextTagVisibility(dat.tt[n],false) set n=n+1 exitwhen n>5 endloop endfunction function SetQuestUnitTextAll takes unit u, string s returns nothing local QuestUnitData dat = GetAttachedInt(u,"QuestUnitData") local integer n = 0 loop call SetTextTagText(dat.tt[n],s,0.025) call SetTextTagVisibility(dat.tt[n],true) set n=n+1 exitwhen n>5 endloop endfunction //============================================================================================================ //Hiding Units //============================================================================================================ function HideUnitsEnum takes nothing returns nothing call GroupAddUnit(PlayerHidedGroup,GetEnumUnit()) call ShowUnit(GetEnumUnit(),false) endfunction function HidePlayerUnits takes boolean hide returns nothing local group g local boolexpr b local unit u local integer n = 0 if hide and not GameSwitch[10] then //hide set GameSwitch[10]=true call GroupClear(PlayerHidedGroup) set g=CreateGroup() set b=Condition(function Teleport_filter) loop call GroupEnumUnitsOfPlayer(g,Player(n),b) call ForGroup(g,function HideUnitsEnum) call GroupClear(g) set n=n+1 exitwhen n>12 endloop call DestroyBoolExpr(b) call DestroyGroup(g) set b=null set g=null elseif not hide and GameSwitch[10] then //unhide set GameSwitch[10]=false loop set u=FirstOfGroup(PlayerHidedGroup) exitwhen u==null call GroupRemoveUnit(PlayerHidedGroup,u) call PauseUnit(u,false) call ShowUnit(u,true) endloop else debug call BJDebugMsg("Game system error: units already hided/revealed") endif endfunction //============================================================================================================ //Moving Heroes //============================================================================================================ function MoveHero takes unit u, real x, real y returns boolean local group g local boolexpr b local unit f if IsUnitType(u,UNIT_TYPE_HERO) then set g = CreateGroup() set b = Condition(function Teleport_filter) call GroupEnumUnitsOfPlayer(g,GetOwningPlayer(u),b) loop set f = FirstOfGroup(g) exitwhen f == null call SetUnitPosition(f,x,y) call GroupRemoveUnit(g,f) endloop call DestroyGroup(g) call DestroyBoolExpr(b) set g=null set b=null set f=null return true else call SetUnitPosition(u,x,y) return false endif endfunction //============================================================================================================ //Quest Initialization //============================================================================================================ private function QuestOnClick takes nothing returns nothing local unit u = GetTriggerUnit() local player p = GetLocalPlayer() local integer n = 5 local real x = GetUnitX(PlayerHero[GetPlayerId(p)]) local real y = GetUnitY(PlayerHero[GetPlayerId(p)]) local string s = GetAttachedString(u,"UAVQuest") if GetAttachedString(u,"UAVQuest")!=null then if DistanceBetweenPointsEx(GetUnitX(u),GetUnitY(u),x,y)<500 then set TempPlayer=p set TempUnit=u call ExecuteFunc(s) else call CS_Error(p,"Too far away from the quest unit") endif endif set u=null set p=null set s=null endfunction function InitQuestSys takes nothing returns nothing set QuestT=CreateTrigger() call TriggerAddAction(QuestT,function QuestOnClick) call RegisterQuests.evaluate() call RegisterQuestsStrings.evaluate() call InitBountyQuest.evaluate() set fil=Condition(function enum_filter) set PlayerHidedGroup=CreateGroup() endfunction endlibrary To make things simple, the game just desync when i called something like this: JASS:function CaptainOnClick takes unit u, player p returns nothing local unit c local integer i = GetAttachedInt(u,"talkedtocaptain"+I2S(GetPlayerId(p))) if i==0 then call RemoveQuestUnitText(u,p) call AttachInt(u,"talkedtocaptain"+I2S(GetPlayerId(p)),99) call TransmissionToPlayer(p,u,"You there! I hired you to kill the restless Skeletons, not stand here! Get your ass moving to the |c007ebff1graveyard|r!",5,true) call UpdateQuest(p,"Slay the Skeletons"," As a hired mecenary, your journey is started by slaying the restless skeleton in the graveyard. Slay as many as possible to gain enough trust from the captain for harder quests.",null) call AttachInt(u,"talkedtocaptain"+I2S(GetPlayerId(p)),1) elseif i==1 then call TransmissionToPlayer(p,u,"Stop poking me and |c00ff0000go|r!!",3,true) elseif i==2 then call RemoveQuestUnitText(u,p) call AttachInt(u,"talkedtocaptain"+I2S(GetPlayerId(p)),99) call AttachInt(gg_rct_EnterTownDefendse,"talkedtoguard"+I2S(GetPlayerId(p)),1) call TransmissionToPlayer(p,u,"Oh, I see you've gained quite some strength from killing those junks. Very well, go to the town gate and join the main forces to defeat the |c007ebff1Bandit Lord|r and burn down his camp!",8,true) call TransmissionToPlayer(p,u,"Here are some rewards for what you've done.",4,true) set c = PlayerHero[GetPlayerId(p)] call DisplayTimedTextToPlayer(p,0,0,6,"|cff00c400Previous quest reward|r: 100 gold") call SetPlayerState(p,PLAYER_STATE_RESOURCE_GOLD,GetPlayerState(p,PLAYER_STATE_RESOURCE_GOLD)+100) call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Items\\ResourceItems\\ResourceEffectTarget.mdl",GetUnitX(c),GetUnitY(c))) call CreateTextEx("+100",GetUnitX(c)-25,GetUnitY(c),255,255,0,3) if GetLocalPlayer() != p then call SetTextTagVisibility(bj_lastCreatedTextTag,false) endif call TriggerSleepAction(2.) call UpdateQuest(p,"Slay the Bandit Lord"," The bandits are invading the town, teach them a lesson by killing the Bandit Lord.","Chief mercenary") if GetLocalPlayer() == p then call PingMinimap(GetUnitX(gg_unit_Hlgr_0039),GetUnitY(gg_unit_Hlgr_0039),15) endif call AttachInt(u,"talkedtocaptain"+I2S(GetPlayerId(p)),3) set c=null endif endfunction |
| 05-14-2008, 06:32 AM | #2 |
From a list of bugs I have: Incorrect use of GetLocalPlayer() with the following things can cause a desync: Using the regular DisplayText function to display text Sending a quest message to a single player Turning Cinematic or Letterbox Mode on Giving gold to a absent player I also seem to recall someone telling me sounds cause problems as well. |
| 05-14-2008, 10:50 AM | #3 |
Use local values instead of local function calls... |
| 05-15-2008, 02:50 AM | #4 | |
Quote:
|
| 05-15-2008, 07:20 AM | #5 |
Like this: JASS:local string s = "" if GetLocalPlayer() == Player(0) then set s = "Message 1" endif call DisplayMessage(s) |
| 05-15-2008, 08:30 AM | #6 |
but i don't have anything like that, the strings are declared in local values before passing to local function calls |
