Libram v3.0.0.0

User avatar
Enalias
Site Admin
Site Admin
Posts: 200
Joined: Sat Sep 15, 2018 1:57 pm
Reputation: 9
Location: Florida, U.S.A.
Website: http://chaosrealm.co/memberlist.php?mod ... rofile&u=2
Discord: https://discord.gg/BUEZkef
Twitch: https://www.twitch.tv/enalias
Contact:
United States of America

Libram v3.0.0.0

#1

Post by Enalias » Mon Nov 05, 2018 12:15 pm

Libram v3.0.0.0
by PurgeandFire111


Type: System
Category: vJASS


Libram:

This is a library that creates a "libram", something very similar to a spellbook. It has the same functionality, but was made for convenience for gameplay.

A libram is essentially a bunch of pages with abilities on them. Much like an extended inventory system, you can flip through the pages and access whatever abilities you need. There are only 5 slots, but you can always remove the page up and page down abilities (and opt for the items or the arrow key method) for 2 more slots per page.

Essentially, you can cast whatever spells you want, and if you need to access another ability, just turn the page. This can lead to cool spell organization, such as if you want one page for damage spells, one page for healing spells, and one page for tank spells. All cooldowns are preserved, passives work just fine (if you read the documentation and follow the instructions), and all that good stuff. You can also edit abilities just as you normally would, so it is completely safe to change the level of an ability in the libram without the use of custom functions.

I also have an optional module that can enable the abilities for page up and page down, or you can alternatively use arrow keys. (or both) With 2.0.0.0, you can also use items for swapping. (they are all optional, but I recommend using at least one of them as it is a pain to code it yourself)

Requirements: Any unit indexer, such as AIDS, UnitIndexer, AutoIndex, Bribe's GUI Indexer, etc..

This library also features nice Lua for easy generation. Just read the trigger, "How to Implement" on how to setup the system in your map, it is pretty easy.

code
Show
library Libram requires optional LibramPageShift // ALSO REQUIRES ANY UNIT INDEXER
//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
//
// Libram v. 3 . 0 . 0 . 0
// ¯¯¯¯¯¯ ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//
// What is it?
// ¯¯¯¯¯¯¯¯¯¯¯
// - This library adds "pages" for abilities, which extends the limit of the amount of abilities
// a hero can have.
// - It simulates a spellbook, but with a bit more convenience in that you still have access to
// standard abilities, such as "move" or "attack".
// - A libram acts as a "book" of one or more pages. Each page has several abilities.
//
// Pros:
// ¯¯¯¯
// - It can support a very large amount of pages and abilities.
// - It supports passive abilities.
// - Cooldowns are maintained when switching between pages.
// - You don't have to use special functions when handling with the abilities.
//
// Cons:
// ¯¯¯¯
// - This currently supports only 11 PASSIVE abilities per unit, assuming you use the spellbook method.
// - This does have a limit of pages and abilities, but you will most likely never reach it. (unless you have like 80 pages per unit)
// - MUI: THIS IS MUI TO AN EXTENT. It will work perfectly fine with multiple units, but those units
// CANNOT share any abilities. For example, two heroes cannot both have the ability "Holy Light", or else
// it will bug out, even if only one of them have a libram activated.
// - Autocast abilities won't be automatically casted if the libram is on a different page than the autocast.
//
// Requirements:
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
// - LibramPageShift : OPTIONAL
// - Any unit indexer, AIDS, UnitIndexer, etc...
//
// Usage:
// ¯¯¯¯¯¯
//
/* call Libram.create(unit) returns Libram */
//
// - This creates a new libram for a unit. It includes one empty, page. The instance returned is
// the user ID of the unit.
//
// Libram(instance).caster - Returns the unit who has that libram.
// Libram(instance).first - Returns the first page of the libram.
// Libram(instance).curr - Returns the page that the player currently has open.
//
/* call Libram(instance).createPage() returns LibramPage */
//
// - This creates a new page for a unit, after the last page.
//
/* call Libram(instance).createPageAfter(Page previous) returns LibramPage */
//
// - This creates a new page ordered after the page you specify.
//
/* call Libram(instance).addAbility(Page, integer ID) */
//
// - This adds an ability to a page, of the "ID" provided. (rawcode)
//
/* call Libram(instance).addPassive(Page, integer ID, integer spellbookID) */
//
// - Adds a passive ability to a page. You must use this function to add
// it if you want it to work properly. However, you must create a dummy
// spellbook for it. You can use my Lua scripts to ease this process.
// If you don't want it to be applied when the page is not shown, then
// you can just add it as if it were a normal ability.
//
/* call Libram(instance).removeAbility(Page, integer ID) */
//
// - This removes an ability from a page, of the "ID" provided. (rawcode)
//
/* call Libram(instance).shiftPages(Page toShiftTo) */
//
// - This flips the page to the page you specify, unlocking its abilities.
//
/* call Libram(instance).refresh() */
//
// - If you had just setup passive abilities, all the abilities might not show up. Use this function
// to refresh the pages, just to make sure that everything displays correctly.
//
/* call Libram(instance).removePage(Page) */
//
// - Removes the specified page and all the abilities associated with it.
//
/* call Libram(instance).destroy() */
//
// - Destroys the libram, removes all of its pages, and removes all of the abilities.
//
/* call Page(instance).findAbility(integer ID) returns AbilityList */
//
// - Finds an ability listed on a page, and returns its AbilityList instance. (return 0 = not found)
//
//
// Notes:
// ¯¯¯¯¯¯
// - If you add an ability normally, without using this system, then it will automatically go in a
// free slot. If there are no free slots, it will not be added. It will appear on each page, as long
// as there is a free slot.
// - If you remove an ability normally that has data on a page (without using this system), then
// it will successfully remove the ability, but the data for it will still exist, so be sure
// to remove it using this system.
//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~

private struct AbilityList
readonly thistype next
readonly thistype prev
readonly integer curr
integer spellbookID

method destroy takes nothing returns nothing
set this.next.prev = this.prev
set this.prev.next = this.next
call this.deallocate()
endmethod

static method attach takes integer abilID, thistype head returns thistype
local thistype this = thistype.allocate()
set head.next.prev = this
set this.next = head.next
set head.next = this
set this.prev = head
set this.curr = abilID
return this
endmethod
endstruct

struct LibramPage
AbilityList list
thistype next
thistype prev

method findAbility takes integer ID returns AbilityList
local AbilityList i = this.list.next
loop
exitwhen i.curr == ID or i == 0
set i = i.next
endloop
return i //it will return "0" if it is not found
endmethod

method destroy takes nothing returns nothing
local AbilityList clear = this.list.next
loop
exitwhen clear == 0
call clear.destroy()
set clear = clear.next
endloop
call this.deallocate()
endmethod

method removeAbility takes integer ID returns nothing
local AbilityList i = this.findAbility(ID)
if i == 0 then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,15,"PAGE_ERROR["+I2S(this)+"]: Ability not listed on this page.")
return
endif
call i.destroy()
endmethod

method addAbility takes integer ID returns AbilityList
return AbilityList.attach(ID, this.list)
endmethod

static method insertAfter takes thistype node returns thistype
local thistype this = thistype.allocate()
set this.list = AbilityList.create()
set node.next.prev = this
set this.next = node.next
set node.next = this
set this.prev = node
return this
endmethod
endstruct

struct Libram extends array
readonly unit caster
readonly LibramPage first
readonly LibramPage curr
private player owner

static method operator [] takes unit u returns thistype
return GetUnitUserData(u)
endmethod

method shiftPages takes LibramPage which returns nothing
local AbilityList i = this.curr.list.next
local integer lvl
loop
exitwhen i == 0
if i.spellbookID != 0 then
set lvl = GetUnitAbilityLevel(this.caster,i.curr)
call UnitRemoveAbility(this.caster,i.curr)
call UnitAddAbility(this.caster,i.spellbookID)
call SetUnitAbilityLevel(this.caster,i.curr,lvl)
else
call SetPlayerAbilityAvailable(this.owner,i.curr,false)
endif
set i = i.next
endloop
set this.curr = which
set i = which.list.next
loop
exitwhen i == 0
if i.spellbookID != 0 then
set lvl = GetUnitAbilityLevel(this.caster,i.curr)
call UnitRemoveAbility(this.caster,i.spellbookID)
call UnitAddAbility(this.caster,i.curr)
call SetUnitAbilityLevel(this.caster,i.curr,lvl)
else
call SetPlayerAbilityAvailable(this.owner,i.curr,true)
endif
set i = i.next
endloop
endmethod

method refresh takes nothing returns nothing
call this.shiftPages(this.curr.next)
call this.shiftPages(this.curr.prev)
endmethod

method createPage takes nothing returns LibramPage
return LibramPage.insertAfter(this.first.prev)
endmethod

method createPageAfter takes LibramPage previous returns LibramPage
return LibramPage.insertAfter(previous)
endmethod

method removeAbility takes LibramPage source, integer abilityID returns nothing
local AbilityList i = source.findAbility(abilityID)
local LibramPage k = source.next
local boolean rem = true
if i.spellbookID != 0 then
call UnitRemoveAbility(this.caster,i.spellbookID)
endif
loop
exitwhen k == source
set rem = k.findAbility(abilityID)==0 //check if any other pages have this ability
set k = k.next
endloop
call source.removeAbility(abilityID)
if rem then
call UnitRemoveAbility(this.caster,abilityID)
call SetPlayerAbilityAvailable(this.owner,abilityID,true)
elseif this.curr == source then
call this.refresh()
endif
endmethod

method addPassive takes LibramPage target, integer abilityID, integer spellbookID returns nothing
set target.addAbility(abilityID).spellbookID = spellbookID
if this.curr != target then
call UnitAddAbility(this.caster,spellbookID)
else
call UnitAddAbility(this.caster,abilityID)
endif
call SetPlayerAbilityAvailable(this.owner,spellbookID,false)
endmethod

method addAbility takes LibramPage target, integer abilityID returns nothing
call target.addAbility(abilityID)
call UnitAddAbility(this.caster,abilityID)
if this.curr != target then
call SetPlayerAbilityAvailable(this.owner,abilityID,false)
endif
endmethod

method removePage takes LibramPage toRemove returns nothing
local AbilityList i = toRemove.list.next
loop
exitwhen i == 0
call this.removeAbility(toRemove,i.curr)
set i = i.next
endloop
if this.curr == toRemove then
call this.shiftPages(this.curr.next)
endif
call toRemove.destroy()
endmethod

method destroy takes nothing returns nothing
local LibramPage p = this.first.next
loop
exitwhen p == this.first
call this.removePage(p)
set p = p.next
endloop
call this.removePage(p) //remove the head as well
static if LIBRARY_LibramPageShift then
static if LibramPageShift_ENABLE_ABILITY_SHIFT then
call UnitRemoveAbility(this.caster,thistype.PAGE_UP)
call UnitRemoveAbility(this.caster,thistype.PAGE_DOWN)
endif
static if LibramPageShift_ENABLE_ITEM_SHIFT then
call RemoveItem(UnitItemInSlot(this.caster,thistype.PAGE_UP_SLOT))
call RemoveItem(UnitItemInSlot(this.caster,thistype.PAGE_DOWN_SLOT))
endif
endif
set this.caster = null
endmethod

static method create takes unit cast returns thistype
local thistype this = GetUnitUserData(cast)
set this.first = LibramPage.create()
set this.first.next = this.first
set this.first.prev = this.first
set this.first.list = AbilityList.create()
set this.curr = this.first
set this.caster = cast
set this.owner = GetOwningPlayer(cast)
static if LIBRARY_LibramPageShift then
static if LibramPageShift_ENABLE_ABILITY_SHIFT then
call UnitAddAbility(cast,thistype.PAGE_UP)
call UnitAddAbility(cast,thistype.PAGE_DOWN)
endif
static if LibramPageShift_ENABLE_ITEM_SHIFT then
call UnitAddItemToSlotById(this.caster,thistype.PAGE_UP_ITEM,thistype.PAGE_UP_SLOT)
call UnitAddItemToSlotById(this.caster,thistype.PAGE_DOWN_ITEM,thistype.PAGE_DOWN_SLOT)
endif
endif
return this
endmethod

implement optional LibramInit

endstruct

// Wrapper functions, you can remove this if you don't need it.

// call AddLibram( unit u )
// Creates a libram for a unit and assigns lastCreatedLibram to it.
// call AddLibramPage()
// Adds a page to the last created libram.
// call AddLibramAbility( integer abilityID )
// Adds an ability to the last created page.
// call AddLibramPassive( integer abilityID , integer spellbookID )
// Adds a passive ability to the last created page. (see documentation for information on passives)
// The functions above are order dependent. The functions below are for general access:

// call AddPageToUnit( unit u )
// Adds a new page to a unit.
// call AddAbilityToPage( unit u, LibramPage page, integer abilityID )
// Adds an ability to a specific page of a unit.
// call AddPassiveToPage( unit u, LibramPage page, integer abilityID, integer spellbookID )
// Adds a passive ability to a specific page of a unit. (see documentation for information on passives)
// call GetUnitLibram( unit u ) returns Libram
// Returns the Libram instance of a unit.
// call GetLibramPageFromIndex( Libram which, integer index ) returns LibramPage
// Returns the nth page of a libram. The first page of a libram has an index
// of 1. The next page has an index of 2. Third page has an index of 3... etc.

// lastCreatedLibram - The last created libram from the wrapper functions.
// lastCreatedPage - The last created page from the wrapper functions.

globals
Libram lastCreatedLibram = 0
LibramPage lastCreatedPage = 0
endglobals

function AddLibram takes unit owner returns nothing
set lastCreatedLibram = Libram.create(owner)
set lastCreatedPage = lastCreatedLibram.first
endfunction

function AddLibramPage takes nothing returns nothing
set lastCreatedPage = lastCreatedLibram.createPage()
endfunction

function AddLibramAbility takes integer abilityID returns nothing
call lastCreatedLibram.addAbility(lastCreatedPage, abilityID)
endfunction

function AddLibramPassive takes integer abilityID, integer spellbookID returns nothing
call lastCreatedLibram.addPassive(lastCreatedPage, abilityID, spellbookID)
endfunction

function AddPageToUnit takes unit u returns nothing
set lastCreatedPage = Libram.createPage()
endfunction

function AddAbilityToPage takes unit u, LibramPage page, integer abilityID returns nothing
call Libram.addAbility(page, abilityID)
endfunction

function AddPassiveToPage takes unit u, LibramPage page, integer abilityID, integer spellbookID returns nothing
call Libram.addPassive(page, abilityID, spellbookID)
endfunction

function GetUnitLibram takes unit u returns Libram
return Libram
endfunction

function GetLibramPageFromIndex takes Libram which, integer index returns LibramPage
local LibramPage i = which.first
local integer c = 1
loop
if index == c then
return i
endif
set i = i.next
set c = c + 1
exitwhen i == which.first
endloop
debug call DisplayTextToPlayer(GetLocalPlayer(),0,0,"GetLibramPageFromIndex: Could not retrieve the page of index "+I2S(index)+" of Libram("+I2S(which)+").")
return 0
endfunction

endlibrary
Page Shift Module
Show
library LibramPageShift
//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
//
// LibramPageShift
// ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
//
// What is it?
// ¯¯¯¯¯¯¯¯¯¯¯
// - This library enables shifting with abilities, items, and arrow keys. (up and down)
// - All of them can be disabled/enabled.
//
// Usage:
// ¯¯¯¯¯
// ENABLE_KEY_SHIFT - Enables shifting pages with arrow keys.
// ENABLE_ABILITY_SHIFT - Enables shifting pages with abilities.
// ENABLE_ITEM_SHIFT - Enables shifting pages with items.
//
// PAGE_UP - The rawcode of the "Page Up" ability.
// PAGE_DOWN - The rawcode of the "Page Down" ability.
//
// PAGE_UP_ITEM - The rawcode of the "Page Up" item.
// PAGE_DOWN_ITEM - The rawcode of the "Page Down" item.
//
// PAGE_UP_BUFF - In order for the abilities to not interrupt the current order,
// they must be based off specific spells. Currently, it is using
// Mana Shield and Berserk. If you change it to something else, then
// you have to change the corresponding buff, so that the buff won't appear.
// PAGE_DOWN_BUFF - Same as above.
//
// NOTE:
// ¯¯¯¯
// For this to work properly, your unit cannot have any abilities based off of Berserk or Mana Shield.
// If you do, then you either need to change the ability or change the abilities in this system. Simply base
// the spell off of a different spell that does not interrupt order:
// Berserk, Defend, Magical Defense, Mana Shield, Immolation, Divine Shield
// And then change the PAGE_UP_BUFF and/or PAGE_DOWN_BUFF accordingly.
//
//~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~

globals
public constant boolean ENABLE_KEY_SHIFT = true
public constant boolean ENABLE_ABILITY_SHIFT = true
public constant boolean ENABLE_ITEM_SHIFT = true
endglobals

module LibramInit
static if ENABLE_KEY_SHIFT then
private static group G = CreateGroup()
static eventid ev
endif

static constant integer PAGE_UP_BUFF = 'BNms' // Mana Shield
static constant integer PAGE_DOWN_BUFF = 'Bbsk' // Berserk

static if ENABLE_ABILITY_SHIFT then
static constant integer PAGE_UP = 'Apup'
static constant integer PAGE_DOWN = 'Apdn'
endif
static if ENABLE_ITEM_SHIFT then
static constant integer PAGE_UP_ITEM = 'Ipup'
static constant integer PAGE_DOWN_ITEM = 'Ipdn'
static constant integer PAGE_UP_SLOT = 4
static constant integer PAGE_DOWN_SLOT = 5
endif

static if ENABLE_KEY_SHIFT then
private static method filter takes nothing returns boolean
local thistype this = Libram(GetUnitUserData(GetFilterUnit()))
if this.caster != null then
if thistype.ev == EVENT_PLAYER_ARROW_UP_DOWN then
call this.shiftPages(this.curr.next)
elseif thistype.ev == EVENT_PLAYER_ARROW_DOWN_DOWN then
call this.shiftPages(this.curr.prev)
endif
endif
return false
endmethod
endif

static timer BuffRemoval = CreateTimer()
static integer RemoveBuffMax = 0
static unit array RemoveBuff

static method RemoveBuffs takes nothing returns nothing
loop
exitwhen RemoveBuffMax == 0
call UnitRemoveAbility(RemoveBuff[RemoveBuffMax], PAGE_UP_BUFF)
call UnitRemoveAbility(RemoveBuff[RemoveBuffMax], PAGE_DOWN_BUFF)
set RemoveBuffMax = RemoveBuffMax - 1
endloop
endmethod

static method onShift takes nothing returns boolean
local unit cast = GetTriggerUnit()
local thistype this = GetUnitUserData(cast)
local integer id = GetSpellAbilityId()

if cast == null then
static if ENABLE_KEY_SHIFT then
set thistype.ev = GetTriggerEventId()
call GroupEnumUnitsSelected(thistype.G,GetTriggerPlayer(),Condition(function thistype.filter))
return false
endif
endif
static if ENABLE_ABILITY_SHIFT then
if id == thistype.PAGE_UP or id == thistype.PAGE_DOWN then
set RemoveBuffMax = RemoveBuffMax + 1
set RemoveBuff[RemoveBuffMax] = cast
call TimerStart(thistype.BuffRemoval,0,false,function thistype.RemoveBuffs)
if id == thistype.PAGE_UP then
if UnitRemoveAbility(cast,id) then
call UnitAddAbility(cast,id)
endif
call this.shiftPages(this.curr.next)
elseif id == thistype.PAGE_DOWN then
call this.shiftPages(this.curr.prev)
endif
set cast = null
return false
endif
endif
static if ENABLE_ITEM_SHIFT then
set id = GetItemTypeId(GetManipulatedItem())
if id != 0 then
set RemoveBuffMax = RemoveBuffMax + 1
set RemoveBuff[RemoveBuffMax] = cast
call TimerStart(thistype.BuffRemoval,0,false,function thistype.RemoveBuffs)
if id == thistype.PAGE_UP_ITEM then
call this.shiftPages(this.curr.next)
elseif id == thistype.PAGE_DOWN_ITEM then
call this.shiftPages(this.curr.prev)
endif
endif
endif
return false
endmethod

static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 11
loop
if GetPlayerSlotState(Player(i))==PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(i))==MAP_CONTROL_USER then
static if ENABLE_ABILITY_SHIFT then
call TriggerRegisterPlayerUnitEvent(t,Player(i),EVENT_PLAYER_UNIT_SPELL_EFFECT,null)
endif
static if ENABLE_ITEM_SHIFT then
call TriggerRegisterPlayerUnitEvent(t,Player(i),EVENT_PLAYER_UNIT_USE_ITEM,null)
endif
static if ENABLE_KEY_SHIFT then
call TriggerRegisterPlayerEvent(t,Player(i),EVENT_PLAYER_ARROW_UP_DOWN)
call TriggerRegisterPlayerEvent(t,Player(i),EVENT_PLAYER_ARROW_DOWN_DOWN)
endif
endif
exitwhen i == 0
set i = i - 1
endloop
call TriggerAddCondition(t,Condition(function thistype.onShift))
endmethod
endmodule

endlibrary
You do not have the required permissions to view the files attached to this post.

Return to “Systems”

×