| 08-11-2009, 05:20 AM | #1 |
I'm not really sure what I did, but I just achieved total anarchy among my own units. I was fooling around trying to get my PlayerSwitch library to work when I tried a few odd things and ended up making my own units autoattack against themselves, and all of the enemy players did the same. I thought I'd share this here in case someone can shed light on what exactly I did. I think it has something to do with my Alliance-setting textmacro loop, but I'm not entirely too sure. JASS:library PlayerSwitch initializer Init uses BoolexprUtils, LinkedList //================================================================ // PlayerSwitch script by Pyrogasm - Version 1.1 - August 9, 2009 //================================================================ // // The function of this script is to switch two players in-game. // Imagine that you and Player X are sitting at two different computers; // you then both stand up and walk to the other's computer and sit down. // // That is effectively what this script does, except you can switch // with any player in the game (not just your buddy next to you, and // you don't have to move :) // // There are a few side-effects: // - You can no longer use Player() GetPlayerId() and // SetPlayerAbilityAvailable(); instead, each has its own // "...Ex()" version that you can use instead with no loss in // functionality. // // - Upgrades are currently broken because you can't un-upgrade something // This really shouldn't be that much of a problem for most mapmakers; // however I am planning on writing a companion library to simulate // upgrades using units so that more functionality may exist. // // Should such a library be written, I will appropriately update this // library. // // - I'm not entirely sure if this all works properly, or even what some // of it does (See the lines marked with "//?"), and there may be // things other than upgrades I haven't thought of yet that are non- // transferrable. If you think of something, bring it to my attention // at [url]http://www.Wc3c.net/member.php?u=747681[/url] (send me a PM) // // Usage: // - Use PlayerEx(), GetPlayerIdEx(), and SetPlayerAbilityAvailableEx() // instead of their normal counterparts // // - Don't store the owner of a unit in a variable for too long // // - Don't use upgrades you don't want transferred (yet) // // - Simply call SwitchPlayers(Player1, Player2) and they will switch // // - Chill, serve, and enjoy //================================================================ // // Thanks to: // - Vexorian, for JASSHelper, and all that jazz // - Mindworx, PitzerMike, Zoxc, Pipedream, and all who have developed // the JASSNewGen Pack at any point // - Ammorth, for his LinkedList script // - Tot, for the inspiration to write this // - Those who have given me critique regarding this // //================================================================ // There is no configuration, in case you were wondering. //================================================================ globals private keyword PlayerInfo //Some relevant globals private PlayerInfo array PIs private player Switch private integer Team //These are used during the switch private playercolor Color private string Name private integer Id private boolean Alliance private integer State private group G1 //Because creating groups all the time is bad private group G2 endglobals private struct PlayerInfo //I could have made it extend an array, but I would have lost the cool [] operator syntax player P //This struct stores the relevant data for every player integer Id //Player Ids are not static, so they must be saved List AList //This list stores which abilities are currently not avaiable to each player static method operator [] takes player P returns PlayerInfo return PIs[GetPlayerId(P)] endmethod static method create takes player P, integer J returns PlayerInfo local PlayerInfo PI = PlayerInfo.allocate() set PI.Id = J set PI.P = P set PI.AList = List.create() return PI endmethod method onDestroy takes nothing returns nothing //When would this ever be called...? call .AList.destroy() endmethod endstruct //Debug functions and hooks to warn against the use of 'deprecated' functions debug function GetPlayerIdError takes nothing returns nothing debug call BJDebugMsg("|cffff0000Warning: Used GetPlayerId() instead of GetPlayerIdEx()!") debug endfunction debug function PlayerError takes nothing returns nothing debug call BJDebugMsg("|cffff0000Warning: Used Player() instead of PlayerEx()!") debug endfunction debug function AvailableError takes nothing returns nothing debug call BJDebugMsg("|cffff0000Warning: Used SetPlayerAbilityAvailable() instead of SetPlayerAbilityAvailableEx()!") debug endfunction debug hook GetPlayerId GetPlayerIdError debug hook Player PlayerError debug hook SetPlayerAbilityAvailable AvailableError function SetPlayerAbilityAvailableEx takes player whichPlayer, integer whichAbil, boolean flag returns nothing local PlayerInfo PI = PlayerInfo[whichPlayer] //Get the relevant PlayerInfo local Link L if not flag then //If the ability is to be unavailable call Link.create(PI.AList, whichAbil) //Add it to the list of unavailable abilities call SetPlayerAbilityAvailable(whichPlayer, whichAbil, false) //And actually make it unavailable else set L = PI.AList.search(whichAbil) //Make sure it is currently disabled if L != 0 then //If it is, then call SetPlayerAbilityAvailable(whichPlayer, whichAbil, true) //Enable it call L.destroy() //Remove the ability from the list of disabled abilities endif endif endfunction function GetPlayerIdEx takes player whichPlayer returns integer local PlayerInfo PI = PlayerInfo[whichPlayer] //I couldn't do return PlayerInfo[whichPlayer].Id, for some godforsaken reason return PI.Id endfunction function PlayerEx takes integer whichId returns player local integer J = 0 local PlayerInfo PI loop set PI = PIs[J] //Iterate through all the PlayerIds if PI.Id == whichId then //If the Ids match then return the player return PI.P endif set J = J+1 exitwhen J >= 16 endloop return null endfunction private function SwitchUnits takes nothing returns nothing call SetUnitOwner(GetEnumUnit(), Switch, true) //Used in SwitchPlayers to change unit ownership endfunction //Textmacroes make our lives easier and code much cleaner! //! textmacro AllianceSet takes ALLIANCE set Alliance = GetPlayerAlliance(P1, PI1.P, $ALLIANCE$) call SetPlayerAlliance(P1, PI1.P, $ALLIANCE$, GetPlayerAlliance(P2, PI1.P, $ALLIANCE$)) call SetPlayerAlliance(P2, PI1.P, $ALLIANCE$, Alliance) //! endtextmacro //! textmacro StateSet takes STATE set State = GetPlayerState(P1, $STATE$) call SetPlayerState(P1, $STATE$, GetPlayerState(P2, $STATE$)) call SetPlayerState(P2, $STATE$, State) //! endtextmacro function SwitchPlayers takes player P1, player P2 returns boolean local integer J = 0 local PlayerInfo PI1 local PlayerInfo PI2 local Link L local List SwapL local player TempP call BJDebugMsg(GetPlayerName(P1)) call BJDebugMsg(GetPlayerName(P2)) call BJDebugMsg("") if P1 == null or P2 == null then //Why would you switch with a null player? return false endif loop set PI1 = PIs[J] //Loop through all players and then set the appropriate alliance properties for each of the switching players call BJDebugMsg(GetPlayerName(PI1.P)) //! runtextmacro AllianceSet("ALLIANCE_PASSIVE") //! runtextmacro AllianceSet("ALLIANCE_HELP_REQUEST") //! runtextmacro AllianceSet("ALLIANCE_HELP_RESPONSE") //! runtextmacro AllianceSet("ALLIANCE_SHARED_XP") //! runtextmacro AllianceSet("ALLIANCE_SHARED_VISION") //! runtextmacro AllianceSet("ALLIANCE_SHARED_CONTROL") //! runtextmacro AllianceSet("ALLIANCE_SHARED_ADVANCED_CONTROL") //! runtextmacro AllianceSet("ALLIANCE_RESCUABLE") //! runtextmacro AllianceSet("ALLIANCE_SHARED_VISION_FORCED") set J = J+1 exitwhen J >= 16 endloop //This is where the playerstates are set, but I'm not really sure what some of them do //Or even if they need to be set //? //! runtextmacro StateSet("PLAYER_STATE_GAME_RESULT") //! runtextmacro StateSet("PLAYER_STATE_RESOURCE_GOLD") //! runtextmacro StateSet("PLAYER_STATE_RESOURCE_LUMBER") //! runtextmacro StateSet("PLAYER_STATE_RESOURCE_HERO_TOKENS") //? //! runtextmacro StateSet("PLAYER_STATE_RESOURCE_FOOD_CAP") //? //! runtextmacro StateSet("PLAYER_STATE_RESOURCE_FOOD_USED") //? //! runtextmacro StateSet("PLAYER_STATE_FOOD_CAP_CEILING") //! runtextmacro StateSet("PLAYER_STATE_GIVES_BOUNTY") //! runtextmacro StateSet("PLAYER_STATE_ALLIED_VICTORY") //! runtextmacro StateSet("PLAYER_STATE_PLACED") //! runtextmacro StateSet("PLAYER_STATE_OBSERVER_ON_DEATH") //! runtextmacro StateSet("PLAYER_STATE_UNFOLLOWABLE") //? //! runtextmacro StateSet("PLAYER_STATE_GOLD_UPKEEP_RATE") //? //! runtextmacro StateSet("PLAYER_STATE_LUMBER_UPKEEP_RATE") //! runtextmacro StateSet("PLAYER_STATE_GOLD_GATHERED") //! runtextmacro StateSet("PLAYER_STATE_LUMBER_GATHERED") //! runtextmacro StateSet("PLAYER_STATE_NO_CREEP_SLEEP") set PI1 = PlayerInfo[P1] set PI2 = PlayerInfo[P2] set Team = GetPlayerTeam(P1) //These need to be stored so they can be switched later set Color = GetPlayerColor(P1) set Name = GetPlayerName(P1) set Id = PI1.Id call SetPlayerTeam(P1, GetPlayerTeam(P2)) call SetPlayerColor(P1, GetPlayerColor(P2)) call SetPlayerName(P1, GetPlayerName(P2)) set PI1.Id = PI2.Id call SetPlayerTeam(P2, Team) //See? call SetPlayerColor(P2, Color) call SetPlayerName(P2, Name) set PI2.Id = Id //Now abilities need to be enabled/disabled properly for both players so nothing stupid happens //It's just a simple loop through the list ending when they both end set L = PI1.AList.first loop exitwhen L == 0 call SetPlayerAbilityAvailable(P2, L.data, false) //Simple switching call SetPlayerAbilityAvailable(P1, L.data, true) set L = L.next endloop set L = PI2.AList.first loop exitwhen L == 0 call SetPlayerAbilityAvailable(P1, L.data, false) call SetPlayerAbilityAvailable(P2, L.data, true) set L = L.next endloop set SwapL = PI1.AList //I could clone the lists or something stupid, but instead I'll just switch them set PI1.AList = PI2.AList set PI2.AList = SwapL call GroupEnumUnitsOfPlayer(G1, P1, BOOLEXPR_TRUE) //"OfPlayer" loops get locust units and all that jazz too call GroupEnumUnitsOfPlayer(G2, P2, BOOLEXPR_TRUE) set Switch = P2 call ForGroup(G1, function SwitchUnits) //Unit switching for both players set Switch = P1 //We need a second group so all the units don't end up in the control of the second player call ForGroup(G2, function SwitchUnits) call GroupClear(G1) call GroupClear(G2) return true endfunction private function Init takes nothing returns nothing local integer J = 0 loop set PIs[J] = PlayerInfo.create(Player(J), J) //Create all of the necessary PlayerInfos set J = J+1 exitwhen J >= 16 endloop set G1 = CreateGroup() //Just initialization setting set G2 = CreateGroup() endfunction endlibrary The code is above, and if you want to test this out in-game download the attached map and test it. Once in-game, do the following:
Yeah... |
| 08-11-2009, 05:26 AM | #2 | |
this reminds me of http://www.wc3c.net/showthread.php?t=91569 hmnn I should really reserve some time to revive old spells now that none of them works... Quote:
|
| 08-11-2009, 05:38 AM | #3 |
Good point... |
| 08-11-2009, 06:46 AM | #4 |
You just remove players ALLIANCE_PASSIVE with themselves |
| 08-11-2009, 06:52 AM | #5 |
That's... insane. Your own units are enemies. You can't give your own units orders exept gather and repair. I think a lot of people have searched to do this with only one unit for a spell :/ |
| 08-11-2009, 08:57 PM | #6 |
JASS:scope CivilWar initializer init private function init takes nothing returns nothing local player p = GetLocalPlayer() call SetPlayerAlliance(p,p,ALLIANCE_PASSIVE,false) endfunction endscope |
| 08-11-2009, 09:40 PM | #7 |
best code evar... |
