library Chest /* v1.0
*************************************************************************************
*
* Create units, acting like treasure chests.
*
*************************************************************************************
*
* */uses/*
*
* */ Table /* Works with Bribes and Vexorians Table.
* */ optional ErrorMessage /* [url]https://github.com/nestharus/JASS/tree/master/jass/Systems/ErrorMessage[/url]
* */ optional Init /* -
*
************************************************************************************
*
* 1. Import instruction
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* Copy the Chest script into your map.
*
* 2. API
* ¯¯¯¯¯¯
* API goes here
*
* 3. Configuration
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*/
globals
private constant boolean ADD_LOCUST_WHEN_OPEN = true// Comment goes here
private constant string PREFIX_RECIEVE_GOLD = "|cffffcc00"
private constant string PREFIX_RECIEVE_LUMBER = "|cff006400"
private constant real TEXT_TAG_HEIGHT = 0.023
private constant real TEXT_TAG_HEIGHT_OFFSET_GOLD = 32.
private constant real TEXT_TAG_HEIGHT_OFFSET_LUMBER = 80.
private constant real TEXT_TAG_VELOCITY_X = 16*0.0005546875*Cos(90*bj_DEGTORAD)
private constant real TEXT_TAG_VELOCITY_Y = 16*0.0005546875*Sin(90*bj_DEGTORAD)
private constant real TEXT_TAG_LIFESPAN = 2.5
private constant real TEXT_TAG_FADEPOINT = 1.75
endglobals
// Configurate how you detect in your map an existing chest key.
private function UnitHasRequiredKey takes unit whichUnit, integer whichKey returns boolean
local integer index = 0
loop
if (GetItemTypeId(UnitItemInSlot(whichUnit, index)) == whichKey) then
return true
endif
set index = index + 1
exitwhen index >= bj_MAX_INVENTORY
endloop
return false
endfunction
//Script code. Do not edit anything below.
static if not LIBRARY_Init then
private module CHEST_INITIALIZER
private static method onInit takes nothing returns nothing
call thistype.init()
endmethod
endmodule
endif
struct Chest
private static sound error = null
private static sound onOpenSound = null
readonly static trigger openEvent = CreateTrigger()
readonly static thistype eventIndex = 0
private static Table table = 0
private static integer goldSlot = -1
private static integer lumberSlot = -2
readonly unit chestUnit
private itempool pool
private Table chestTable
private integer itemCounter
private boolean isOpen
integer requiredKey
method destroyEx takes boolean wantDestroyPool returns nothing
call deallocate()
static if Table.flush2D.exists then
call table.flush(GetHandleId(chestUnit))
else
call table.remove(GetHandleId(chestUnit))
endif
call chestTable.destroy()
if (wantDestroyPool) then
call DestroyItemPool(pool)
endif
set pool = null
set chestUnit = null
endmethod
private method manipulateResource takes unit forUnit, playerstate whichPlayerState, integer childKey, string prefix, real offset returns nothing
local player forPlayer = GetOwningPlayer(forUnit)
local integer amount = chestTable[childKey]
local string text = prefix + "+"
if (amount != 0) then
if (amount < 0) then
set text = prefix + "-"
endif
set text = text + I2S(amount)
call SetPlayerState(forPlayer, whichPlayerState, GetPlayerState(forPlayer, whichPlayerState) + amount)
if (GetLocalPlayer() == forPlayer) then
set bj_lastCreatedTextTag = CreateTextTag()
call SetTextTagText(bj_lastCreatedTextTag, text, TEXT_TAG_HEIGHT)
call SetTextTagPosUnit(bj_lastCreatedTextTag, forUnit, offset)
call SetTextTagVelocity(bj_lastCreatedTextTag, TEXT_TAG_VELOCITY_X, TEXT_TAG_VELOCITY_Y)
call SetTextTagPermanent(bj_lastCreatedTextTag, false)
call SetTextTagLifespan(bj_lastCreatedTextTag, TEXT_TAG_LIFESPAN)
call SetTextTagFadepoint(bj_lastCreatedTextTag, TEXT_TAG_FADEPOINT)
call SetTextTagVisibility(bj_lastCreatedTextTag, true)
endif
set bj_lastCreatedTextTag = null
endif
endmethod
// Uses operating unit as argument.
method open takes unit trysToOpen, integer itemDropAmount, boolean ignoreKey returns boolean
local thistype prev = eventIndex
local real x = GetUnitX(chestUnit)
local real y = GetUnitY(chestUnit)
if (isOpen) then
return false
endif
// Check for wrong usage.
static if DEBUG_MODE and LIBRARY_ErrorMessage then
call ThrowError((trysToOpen == null), "Chest", "open", "unit trysToOpen", this, "Invalid Unit Argument (null)!")
call ThrowError((itemDropAmount < 0), "Chest", "open", "itemDropAmount", this, "Invalid Integer Argument (<0)!")
endif
// Check if a key is required
if (requiredKey != 0) and not (ignoreKey) and not (UnitHasRequiredKey(trysToOpen, requiredKey)) then
// Error message.
if GetLocalPlayer() == GetOwningPlayer(trysToOpen) then
call StartSound(error)
call ClearTextMessages()
endif
call DisplayTimedTextToPlayer(GetOwningPlayer(trysToOpen), 0.52, 0.96, 2., "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n|cffffcc00Required key:|r " + GetObjectName(requiredKey))
return false
endif
set isOpen = true
// Visuals + Sounds
call SetUnitAnimationByIndex(chestUnit, 0)
static if ADD_LOCUST_WHEN_OPEN then
call UnitAddAbility(chestUnit, 'Aloc')
// Makes sense to me.
call SetTerrainPathable(x, y, PATHING_TYPE_WALKABILITY, false)
endif
call AttachSoundToUnit(onOpenSound, chestUnit)
call SetSoundVolume(onOpenSound, 50)
call StartSound(onOpenSound)
// Generate Items.
loop
exitwhen (itemDropAmount == 0)
call PlaceRandomItem(pool, x, y)
set itemDropAmount = itemDropAmount - 1
endloop
call manipulateResource(trysToOpen, PLAYER_STATE_RESOURCE_GOLD, goldSlot, PREFIX_RECIEVE_GOLD, TEXT_TAG_HEIGHT_OFFSET_GOLD)
call manipulateResource(trysToOpen, PLAYER_STATE_RESOURCE_LUMBER, lumberSlot, PREFIX_RECIEVE_LUMBER, TEXT_TAG_HEIGHT_OFFSET_LUMBER)
loop
exitwhen (itemCounter == 0)
set itemCounter = itemCounter - 1
call CreateItem(chestTable[itemCounter], x, y)
endloop
// Fire Event.
set thistype.eventIndex = this
call TriggerEvaluate(thistype.openEvent)
set thistype.eventIndex = prev
// Return boolean
return true
endmethod
static method operator [] takes unit whichUnit returns thistype
static if DEBUG_MODE and LIBRARY_ErrorMessage then
call ThrowWarning((whichUnit == null), "Chest", "[]", "whichUnit", 0, "Invalid Unit (null)!")
call ThrowWarning((not table.has(whichUnit)), "Chest", "[]", "whichUnit", 0, GetUnitName(whichUnit) + " Is Not A ChestUnit!")
endif
return table[GetHandleId(whichUnit)]
endmethod
method addLumber takes integer minLumber, integer maxLumber returns nothing
static if DEBUG_MODE and LIBRARY_ErrorMessage then
call ThrowError((minLumber > maxLumber), "Chest", "addLumber", "min > max", this, "Passed In Minimum Lumber > Passed In Maximum Lumber!")
endif
set chestTable[thistype.lumberSlot] = GetRandomInt(minLumber, maxLumber)
endmethod
method addGold takes integer minGold, integer maxGold returns nothing
static if DEBUG_MODE and LIBRARY_ErrorMessage then
call ThrowError((minGold > maxGold), "Chest", "addGold", "min > max", this, "Passed In Minimum Gold > Passed In Maximum Gold!")
endif
set chestTable[thistype.goldSlot] = GetRandomInt(minGold, maxGold)
endmethod
method addItemIdExplicit takes integer itemid returns nothing
static if DEBUG_MODE and LIBRARY_ErrorMessage then
call ThrowError((itemid == 0), "Chest", "addItemIdExplicit", "itemid", this, "Invalid Integer Argument (0)!")
endif
set chestTable[itemCounter] = itemid
set itemCounter = itemCounter + 1
endmethod
method applyItemPool takes itempool whichItempool returns nothing
static if DEBUG_MODE and LIBRARY_ErrorMessage then
call ThrowError((whichItempool == null), "Chest", "applyItempool", "itempool", this, "Invalid Itempool (null)!")
call ThrowWarning((pool != null), "Chest", "applyItempool", "itempool", this, "Over-writting Itempool Handle!")
endif
set pool = whichItempool
endmethod
static method create takes player forWho, integer unitid, real x, real y, real face returns thistype
local thistype this = thistype.allocate()
set chestUnit = CreateUnit(forWho, unitid, x, y, face)
set chestTable = Table.create()
set table[GetHandleId(chestUnit)] = this
set requiredKey = 0
set itemCounter = 0
set isOpen = false
call PauseUnit(chestUnit, true)
static if DEBUG_MODE and LIBRARY_ErrorMessage then
call ThrowError((GetUnitTypeId(chestUnit) == 0), "Chest", "create", "unitid", unitid, "Invalid unitid! Created Chest Unit Is null!")
endif
return this
endmethod
private static method init takes nothing returns nothing
set Chest.table = Table.create()
set onOpenSound = CreateSound("Sound\\Ambient\\DoodadEffects\\DoorSlam1.wav", false, false, true, 10, 10, "CombatSoundsEAX")
set error = CreateSoundFromLabel("InterfaceError", false, false, false, 10, 10)
endmethod
implement optional CHEST_INITIALIZER
implement optional Init
endstruct
function GetTriggerChest takes nothing returns Chest
return Chest.eventIndex
endfunction
endlibrary