//===========================================================================
// Utility Functions required by the Selection System
//===========================================================================
//===========================================================================
// SimError
// Shows a fake error message to a player
//
function SimError takes player ForPlayer, string msg returns nothing
local sound error = CreateSound( "Sound\\Interface\\Error.wav", false, false, false, 10, 10, "DefaultEAXON" )
call SetSoundParamsFromLabel( error, "InterfaceError" )
if (GetLocalPlayer() == ForPlayer) then
call ClearTextMessages()
call DisplayTimedTextFromPlayer( ForPlayer, 0.515, 0, 2, "|cffffcc00"+msg+"|r" )
call StartSound( error )
// call KillSoundWhenDone( error)
endif
set error=null
endfunction
//===========================================================================
// Returns A Colored Version of A Player`s Name
//
function GetPlayerNameColored takes player id returns string
local playercolor col=GetPlayerColor(id)
local string r=GetPlayerName(id)
if col == PLAYER_COLOR_RED then
set r="|cffff0000"+r+"|r"
elseif col == PLAYER_COLOR_BLUE then
set r="|cff0000ff"+r+"|r"
elseif col == PLAYER_COLOR_CYAN then
set r="|cff93ffc9"+r+"|r"
elseif col == PLAYER_COLOR_PURPLE then
set r="|cff400080"+r+"|r"
elseif col == PLAYER_COLOR_YELLOW then
set r="|cffffff00"+r+"|r"
elseif col == PLAYER_COLOR_ORANGE then
set r="|cffff8000"+r+"|r"
elseif col == PLAYER_COLOR_GREEN then
set r="|cff00c400"+r+"|r"
elseif col == PLAYER_COLOR_PINK then
set r="|cffff80c0"+r+"|r"
elseif col == PLAYER_COLOR_LIGHT_GRAY then
set r="|cff808080"+r+"|r"
elseif col == PLAYER_COLOR_LIGHT_BLUE then
set r="|cffc1c1ff"+r+"|r"
elseif col == PLAYER_COLOR_AQUA then
set r="|cff5e5e2f"+r+"|r"
elseif col == PLAYER_COLOR_BROWN then
set r="|cff004000"+r+"|r"
else
set r="|cff000000"+r+"|r"
endif
set col=null
return r
endfunction
//######################################################################################################
//
// Vexorian Hero Selection System V
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
// Theorically you won't need to change these functions unless you are an advanced mapper
// that wants to improve the Selection System, I left a lot of comments just in case you want
// to try, If you find a better way of doing this stuff send me the new functions in a pm at
// wc3campaingns, If I they improve the system, I'll replace mine with them and give you credit.
//
// ..........................
// : Input Global Variables : (Used by the mapper to configure the Selection system)
// ``````````````````````````
// group udg_SelectableHeroes Heroes used by the selection system
//
// group udg_AvailableHeroes Heroes use by Random Hero functions
//
// rect array udg_HeroSection Determines a Player's Hero Gallery (1 to 12)
//
// rect array udg_HeroCreation Determines a Player's Hero Spawn Rect (1 to 12)
//
// boolean udg_DoubleHeroesEnabled Determines if players can use already chosen heroes
//
// trigger udg_CreatedHeroTrigger Determines the trigger to be executed after hero creation
//
// integer array udg_hss_abilities Determines the abilities used by the Selection System
// udg_hss_abilities[0] must store Choose Hero
// udg_hss_abilities[1] must store Random Hero
// udg_hss_abilities[3] must store Selection Arrow
// ...........................
// : Output Global Variables : (Used to store the results of the Selection system)
// ```````````````````````````
// unit array udg_Heroes Stores a player's hero after its creation (1 to 12)
// 13 to 24 temporary store the current selected hero
//
//######################################################################################################
//======================================================================================================
// Filter functions:
//
function hssFilterIsPossible takes nothing returns boolean
return IsUnitInGroup(GetFilterUnit(), udg_SelectableHeroes) and RectContainsUnit( udg_HeroSection[GetConvertedPlayerId(bj_groupEnumOwningPlayer)], GetFilterUnit() )
endfunction
function hssFilterIsAvailable takes nothing returns boolean
if GetTriggerUnit() == null and FirstOfGroup(udg_AvailableHeroes) == null then
//* In Case a Weird thing happened and there were not heroes available for computers
return hssFilterIsPossible()
endif
return IsUnitInGroup(GetFilterUnit(), udg_AvailableHeroes) and RectContainsUnit( udg_HeroSection[GetConvertedPlayerId(bj_groupEnumOwningPlayer)], GetFilterUnit() )
endfunction
function hssFilterIsComputerWithoutHero takes nothing returns boolean
return GetPlayerController(GetFilterPlayer()) == MAP_CONTROL_COMPUTER and udg_Heroes[GetConvertedPlayerId(GetFilterPlayer())] == null
endfunction
//======================================================================================================
//********************************************************************************************
function SetPlayerHero takes player id, unit hero, string suffix returns nothing
//*
//* Determines a player's hero
//* - id player argument is self explanatory (Create the hero for that player)
//* - hero unit argument is self explanatory too (The hero that was in the gallery)
//* - suffix string argument is added to the "(Player) has selected the (Hero)" message
//*
//* Will Run the trigger udg_CreatedHeroTrigger after creating the hero
//* (Use last created unit to reffer to the hero)
//*
local unit newhero
local real x=GetRectCenterX(udg_HeroCreation[GetConvertedPlayerId(id)])
local real y=GetRectCenterY(udg_HeroCreation[GetConvertedPlayerId(id)])
if (id == null) or (GetPlayerId(id) > 11) or (hero == null) then
return //* Invalid Request, halt the function
endif
call GroupRemoveUnitSimple( hero, udg_AvailableHeroes ) //*Makes Hero Unselectable by Random Hero button / Computers
if not udg_DoubleHeroesEnabled then
//*In case DoubleHeroesEnabled is false, make hero unselectable
call SetUnitColor( hero, GetPlayerColor(id) )
call UnitAddAbility(hero,'Aloc')
call SetUnitVertexColor( hero, 255, 255, 255, 127 )
endif
//* Create the new hero, select it and move the camera
set newhero=CreateUnit(id, GetUnitTypeId(hero),x,y, bj_UNIT_FACING )
call SelectUnitAddForPlayer( newhero, id )
call SetCameraPositionForPlayer(id, x, y)
call DisplayTextToForce( GetPlayersAll(), GetPlayerNameColored(id)+" has selected the "+GetUnitName(newhero)+" "+suffix)
set udg_Heroes[GetConvertedPlayerId(GetOwningPlayer(newhero))] = newhero
//* In case there is a CreateHeroTrigger, Execute it and make sure Last Created Unit works
if udg_CreatedHeroTrigger != null then
set bj_lastCreatedUnit=newhero
call ConditionalTriggerExecute( udg_CreatedHeroTrigger )
endif
set newhero=null
endfunction
//********************************************************************************************
function hss_OrderToPreviewHero takes nothing returns nothing
//*
//* When A hero from the gallery is issued an order, check if it was the choose hero or the
//* Random Hero Button, after that block the order by pausing the unit and ordering it to stop
//*
local unit selunit=GetTriggerUnit()
local player selplayer=GetOwningPlayer(selunit)
local group uu
if GetIssuedOrderId() == String2OrderIdBJ("stop") or GetUnitUserData( selunit) == 1 or udg_Heroes[13+GetPlayerId(selplayer)] != selunit then
//* A lot of conditions added because this trigger was causing massive lag
set selunit=null
set selplayer=null
return
endif
call SetUnitUserData(selunit,1) //* Part of the things that help this trigger to be lag-free, this trigger won't run when the unit has a Custom Value of 1
if GetIssuedOrderId() == 852273 then //*Select Hero Clicked
call SetUnitOwner( selunit, Player(PLAYER_NEUTRAL_PASSIVE), true )
call UnitRemoveAbility( selunit,udg_hss_abilities[2]) //* Remove the Selection Arrow Special Effect
call SetPlayerHero(selplayer, selunit, "")
elseif GetIssuedOrderId() == 852277 then //*Random Hero Clicked
set bj_groupEnumOwningPlayer=selplayer //* I use that Blizzard variable to make sure the filter chooses only the heroes a player can have
set uu=GetUnitsOfPlayerMatching(Player(PLAYER_NEUTRAL_PASSIVE), Condition(function hssFilterIsAvailable))
if FirstOfGroup(uu) == null then
//* There is a chance that the map had an incredibly low number of heroes and that eventually there
// weren't heroes available, in that case show an error message instead of continuing with the selection
call SimError(GetOwningPlayer(selunit), "Couldn't find heroes for Random Hero feature")
else
set selunit = GroupPickRandomUnit(uu) //* Save a random unit from the available heroes into a variable
call SetUnitOwner( GetTriggerUnit(), Player(PLAYER_NEUTRAL_PASSIVE), true )
call UnitRemoveAbility( GetTriggerUnit(), udg_hss_abilities[2]) //* Remove the Selection Arrow Special Effect
call SetPlayerHero(selplayer, selunit, "(Random Hero)") //* Calls the SetPlayerHero function with a "(Random Hero)" suffix for the message
endif
call DestroyGroup(uu)
set uu=null
else
call SimError(GetOwningPlayer(selunit), "Please choose your hero") //* The Player was trying to use an ability, show an error to him/her/ it?
endif
//* Pause the unit, order it to stop and unpause the unit, so it ignores the issued order
set selunit=GetTriggerUnit()
call PauseUnit( selunit, true)
call IssueImmediateOrder( selunit, "stop" )
call PauseUnit(selunit, false)
call SetUnitUserData( selunit, 0 )
set selunit=null
set selplayer=null
endfunction
//********************************************************************************************
function hss_HeroIsClicked takes nothing returns nothing
//
// This function is executed when a Player Clicks an unit, if the unit belongs to his gallery,
// Give the unit to the player, and show the Selection Arrow, if it doesn't, restore the previus
// selected unit.
//
local unit sel=GetTriggerUnit()
local player sp=GetTriggerPlayer()
local integer a
local unit old=udg_Heroes[13+GetPlayerId(sp)] //* Save the current hero that is selected by the player into a variable
if old != sel then //* Just to make "clicking a hero a lot of times till it says something funny" possible
call SetUnitOwner( old, Player(PLAYER_NEUTRAL_PASSIVE), true ) //* give the last unit back to Neutral Passive
call UnitRemoveAbility( old, udg_hss_abilities[2]) //* Remove the Selection Arrow Special Effect
set udg_Heroes[13+GetPlayerId(sp)] = null //* Clear the Global Variable
if udg_Heroes[GetConvertedPlayerId(sp)] == null and IsUnitInGroup(sel,udg_SelectableHeroes) and IsUnitOwnedByPlayer(sel,Player(PLAYER_NEUTRAL_PASSIVE)) then
//* The Hero is a member of the Possible Selectable Heroes
if RectContainsUnit( udg_HeroSection[GetConvertedPlayerId(sp)], sel ) then
//* The Hero can be used by the player
call SetUnitManaPercentBJ( sel, 100 ) //* Just in case the map author forgot to give the hero mana (So the hero abilities buttons don't show up blue)
set udg_Heroes[13+GetPlayerId(sp)] = sel //* Save the selected unit into a global
call UnitAddAbility(sel, udg_hss_abilities[2]) //* Show the Selection Arrow Special Effect
call SetUnitUserData( sel,1) //* Just In case. (See the OrderToPreviewHero function for more information)
call SetUnitOwner( sel, sp, true ) //* Give the selected unit to the player
call SetUnitUserData( sel,0) //* Just In case. ^
else
//* The Hero doesn't belong to the player's team, show error message
call SimError(sp, "Your team can't choose that hero")
endif
endif
endif
set sel=null
set sp=null
set old=null
endfunction
//********************************************************************************************
function StartVxHSS takes boolean rand, boolean comps, boolean cleanup returns nothing
//
// (The Main Function that Starts the Selection System and Finishes it)
//
// - rand boolean argument determines the availability of the random hero option.
// - comps boolean argument determines if Computer Players can Choose their Heroes
// - cleanup boolean argument determines if the gallery heroes are removed once everybody gets hero.
//
local group heroes=CreateGroup()
local unit current
local integer a=0
local real x //* To easily save a coordinate I use x and y
local real y
local trigger UnitSel=CreateTrigger()
local trigger UnitOrder=CreateTrigger()
local force forcevar
local player ai
call TriggerAddAction(UnitOrder, function hss_OrderToPreviewHero)
call TriggerAddAction(UnitSel, function hss_HeroIsClicked)
call GroupAddGroup(udg_SelectableHeroes,heroes)
loop
set current = FirstOfGroup(heroes)
exitwhen current == null //* Clearly better than a ForGroup call
//* Hero Setup for the Selection System:
call GroupRemoveUnit(heroes, current)
call UnitRemoveAbility(current, 'Amov' ) //* Removes movement
call UnitRemoveAbility(current, 'Aatk' ) //* Removes Attack
call UnitRemoveAbility(current, 'Afin' ) //* Removes Stop Button (Unit can still be ordered to stop)
call UnitAddAbility(current, udg_hss_abilities[0] ) //* Adds Choose Hero Button
if rand then
call UnitAddAbility(current, udg_hss_abilities[1] ) //* Adds Random Hero Button
endif
//* Register Order events for the hero
call TriggerRegisterUnitEvent( UnitOrder, current, EVENT_UNIT_ISSUED_TARGET_ORDER )
call TriggerRegisterUnitEvent( UnitOrder, current, EVENT_UNIT_ISSUED_POINT_ORDER )
call TriggerRegisterUnitEvent( UnitOrder, current, EVENT_UNIT_ISSUED_ORDER )
endloop
call DestroyGroup(heroes)
loop
exitwhen a>11
set x=GetRectCenterX(udg_HeroSection[a+1])
set y=GetRectCenterY(udg_HeroSection[a+1])
//* Move camera and spacebar point for the player
if GetLocalPlayer() == Player(a) then
call SetCameraPosition(x,y)
call SetCameraQuickPosition(x,y)
endif
call SetPlayerAllianceStateBJ( Player(PLAYER_NEUTRAL_PASSIVE), Player(a), bj_ALLIANCE_NEUTRAL_VISION ) //* Neutral Passive Must have shared Vision with the human players
call TriggerRegisterPlayerSelectionEventBJ( UnitSel, Player(a), true ) //* Register a selection event for the player
set a=a+1
endloop
//* Setup Completed
if rand and IsMapFlagSet(MAP_RANDOM_HERO) then
//* Random Hero feature is enabled and the Game Created Checked the Random Hero Option
//* So this will automatically choose a Random Hero for every player
set a=0
loop
exitwhen a>11
call TriggerSleepAction(0) //* Just to give war3 a breathing space
if GetPlayerSlotState(Player(a)) == PLAYER_SLOT_STATE_PLAYING and (comps or GetPlayerController(Player(a)) != MAP_CONTROL_COMPUTER) then
//* The Player is playing (uh?)
//* Computer Players shouldn't automatically get a hero if comps is false
set bj_groupEnumOwningPlayer=Player(a) //* I use that Blizzard variable to make sure the filter chooses only the heroes a player can have
set heroes = GetUnitsOfPlayerMatching(Player(PLAYER_NEUTRAL_PASSIVE), Condition(function hssFilterIsAvailable))
set current = GroupPickRandomUnit(heroes)
if current == null then //* No more available heroes, use a repeated hero
call DestroyGroup(heroes)
set bj_groupEnumOwningPlayer=Player(a)
set heroes = GetUnitsOfPlayerMatching(Player(PLAYER_NEUTRAL_PASSIVE), Condition(function hssFilterIsPossible))
set current = GroupPickRandomUnit(heroes)
endif
call SetPlayerHero(Player(a), current, "(Automatic)") //* Calls the SetPlayerHero function with an "(Automatic)" preffix
call DestroyGroup(heroes)
endif
set a=a+1
endloop
elseif comps then
//* Automatically Choose random heroes for computer players when comps is true
set a=0
loop
call TriggerSleepAction( GetRandomReal(1.50, 2.50) ) //* To make things realistic
set forcevar = GetPlayersMatching(Condition(function hssFilterIsComputerWithoutHero)) //* Save Computer Players that don't have heroes into a force
set ai = ForcePickRandomPlayer(forcevar)
//* Once ai==null the force is empty => there are no more computer players that need a hero
exitwhen ai==null or a>40 //* About the a>40 : There is a chance that it would happen (Low number of available heroes)
set bj_groupEnumOwningPlayer=ai //* Once again this thing
set heroes = GetUnitsOfPlayerMatching(Player(PLAYER_NEUTRAL_PASSIVE), Condition(function hssFilterIsAvailable))
set current = GroupPickRandomUnit(heroes)
if current == null and a>30 then //* a>30 because it could be that a player was about to select somebody
call DestroyGroup(heroes)
set bj_groupEnumOwningPlayer=ai //* Once again this thing
set heroes = GetUnitsOfPlayerMatching(Player(PLAYER_NEUTRAL_PASSIVE), Condition(function hssFilterIsPossible))
set current = GroupPickRandomUnit(heroes)
endif
call SetPlayerHero(ai, current, "")
call DestroyGroup(heroes)
call DestroyForce(forcevar)
set a=a+1
endloop
set forcevar=null
set ai=null
endif
//Periodic Check
//* The Function will now looping till the time every player has a hero, so the gallery and the variables
// will be cleared
set x=0 //* Now it gets funny, I am using the x real variable as a time counter
loop
set a=0
set y=0 //* Even more funny the y real counts the players that didn't choose a hero yet
loop
exitwhen a>11
if udg_Heroes[a+1] == null and GetPlayerSlotState(Player(a)) == PLAYER_SLOT_STATE_PLAYING and (comps or GetPlayerController(Player(a)) != MAP_CONTROL_COMPUTER) then
//* The Player Doesn't have a hero yet, ignore Computer Players in case comps is false
set y=y+1
endif
set a=a+1
endloop
exitwhen y <= 0 or x > 600 //* If a player didn't choose a hero in the first 10 minutes, ignore him
call DestroyForce(forcevar)
call TriggerSleepAction(10) //* I don't feel like checking this too often, so the function sleeps for 10 seconds
set x=x+10 //* Increase time by 10
endloop
//* Every player has already selected a hero, so start self destruction (So your map has a little more memory available)
loop
set current = FirstOfGroup(udg_SelectableHeroes)
exitwhen current == null or not cleanup //* So it won't remove the gallery when removegallery is false
call GroupRemoveUnit(udg_SelectableHeroes, current)
call RemoveUnit( current)
endloop
//* Variable Cleanup :
call DestroyGroup(udg_SelectableHeroes)
call DestroyGroup(udg_AvailableHeroes)
call DestroyTrigger(UnitSel)
call DestroyTrigger(UnitOrder)
set a=1
loop
exitwhen a>12
call TriggerSleepAction(0)
call RemoveRect(udg_HeroSection[a])
call RemoveRect(udg_HeroCreation[a])
set udg_HeroSection[a] = null
set udg_HeroCreation[a] = null
set udg_Heroes[13+a-1] = null
set a=a+1
endloop
set udg_hss_abilities[0] = 0
set udg_hss_abilities[1] = 0
set udg_hss_abilities[2] = 0
set udg_SelectableHeroes=null
set udg_AvailableHeroes=null
set forcevar=null
set heroes=null
set current=null
endfunction
Name | Type | is_array | initial_value |
AvailableHeroes | group | No | |
Barracke | unit | Yes | |
Blitzfallen | group | Yes | |
countkick | integer | Yes | |
CreatedHeroTrigger | trigger | No | |
DoubleHeroesEnabled | boolean | No | |
Exprate | real | No | |
Fliegelevel | integer | Yes | |
Folterkammer | unit | Yes | |
Friedhof | unit | Yes | |
frogsplashtarget | location | Yes | |
games | button | Yes | |
gametype | dialog | No | |
Gefangennehmen | boolean | No | |
Geistlevel | integer | Yes | |
Giftgasfallen | group | Yes | |
Handwerkskammer | unit | Yes | |
hctimer | timer | No | |
hctimerfenster | timerdialog | No | |
Heldengruppe | group | No | |
HeroCreation | rect | Yes | |
Heroes | unit | Yes | |
HeroSection | rect | Yes | |
Herz | unit | No | |
hipointtimerwindow | timerdialog | No | |
hitpoints | integer | No | |
hitpoints2 | real | No | |
hitpointstimer | timer | No | |
hss_abilities | abilcode | Yes | |
Jungfraunlevel | integer | Yes | |
Kaeferlevel | integer | Yes | |
Keeperrunits | group | No | |
Keepers | force | No | |
kick | button | Yes | |
kickcount | integer | Yes | |
kickplayer | integer | No | |
kickvote | dialog | No | |
kickvotefor | button | Yes | |
kickvotesystemtimer | timer | No | |
kickvotesystemtimerwindow | timerdialog | No | |
kills | integer | Yes | |
Koederraum | unit | Yes | |
Lavafallen | group | Yes | |
Level | integer | No | |
Level10trainer | player | No | |
lifeshuman | integer | No | |
Machtwortfallen | group | Yes | |
Matchzentrum | unit | Yes | |
missiletarget | location | Yes | |
Opferfliege | group | Yes | |
OpferGeist | group | Yes | |
Opferjungfrau | group | Yes | |
Opferkaefer | group | Yes | |
Opferlevel | integer | Yes | |
Opferleveljungfrau | integer | Yes | |
Opferlevelteufler | integer | Yes | |
Opferlevelzauberer | integer | Yes | |
Opfersspinne | group | Yes | |
Opferteufler | group | Yes | |
OpferTroll | group | Yes | |
runde | integer | No | |
rundesprung | integer | No | |
SelectableHeroes | group | No | |
spawnA | unitcode | Yes | |
spawnB | unitcode | Yes | |
spawnC | unitcode | Yes | |
spawnE | unitcode | Yes | |
Spellschrank | unit | Yes | |
Spinnenlevel | integer | Yes | |
startgeld | integer | No | |
stratustarget | location | Yes | |
stuhlsepp | effect | Yes | |
Tempel | unit | Yes | |
Teuflerlevel | integer | Yes | |
theboard | leaderboard | No | |
tisch | effect | Yes | |
trainingseinheit | unitcode | No | |
trainingseinheitexakt | unit | No | |
Trolllevel | integer | Yes | |
UnitcounterA | integer | No | |
UnitcounterB | integer | No | |
UnitcounterC | integer | No | |
votedplayers | integer | No | |
voteforout | dialog | No | |
votesystemon | boolean | No | |
Waffenschrank | unit | Yes | |
walktimer | timer | No | |
walktimerfenster | timerdialog | No |