- Joined
- Feb 3, 2013
- Messages
- 277
Trouble with Meathook Spell -__-
NEW EDIT:
I cleand it up even more making sure every struct extends array and deleted all this other crap I felt it didn't need (to help me understand).
BTW credit to the original guy : Kenny on TH
Now... the part that confuses me the most.
I don't fully understand this concept - the second struct, has two members of struct type 'Link' - but after it gets compiled, it will turn into integer arrays not 'Link' arrays. So how can something like lead to being capable of holding 8191 units in a total of 8191 instances??? I mean it works but I'm just so confused... ned help again :<
I'm not sure if this make sense but it's like taking something 2D and making it 3D? Wat da heck?
Like I could imagine setting a static integer array member and capping a max instance number,... but this is like having an array member in an array struct.
ㄱㄱㄱㄱㄱㄱ
NEW EDIT:
I cleand it up even more making sure every struct extends array and deleted all this other crap I felt it didn't need (to help me understand).
BTW credit to the original guy : Kenny on TH
JASS:
library LinkedMeatHook
/**************************************************************************/
/* */
/* Linked Meat Hook v1.0 */
/* by: msongyyy */
/* */
/* HOW TO IMPORT: */
/* 1. Import dummy units MeatHook - head and chain and */
/* and the meathook ability */
/* 2. Import this trigger and the headshot.wav file */
/* 3. Setup configurables to your liking */
/* */
/* Enjoy ^^ */
/* */
/* THANKS TO: (PLEASE READ) */
/* 1. ****BIG THANKS TO KENNY, TROLLVOTEL, AND TOSSROCK***** */
/* THIS TRIGGER IS EDITED ON TOP OF KENNY'S, WHICH */
/* WAS INSPIRED BY TROLLVOTEL'S REINVENTION OF TOSSROCK'S */
/* MEAT HOOK SKILL IN HIS CUSTOM MOD PUGDE WARS. */
/* */
/* NONE OF THIS WOULD BE POSSIBLE WITHOUT THEIR VIEWS */
/* AND ORIGINAL CREATION. I LEARNED A LITTLE BIT MORE */
/* THANKS TO KENNY'S ORIGINAL VERSION, SO TRULY THANKS */
/* TO HIM MORE THAN MOST) */
/* */
/* 2. THANKS TO MR_BEAN, FOR THAT ONE IMPORTANT READ */
/* 3. THANKS TO HIVE, FOR GREAT COMMUNITY */
/* */
/* */
/* HAVING SAID THAT, PLEASE CHECK KENNY'S */
/* VERSION ON THE HELPER */
/* */
/* */
/**************************************************************************/
globals
private constant integer ABIL_ID = 'A000'
private constant integer HEAD_ID = 'h002'
private constant integer LINK_ID = 'h001'
private constant integer LOCUST_ID = 'Aloc'
endglobals
/**************************************************************************/
/* START OF CONFIGURABLES */
/**************************************************************************/
globals
private constant real MAX_HEIGHT = 40.00
private constant real UNIT_RADIUS = 225.00
private constant real BUILD_RADIUS = 270.00
private constant real DEST_RADIUS = 270.00
private constant real TIME_SCALE = 1.00
private constant real HEAD_SCALE = 5.00
private constant real LINK_SCALE = 3.00
private constant real FLY_HEIGHT = 75.00
private constant real DEST_DMG_PERC = 0.00
private constant real HEADSHOT_DMG = 999999999999999999999999999999.00
private constant string BLOOD_SFX = "Objects\\Spawnmodels\\Human\\HumanBlood\\BloodElfSpellThiefBlood.mdl"
private constant string BLOOD_POINT = "origin"
private constant string HEADSHOT_FX = "Units\\Undead\\Abomination\\AbominationExplosion.mdl"
private constant string HEADSHOT_SOUND = "war3mapImported\\headshot.wav"
private constant integer HEADSHOT_VOL = 127
private constant attacktype A_TYPE = ATTACK_TYPE_CHAOS
private constant damagetype D_TYPE = DAMAGE_TYPE_UNIVERSAL
private constant weapontype W_TYPE = WEAPON_TYPE_WHOKNOWS
private constant boolean ALLOW_HEADSHOT = true
private constant boolean ALLOW_PRELOAD = true
private constant boolean ALLOW_BOUNCE = true
private constant boolean DEST_BOUNCE = true
private constant boolean ABOVE_CASTER = false
private constant boolean DISCARD_TARGET = false
private constant boolean KILL_DESTS = false
private constant timer TMR = CreateTimer()
private constant real INC = 45.00
private constant real PERIOD = .03125000
private constant hashtable HASH = InitHashtable()
endglobals
private constant function MAXDIST takes integer lvl returns real
return 5000.00 + (2000.00 * lvl)
endfunction
private constant function DAMAGE takes integer lvl returns real
return 50.00 + (75.00 * lvl)
endfunction
private constant function SPEED takes integer lvl returns real
return 2000.00 + (0000.00 * lvl)
endfunction
private function FilterUnits takes unit filter returns boolean
return GetUnitFlyHeight(filter) < MAX_HEIGHT and GetUnitAbilityLevel(filter,LOCUST_ID) == 0
endfunction
/**************************************************************************/
/* END OF CONFIGURABLES */
/**************************************************************************/
// To make peoples happy. To bad there is no WidgetAlive native.
native UnitAlive takes unit id returns boolean
private struct Link extends array // Individual links in the linked list for units.
thistype next // Next link in the list.
thistype prev // Previous link in the list.
unit link // The actual chain link.
static integer array rn
static integer ic = 0
static method create takes nothing returns thistype
local thistype this = rn[0]
if this == 0 then
set ic = ic + 1
set this = ic
else
set rn[0] = rn[this]
endif
set .next = 0
set .prev = 0
set .link = null
return this
endmethod
method destroy takes nothing returns nothing
call RemoveUnit(this.link)
set this.link = null
set rn[this] = rn[0]
set rn[0] = this
endmethod
endstruct
//---------------------------------------------------------------------\\
private struct List extends array // Linked list to hold all the units that make the chain.
Link head // First link in the list.
Link last // Last link in the list.
integer size // Size of the list.
static integer array rn
static integer ic = 0
static method create takes nothing returns thistype
local thistype this = rn[0]
if this == 0 then
set ic = ic + 1
set this = ic
else
set rn[0] = rn[this]
endif
set .head = 0
set .last = 0
set .size = 0
return this
endmethod
// Attach a link to the list.
method attach takes nothing returns Link
local Link curr = Link.create() // Create a link.
// Restructuring the start of the list.
if this.head == 0 then
// If there is nothing in the first, set the new link to the head.
set this.head = curr
else
// Otherwise, attach the new link to the end of the list.
set curr.prev = this.last
set this.last.next = curr
endif
// Setting the rest of this link and incrementing list size.
set this.last = curr
set this.size = this.size + 1
return curr
endmethod
// Detach a link from the list.
method detach takes Link curr returns nothing
// Removing a link from the list.
if curr.next == 0 then
// If we are removing the last node, reset last.
set this.last = curr.prev
else
set curr.next.prev = curr.prev
endif
set curr.prev.next = curr.next
// Destroy the link.
call curr.destroy()
// Decrement size of list.
set this.size = this.size - 1
endmethod
// Destroy the list.
method destroy takes nothing returns nothing
// Just to make sure no links are left.
loop
exitwhen this.size == 0
call this.detach(this.last)
endloop
set rn[this] = rn[0]
set rn[0] = this
endmethod
endstruct
//---------------------------------------------------------------------\\
private struct Hook extends array// Struct that takes care of the rest.
// Instance members.
unit cast // The caster.
unit targ // The possible target.
unit head // The head of the chain.
player own // The owner of the caster.
real ang // The angle the chain is travelling in.
real dist // The current distance travelled.
real max // Maximum distance of the hook.
real cos // Cos of the current angle.
real sin // Sin of the current angle.
real speed // Speed of the hook, saves function calls.
integer level // Level of the Meat Hook spell for the caster.
List list // Linked list needed to track chain links.
boolean ret // If the hook is extending.
boolean hit // If a unit has been hit.
// Static members.
static thistype tempData = 0 // Temp struct needed for data transfer.
static rect enumRect = null // Rect for bouncing off destructables.
static group enumGroup = null // Group for enumerating units and buildings.
static code enumDests = null // Filter function for finding destructables.
static boolexpr enumUnits = null // Filter function for finding units.
static boolexpr enumBuild = null // Filter function for finding buildings.
static real worldMaxX = 0.00 // Map boundaries.
static real worldMaxY = 0.00 // Map boundaries.
static real worldMinX = 0.00 // Map boundaries.
static real worldMinY = 0.00 // Map boundaries.
static integer array prev
static integer array next
static integer array rn
static integer ic = 0
// Set the new angle for bouncing.
method setAngle takes real tempx, real tempy returns boolean
local real ang1 = this.ang * bj_RADTODEG
local real ang2 = ModuloReal(Atan2((GetUnitY(this.head) - tempy),(GetUnitX(this.head) - tempx)) * bj_RADTODEG,360.00)
local real diff = RAbsBJ(ang2 - ang1)
// Lots of math stuff :).
if diff >= 90.00 and diff <= 270.00 then
if ( ang2 > 45.00 and ang2 < 135.00 ) or ( ang2 > 225.00 and ang2 < 315.00 ) then
set this.ang = -ang1 * bj_DEGTORAD
else
set this.ang = (180.00 - ang1) * bj_DEGTORAD
endif
// Set the new travelling angle.
set this.sin = Sin(this.ang)
set this.cos = Cos(this.ang)
return true
endif
return false
endmethod
// Sets the target unit.
method setTarget takes unit target returns boolean
local sound shot
set this.targ = target
set this.hit = true
// Damage the target if it is an enemy.
if IsUnitEnemy(this.targ,this.own) then
call UnitDamageTarget(this.cast,this.targ,DAMAGE(this.level),true,false,A_TYPE,D_TYPE,W_TYPE)
call DestroyEffect(AddSpecialEffectTarget(BLOOD_SFX,this.targ,BLOOD_POINT))
endif
if ALLOW_HEADSHOT then
if HaveSavedBoolean(HASH, GetHandleId(this.targ), 0) then
call UnitDamageTarget(this.cast, this.targ, HEADSHOT_DMG, true, false, A_TYPE, D_TYPE, W_TYPE)
call DestroyEffect(AddSpecialEffect(HEADSHOT_FX, GetUnitX(this.targ), GetUnitY(this.targ)))
call FlushChildHashtable(HASH, GetHandleId(this.targ))
set shot = CreateSound(HEADSHOT_SOUND,false,false,false,10,10,"")
call SetSoundVolume(shot, HEADSHOT_VOL)
call StartSound(shot)
call KillSoundWhenDone(shot)
else
call SaveBoolean(HASH, GetHandleId(this.targ), 0, true)
endif
endif
// Stop the hook from moving.
call SetUnitTimeScale(this.head,0.00)
return true
endmethod
// Searches for units to become the hook's target.
static method getUnit takes nothing returns boolean
local thistype this = thistype.tempData
local unit filt = GetFilterUnit()
local sound shot = null
if UnitAlive(filt) and IsUnitType(filt,UNIT_TYPE_STRUCTURE) == false and GetUnitTypeId(filt) != LINK_ID and GetUnitTypeId(filt) != HEAD_ID then
if this.cast != filt and FilterUnits(filt) then
if not this.hit then
call this.setTarget(filt)
endif
endif
endif
set filt = null
return false
endmethod
static method getDest takes nothing returns nothing
local thistype this = thistype.tempData
local destructable dest = GetEnumDestructable()
// Only bounce off alive destructables.
if GetWidgetLife(dest) > 0.406 then
call this.setAngle(GetWidgetX(dest),GetWidgetY(dest))
// Kill them if you want.
static if KILL_DESTS then
call KillDestructable(dest)
else
call UnitDamageTarget(this.cast,dest,(DAMAGE(this.level) * DEST_DMG_PERC),true,false,A_TYPE,D_TYPE,W_TYPE)
endif
endif
set dest = null
endmethod
// Searches for buildings to bounce off.
static method getBuild takes nothing returns boolean
local thistype this = thistype.tempData
local unit filt = GetFilterUnit()
if UnitAlive(filt) and IsUnitType(filt,UNIT_TYPE_STRUCTURE) == true and GetUnitTypeId(filt) != LINK_ID and GetUnitTypeId(filt) != HEAD_ID then
if this.cast != filt and FilterUnits(filt) then
static if ALLOW_BOUNCE then // If bouncing is allowed, then set the new angle.
call this.setAngle(GetUnitX(filt),GetUnitY(filt))
endif
endif
endif
set filt = null
return false
endmethod
// Retract the hook.
method retract takes nothing returns nothing
local Link linkx = 0
local unit temp = this.list.last.link
local unit prev = null
local unit dumm = null
local real casx = GetUnitX(this.cast)
local real casy = GetUnitY(this.cast)
local real temx = GetUnitX(temp)
local real temy = GetUnitY(temp)
local real newx = 0.00
local real newy = 0.00
local real ang2 = 0.00
local real dist = SquareRoot((temx - casx) * (temx - casx) + (temy - casy) * (temy - casy))
// If the distance between the caster and the last link is too much, create more links.
if dist > (INC) then
// Using a loop so the hooks work when great distances are covered in a short time.
loop
exitwhen dist <= (INC) // Create as many links as needed to fill the gap.
set ang2 = Atan2((casy - temy),(casx - temx))
set temx = temx + (INC) * Cos(ang2)
set temy = temy + (INC) * Sin(ang2)
// Create a new chain link.
set linkx = this.list.attach()
set linkx.link = CreateUnit(this.own,LINK_ID,temx,temy,(ang2 * bj_RADTODEG) + 180.00)
// Set its height and size.
call SetUnitScale(linkx.link,LINK_SCALE,LINK_SCALE,LINK_SCALE)
// Set the new last link in the chain to the last created link.
set temp = linkx.link
set temx = GetUnitX(temp)
set temy = GetUnitY(temp)
set dist = dist - INC
endloop
endif
// If the caster is no grappling, check for a target unit.
if this.targ != null then
// If there is a target unit, set it's new position.
call SetUnitX(this.targ,GetUnitX(this.head))
call SetUnitY(this.targ,GetUnitY(this.head))
static if DISCARD_TARGET then
// Check if it is bead so it can be discarded.
if not UnitAlive(this.targ) then
set this.targ = null
call SetUnitTimeScale(this.head,TIME_SCALE)
endif
endif
else
// Otherwise, find a new unit.
call GroupEnumUnitsInRange(thistype.enumGroup,GetUnitX(this.head),GetUnitY(this.head),UNIT_RADIUS,thistype.enumUnits)
endif
set linkx = this.list.last
// This is used to remove the unneeded links and to set their new position if they are needed.
loop
exitwhen linkx == 0
set temp = linkx.link
set temx = GetUnitX(temp)
set temy = GetUnitY(temp)
if linkx.prev.prev != 0 then
set dumm = linkx.prev.prev.link
if IsUnitInRange(temp,dumm,(INC)) then
call this.list.detach(linkx.prev)
call SetUnitFacing(temp,(Atan2((GetUnitY(dumm) - temy),(GetUnitX(dumm) - temx)) * bj_RADTODEG) + 180.00)
endif
endif
// Find the angle that the chain link should be facing.
if temp == this.list.last.link then
set ang2 = Atan2((casy - temy),(casx - temx))
else
set ang2 = Atan2((GetUnitY(prev) - temy),(GetUnitX(prev) - temx))
endif
if linkx == this.list.last and IsUnitInRange(temp,this.cast, INC) then
call this.list.detach(linkx)
// Detach the link if needed.
endif
// Set the chain links new position.
call SetUnitX(temp,temx + this.speed * Cos(ang2))
call SetUnitY(temp,temy + this.speed * Sin(ang2))
call SetUnitFacing(temp,(ang2 * bj_RADTODEG) + 180.00)
set prev = temp
set linkx = linkx.prev
endloop
set temp = null
set prev = null
set dumm = null
endmethod
// Extend the hook.
method extend takes nothing returns nothing
local Link linkx = 0
local unit temp = this.list.last.link
local unit next = null
local unit dumm = null
local real casx = GetUnitX(this.cast)
local real casy = GetUnitY(this.cast)
local real temx = GetUnitX(temp)
local real temy = GetUnitY(temp)
local real newx = 0.00
local real newy = 0.00
local real ang2 = 0.00
local real dist = SquareRoot((temx - casx) * (temx - casx) + (temy - casy) * (temy - casy))
// If the distance between the caster and the last link is too much, create more links.
if dist > (INC) then
// Using a loop so the hooks work when great distances are covered in a short time.
loop
exitwhen dist <= (INC) // Create as many links as needed to fill the gap.
set ang2 = Atan2((casy - temy),(casx - temx))
set temx = temx + (INC) * Cos(ang2)
set temy = temy + (INC) * Sin(ang2)
// Create a new chain link.
set linkx = this.list.attach()
set linkx.link = CreateUnit(this.own,LINK_ID,temx,temy,(ang2 * bj_RADTODEG) + 180.00)
// Set its height and size.
call SetUnitScale(linkx.link,LINK_SCALE,LINK_SCALE,LINK_SCALE)
// Set the new last link of the chain the the last created link.
set temp = linkx.link
set temx = GetUnitX(temp)
set temy = GetUnitY(temp)
set dist = dist - INC
endloop
endif
set linkx = this.list.head
// This loop moves all the current links in the chain.
loop
exitwhen linkx == 0
set temp = linkx.link
set temx = GetUnitX(temp)
set temy = GetUnitY(temp)
if linkx.next.next != 0 then
set dumm = linkx.next.next.link
if IsUnitInRange(temp,dumm,(INC)) then
call this.list.detach(linkx.next)
call SetUnitFacing(temp,(Atan2((GetUnitY(dumm) - temy),(GetUnitX(dumm) - temx)) * bj_RADTODEG) + 180.00)
endif
endif
// Set the new angle for each chain link.
if temp == this.head then
set ang2 = this.ang // If it is the head link, get the angle to the travelling angle.
else
set ang2 = Atan2((GetUnitY(next) - temy),(GetUnitX(next) - temx))
endif
set newx = temx + this.speed * Cos(ang2)
set newy = temy + this.speed * Sin(ang2)
// If the new point is outside the map, find a new point and make the hook bounce.
if temp == this.head then
if newx > thistype.worldMaxX or newx < thistype.worldMinX then
if this.ang < 0.00 then
set this.ang = -1.57079 + (-1.57079 - this.ang)
else
set this.ang = 1.57079 - (this.ang - 1.57079)
endif
set this.cos = Cos(this.ang)
set this.sin = Sin(this.ang)
elseif newy > thistype.worldMaxY or newy < thistype.worldMinY then
if this.ang < 1.57079 then
set this.ang = 0.00 - this.ang
else
set this.ang = -this.ang
endif
set this.cos = Cos(this.ang)
set this.sin = Sin(this.ang)
endif
// Search for units, buildings and destructables.
set thistype.tempData = this
call GroupEnumUnitsInRange(thistype.enumGroup,newx,newy,UNIT_RADIUS,thistype.enumUnits)
call GroupEnumUnitsInRange(thistype.enumGroup,newx,newy,BUILD_RADIUS,thistype.enumBuild)
static if DEST_BOUNCE then
call SetRect(thistype.enumRect,newx - DEST_RADIUS,newy - DEST_RADIUS,newx + DEST_RADIUS,newy + DEST_RADIUS)
call EnumDestructablesInRect(thistype.enumRect,null,thistype.enumDests)
endif
endif
// Set the new position of each hook.
call SetUnitX(temp,newx)
call SetUnitY(temp,newy)
call SetUnitFacing(temp,ang2 * bj_RADTODEG)
set next = temp
set linkx = linkx.next
endloop
// If the max distance has been reached or a unit has been hit, stop extending.
if this.dist >= this.max or this.hit then
set this.ret = true
else
set this.dist = this.dist + this.speed
endif
set temp = null
set next = null
set dumm = null
endmethod
// The handler method, makes things much easier.
static method periodic takes nothing returns nothing
local thistype this = next[0]
loop
exitwhen this == 0
if this.list.size == 0 then // If the hook is done.
call this.list.destroy() // Destroy the unit list.
call FlushChildHashtable(HASH, GetHandleId(this.targ)) // Get rid of headshot boolean stored in unit
// Clear struct members.
set this.cast = null
set this.targ = null
set this.head = null
set next[prev[this]] = next[this]
set prev[next[this]] = prev[this]
set rn[this] = rn[0]
set rn[0] = this
else
if this.ret then // If the hook is retracting.
call this.retract() // Keep retracting.
else // Otherwise.
call this.extend() // Extend it.
endif
endif
set this = next[this]
endloop
if next[0] == 0 then
call PauseTimer(TMR)
endif
endmethod
// Start of the hook, assembles struct members and stuff.
static method actions takes nothing returns nothing
local thistype this = rn[0]
local real casx = 0.00
local real casy = 0.00
if this == 0 then
set ic = ic + 1
set this = ic
else
set rn[0] = rn[this]
endif
// Sets struct members.
set this.cast = GetTriggerUnit()
set this.own = GetOwningPlayer(this.cast)
set casx = GetUnitX(this.cast)
set casy = GetUnitY(this.cast)
set this.ang = Atan2((GetSpellTargetY() - casy),(GetSpellTargetX() - casx))
set this.cos = Cos(this.ang)
set this.sin = Sin(this.ang)
set this.list = List.create()
set this.level = GetUnitAbilityLevel(this.cast,ABIL_ID)
set this.speed = SPEED(this.level) * PERIOD
set this.max = MAXDIST(this.level)
set this.dist = 0.00
set this.ret = false
set this.hit = false
// Create the head of the chain.
set this.head = CreateUnit(this.own,HEAD_ID,casx + this.speed * this.cos,casy + this.speed * this.sin,this.ang * bj_RADTODEG)
set this.list.attach().link = this.head
// Set up the head unit.
call SetUnitTimeScale(this.head,TIME_SCALE)
call SetUnitScale(this.head,HEAD_SCALE,HEAD_SCALE,HEAD_SCALE)
// Basically do what T32 does for you
set prev[this] = prev[0]
set next[this] = 0
set next[prev[0]] = this
set prev[0] = this
if prev[this] == 0 then
call TimerStart(TMR, PERIOD, true, function thistype.periodic)
endif
endmethod
static method Cond takes nothing returns boolean
local unit lvCaster = GetTriggerUnit()
local real x
local real y
if GetSpellAbilityId() == ABIL_ID then
call thistype.actions()
endif
set lvCaster = null
return false
endmethod
static method loadSound takes nothing returns nothing
local timer time = GetExpiredTimer()
local sound shot = CreateSound(HEADSHOT_SOUND,false,false,false,10,10,"")
// Play the sound, but quietly.
call SetSoundVolume(shot,0)
call StartSound(shot)
call KillSoundWhenDone(shot)
// Using the static timer for this, seeing as no one will cast hook at 0.00 seconds game time.
call PauseTimer(time)
call DestroyTimer(time)
set time = null
set shot = null
endmethod
// Initialisation method.
static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
local unit dummy = null
// Set all the static struct members.
set thistype.enumRect = Rect(0.00,0.00,1.00,1.00)
set thistype.enumGroup = CreateGroup()
set thistype.enumDests = function thistype.getDest
set thistype.enumUnits = Filter(function thistype.getUnit)
set thistype.enumBuild = Filter(function thistype.getBuild)
set thistype.worldMaxX = GetRectMaxX(bj_mapInitialPlayableArea) - 64.00
set thistype.worldMaxY = GetRectMaxY(bj_mapInitialPlayableArea) - 64.00
set thistype.worldMinX = GetRectMinX(bj_mapInitialPlayableArea) + 64.00
set thistype.worldMinY = GetRectMinY(bj_mapInitialPlayableArea) + 64.00
// Add a "starts effect" event to the spell.
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(t, Condition(function thistype.Cond))
// If preloading is allowed, then preload.
static if ALLOW_PRELOAD then
// Load the "chain" unit and add the crow form ability to load that too.
set dummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),LINK_ID,0.00,0.00,0.00)
call RemoveUnit(dummy)
// Load the "head" unit.
set dummy = CreateUnit(Player(PLAYER_NEUTRAL_PASSIVE),HEAD_ID,0.00,0.00,0.00)
call RemoveUnit(dummy)
set dummy = null
call TimerStart(CreateTimer(), .1, false, function thistype.loadSound)
endif
set t = null
endmethod
endstruct
endlibrary
JASS:
private struct Link extends array // Individual links in the linked list for units.
thistype next // Next link in the list.
thistype prev // Previous link in the list.
unit link // The actual chain link.
static integer array rn
static integer ic = 0
static method create takes nothing returns thistype
local thistype this = rn[0]
if this == 0 then
set ic = ic + 1
set this = ic
else
set rn[0] = rn[this]
endif
set .next = 0
set .prev = 0
set .link = null
return this
endmethod
method destroy takes nothing returns nothing
call RemoveUnit(this.link)
set this.link = null
set rn[this] = rn[0]
set rn[0] = this
endmethod
endstruct
//---------------------------------------------------------------------\\
private struct List extends array // Linked list to hold all the units that make the chain.
Link head // First link in the list.
Link last // Last link in the list.
integer size // Size of the list.
static integer array rn
static integer ic = 0
static method create takes nothing returns thistype
local thistype this = rn[0]
if this == 0 then
set ic = ic + 1
set this = ic
else
set rn[0] = rn[this]
endif
set .head = 0
set .last = 0
set .size = 0
return this
endmethod
// Attach a link to the list.
method attach takes nothing returns Link
local Link curr = Link.create() // Create a link.
// Restructuring the start of the list.
if this.head == 0 then
// If there is nothing in the first, set the new link to the head.
set this.head = curr
else
// Otherwise, attach the new link to the end of the list.
set curr.prev = this.last
set this.last.next = curr
endif
// Setting the rest of this link and incrementing list size.
set this.last = curr
set this.size = this.size + 1
return curr
endmethod
// Detach a link from the list.
method detach takes Link curr returns nothing
// Removing a link from the list.
if curr.next == 0 then
// If we are removing the last node, reset last.
set this.last = curr.prev
else
set curr.next.prev = curr.prev
endif
set curr.prev.next = curr.next
// Destroy the link.
call curr.destroy()
// Decrement size of list.
set this.size = this.size - 1
endmethod
// Destroy the list.
method destroy takes nothing returns nothing
// Just to make sure no links are left.
loop
exitwhen this.size == 0
call this.detach(this.last)
endloop
set rn[this] = rn[0]
set rn[0] = this
endmethod
endstruct
I'm not sure if this make sense but it's like taking something 2D and making it 3D? Wat da heck?
Like I could imagine setting a static integer array member and capping a max instance number,... but this is like having an array member in an array struct.
ㄱㄱㄱㄱㄱㄱ
Attachments
Last edited: