- Joined
- Nov 4, 2007
- Messages
- 337
Well, the library description should do it.
JASS:
library GetUnitCost initializer Init requires Table, CommonAIimports
//===========================================================================
// Information:
//==============
//
// This library allows you to get the cost of units in the following devices:
// Gold, Wood, Food, FoodIncrement. Normally this is not possible. This is useful
// for example, if you want to make a towerdefense and you want a sell button which gives
// 75% of the gold and wood back you payed for it. But when the tower is an upgrade, so the
// tower itself costs 100 gold plus 100 gold upgrade, and you'd use a dummy to cast Transmute on
// the unit, the player would only get 75% gold back, not the gold for all the upgrades.
// If you used this library, you'd be able to give him 150 instead of 75 gold back.
//
//===========================================================================
// Implementation:
//================
//
// 1. Make a new trigger, convert it to custom text
// and replace all the code in the trigger by this.
// 2. Give credits to Mr.Malte (:P) and use the system.
//===========================================================================
// Functions:
//===========
//
// GetUnitCost(unit,type*) : Returns the total gold cost of a unit (upgrades included)
// GetUnitTypeCost(unitId,type*) : Returns, how much a unit with ID X would cost. Note:
// This ignores upgrade gold costs, so when you just want the cost of
// THIS building/unit, you can use GetUnitTypeCost(GetUnitTypeId(#),#)
//
// * type can be COST_GOLD or COST_LUMBER
//
//===========================================================================
// Features:
//==========
// 1. Gets the cost of Units including its previous forms (when upgraded)
// 2. Works for units and structures
// 3. Uses a smart way to detect gold and wood
// 4. Destroys UnitCost structs automatically, even when the units are removed.
//
//===========================================================================
globals
private constant integer PLAYER_ID = 14
private constant integer DUMMY_ID = 'hpea'
private constant integer RESOURCE_LIMIT = 100000
private constant boolean CLONE = true
endglobals
globals
private trigger unitEnters = CreateTrigger()
private trigger unitDies = CreateTrigger()
private trigger unitUpgrades = CreateTrigger()
private HandleTable UnitData
private Table RawcodeData
private real maxX
private real maxY
private unit dummy = null
private player dummyOwner = Player(PLAYER_ID)
endglobals
// return true: Save the unit's cost.
// return false: Don't save the unit's cost.
private function UserFilter takes unit u returns boolean
return ( GetUnitAbilityLevel(u,'Aloc') == 0 )
endfunction
struct UnitCost
integer Lumber
integer Gold
UnitCost Link = 0
method increaseBy takes UnitCost inc returns nothing
set .Lumber = .Lumber + inc.Lumber
set .Gold = .Gold + inc.Gold
call inc.destroy()
// And now synchronize the Clone.
// Destroying and recreating would change its ID, so..
if CLONE then
if .Link != 0 then
set .Link.Gold = .Gold
set .Link.Lumber = .Lumber
endif
endif
endmethod
// We want to give the user the UnitCost struct, but we dont want him to access it
// and change its data. So we make a 'Parastruct'
method Clone takes nothing returns UnitCost
if CLONE then
if .Link == 0 then
set .Link = UnitCost.create()
endif
// Always restore the data to be safe.
set .Link.Gold = .Gold
set .Link.Lumber = .Lumber
set .Link.Link = -1 // -1 means: This is just a clone.
return .Link
else
return this
endif
endmethod
method onDestroy takes nothing returns nothing
if .Link > 0 then
call .Link.destroy()
endif
endmethod
endstruct
private function GetUnitCostSimple takes integer ID returns UnitCost
local UnitCost u = UnitCost.create()
//if RawcodeData.exists(ID) then
// return RawcodeData[ID]
//endif
if IsUnitIdType(ID,UNIT_TYPE_HERO) then
call SetPlayerState(dummyOwner, PLAYER_STATE_RESOURCE_GOLD, RESOURCE_LIMIT)
call SetPlayerState(dummyOwner, PLAYER_STATE_RESOURCE_LUMBER, RESOURCE_LIMIT)
call SetPlayerState(dummyOwner, PLAYER_STATE_RESOURCE_FOOD_USED,0)
call AddUnitToStock(dummy, ID, 1, 1)
call IssueNeutralImmediateOrderById(dummyOwner, dummy, ID)
call RemoveUnitFromStock(dummy,ID)
set u.Gold = RESOURCE_LIMIT - GetPlayerState(dummyOwner,PLAYER_STATE_RESOURCE_GOLD)
set u.Lumber = RESOURCE_LIMIT - GetPlayerState(dummyOwner,PLAYER_STATE_RESOURCE_LUMBER)
else
set u.Gold = GetUnitGoldCost(ID)
set u.Lumber = GetUnitWoodCost(ID)
endif
//set RawcodeData[ID] = u
return u
endfunction
// ======================================================================
// ============== USER FUNCTIONS ==============
// ======================================================================
globals
constant integer COST_GOLD = 0
constant integer COST_LUMBER = 1
endglobals
function GetUnitCost takes unit u, integer cost returns integer
local UnitCost temp = UnitData[u]
if cost == COST_GOLD then
return temp.Gold
elseif cost == COST_LUMBER then
return temp.Lumber
else
debug call BJDebugMsg("GetUnitCost: Used undefined cost-type")
endif
return 0
endfunction
function GetUnitTypeCost takes integer unitId, integer cost returns integer
local UnitCost temp = GetUnitCostSimple(unitId)
if cost == COST_GOLD then
return temp.Gold
elseif cost == COST_LUMBER then
return temp.Lumber
else
debug call BJDebugMsg("GetUnitCost: Used undefined cost-type")
endif
return 0
endfunction
// ======================================================================
// ======================================================================
// ======================================================================
private function onEnter takes nothing returns nothing
local UnitCost uc
local unit u = GetTriggerUnit()
// Kill dummies.
if GetOwningPlayer(u) == dummyOwner then
call RemoveUnit(u)
return
endif
// Actually it would make sense to only save the cost to the unit,
// when it has been upgraded. But we can't detect the unit type it was
// before, because the unit ID already changed when the onUpgrade trigger
// fired.
if UserFilter(u) then
set uc = GetUnitCostSimple(GetUnitTypeId(u))
set UnitData[u] = uc
endif
endfunction
private function onUpgrade takes nothing returns nothing
local UnitCost uc = GetUnitCostSimple(GetUnitTypeId(GetTriggerUnit()))
local UnitCost ucPrev = UnitData[GetTriggerUnit()]
call ucPrev.increaseBy(uc)
endfunction
private function Destruct takes unit u returns nothing
local UnitCost uc
if GetOwningPlayer(u) != dummyOwner then
set uc = UnitData[u]
if uc != null then
call uc.destroy()
endif
endif
endfunction
private function onDie takes nothing returns nothing
call Destruct(GetTriggerUnit())
endfunction
hook RemoveUnit Destruct
private function returnFlag takes nothing returns boolean
return UserFilter(GetFilterUnit())
endfunction
private function Init takes nothing returns nothing
local integer index = 0
local group g = CreateGroup() // Catch also initial units.
local unit u
local boolexpr condition = Condition(function returnFlag)
local UnitCost uc
set UnitData = HandleTable.create()
set RawcodeData = Table.create()
// ==========================================================================
set dummy = CreateUnit(dummyOwner,DUMMY_ID,GetRectMaxX(bj_mapInitialPlayableArea),GetRectMaxY(bj_mapInitialPlayableArea),270)
call UnitAddAbility(dummy,'Asud')
call UnitAddAbility(dummy,'Aloc')
call SetUnitAcquireRange(dummy,0.)
call ShowUnit(dummy,false)
call SetUnitInvulnerable(dummy,true)
// ==========================================================================
call SetPlayerState(dummyOwner, PLAYER_STATE_RESOURCE_FOOD_CAP,300)
call TriggerRegisterEnterRectSimple(unitEnters,bj_mapInitialPlayableArea)
loop
call TriggerRegisterPlayerUnitEvent(unitUpgrades, Player(index), EVENT_PLAYER_UNIT_UPGRADE_START, condition)
call TriggerRegisterPlayerUnitEvent(unitDies, Player(index), EVENT_PLAYER_UNIT_DEATH, condition)
set index = index + 1
exitwhen index == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddAction(unitEnters,function onEnter)
call TriggerAddAction(unitUpgrades,function onUpgrade)
call TriggerAddAction(unitDies,function onDie)
// ==========================================================================
call GroupEnumUnitsInRect(g,bj_mapInitialPlayableArea,condition)
loop
set u = FirstOfGroup(g)
exitwhen u == null
set uc = GetUnitCostSimple(GetUnitTypeId(u))
set UnitData[u] = uc
call GroupRemoveUnit(g,u)
endloop
call DestroyBoolExpr(condition)
call DestroyGroup(g)
endfunction
endlibrary
Attachments
Last edited: