Nestharus
o-o
- Reaction score
- 84
From Demo 1 of Stacked Fields as that demo was just so awesome ; D.
Getting some major updates to use Unit Indexer
Requires- http://www.thehelper.net/forums/showthread.php?t=151978 (2.1.0.0)
Notes-
I am not making a plain evolution system as they are unsafe with unit indexing systems. Evolution/Devolution systems like this one are safe.
Introduction
This is safe with index systems
If you attach a struct to a unit and evolve that unit, the struct will still be on it.
If you evolve a unit, triggers that were registered specifically with it will not run anymore.
If a unit decays/is removed, the struct will still get destroyed, so don't worry =).
Safe Usage
Code
Demo Code
Getting some major updates to use Unit Indexer
Requires- http://www.thehelper.net/forums/showthread.php?t=151978 (2.1.0.0)
Notes-
I am not making a plain evolution system as they are unsafe with unit indexing systems. Evolution/Devolution systems like this one are safe.
Introduction
Wouldn't it be cool if you had like a peasant and he trained really hard and became a footman? Then he trained hard some more by killing guys or w/e and became a swordsman? Eventually a captain? A knight? A full fledged hero?
What if he screws up or gets lazy and goes from hero back to knight? Maybe he lost too many battles, lost some skills, or w/e else?
This system let's you do that with ease. When a unit changes (up a rank), it's called an evolution. When a unit goes down a rank, it's called a devolution. This system can do both =D.
Try the test map out for yourself. Move the unit around, order it to attack, and etc.
Test Map Command-
pop [num]
Devolves a unit num times.
you can type pop by itself, pop0, pop 1, or even pop 335939 and it'll all work ; D. You can even have a typo like adadsa a apopa 2 and it'll still work >.<. Just need to have the pop somewhere in there ; O.
This is safe with index systems
If you attach a struct to a unit and evolve that unit, the struct will still be on it.
If you evolve a unit, triggers that were registered specifically with it will not run anymore.
If a unit decays/is removed, the struct will still get destroyed, so don't worry =).
Safe Usage
If you have a trigger that runs and you use get(handle) to retrieve the EvolvingUnit index, it is always a good idea to make sure that the index is not 0.
If it is 0, the struct you retrieved is null, meaning your evolving unit no longer exists.
If you don't use get, then make sure the evolving unit (unit) is not null.
Code
JASS:
library EvoDevoUnit
globals
//only use hash if you plan on having a crap load of units with a crap
//load of evolutions, like 100 units that each evolve 100 times.
private constant boolean USE_HASH = false
endglobals
//1.2.0.6
//Description
// Evolves and Devolves units. Retains all unit data.
////////////////////////////////////////////////////
//EvolveUnit struct API
////////////////////////////////////////////////////
//Fields/Properties
// readonly unit unit
// the evolution unit handle
// readonly integer level
// current evolution level
//Methods
// static get(handle h) returns EvolvingUnit
// used with for handle attachment
// evolve(integer unitType) returns nothing
// evolve
// devolve() returns nothing
// devolve
// devolveCount(integer count) returns nothing
// devolve certain amount of times. If you want to devolve more than once but you don't want to clear,
// use this instead of devolve as it'll be much faster
// base() returns nothing
// devolve to original
// create(unit) returns EvolveUnit
// create new
// destroy() returns nothing
// destroy
// attach(handle) returns nothing
// attaches instance to handle
scope sdfidsjfosi
endscope
private keyword evoCodeDId
private keyword hashref
private keyword HASH_EvolvingDevolvingUnit
private struct EvolvingDevolvingUnit extends array
public unit unit
static if HASH_EvolvingDevolvingUnit then
private static key k_unit
public method restore takes hashtable h, integer instance returns nothing
set unit = LoadUnitHandle(h, instance, k_unit)
endmethod
public method archive takes hashtable h, integer instance returns nothing
if (unit != null) then
call SaveUnitHandle(h, instance, k_unit, unit)
endif
endmethod
endif
public method allocate takes nothing returns nothing
set unit = null
endmethod
public method deallocate takes nothing returns nothing
//should pretty much just be used for cleaning up handles/structs
if (unit != null) then
call RemoveUnit(unit)
endif
endmethod
endstruct
//! runtextmacro MAKE_FIELD_STACK("EvolvingDevolvingUnit", "USE_HASH")
private struct Order extends array
public integer order
public widget targetWidget
public real targetX
public real targetY
endstruct
private struct SpawnData extends array
public static real x
public static real y
public static real lifeRatio
public static real facing
public static player p
public static integer i
public static integer count
public static integer count2
public static item array items
public static real manaRatio
public static boolean select
public static real mana
public static integer userData
public static boolean useFood
public static delegate Order orderX
public static method allocate takes unit u, Order ordered returns nothing
local integer unitId = GetUnitTypeId(u)
set useFood = GetUnitFoodUsed(u) != 0
set userData = GetUnitUserData(u)
set orderX = ordered
if (GetUnitCurrentOrder(u) != ordered.order) then
set order = -1
endif
set select = IsUnitSelected(u, GetLocalPlayer())
set x = GetUnitX(u)
set y = GetUnitY(u)
set facing = GetUnitFacing(u)
set p = GetOwningPlayer(u)
set mana = GetUnitState(u, UNIT_STATE_MANA)
if (mana != 0) then
set manaRatio = mana/GetUnitState(u, UNIT_STATE_MAX_MANA)
else
set manaRatio = 0
endif
set lifeRatio = GetWidgetLife(u)/GetUnitState(u, UNIT_STATE_MAX_LIFE)
set count = UnitInventorySize(u)
set i = 0
loop
exitwhen i == count
set items<i> = UnitItemInSlot(u, i)
if (items<i> != null) then
call UnitDropItemSlot(u, items<i>, i)
endif
set i = i + 1
endloop
endmethod
public static method copy takes unit u, boolean basics returns nothing
call IssueImmediateOrder(u, "stop")
if (basics) then
call SetUnitX(u, x)
call SetUnitY(u, y)
call SetUnitFacingTimed(u, facing, 0)
call SetUnitOwner(u, p, true)
endif
call SetUnitUserData(u, userData)
call SetUnitUseFood(u, useFood)
call SelectUnit(u, select)
call SetWidgetLife(u, GetUnitState(u, UNIT_STATE_MAX_LIFE)*lifeRatio)
set mana = GetUnitState(u, UNIT_STATE_MANA)
if (mana != 0) then
call SetUnitState(u, UNIT_STATE_MANA, mana*manaRatio)
endif
set i = 0
loop
exitwhen i == count
if (items<i> != null) then
call UnitAddItem(u, items<i>)
set items<i> = null
endif
set i = i + 1
endloop
if (order != -1) then
if (targetWidget != null) then
call IssueTargetOrderById(u, order, targetWidget)
else
call IssuePointOrderById(u, order, targetX, targetY)
endif
endif
endmethod
endstruct
struct EvolvingUnit extends array
implement EvolvingDevolvingUnitStack
private static hashtable hashref = InitHashtable()
private integer tCount
private static boolexpr pointOrder
private static boolexpr targetOrder
private trigger trackPointOrder
private trigger trackTargetOrder
private integer trackPointOrderId
private integer trackTargetOrderId
private static real hideX
private static real hideY
//recycler
private thistype next
private thistype previous
private static timer recycler = CreateTimer()
private static boolean recycleRunning = false
private static method operator head takes nothing returns thistype
return 0
endmethod
public method attach takes handle h returns nothing
local integer id = GetHandleId(h)
call SaveInteger(hashref, id, 0, this)
call SaveInteger(hashref, this, tCount, id)
set tCount = tCount + 1
endmethod
public static method get takes handle h returns thistype
return LoadInteger(hashref, GetHandleId(h), 0)
endmethod
//hide unit
public method operator unit takes nothing returns unit
return EvolvingDevolvingUnit.unit
endmethod
private method operator unit= takes unit u returns nothing
set EvolvingDevolvingUnit.unit = u
endmethod
public method operator level takes nothing returns integer
return EvolvingDevolvingUnit.size
endmethod
public method destroy takes nothing returns nothing
if (trackPointOrder != null) then //make sure allocated
call deallocateEvolvingDevolvingUnit() //all you have to do
////////////////////////////////////////////////////////
call RemoveSavedInteger(hashref, trackPointOrderId, 0)
call RemoveSavedInteger(hashref, trackTargetOrderId, 0)
call DestroyTrigger(trackPointOrder)
call DestroyTrigger(trackTargetOrder)
set Order(this).targetWidget = null
set trackPointOrder = null
set trackTargetOrder = null
set next.previous = previous
set previous.next = next
loop
exitwhen tCount == 0
set tCount = tCount - 1
call RemoveSavedInteger(hashref, LoadInteger(hashref, this, tCount), 0)
endloop
call FlushChildHashtable(hashref, this)
endif
endmethod
private static method runRecycle takes nothing returns nothing
local thistype this = head.next
loop
exitwhen this == 0
if (unit == null) then
call destroy()
endif
set this = next
endloop
if (head.next == 0) then
set recycleRunning = false
call PauseTimer(recycler)
endif
endmethod
private method recycle takes nothing returns nothing
set head.next.previous = this
set next = head.next
set head.next = this
set previous = head
if (not recycleRunning) then
set recycleRunning = true
call TimerStart(recycler, 2, true, function thistype.runRecycle)
endif
endmethod
private static method trackPointOrderX takes nothing returns boolean
local Order this = get(GetTriggeringTrigger())
set this.targetWidget = null
set this.targetX = GetOrderPointX()
set this.targetY = GetOrderPointY()
set this.order = GetIssuedOrderId()
return false
endmethod
private static method trackTargetOrderX takes nothing returns boolean
local Order this = get(GetTriggeringTrigger())
set this.targetWidget = GetOrderTarget()
set this.order = GetIssuedOrderId()
return false
endmethod
private method registerTrigs takes nothing returns nothing
call TriggerRegisterUnitEvent(trackPointOrder, unit, EVENT_UNIT_ISSUED_POINT_ORDER)
call TriggerRegisterUnitEvent(trackTargetOrder, unit, EVENT_UNIT_ISSUED_TARGET_ORDER)
endmethod
public static method create takes unit u returns thistype
local thistype this = 0
if (u != null) then
set this = allocateEvolvingDevolvingUnit()
set unit = u
set trackPointOrder = CreateTrigger()
set trackTargetOrder = CreateTrigger()
set trackPointOrderId = GetHandleId(trackPointOrder)
set trackTargetOrderId = GetHandleId(trackTargetOrder)
call SaveInteger(hashref, trackPointOrderId, 0, this)
call SaveInteger(hashref, trackTargetOrderId, 0, this)
set Order(this).order = -1
call TriggerAddCondition(trackPointOrder, pointOrder)
call TriggerAddCondition(trackTargetOrder, targetOrder)
call registerTrigs()
call recycle()
endif
return this
endmethod
private method startCopy takes nothing returns nothing
call DisableTrigger(trackPointOrder)
call DisableTrigger(trackTargetOrder)
call SpawnData.allocate(unit, this)
call ShowUnit(unit, false)
call PauseUnit(unit, true)
call SetUnitX(unit, hideX)
call SetUnitY(unit, hideY)
endmethod
private method finishCopy takes boolean basics returns nothing
call ShowUnit(unit, true)
call PauseUnit(unit, false)
call SpawnData.copy(unit, basics)
call EnableTrigger(trackPointOrder)
call EnableTrigger(trackTargetOrder)
endmethod
public method devolve takes nothing returns nothing
if (trackPointOrder != null) then
if (unit != null) then
if (not EvolvingDevolvingUnit.empty) then
call startCopy()
call EvolvingDevolvingUnit.pop()
call finishCopy(true)
endif
else
call destroy()
endif
endif
endmethod
public method devolveCount takes integer steps returns nothing
if (trackPointOrder != null) then
if (unit != null) then
if (steps != 0 and not EvolvingDevolvingUnit.empty) then
call startCopy()
call EvolvingDevolvingUnit.popCount(steps)
call finishCopy(true)
endif
else
call destroy()
endif
endif
endmethod
public method evolve takes integer unitType returns nothing
if (trackPointOrder != null) then
if (unit != null) then
call startCopy()
call EvolvingDevolvingUnit.push()
set unit = CreateUnit(SpawnData.p, unitType, SpawnData.x, SpawnData.y, SpawnData.facing)
call finishCopy(false)
call registerTrigs()
else
call destroy()
endif
endif
endmethod
public method base takes nothing returns nothing
if (trackPointOrder != null) then
if (unit != null) then
if (not EvolvingDevolvingUnit.empty) then
call startCopy()
call EvolvingDevolvingUnit.clear()
call finishCopy(true)
endif
else
call destroy()
endif
endif
endmethod
private static method onInit takes nothing returns nothing
local rect world = GetWorldBounds()
set hideX = GetRectMaxX(world)
set hideY = GetRectMaxY(world)
call RemoveRect(world)
set world = null
set pointOrder = Condition(function thistype.trackPointOrderX)
set targetOrder = Condition(function thistype.trackTargetOrderX)
endmethod
endstruct
endlibrary
</i></i></i></i></i></i>
Demo Code
JASS:
//Order the unit around the map so you can see that it is still moving even while evolving/devolving
//type pop to devolve the unit
//watch as its evolution takes longer and longer as the xp required increases
//Commands-
//pop [num]
// devolve num times. If num isn't specified, pop once
scope EvoDevoDemonstration
private scope EvoUnit
private keyword allocate
private keyword deallocate
private keyword evolution
private keyword super
private module EvoUnit
private delegate EvolvingUnit un
private integer levelX
private integer xpX
public static integer array evolution
public method operator super takes nothing returns EvolvingUnit
return un
endmethod
public method operator evoLevel takes nothing returns integer
return super.level
endmethod
public method operator canEvolve takes nothing returns boolean
return evolution[evoLevel+1] != 0
endmethod
public method operator canDevolve takes nothing returns boolean
return evoLevel != 0
endmethod
public method operator level takes nothing returns integer
return levelX
endmethod
public method operator xp takes nothing returns integer
return xpX
endmethod
public method evolve takes nothing returns nothing
if (canEvolve) then
set levelX = 0
set xpX = 0
call super.evolve(evolution[evoLevel+1])
endif
endmethod
public method evolveCount takes integer steps returns nothing
set levelX = 0
set xpX = 0
loop
exitwhen steps == 0 or evolution[evoLevel+1] == 0
set steps = steps - 1
call super.evolve(evolution[evoLevel+1])
endloop
endmethod
public method devolveCount takes integer steps returns nothing
if (canDevolve) then
set levelX = 0
set xpX = 0
call super.devolveCount(steps)
endif
endmethod
public method devolve takes nothing returns nothing
if (canDevolve) then
set levelX = 0
set xpX = 0
call super.devolve()
endif
endmethod
public method base takes nothing returns nothing
if (canDevolve) then
set levelX = 0
set xpX = 0
call super.base()
endif
endmethod
public method operator level= takes integer val returns nothing
set levelX = val
set xpX = 0
if (levelX >= EVO_LEVEL) then
call evolve()
elseif (levelX < 0) then
call devolve()
endif
endmethod
public method operator xp= takes integer val returns nothing
set xpX = val
if (xpX >= evoLevel*EVO_LEVEL) then
set level = level + 1
elseif (xpX < 0) then
set level = level - 1
endif
endmethod
public static method allocate takes unit u returns thistype
local thistype this = EvolvingUnit.create(u)
set un = this
return this
endmethod
public method deallocate takes nothing returns nothing
call super.destroy()
endmethod
endmodule
struct HumanSoldier extends array
private static constant real LEVEL_MULTIPLIER = 2
private static constant integer EVO_LEVEL = 1
implement EvoUnit
public static method create takes player p, real x, real y, real facing returns thistype
return allocate(CreateUnit(p, thistype.evolution[0], x, y, facing))
endmethod
public method destroy takes nothing returns nothing
call deallocate()
endmethod
private static method onInit takes nothing returns nothing
set evolution[0] = 039;hpea039;
set evolution[1] = 039;hmil039;
set evolution[2] = 039;hfoo039;
set evolution[3] = 039;hcth039;
set evolution[4] = 039;hkni039;
endmethod
endstruct
endscope
private struct Demonstration extends array
private static constant string POP = "pop"
private static integer popSize
private static constant player P = Player(0)
private static constant real X = 2000
private static constant real Y = 2000
private static constant real TICK = 1
private static constant integer XP_PER_TICK = 1
private delegate HumanSoldier humanSoldier
private static method addXp takes nothing returns nothing
local thistype this = HumanSoldier.get(GetExpiredTimer())
set xp = xp + 1
endmethod
private static method delevel takes nothing returns boolean
local thistype this = HumanSoldier.get(GetTriggeringTrigger())
local integer count
local integer i
local string char
local string str = GetEventPlayerChatString()
local integer length
local boolean useCount = false
if (str == POP) then
call devolve()
elseif (SubString(str, 0, popSize) == POP) then
set str = SubString(str, popSize, StringLength(str))
set i = 0
set count = 0
set length = StringLength(str)
loop
set char = SubString(str, i, i+1)
if (char == "0" or char == "1" or char == "2" or char == "3" or char == "4" or char == "5" or char == "6" or char == "7" or char == "8" or char == "9") then
set count = count * 10 + S2I(char)
set useCount = true
endif
set i = i + 1
exitwhen i == length
endloop
if (not useCount) then
set count = 1
endif
if (count >= evoLevel) then
call base()
else
call devolveCount(count)
endif
endif
return false
endmethod
private static method onInit takes nothing returns nothing
local trigger deTr = CreateTrigger()
local timer xpT = CreateTimer()
local thistype this = HumanSoldier.create(P, X, Y, 0)
set humanSoldier = this
set popSize = StringLength(POP)
call TriggerRegisterPlayerChatEvent(deTr, Player(0), POP, false)
call TriggerAddCondition(deTr, Condition(function thistype.delevel))
call attach(deTr)
call attach(xpT)
call TimerStart(xpT, TICK, true, function thistype.addXp)
endmethod
endstruct
endscope