|
|
#1 |
|
master of fugue
Join Date: Jun 2007
Posts: 2,558
![]() ![]() ![]() ![]()
|
Undead Hero Siege needs items that will benefit teamplay.
__________________We need an item with a complicated ability. You can choose the name and the icon for the item. Item ability must be MPI (multi player instanceable) Effect: When item is equipped on a hero it will automatically cast Spirit Touch (mass mana regen) every X seconds. X has a random shift of 1-3 seconds to avoid all heroes always casting the spell at the same time. The overhead spell effect on hero must be properly displayed on every cast. Item autocast needs Y mana and will not work if hero does not have mana. Hero can turn on/off item autocasting by clicking on the item, this should change the item icon. Turning on/off costs Y mana. Last edited by cohadar : 03-05-2013 at 03:27 PM. |
|
|
|
| Sponsored Links - Login to hide this ad! |
|
|
|
|
#2 |
|
User
Join Date: Mar 2013
Posts: 49
|
Not sure if I understood the request correctly but I gave it a try.
I think it would look great with the icons for Mana Flare on and off (active & inactive version). I can't think of an appropriate name and description, that's up to someone more creative. Also, in order for this to work the Inactive version must be undroppable! Actually, players must not be allowed to manually pick an Inactive version (like from the ground or from a shop). Otherwise this bugs. Wasn't sure if Spirit Touch should restore mana to the owner so I left it as such. Zinc://! zinc // Should exclude caster on Spirit Touch restoration? // NOTE: Inactive version must be undroppable item! library ItemRequest01 requires TimedLoop { // Raw code of the ability supplied in items. // Both active & inactive version will share it. constant integer AID_ITEM_SWITCH = 'A000'; // Self-descriptive (active & inactive versions): constant integer IID_ACTIVE_ITEM = 'I000'; constant integer IID_INACTIVE_ITEM = 'I001'; // When passive Spirit Touch procs, this effect is applied on the caster: constant string SFX_ON_CASTER = "Abilities\\Spells\\Undead\\ReplenishMana\\ReplenishManaCasterOverhead.mdl"; constant string AP_ON_CASTER = "overhead"; // Units that get mana restored get this effect as well: constant string SFX_ON_TARGET = "Abilities\\Spells\\Undead\\ReplenishMana\\SpiritTouchTarget.mdl"; constant string AP_ON_TARGET = "chest"; // Self-descriptive functions: function GetAoE(unit whichUnit) -> real { return 475.; } // NOTE: Mana is taken when the passive spirit touch procs. function GetManaCost(unit whichUnit) -> real { return 25.; } function GetManaRestored(unit whichUnit) -> real { return 50.; } // Hopefully this inlines (if I understand inline rules correctly). // These are used to determine interval between mana restoration. // Used as in GetRandomReal(min_bound, max_bound). function GetMinRandBound(unit whichUnit) -> real { return 1.; } function GetMaxRandBound(unit whichUnit) -> real { return 3.; } //=========================================================================== // END OF CONFIGURATION //=========================================================================== trigger TRIGGER_ON_PICK = CreateTrigger(); group GROUP = CreateGroup(); unit UNIT = null; struct Data { unit cast; timer tim; integer ticks; static method SetAlliesMana() // need better name { unit enum = GetEnumUnit(); SetUnitState(enum, UNIT_STATE_MANA, /* */ GetUnitState(enum, UNIT_STATE_MANA) + GetManaRestored(UNIT)); DestroyEffect(AddSpecialEffectTarget(SFX_ON_TARGET, enum, AP_ON_TARGET)); enum = null; } static method GetAllies() -> boolean { return ( IsUnitAlly(GetFilterUnit(), GetOwningPlayer(UNIT)) && /* */ GetUnitState(GetFilterUnit(), UNIT_STATE_MANA) > 0. ); } method applyRestoration() { real mana = GetUnitState(this.cast, UNIT_STATE_MANA); real mana_req = GetManaCost(this.cast); if ( mana >= mana_req ) { UNIT = this.cast; SetUnitState(UNIT, UNIT_STATE_MANA, mana - mana_req); DestroyEffect(AddSpecialEffectTarget(SFX_ON_CASTER, UNIT, AP_ON_CASTER)); GroupEnumUnitsInRange(GROUP, GetUnitX(UNIT), GetUnitY(UNIT), /* */ GetAoE(UNIT), Condition(function thistype.GetAllies)); ForGroup(GROUP, function thistype.SetAlliesMana); // need better name } } method onTimedLoop() -> boolean { boolean hasActive = UnitHasItemOfTypeBJ(this.cast, IID_ACTIVE_ITEM); if ( UnitHasItemOfTypeBJ(this.cast, IID_ACTIVE_ITEM) ) { this.ticks -= 1; if ( this.ticks <= 0 ) { this.applyRestoration(); this.ticks = R2I(GetRandomReal(GetMinRandBound(this.cast), GetMaxRandBound(this.cast))); this.ticks *= R2I(1. / TimedLoop_PERIOD); } } else if ( UnitHasItemOfTypeBJ(this.cast, IID_INACTIVE_ITEM) ) { this.ticks -= 1; // Ticks should get reduced even when inactive version is on the unit. // This way when somebody switches to active, the restoration will be ready. } else return TimedLoop_STOP; return TimedLoop_CONTINUE; } module TimedLoop; static method create(unit whichUnit) -> thistype { thistype this = thistype.allocate(); this.cast = whichUnit; this.ticks = R2I(GetRandomReal(GetMinRandBound(this.cast), GetMaxRandBound(this.cast))); this.ticks *= R2I(1. / TimedLoop_PERIOD); this.applyRestoration(); this.startTimedLoop(); return this; } } function OnItemPickup() -> boolean { unit cast = GetTriggerUnit(); item it = GetManipulatedItem(); integer itemId = GetItemTypeId(it); if ( itemId == IID_ACTIVE_ITEM || itemId == IID_INACTIVE_ITEM ) { UnitRemoveItem(cast, it); DisableTrigger(TRIGGER_ON_PICK); if ( UnitHasItemOfTypeBJ(cast, IID_ACTIVE_ITEM) || /* */ UnitHasItemOfTypeBJ(cast, IID_INACTIVE_ITEM) ) { } else { UnitAddItem(cast, it); if ( itemId == IID_ACTIVE_ITEM ) Data.create(cast); } EnableTrigger(TRIGGER_ON_PICK); } cast = null; it = null; return false; } function Actions() { unit cast = GetTriggerUnit(); if ( UnitHasItemOfTypeBJ(cast, IID_ACTIVE_ITEM) ) { RemoveItem(GetItemOfTypeFromUnitBJ(cast, IID_ACTIVE_ITEM)); bj_lastCreatedItem = CreateItem(IID_INACTIVE_ITEM, GetUnitX(cast), GetUnitY(cast)); } else { RemoveItem(GetItemOfTypeFromUnitBJ(cast, IID_INACTIVE_ITEM)); bj_lastCreatedItem = CreateItem(IID_ACTIVE_ITEM, GetUnitX(cast), GetUnitY(cast)); } DisableTrigger(TRIGGER_ON_PICK); UnitAddItem(cast, bj_lastCreatedItem); EnableTrigger(TRIGGER_ON_PICK); cast = null; } function Conditions() -> boolean { return ( GetSpellAbilityId() == AID_ITEM_SWITCH ); } function onInit() { trigger trig = CreateTrigger(); TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_SPELL_ENDCAST); TriggerAddCondition(trig, Condition(function Conditions)); TriggerAddAction(trig, function Actions); TriggerRegisterAnyUnitEventBJ(TRIGGER_ON_PICK, EVENT_PLAYER_UNIT_PICKUP_ITEM); TriggerAddCondition(TRIGGER_ON_PICK, Condition(function OnItemPickup)); } } //! endzinc Last edited by HerrStanev : 03-10-2013 at 10:51 PM. |
|
|
|
|
|
#3 | |
|
master of fugue
Join Date: Jun 2007
Posts: 2,558
![]() ![]() ![]() ![]()
|
The period is X + (1 to 3) seconds, not (1 to 3)
__________________So if X is 10, the item will regen mana at: 10+1, 20-2, 30+3, 40-1, 50+2,... Quote:
Also there is no reason why players should not be able to pick more than one of this items at the same time, and even have both active and inactive versions in inventory at the same time. Would you like me to describe the algorithm to you or you prefer to take the challenge? TIP: note that I was talking about players picking items, not heroes. Last edited by cohadar : 03-06-2013 at 06:27 AM. |
|
|
|
|
|
|
#4 |
|
User
Join Date: Mar 2013
Posts: 49
|
I knew I've misunderstood what you wanted, especially the period.
I assumed only 1 item was allowed per unit. Reworked this but I'm really not sure what the mechanics should be. What I've accomplished is this: - unit picks up active version - Spirit Touch struct activates - after <insert formula w/ random period> time, Spirit Touch procs - picked active item gets checked periodically if it's still on unit - if not on unit, abort timed Spirit Touch (possibly the item is dropped or the inactive version is obtained) Btw, to prevent abuses with actively picking and dropping the active item, on first picking of the item the first Spirit Touch will proc after X +- 1-3 seconds, not on struct creation. This impacts shifting from Inactive to Active because this way you have to wait X +- 1-3 secs before Spirit Touch procs. Workaround might be to apply restoration whenever shift from Inactive to Active is detected? Zinc://! zinc library IReq01 requires TimedLoop { constant integer IID_ACTIVE_ITEM = 'I000'; constant integer IID_INACTIVE_ITEM = 'I001'; // When passive Spirit Touch procs, this effect is applied on the caster: constant string SFX_ON_CASTER = "Abilities\\Spells\\Undead\\ReplenishMana\\ReplenishManaCasterOverhead.mdl"; constant string AP_ON_CASTER = "overhead"; // Units that get mana restored get this effect as well: constant string SFX_ON_TARGET = "Abilities\\Spells\\Undead\\ReplenishMana\\SpiritTouchTarget.mdl"; constant string AP_ON_TARGET = "chest"; // Self-descriptive functions: function GetAoE(unit whichUnit) -> real { return 475.; } // NOTE: Mana is taken when the passive spirit touch procs. function GetManaCost(unit whichUnit) -> real { return 25.; } function GetManaRestored(unit whichUnit) -> real { return 50.; } function GetInterval(unit whichUnit) -> real { return 10.; } function GetMinShiftBound(unit whichUnit) -> real { return -3.; } function GetMaxShiftBound(unit whichUnit) -> real { return 3.; } //=========================================================================== // END OF CONFIGURATION //=========================================================================== group GROUP = CreateGroup(); unit UNIT = null; constant integer TICKS_PER_SECOND = R2I(1. / TimedLoop_PERIOD); struct Data { unit u; item it; integer ticks; static method SetAlliesMana() // need better name { unit enum = GetEnumUnit(); SetUnitState(enum, UNIT_STATE_MANA, /* */ GetUnitState(enum, UNIT_STATE_MANA) + GetManaRestored(UNIT)); DestroyEffect(AddSpecialEffectTarget(SFX_ON_TARGET, enum, AP_ON_TARGET)); enum = null; } static method GetAllies() -> boolean { return ( IsUnitAlly(GetFilterUnit(), GetOwningPlayer(UNIT)) && /* */ GetUnitState(GetFilterUnit(), UNIT_STATE_MANA) > 0. ); } method applyRestoration() { real mana = GetUnitState(this.u, UNIT_STATE_MANA); real mana_req = GetManaCost(this.u); if ( mana >= mana_req ) { UNIT = this.u; SetUnitState(UNIT, UNIT_STATE_MANA, mana - mana_req); DestroyEffect(AddSpecialEffectTarget(SFX_ON_CASTER, UNIT, AP_ON_CASTER)); GroupEnumUnitsInRange(GROUP, GetUnitX(UNIT), GetUnitY(UNIT), /* */ GetAoE(UNIT), Condition(function thistype.GetAllies)); ForGroup(GROUP, function thistype.SetAlliesMana); // need better name } } method onTimedLoop() -> boolean { if ( !UnitHasItem(this.u, this.it) ) return TimedLoop_STOP; else { this.ticks -= 1; if ( this.ticks <= 0 ) { this.applyRestoration(); this.ticks = R2I(GetInterval(this.u) + /* */ GetRandomReal(GetMinShiftBound(this.u), GetMaxShiftBound(this.u))); this.ticks *= TICKS_PER_SECOND; } } return TimedLoop_CONTINUE; } module TimedLoop; static method create(unit whichUnit, item whichItem) -> thistype { thistype this = thistype.allocate(); this.u = whichUnit; this.it = whichItem; this.ticks = R2I(GetInterval(this.u) + /* */ GetRandomReal(GetMinShiftBound(this.u), GetMaxShiftBound(this.u))); this.ticks *= TICKS_PER_SECOND; this.startTimedLoop(); return this; } } function OnItemPickup() -> boolean { unit picker = GetTriggerUnit(); item it = GetManipulatedItem(); if ( GetItemTypeId(it) == IID_ACTIVE_ITEM ) Data.create(picker, it); it = null; picker = null; return false; } function OnItemUse() -> boolean { item it = GetManipulatedItem(); integer itemId = GetItemTypeId(it); unit user = GetTriggerUnit(); if ( itemId == IID_ACTIVE_ITEM ) { RemoveItem(it); it = CreateItem(IID_INACTIVE_ITEM, GetUnitX(user), GetUnitY(user)); UnitAddItem(user, it); } else if ( itemId == IID_INACTIVE_ITEM ) { RemoveItem(it); it = CreateItem(IID_ACTIVE_ITEM, GetUnitX(user), GetUnitY(user)); UnitAddItem(user, it); } it = null; user = null; return false; } function onInit() { trigger trig = CreateTrigger(); TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_USE_ITEM); TriggerAddCondition(trig, Condition(function OnItemUse)); trig = CreateTrigger(); TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_PICKUP_ITEM); TriggerAddCondition(trig, Condition(function OnItemPickup)); } } //! endzinc Last edited by HerrStanev : 03-10-2013 at 10:51 PM. |
|
|
|
|
|
#5 |
|
master of fugue
Join Date: Jun 2007
Posts: 2,558
![]() ![]() ![]() ![]()
|
Why are you using multiple timers when one timer can do it all?
__________________Multiple timers for item ability are just begging for some abuse to create errors. Use ticks on one timer to handle stuff. Attach data to heroes, not timers. Put heroes who have active item in a group. On every timer tick check everybody in group, increase counters and if reached period do the spell. Never remove this structs from heroes. This way picking and dropping abuse will not have any effects because timer will just continue counting where it stopped for that hero the last time. |
|
|
|
|
|
#6 |
|
User
Join Date: Mar 2013
Posts: 49
|
I feel like I've coded this really ugly.
Tell me if it needs changing. Possibly should use an indexing system (PUI/AutoIndex)? Zinc://! zinc library ItemRequest01 { constant integer IID_ACTIVE_ITEM = 'I000'; constant integer IID_INACTIVE_ITEM = 'I001'; // When passive Spirit Touch procs, this effect is applied on the caster: constant string SFX_ON_CASTER = "Abilities\\Spells\\Undead\\ReplenishMana\\ReplenishManaCasterOverhead.mdl"; constant string AP_ON_CASTER = "overhead"; // Units that get mana restored get this effect as well: constant string SFX_ON_TARGET = "Abilities\\Spells\\Undead\\ReplenishMana\\SpiritTouchTarget.mdl"; constant string AP_ON_TARGET = "chest"; // Self-descriptive functions: function GetAoE(unit whichUnit) -> real { return 475.; } // NOTE: Mana is taken when the passive spirit touch procs. function GetManaCost(unit whichUnit) -> real { return 25.; } function GetManaRestored(unit whichUnit) -> real { return 50.; } function GetInterval(unit whichUnit) -> real { return 10.; } function GetMinShiftBound(unit whichUnit) -> real { return -3.; } function GetMaxShiftBound(unit whichUnit) -> real { return 3.; } //=========================================================================== // END OF CONFIGURATION //=========================================================================== keyword Data; Data STRUCT_DATA[]; timer TIMER = CreateTimer(); group GROUP = CreateGroup(); unit UNIT = null; constant real TIMER_PERIOD = 0.025; constant integer TICKS_PER_SECOND = R2I(1. / TIMER_PERIOD); struct Data { unit u; integer ticks; static method SetAlliesMana() // need better name { unit enum = GetEnumUnit(); SetUnitState(enum, UNIT_STATE_MANA, /* */ GetUnitState(enum, UNIT_STATE_MANA) + GetManaRestored(UNIT)); DestroyEffect(AddSpecialEffectTarget(SFX_ON_TARGET, enum, AP_ON_TARGET)); enum = null; } static method GetAllies() -> boolean { return ( IsUnitAlly(GetFilterUnit(), GetOwningPlayer(UNIT)) && /* */ GetUnitState(GetFilterUnit(), UNIT_STATE_MANA) > 0. ); } method applyRestoration() { real mana = GetUnitState(this.u, UNIT_STATE_MANA); real mana_req = GetManaCost(this.u); if ( mana >= mana_req ) { UNIT = this.u; SetUnitState(UNIT, UNIT_STATE_MANA, mana - mana_req); DestroyEffect(AddSpecialEffectTarget(SFX_ON_CASTER, UNIT, AP_ON_CASTER)); GroupEnumUnitsInRange(GROUP, GetUnitX(UNIT), GetUnitY(UNIT), /* */ GetAoE(UNIT), Condition(function thistype.GetAllies)); ForGroup(GROUP, function thistype.SetAlliesMana); // need better name } } method Callback() { this.ticks -= 1; if ( this.ticks <= 0 ) { this.applyRestoration(); this.ticks = R2I(GetInterval(this.u) + /* */ GetRandomReal(GetMinShiftBound(this.u), GetMaxShiftBound(this.u))); this.ticks *= TICKS_PER_SECOND; } } static method create(unit whichUnit) -> thistype { thistype this = thistype.allocate(); this.u = whichUnit; this.ticks = R2I(GetInterval(this.u) + /* */ GetRandomReal(GetMinShiftBound(this.u), GetMaxShiftBound(this.u))); this.ticks *= TICKS_PER_SECOND; this.applyRestoration(); return this; } } function TimerCallback() { ForGroup(GROUP, function() { unit enum = GetEnumUnit(); if ( UnitHasItemOfTypeBJ(enum, IID_ACTIVE_ITEM) ) STRUCT_DATA[GetHandleId(enum) - 0x100000].Callback(); enum = null; }); } function OnItemPickup() -> boolean { unit picker = GetTriggerUnit(); item it = GetManipulatedItem(); integer h2i = GetHandleId(picker) - 0x100000; if ( GetItemTypeId(it) == IID_ACTIVE_ITEM && STRUCT_DATA[h2i] == 0 ) { STRUCT_DATA[h2i] = Data.create(picker); GroupAddUnit(GROUP, picker); } it = null; picker = null; return false; } function OnItemUse() -> boolean { item it = GetManipulatedItem(); integer itemId = GetItemTypeId(it); unit user = GetTriggerUnit(); if ( itemId == IID_ACTIVE_ITEM ) { RemoveItem(it); it = CreateItem(IID_INACTIVE_ITEM, GetUnitX(user), GetUnitY(user)); UnitAddItem(user, it); } else if ( itemId == IID_INACTIVE_ITEM ) { RemoveItem(it); it = CreateItem(IID_ACTIVE_ITEM, GetUnitX(user), GetUnitY(user)); UnitAddItem(user, it); } it = null; user = null; return false; } function onInit() { trigger trig = CreateTrigger(); TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_USE_ITEM); TriggerAddCondition(trig, Condition(function OnItemUse)); trig = CreateTrigger(); TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_PICKUP_ITEM); TriggerAddCondition(trig, Condition(function OnItemPickup)); TimerStart(TIMER, TIMER_PERIOD, true, function TimerCallback); } } //! endzinc Last edited by HerrStanev : 03-10-2013 at 10:51 PM. |
|
|
|
|
|
#7 |
|
master of fugue
Join Date: Jun 2007
Posts: 2,558
![]() ![]() ![]() ![]()
|
integer h2i = GetHandleId(picker) - 0x100000;
__________________Oh come on it is 2013 not 2003. Use Autoindex, it is approved, PUI is not. And I think more people will prefer it. I also want you to break down that spell into 3 triggers. One main with timer and 2 helper triggers with Pickup and Use events. And moar comments ffs. Last edited by cohadar : 03-07-2013 at 07:56 PM. |
|
|
|
|
|
#8 |
|
User
Join Date: Mar 2013
Posts: 49
|
Don't know why you want it in 3 separate triggers.
But revisiting the code helped me spot a bug. Also, I found no need for structs, just an integer array counter works fine. What I find irritating is that you'd have to edit raw codes at 3 different places. Should I make them global in the main trigger so that the other two can use them? I added a name to the item... How do I put spoiler tags? Zinc://! zinc // Handles timer ticks and proper mana restoration. library ReplenishmentSphere requires AutoIndex { // Raw code of the active version of the item: public constant integer IID_REP_SPHERE_ACTIVE_ITEM = 'I000'; public constant integer IID_REP_SPHERE_INACTIVE_ITEM = 'I001'; // When passive Spirit Touch procs, this effect is applied on the caster: constant string SFX_ON_CASTER = "Abilities\\Spells\\Undead\\ReplenishMana\\ReplenishManaCasterOverhead.mdl"; constant string AP_ON_CASTER = "overhead"; // Units that get mana restored get this effect as well: constant string SFX_ON_TARGET = "Abilities\\Spells\\Undead\\ReplenishMana\\SpiritTouchTarget.mdl"; constant string AP_ON_TARGET = "chest"; // AoE of mana restoration when Spirit Touch procs: function GetAoE(unit whichUnit) -> real { return 475.; } // NOTE: Mana is taken from the owner of the item // when the passive spirit touch procs. function GetManaCost(unit whichUnit) -> real { return 25.; } // Mana restored when Spirit Touch procs: function GetManaRestored(unit whichUnit) -> real { return 50.; } // The following functions are used to calculate proc interval. // Formula is: Interval + Random( min_bound, max_bound ). // With current settings it can vary from 7 to 13 seconds. function GetInterval(unit whichUnit) -> real { return 10.; } function GetMinShiftBound(unit whichUnit) -> real { return -3.; } function GetMaxShiftBound(unit whichUnit) -> real { return 3.; } //=========================================================================== // END OF CONFIGURATION //=========================================================================== // ReplenishmentSphere_GROUP contains all units that have obtained the // active version of the item. Units in this group get checked periodically // if they have the item, and if they do their timer runs until it hits 0. // On 0 timer ticks the passive Spirit Touch procs. public group ReplenishmentSphere_GROUP = CreateGroup(); // UNIT is an argument for global passing to Condition() filter. // GROUP is a group used in ForGroup() calls. group GROUP = CreateGroup(); unit UNIT = null; // TIMER runs every TIMER_PERIOD. Used to subtract ticks from units. timer TIMER = CreateTimer(); // Every unit with the Replenishment Sphere item contains this property: integer UNIT_TICKS[]; constant real TIMER_PERIOD = 0.025; constant integer TICKS_PER_SECOND = R2I(1. / TIMER_PERIOD); // Main restoration function on Spirit Touch procs: function SetAlliesMana() { unit enum = GetEnumUnit(); SetUnitState(enum, UNIT_STATE_MANA, /* */ GetUnitState(enum, UNIT_STATE_MANA) + GetManaRestored(UNIT)); DestroyEffect(AddSpecialEffectTarget(SFX_ON_TARGET, enum, AP_ON_TARGET)); enum = null; } // Gets valid units to restore their mana on Spirit Touch proc: function GetAllies() -> boolean { return ( IsUnitAlly(GetFilterUnit(), GetOwningPlayer(UNIT)) && /* */ GetUnitState(GetFilterUnit(), UNIT_STATE_MANA) > 0. ); } // Handles ticks subtraction and restoration when ticks for // certain units are less than 0 (time to restore mana). Also // checks if units with 0 ticks have enough mana to proc Spirit Touch. function TimerCallback() { ForGroup(ReplenishmentSphere_GROUP, function() { unit enum = GetEnumUnit(); // Have some sort of active version? if ( UnitHasItemOfTypeBJ(enum, IID_REP_SPHERE_ACTIVE_ITEM) ) { UNIT_TICKS[GetUnitId(enum)] -= 1; // Is it time to proc Spirit Touch? Is there enough mana to proc? if ( UNIT_TICKS[GetUnitId(enum)] <= 0 && /* */ GetUnitState(enum, UNIT_STATE_MANA) >= GetManaCost(enum) ) { UNIT = enum; // UNIT is for passing in Enum filter. SetUnitState(UNIT, UNIT_STATE_MANA, GetUnitState(UNIT, UNIT_STATE_MANA) - GetManaCost(UNIT)); DestroyEffect(AddSpecialEffectTarget(SFX_ON_CASTER, UNIT, AP_ON_CASTER)); GroupEnumUnitsInRange(GROUP, GetUnitX(UNIT), GetUnitY(UNIT), /* */ GetAoE(UNIT), Condition(function GetAllies)); ForGroup(GROUP, function SetAlliesMana); // Reset ticks to random period. UNIT_TICKS[GetUnitId(enum)] = R2I(GetInterval(enum) + /* */ GetRandomReal(GetMinShiftBound(enum), GetMaxShiftBound(enum))) * TICKS_PER_SECOND; } } enum = null; }); } function onInit() { TimerStart(TIMER, TIMER_PERIOD, true, function TimerCallback); } } //! endzinc Zinc://! zinc // Adds units that have picked the active version of the item in a group. library ReplenishmentSpherePick requires ReplenishmentSphere { // Raw code of the active version of the item: constant integer IID_ACTIVE_ITEM = IID_REP_SPHERE_ACTIVE_ITEM; function Conditions() -> boolean { return ( GetItemTypeId(GetManipulatedItem()) == IID_ACTIVE_ITEM ); } function Actions() { unit picker = GetTriggerUnit(); // First time acquiring the Replenishment Sphere item? if ( !IsUnitInGroup(picker, ReplenishmentSphere_GROUP) ) GroupAddUnit(ReplenishmentSphere_GROUP, picker); picker = null; } function onInit() { trigger trig = CreateTrigger(); TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_PICKUP_ITEM); TriggerAddCondition(trig, Condition(function Conditions)); TriggerAddAction(trig, function Actions); } } //! endzinc Zinc://! zinc // Handles switching between active and inactive version of the item. library ReplenishmentSphereUse requires ReplenishmentSphere { // Raw code of the active version of the item: constant integer IID_ACTIVE_ITEM = IID_REP_SPHERE_ACTIVE_ITEM; // Raw code of the inactive version of the item: constant integer IID_INACTIVE_ITEM = IID_REP_SPHERE_INACTIVE_ITEM; function Conditions() -> boolean { return ( GetItemTypeId(GetManipulatedItem()) == IID_ACTIVE_ITEM || /* */ GetItemTypeId(GetManipulatedItem()) == IID_INACTIVE_ITEM ); } function Actions() { unit user = GetTriggerUnit(); item it = GetManipulatedItem(); integer itemId = GetItemTypeId(it); RemoveItem(it); // Determines which version was used (active or inactive) // and adds swaps it with the opposite one. if ( itemId == IID_ACTIVE_ITEM ) it = CreateItem(IID_INACTIVE_ITEM, GetUnitX(user), GetUnitY(user)); else it = CreateItem(IID_ACTIVE_ITEM, GetUnitX(user), GetUnitY(user)); UnitAddItem(user, it); user = null; it = null; } function onInit() { trigger trig = CreateTrigger(); TriggerRegisterAnyUnitEventBJ(trig, EVENT_PLAYER_UNIT_USE_ITEM); TriggerAddCondition(trig, Condition(function Conditions)); TriggerAddAction(trig, function Actions); } } //! endzinc Last edited by HerrStanev : 03-10-2013 at 10:51 PM. |
|
|
|
|
|
#9 | ||
|
master of fugue
Join Date: Jun 2007
Posts: 2,558
![]() ![]() ![]() ![]()
|
Quote:
I might also add that any software developer on the surface of earth would laugh at that question. Divide and Conquer is the single most important skill for a person who wants to live by his code. Quote:
Made a mistake there, forgot we were working in a language without static imports, global is fine. EDIT2: Also if you really want to do it properly, that timer should not run when noone is using the active items. Start timer only when it is first time needed and use PauseTimer and ResumeTimer functions later. Last edited by cohadar : 03-08-2013 at 06:29 PM. |
||
|
|
|
|
|
#10 | |
|
User
Join Date: Mar 2013
Posts: 49
|
Updated the previous post with the global version.
Quote:
But I have no idea how to approach this with Pause and Resume. :( |
|
|
|
|
|
|
#11 |
|
master of fugue
Join Date: Jun 2007
Posts: 2,558
![]() ![]() ![]() ![]()
|
You create and activate the timer the first time it is needed.
__________________This is a very often used technique in software development: http://en.wikipedia.org/wiki/Lazy_initialization Than you maintain a counter of active items that are equipped on a hero. When active item is equipped, you increase a counter. When active item is dropped, you decrease a counter. When passive item is changed to active you increase a counter. When active item is changed to passive you decrease a counter. When passive item is picked or dropped you do NOT change the counter. When counter becomes equal to 1, you ResumeTimer, When counter becomes equal to 0, you PauseTimer. In programming counters that can be zero or higher and activate and deactivate something on 1 and 0, are called Semaphores. http://en.wikipedia.org/wiki/Semapho...programming%29 TIP: Use the LOG library from UHS to debug your code while you work. Log the timer creation and every counter change so you can track what is going on. Last edited by cohadar : 03-08-2013 at 07:19 PM. |
|
|
|
|
|
#12 |
|
User
Join Date: Mar 2013
Posts: 49
|
Just ran into something weird.
If I resume a previously paused periodic timer it only runs TWO times. So what I have to do is just call TimerStart and make the callback function global, zzzzzz. Maybe I'm doing something wrong but try this out, it just prints twice for me: Zinc://! zinc library test { boolean b = false; timer tim = CreateTimer(); function Callback() { BJDebugMsg("abc"); } function onInit() { TimerStart(tim, 0.33, true, function Callback); PauseTimer(tim); TimerStart(CreateTimer(), 3., true, function() { b = !b; if ( b ) ResumeTimer(tim); else PauseTimer(tim); } ); } } //! endzinc |
|
|
|
|
|
#13 |
|
master of fugue
Join Date: Jun 2007
Posts: 2,558
![]() ![]() ![]() ![]()
|
Zinc://! zinc library test { boolean b = false; timer tim = CreateTimer(); integer counter = 0; function Callback() { counter = counter + 1; BJDebugMsg(I2S(counter)); } function onInit() { TimerStart(tim, 0.33, true, function Callback); PauseTimer(tim); TimerStart(CreateTimer(), 3., true, function() { b = !b; if ( b ) ResumeTimer(tim); else PauseTimer(tim); } ); } } //! endzinc This prints 12 34 56 78, all normal. Dunno what your problem is. Are you using NewGen 5e ? Last edited by cohadar : 03-09-2013 at 05:44 PM. |
|
|
|
|
|
#14 |
|
User
Join Date: Mar 2013
Posts: 49
|
Well yes, that's the issue. It should print "12345678", not "12, 34, 56, 78".
After all, the "tim" timer should run 9 times (3 / 0.33), then get paused for 3 seconds, then run another 9 times during the 3 seconds it is resumed. The same thing happens in the item script. The 0.025 timer after being resumed runs only two times, then just stops... It's as if the ResumeTimer function resets the timer to non-periodic. Or maybe I'm doing some total bullshit. Yes, I'm with 1.5e NewGen. Last edited by HerrStanev : 03-09-2013 at 06:16 PM. |
|
|
|
|
|
#15 |
|
master of fugue
Join Date: Jun 2007
Posts: 2,558
![]() ![]() ![]() ![]()
|
No it is just another error in jass.
__________________Please report it here: http://www.wc3c.net/showthread.php?t=80693 This works ok: Zinc://! zinc library test { boolean b = false; timer tim = CreateTimer(); integer counter = 0; function Callback() { counter = counter + 1; BJDebugMsg(I2S(counter)); } function onInit() { TimerStart(tim, 0.33, true, function Callback); PauseTimer(tim); TimerStart(CreateTimer(), 3., true, function() { b = !b; if ( b ) //ResumeTimer(tim); TimerStart(tim, 0.33, true, function Callback); else PauseTimer(tim); counter = 0; // reset counter } ); } } //! endzinc |
|
|
|
![]() |
| Thread Tools | Search this Thread |
|
|
|
Donate |