|
|
|
|
 |
|
The Hive Workshop Spells:
HeroImage
|
|
|
|
Images
|
|
|
| Details |
| Uploaded: | 07:23, 6th Aug 2012 |
| Last Updated: | 01:59, 20th Jan 2013 |
| Keywords: | aos, stats, hero, heroes |
| Type: | System |
| Category: | vJASS |
This is an old idea that I had a long time ago. The code itself explains what this monster do. Enjoy it :3.
Comments, suggestions, etc. are welcome.
Jass:
library HeroImage /* v1.0.0.0
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* HeroImage it's a simple library (very useful for AoS maps) who can
* be used to show the stats (life and mana) of our allies heroes.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* struct UnitIndex
*
* static method create takes unit u returns thistype
* - Creates the copy for "u"
*
* method destroy takes nothing returns nothing
* - Destroys the copy
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Thanks to
*
* - Magtheridon96 from hiveworkshop.com
* - rulerofiron99 from hiveworkshop.com
* - Jesus4Lyf from thehelper.net
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
globals
// Lower value = higher quality but more lag
private constant real TIMEOUT = 1
private constant trigger TARGET_ORDER = CreateTrigger()
private constant trigger SELECTION = CreateTrigger()
private constant trigger LEARN_SPELL = CreateTrigger()
private constant hashtable HASHTABLE = InitHashtable()
endglobals
struct HeroImage
private thistype prev
private thistype next
readonly unit original
readonly unit array copies[12]
method destroy takes nothing returns nothing
local integer n = 0
set this.original = null
loop
set n = n + 1
exitwhen this.copies[n] == null
call RemoveUnit(this.copies[n])
set this.copies[n] = null
endloop
set this.prev.next = this.next
set this.next.prev = this.prev
call this.deallocate()
endmethod
private static method getInstance takes integer id returns thistype
return LoadInteger(HASHTABLE, id, 0)
endmethod
private static method periodic takes nothing returns nothing
local thistype this = thistype(0).next
local real originalHp
local real originalMp
local integer originalXp
local integer originalSkillPoints
local integer originalLevel
local unit copy
local integer slot = 0
local integer array originalItem
local integer n = 0
loop
exitwhen this == 0
if (this.original == null) then
call this.destroy()
else
set originalHp = GetWidgetLife(this.original)
set originalMp = GetUnitState(this.original, UNIT_STATE_MANA)
set originalXp = GetHeroXP(this.original)
set originalSkillPoints = GetHeroSkillPoints(this.original)
set originalLevel = GetHeroLevel(this.original)
// Items
loop
exitwhen (slot > 6)
set originalItem[slot] = GetItemTypeId(UnitItemInSlot(this.original, slot))
set slot = slot + 1
endloop
loop
set n = n + 1
exitwhen this.copies[n] == null
set copy = this.copies[n]
// Cheking if the copy isn't dead
if (GetWidgetLife(copy) <= 0.405) then
call ReviveHero(copy, GetRectMaxX(GetWorldBounds()), GetRectMaxY(GetWorldBounds()), false)
endif
// HP
if (originalHp <= 0.405) then
call SetWidgetLife(copy, 1)
else
call SetWidgetLife(copy, originalHp)
endif
// MP
call SetUnitState(copy, UNIT_STATE_MANA, originalMp)
// Level
call SetHeroXP(copy, originalXp, false)
// Items
set slot = 0
loop
exitwhen (slot > 6)
if (originalItem[slot] != GetItemTypeId(UnitItemInSlot(copy, slot))) then
call UnitRemoveItemFromSlot(copy, slot)
call UnitAddItemToSlotById(copy, originalItem[slot], slot)
call SetItemCharges(UnitItemInSlot(copy, slot), GetItemCharges(UnitItemInSlot(this.original, slot)))
endif
set slot = slot + 1
endloop
endloop
endif
set this = this.next
endloop
set copy = null
endmethod
private static method order takes nothing returns boolean
local unit target = GetOrderTargetUnit()
local thistype this = thistype.getInstance(GetHandleId(target))
local boolean redirect = false
local integer n = 0
loop
set n = n + 1
exitwhen this.copies[n] == null
if (target == this.copies[n]) then
set redirect = true
exitwhen true
endif
endloop
if (redirect) then
call IssueTargetOrder(GetTriggerUnit(), OrderId2String(GetIssuedOrderId()), this.original)
endif
set target = null
return false
endmethod
private static method selection takes nothing returns boolean
local unit original
local unit copy
if (GetLocalPlayer() == GetTriggerPlayer()) then
set copy = GetTriggerUnit()
set original = thistype.getInstance(GetHandleId(copy)).original
call ClearSelection()
call SelectUnit(copy, false)
call SelectUnit(original, true)
call SetCameraPosition(GetUnitX(original), GetUnitY(original))
set copy = null
set original = null
endif
return false
endmethod
private static method learnSpell takes nothing returns boolean
local unit originalUnit = GetLearningUnit()
local thistype this = thistype.getInstance(GetHandleId(originalUnit))
local integer spellId = GetLearnedSkill()
local integer spellLevel = GetLearnedSkillLevel()
local unit copy
local integer n = 0
loop
set n = n + 1
exitwhen this.copies[n] == null
set copy = this.copies[n]
if (GetUnitAbilityLevel(copy, spellId) != 0) then
call SetUnitAbilityLevel(copy, spellId, spellLevel)
else
call UnitAddAbility(copy, spellId)
endif
call UnitModifySkillPoints(copy, -1)
endloop
set originalUnit = null
set copy = null
return false
endmethod
static method create takes unit u returns thistype
local thistype this
local integer id
local player playerOwner
local player p
local unit copy
local integer unitTypeId
local real x
local real y
local rect worldBounds
local integer i = 0
local integer n = 0
if (IsUnitType(u, UNIT_TYPE_HERO)) then
set id = GetHandleId(u)
if (HaveSavedInteger(HASHTABLE, id, 0)) then
debug call BJDebugMsg("HeroImage ERROR: That unit has already a copy or it is one")
else
set this = thistype.allocate()
// thanks Jesus4Lyf =3
set thistype(0).next.prev = this
set this.next = thistype(0).next
set thistype(0).next = this
set this.prev = thistype(0)
set playerOwner = GetOwningPlayer(u)
set unitTypeId = GetUnitTypeId(u)
set worldBounds = GetWorldBounds()
set x = GetRectMaxX(worldBounds)
set y = GetRectMaxY(worldBounds)
set this.original = u
call TriggerRegisterUnitEvent(LEARN_SPELL, u, EVENT_UNIT_HERO_SKILL)
call SaveInteger(HASHTABLE, id, 0, this)
loop
exitwhen i == bj_MAX_PLAYERS
set p = Player(i)
if (IsPlayerAlly(p, playerOwner) and p != playerOwner) then
set copy = CreateUnit(p, unitTypeId, x, y, 0)
call SaveInteger(HASHTABLE, GetHandleId(copy), 0, this)
set n = n + 1
set this.copies[n] = copy
call TriggerRegisterUnitEvent(SELECTION, copy, EVENT_UNIT_SELECTED)
endif
set i = i + 1
endloop
set playerOwner = null
set copy = null
set worldBounds = null
endif
else
debug call BJDebugMsg("HeroImage ERROR: You can not create a copy of a non-hero unit")
endif
return this
endmethod
private static method onInit takes nothing returns nothing
call TimerStart(CreateTimer(), TIMEOUT, true, function thistype.periodic)
call TriggerRegisterAnyUnitEventBJ(TARGET_ORDER, EVENT_PLAYER_UNIT_ISSUED_TARGET_ORDER)
call TriggerAddCondition(TARGET_ORDER, Condition(function thistype.order))
call TriggerAddCondition(SELECTION, Condition(function thistype.selection))
call TriggerAddCondition(LEARN_SPELL, Condition(function thistype.learnSpell))
endmethod
endstruct
endlibrary
Changelog
v1.0.0- Now does not desync
- Re-writed
|
| Rating - 0.00 (0 votes) |
|
|
| Moderator Comments |
|
Not Rated
04:29, 8th Aug 2012
Magtheridon96: GetWorldBounds() leaks.
You should store it into a rect variable and use RemoveRect to delete it.
Other than that, wonderful spell! ^_^
edit
Just realized that this also leaks events.
It would be better to have the events registered for all units instead of specific ones, and you would figure out when to run your spell's code based on the triggering unit. (You have a hashtable in there, so you are capable of attaching data to units. Store a boolean into the hashtable using the handle id and any key so that you keep track of units that should have code run for them upon the firing of the event.)
|
|
This spell is awaiting update.
 (18.42 KB, 208 Downloads)
|
08-06-2012, 07:55 AM
|
#2 (permalink)
|
|
The real me RnR forever
Join Date: Aug 2010
Posts: 236
|
It looks interesting.
__________________
|
|
|
08-06-2012, 09:05 AM
|
#3 (permalink)
|
|
JESUS MAN
Resource Moderator
Join Date: Dec 2008
Posts: 5,699
|
Use a doubly linked list.
Your current list-remove method is not totally functional since you're using dynamic indexing like that.
Jass:
// insert to list:
set next[this] = 0
set prev[this] = prev[0]
set next[prev[0]] = this
set prev[0] = this
// remove from list:
set next[prev[this]] = next[this]
set prev[next[this]] = prev[this]
// iterate over list, pretty much the same thing you're doing here
local thistype this = next[0]
loop
exitwhen this == 0
set this = next[this]
endloop
My method is using arrays now, but it can be easily changed to use the '.' operator, and it would still be the same thing.
edit
By the way, you can use 0.03125 without the trailing 0's. I debunked that myth about inaccuracy a very long time ago.
You need to run the map for a year to be a few seconds off. <.<
|
|
|
08-06-2012, 12:23 PM
|
#4 (permalink)
|
|
aka. GHH
Join Date: Feb 2009
Posts: 2,865
|
Is it just me or it doesn't work at all?
The bellow trigger, it created a paladin but no clone.
 GUI
__________________
GHH aka. Rikudou Sennin

|
|
|
08-06-2012, 03:29 PM
|
#5 (permalink)
|
|
( > *_*)>
Join Date: Sep 2011
Posts: 136
|
Quote:
My method is using arrays now, but it can be easily changed to use the '.' operator, and it would still be the same thing.
edit
By the way, you can use 0.03125 without the trailing 0's. I debunked that myth about inaccuracy a very long time ago.
You need to run the map for a year to be a few seconds off. <.<
|
Ok, I will use the '.' method to make it more readable.
Quote:
Originally Posted by Ironside
Is it just me or it doesn't work at all?
The bellow trigger, it created a paladin but no clone.
 GUI
|
It doesn't create another copy of your hero (why you want two icons on the top?).
__________________
PHP, Javascript & CSS programmer.
|
|
|
08-06-2012, 04:29 PM
|
#6 (permalink)
|
|
( > *_*)>
Join Date: Sep 2011
Posts: 136
|
Updated, thanks Magtheridon96.
I was thinking on add an alert when our allies heroes are being attacked.
But if I try with
call UnitDamageTarget(this.copyUnit, this.copyUnit, 1, true, true, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, null)
It doesn't alert you (red icon)... any ideas?.
Greetings
__________________
PHP, Javascript & CSS programmer.
|
|
|
08-06-2012, 04:32 PM
|
#7 (permalink)
|
|
JESUS MAN
Resource Moderator
Join Date: Dec 2008
Posts: 5,699
|
It usually doesn't alert you.
Sometimes it does, sometimes it doesn't.
It depends on a lot of factors including the last time it alerted you, how often you're taking damage, can you see the unit taking damage, etc...
|
|
|
08-06-2012, 04:41 PM
|
#8 (permalink)
|
|
moo moo
Join Date: Jan 2011
Posts: 1,047
|
Quite a nice system. I believe this was done in tKoK, and it is a fantastic idea.
Only problem is, what if they target the ally with some healing spell and it does either of two things.
Error: Out of Range
Or
It heals the image and not the real unit
I'm wondering if you covered this or not, but if you didn't keep it in mind :p
__________________
|
|
|
08-06-2012, 04:54 PM
|
#9 (permalink)
|
|
( > *_*)>
Join Date: Sep 2011
Posts: 136
|
Quote:
Originally Posted by maddeem
Quite a nice system. I believe this was done in tKoK, and it is a fantastic idea.
Only problem is, what if they target the ally with some healing spell and it does either of two things.
Error: Out of Range
Or
It heals the image and not the real unit
I'm wondering if you covered this or not, but if you didn't keep it in mind :p
|
Orders are redirected to its original.
Check 'order' method
__________________
PHP, Javascript & CSS programmer.
|
|
|
08-08-2012, 01:58 AM
|
#10 (permalink)
|
|
( > *_*)>
Join Date: Sep 2011
Posts: 136
|
@Mag: The problem with removing the local player' block, is that the local player will have two icons on the top (one real, and one copy).
Mmm, maybe with a dummy unit...
I will check it out, thanks.
__________________
PHP, Javascript & CSS programmer.
|
|
|
01-20-2013, 09:27 AM
|
#11 (permalink)
|
|
The Hive's Breakdancer
Join Date: Aug 2010
Posts: 963
|
This is a cool thing. But is there a way you can make it show the stats (above the unit's model) without having the user hold the "Alt" key?
I am not saying to put this in the system. I ask this "off-topically".
|
|
|
01-21-2013, 06:48 PM
|
#12 (permalink)
|
|
★ SotP Project Leader ★
Join Date: Jan 2010
Posts: 5,869
|
Not big deal, more like a hint. When you use debug messages it's always better to state name of functions.
In your example
Jass:
call BJDebugMsg("HeroImage ERROR: That unit has already a copy or it is one")
//Can be
call BJDebugMsg("HeroImage_HeroImage.create() -> That unit has already a copy or it is one")
Someday you will code 500-600 even 1000 lines of code long script, and you will get lost without good "documentation".
|
|
|
02-27-2013, 07:01 AM
|
#13 (permalink)
|
|
User
Join Date: Nov 2012
Posts: 21
|
call IssueTargetOrder(GetTriggerUnit(), OrderId2String(GetIssuedOrderId()), this.original)
-->
call IssueTargetOrderById(GetTriggerUnit(), GetIssuedOrderId(), this.original)
|
|
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
|
|
|
|
|
|
|
|
|
All times are GMT. The time now is 11:48 PM.
|