Tukki
is Skeleton Pirate.
- Reaction score
- 29
Ability System
This system has been revamped! Now it's using structs instead.
Check the readme for more info. The old version will still be available.
Requirements:
Features:
Purpose: Making a cool way of adding spells to units! Adds spells to units depending on items.
Methods for different ways of registering spells with items.
Arguments: iid - the ItemID, sid - the SpellID, max - the maximum level
If you want to add a spell into a spellbook use;
Argument: sbid - SpellBookID
Changelog:
Readme and examples of usage are included in the demo map provided.
Screenshots: -
If you have any questions regarding the system post them here, the same applies to bugg reports and improvements. I'm open to your suggestions.
ABILITY SYSTEM
Version: 2.1
Version: 2.1
This system has been revamped! Now it's using structs instead.
Check the readme for more info. The old version will still be available.
Requirements:
- Jass New Gen Pack 1.5b +
- Basic knowledge of structs and jass;
- Know what a rawcode is;
- Table
Features:
- MUI/MPI;
- Supports: Ability Requirements, Attribute/Level Requirements, Level Factor and Instant Use;
- Capable of adding spells into spell books, but also the regular way;
- Units are able to unlearn specific spells, but also all of them. (note: the spells must have been added by the system for this to work)
Purpose: Making a cool way of adding spells to units! Adds spells to units depending on items.
CODE
JASS:
//===========================================================================
// Ability System v 2.1 - by Tukki
//===========================================================================
//*
//* Example of use:
//* local spellData d = spellData.create('I000', 'A000', 3) - add the spell with
//* 3 levels.
//*
//* set d.instant = true - make it instantly
//* try to give the unit
//* this spell.
//*
//* call d.addStatReq(0, 0, 0, 2, 1) - make it require
//* 2*ABILITY_LEVEL in level
//* to learn the spell.
//*
//* set d.addSpellBook = 'A001' - add the spell into a
//* spell book when learned.
//* 'A001' is the rawcode of
//* the dummy spell book.
//***************************************************************************
//* Now when a unit picks up a item of 'I000' type it will check if he meets
//* the requirements. In this case it requires that he is in level 2/4/6 +.
//*
//* Stuff you may read, but not set:
//*
//* itemId - the rawcode of the item (integer)
//* maxLevel - the max level of the spell (integer)
//* spellId - the rawcode of the ability (integer)
//* spellBook - rawcode of the dummy spell book (integer)
//* agiReq - agility requirement (integer)
//* strReq - strength requirement (integer)
//* intReq - intelligence requirement (integer)
//* lvlReq - the hero-level requirement (integer)
//* factor - level factor of the requirements (real)
//* useReq - whether it has requirements or not (boolean)
//* spellReq - the rawcode of the required spell (integer)
//* spellLvl - the required level of above spell (integer)
//*
//* Stuff you may read and set:
//*
//* instant - if the spell will be instantly learned (boolean)
//===========================================================================
library AbilitySystem initializer InitTrig requires Table
globals
//===========================================================================
// START OF CONFIGURATION
//===========================================================================
private constant integer MAXIMUM_ABILITIES = 5 // Max abilities a unit may learn.
private constant integer MAXIMUM_INSTANCES = 8100 // MAXIMUM_INSTANCES/MAXIMUM_ABILITIES is the maximum number of units who can use this system.
// NOTE: Only if RETAIN_ON_FAIL and the user fails to learn the spell he will get his
// resources back.
private constant integer GOLD_COST = 0 // The gold cost of the item.
private constant integer LUMBER_COST = 0 // The lumber cost of the item.
private constant boolean RETAIN_ON_FAIL = false // Give a new item to a failing unit.
private constant boolean COUNT_BONUSES = false // Count attribute bonuses (in green)
private constant boolean INSTANT_LEARN = false // Instantly learn the item's spell.
private constant boolean USE_CHARGES = false // Do you use charged items?
private constant string DIALOG_MENU = "Choose ability to unlearn" // Menu text.
//----------------
// Error message when a unit tries to learn/unlearn spells.
private constant string ERROR_DIALOG = "No abilities to unlearn!" // no abilities?
private constant string ERROR_MAX_LEARNED = "Maximum amount of spells learned!" // maximum spells learned!!
private constant string ERROR_MAX_LEVELD = "You have mastered this spell!" // When the unit has maxed the spell.
// Error messages for different requirements, should be rather clear.
private constant string ERROR_COLOR = "|CFFFFCC00" // Color of the error text.
private constant string ERROR_FAIL_REQ = "You must have following in order to learn the spell:"
// Different Strength/Agility/Intelligence/Level and ability requirements fail-texts.
private constant string ERROR_STRENGTH = "Strength: "
private constant string ERROR_AGILITY = "Agility: "
private constant string ERROR_INTELLIGENCE = "Intelligence"
private constant string ERROR_LEVEL = "Hero level: "
private constant string ERROR_ABILITY_REQ = "The spell: "
private constant string EFFECT_PATH = "" // The effect path.
private constant string ATTACHMENT_POS = "origin" // Attachment point on the unit.
//===========================================================================
// END OF CONFIGURATION
//===========================================================================
endglobals
//===========================================================================
globals
private HandleTable unitTable
private Table itemTable
private HandleTable dialogTable
endglobals
//===========================================================================
struct spellData
readonly integer itemId = 0
readonly integer maxLevel = 1
readonly integer spellId
readonly integer spellBook = 0
readonly integer agiReq = 0
readonly integer strReq = 0
readonly integer intReq = 0
readonly integer lvlReq = 0
readonly real factor = 0
readonly boolean useReq = false
readonly integer spellReq = 0
readonly integer spellLvl = 0
boolean instant
//---------------------------------------------------------------------------
static method create takes integer iid, integer sid, integer max returns spellData
local spellData this = spellData.allocate()
set .spellId = sid
set .maxLevel = max
set .itemId = iid
set .instant = INSTANT_LEARN
set itemTable[iid] = this
return this
endmethod
//---------------------------------------------------------------------------
method operator addSpellBook= takes integer sbid returns nothing
local integer i = 0
set .spellBook = sbid
loop
exitwhen i > 11
call SetPlayerAbilityAvailable(Player(i), sbid, false)
set i = i + 1
endloop
endmethod
//---------------------------------------------------------------------------
method addStatReq takes integer str, integer agi, integer int, integer lvl, real f returns nothing
set .strReq = str
set .agiReq = agi
set .intReq = int
set .lvlReq = lvl
set .factor = f
set .useReq = true
endmethod
//---------------------------------------------------------------------------
method addAbilReq takes integer reqId, integer reqLevel returns nothing
set .spellReq = reqId
set .spellLvl = reqLevel
endmethod
//---------------------------------------------------------------------------
private method onDestroy takes nothing returns nothing
call itemTable.flush(.itemId)
endmethod
endstruct
//===========================================================================
private struct unitData[MAXIMUM_INSTANCES]
unit u
integer array spells[MAXIMUM_ABILITIES]
integer counter = 0
//---------------------------------------------------------------------------
method add takes integer id returns nothing
call UnitAddAbility(.u, id)
set .spells[.counter] = id
set .counter = .counter + 1
endmethod
//---------------------------------------------------------------------------
private method onDestroy takes nothing returns nothing
call unitTable.flush(.u)
endmethod
endstruct
//===========================================================================
private struct dialogData
unit u
dialog d
integer array buttonId[32]
button array buttons[32]
integer counter = 0
//---------------------------------------------------------------------------
private method onDestroy takes nothing returns nothing
call dialogTable.flush(.d)
endmethod
endstruct
//===========================================================================
private function ErrorMessage takes player p, string message returns boolean
call DisplayTextToPlayer(p, 0, 0, message)
return false
endfunction
//===========================================================================
private function ReturnItem takes spellData d, unit to returns nothing
if (RETAIN_ON_FAIL) then
if (d.instant) then
call CreateItem(d.itemId, GetUnitX(to), GetUnitY(to))
return
endif
call UnitAddItemById(to, d.itemId)
else
call SetPlayerState(GetOwningPlayer(to), PLAYER_STATE_RESOURCE_GOLD, GetPlayerState(GetOwningPlayer(to), PLAYER_STATE_RESOURCE_GOLD)+GOLD_COST)
call SetPlayerState(GetOwningPlayer(to), PLAYER_STATE_RESOURCE_LUMBER, GetPlayerState(GetOwningPlayer(to), PLAYER_STATE_RESOURCE_LUMBER)+GOLD_COST)
endif
endfunction
//===========================================================================
private function CheckStats takes spellData d, unit u returns boolean
local real f = 1
local integer agi = d.agiReq
local integer str = d.strReq
local integer int = d.intReq
local integer lvl = d.lvlReq
local string s = ERROR_COLOR + ERROR_FAIL_REQ
local integer i = 0
if (d.factor > 0) then
set f = d.factor * (GetUnitAbilityLevel(u, d.spellId)+1)
set agi = R2I(agi * f)
set str = R2I(str * f)
set int = R2I(int * f)
set lvl = R2I(lvl * f)
endif
if (GetHeroAgi(u, COUNT_BONUSES) < agi) then
set s = s + "\n"+ERROR_COLOR + ERROR_AGILITY + "|CFFFF0000" + I2S(agi) + "|r"
set i = 1
endif
if (GetHeroStr(u, COUNT_BONUSES) < str) then
set s = s + "\n"+ERROR_COLOR + ERROR_STRENGTH + "|CFFFF0000" + I2S(str) + "|r"
set i = 1
endif
if (GetHeroInt(u, COUNT_BONUSES) < int) then
set s = s + "\n"+ERROR_COLOR + ERROR_INTELLIGENCE + "|CFFFF0000" + I2S(int) + "|r"
set i = 1
endif
if (GetHeroLevel(u) < lvl) then
set s = s + "\n"+ERROR_COLOR + ERROR_LEVEL + "|CFFFF0000" + I2S(lvl) + "|r"
set i = 1
endif
if (i == 1) then
return ErrorMessage(GetOwningPlayer(u), s)
endif
return true
endfunction
//===========================================================================
private function CheckSpell takes spellData d, unit u returns boolean
local string s = ERROR_COLOR + ERROR_FAIL_REQ
if not (GetUnitAbilityLevel(u, d.spellReq) >= d.spellLvl) then
set s = s + "\n"+ERROR_COLOR + ERROR_ABILITY_REQ + GetObjectName(d.spellReq) + ERROR_COLOR + " at level " + "|CFFFF0000" + I2S(d.spellLvl) + "|r"
return ErrorMessage(GetOwningPlayer(u), s)
endif
return true
endfunction
//===========================================================================
// MAIN - checks requirements and adds the spell to the unit if he passes
//===========================================================================
private function AddAbilityMain takes unit to, spellData d returns boolean
local unitData a = unitTable[to]
local integer c = d.spellId
if (GetUnitAbilityLevel(to, c) >= d.maxLevel) then
call ReturnItem(d, to)
return ErrorMessage(GetOwningPlayer(to), ERROR_MAX_LEVELD)
endif
if (d.useReq) then
if not (CheckStats(d, to)) then
call ReturnItem(d, to)
return false
endif
endif
if (d.spellReq != 0) then
if not (CheckSpell(d, to)) then
call ReturnItem(d, to)
return false
endif
endif
if (a.counter >= MAXIMUM_ABILITIES) then
if (GetUnitAbilityLevel(to, c) <= 0) then
call ReturnItem(d, to)
return ErrorMessage(GetOwningPlayer(to), ERROR_MAX_LEARNED)
endif
endif
if (GetUnitAbilityLevel(to, c) <= 0) then
if (d.spellBook != 0) then
set c = d.spellBook
endif
call a.add(c)
else
call IncUnitAbilityLevel(to, c)
endif
call DestroyEffect(AddSpecialEffectTarget(EFFECT_PATH, to, ATTACHMENT_POS))
return true
endfunction
//===========================================================================
private function RemoveAbilities takes nothing returns nothing
local dialog di = GetClickedDialog()
local dialogData d = dialogTable[di]
local button clicked = GetClickedButton()
local integer i = d.counter-2
local unitData a = unitTable[d.u]
if (clicked == d.buttons[d.counter-1]) then
set i = a.counter-1
loop
exitwhen i < 0
call UnitRemoveAbility(a.u, a.spells<i>)
set a.spells<i> = 0
set i = i - 1
endloop
call a.destroy()
endif
loop
exitwhen i < 0
if (clicked == d.buttons<i>) then
call UnitRemoveAbility(a.u, a.spells<i>)
set a.spells<i> = 0
set a.counter = a.counter - 1
if (a.counter < 0) then
set a.counter = 0
else
set a.spells<i> = a.spells[a.counter]
endif
endif
set i = i - 1
endloop
call d.destroy()
call DialogClear(di)
call DialogDestroy(di)
call DestroyTrigger(GetTriggeringTrigger())
set di = null
endfunction
//===========================================================================
private function BeginUnlearn takes unit who returns nothing
local dialog di = DialogCreate()
local trigger t = CreateTrigger()
local integer i = 0
local dialogData d = dialogData.create()
local unitData a = unitTable[who]
set dialogTable[di] = d
set d.u = who
set d.d = di
call DialogSetMessage(di, DIALOG_MENU)
loop
exitwhen i >= a.counter
set d.buttons<i> = DialogAddButton(di, GetObjectName(a.spells<i>), 0)
set d.buttonId<i> = a.spells<i>
set i = i + 1
endloop
set d.buttons<i> = DialogAddButton(di, "Unlearn All", 0)
set d.buttons[i+1] = DialogAddButton(di, "Cancel", 0)
set d.counter = i+1
call TriggerRegisterDialogEvent(t, di)
call TriggerAddAction(t, function RemoveAbilities)
call DialogDisplay(GetOwningPlayer(who), di, true)
set di = null
set t = null
endfunction
//===========================================================================
public function Unlearn takes unit who returns boolean
if (who != null and unitTable[who] != 0) then
if (unitData(unitTable[who]).counter != 0) then
call BeginUnlearn(who)
else
return ErrorMessage(GetOwningPlayer(who), ERROR_DIALOG)
endif
endif
return true
endfunction
//===========================================================================
private function remove takes item i returns nothing
call TriggerSleepAction(0)
if (GetWidgetLife(i)>0) then
if (USE_CHARGES) then
call SetItemCharges(i, GetItemCharges(i)-1)
if (GetItemCharges(i) <= 0) then
call RemoveItem(i)
endif
return
endif
call RemoveItem(i)
endif
endfunction
//===========================================================================
// CORE - checks and makes the appropriate calls
//===========================================================================
private function Core takes nothing returns boolean
local integer id = GetItemTypeId(GetManipulatedItem())
local unit u = GetTriggerUnit()
local spellData d = itemTable[id]
local unitData a = unitTable<u>
local eventid e = GetTriggerEventId()
if (d!=0) then
if (a == 0) then
set a = unitData.create()
set a.u = GetTriggerUnit()
set unitTable<u> = a
endif
if (e == EVENT_PLAYER_UNIT_PICKUP_ITEM) then
if (d.instant) then
call AddAbilityMain(GetManipulatingUnit(), d)
call RemoveItem(GetManipulatedItem())
endif
else
call AddAbilityMain(GetManipulatingUnit(), d)
call remove.execute(GetManipulatedItem())
endif
endif
set u = null
set e = null
return false
endfunction
//===========================================================================
// DEATH RECYCLER - destroys struct on dying non-hero units (as heroes are revivable)
//===========================================================================
private function death takes nothing returns boolean
local unit u = GetTriggerUnit()
if (unitData(unitTable<u>) != 0 and IsUnitType(u, UNIT_TYPE_HERO) == false) then
call unitData(unitTable<u>).destroy()
endif
set u = null
return false
endfunction
//===========================================================================
// INITIALIZER - sets the stone rollin'
//===========================================================================
private function InitTrig takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
set unitTable = HandleTable.create()
set itemTable = Table.create()
set dialogTable = HandleTable.create()
call unitTable.reset()
call itemTable.reset()
call dialogTable.reset()
loop
exitwhen i == bj_MAX_PLAYER_SLOTS
call TriggerRegisterPlayerUnitEvent(t, Player(i),EVENT_PLAYER_UNIT_USE_ITEM, null)
call TriggerRegisterPlayerUnitEvent(t, Player(i),EVENT_PLAYER_UNIT_PICKUP_ITEM, null)
set i = i + 1
endloop
call TriggerAddCondition(t, Condition(function Core))
set t = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(t, EVENT_PLAYER_UNIT_DEATH)
call TriggerAddCondition(t, Condition(function death))
endfunction
endlibrary</u></u></u></u></i></i></i></i></i></i></i></i></i></i></i>
Methods for different ways of registering spells with items.
Arguments: iid - the ItemID, sid - the SpellID, max - the maximum level
If you want to add a spell into a spellbook use;
Argument: sbid - SpellBookID
README
JASS:
*********************************************************
* ITEM ABILITY LEARN SYSTEM - v 2.1 *
* by: Tukki *
* Give credits when used! *
*********************************************************
* *
* CONTENTS: *
* *
* 1 - Implementation/Misc *
* 2 - Available Functions *
* 3 - Argument Explanations *
* *
*********************************************************
======================================================================================
[1] 039;Implementation/Misc039;
======================================================================================
=IMPLEMENTATION=======================================================================
Requirements;
* JASS New Gen Pack 1.5b or newer
* A dummy ability which your items use (Makes them usable) - not really required
1. Click on the Map System folder and press [Ctrl] + C (hotkey for "Copy")
2. Go to your map and press [Ctrl] + V (hotkey for "Paste")
3. Save. If it works, congratulations! Else maybe you already have an existing trigger
with the same name as one of my triggers. If that is the problem then do following
1. left-click on the name of one of my triggers (the one who is the problem) and change
the name to something completely different.
2. Save and if there are no problems then thumbs-up!
3. Report the problem following the next steps.
=BUGG REPORTS=========================================================================
If you experiance that something is wrong, or see in the code that something is leaking
/missing, please post it in the thread located at thehelper.net from which you downloaded
this map.
======================================================================================
[2] 039;Available Functions039;
======================================================================================
=FUNCTION LIST========================================================================
call spellData.create(integer itemId, integer spellId, integer maxLevel)
call <spellData-variable>.addStatReq(integer str, integer agi, integer int, integer lvl, real factor)
call <spellData-variable>.addAbilReq(integer spellId, integer requiredLevel)
set <spellData-variable>.addSpellBook = integer spellBookId
set <spellData-variable>.instant = boolean isInstant
call AbilitySystem_Unlearn(unit whichUnit)
call <spellData-variable>.destroy()
The <spellData-variable> is the spellData variable you stored the struct in when you created it
using spellData.create(...).
Example:
local spellData d = spellData.create(....)
======================================================================================
The function names are rather self-explaining. But I will give a short description of
each of them.
--------------------------------------------------------------------------------------
create takes integer itemId, integer spellId, integer maxLevel
--------------------------------------------------------------------------------------
Syntax: call spellData.create(...) OR set "someVariable" = spellData.create(...)
The basic function. It gives you the spellId ability when you use/pick up the itemId
item. Store the returned struct in order to use the functions below.
--------------------------------------------------------------------------------------
addStatReq takes integer str, integer agi, integer int, integer lvl, real factor
--------------------------------------------------------------------------------------
Syntax: call "someVariable".spellStatReq(......)
Adds stat requirements to the spell. If factor > 0 then all stat requirements will
increase with "stat*factor" per level. The hero must have higher or equal stats in order
to learn the spell.
--------------------------------------------------------------------------------------
addAbilReq takes integer spellId, integer requiredLevel
--------------------------------------------------------------------------------------
Syntax: call "someVariable".spellAbilReq(....)
Adds an ability requirement, the hero must have the spell at same or higher level than
the requiredLevel argument.
--------------------------------------------------------------------------------------
addSpellBook takes integer spellbookId
--------------------------------------------------------------------------------------
Syntax: set "someVariable".addSpellBook = 039;A000039;, where 039;A000039; is the spell book id.
Adds the spell directly into a spellbook on the hero instead of onto the usual command
card.
--------------------------------------------------------------------------------------
instant takes boolean isInstant
--------------------------------------------------------------------------------------
Syntax: set "someVariable".instant = true/false
Makes the unit who picks up the item instantly learn the spell or not.
Note: This will initially be set to the INSTANT_LEARN boolean.
--------------------------------------------------------------------------------------
Unlearn takes unit whichUnit
--------------------------------------------------------------------------------------
Syntax: call AbilitySystem_Unlearn(...)
Pops up a dialog with spells the hero may unlearn.
--------------------------------------------------------------------------------------
destroy
--------------------------------------------------------------------------------------
Syntax: "someVariable".destroy()
Removes the registered spell from the system.
======================================================================================
[3] - 039;Argument Explanations039;
======================================================================================
=ARGUMENTS USED=======================================================================
boolean isInstant - boolean which may be true or false
unit whichUnit - the unit who will learn/unlearn things
real factor - factor for the stat-requirements. [STAT] * [FACTOR*ABILITY_LEVEL]
integer str/agi/int/lvl - different stat names, pretty obvious
"someVariable" - the spellData variable I store the struct in.
integer ..Id - the .. rawcode. I.e: The rawcode of the item
======================================================================================
END OF README
======================================================================================
Changelog:
- 2.0 - System revamped.
- 2.1 - A small update, struct 'recycler' added.
Readme and examples of usage are included in the demo map provided.
Screenshots: -
If you have any questions regarding the system post them here, the same applies to bugg reports and improvements. I'm open to your suggestions.