Name | Type | is_array | initial_value |
//TESH.scrollpos=87
//TESH.alwaysfold=0
/*
Never cnp systems from a demo map as the systems in the demo map may not be the latest versions.
Installation:
Go to the thread specified by the link and copy the JASS script found there.
Create a new trigger in your map, convert it to custom text, and then paste
the script into it.
Required Systems:
BigInt hiveworkshop.com/forums/jass-functions-413/system-bigint-188973/
This is used to handle extremely large numbers that normally can't
be handled by Warcraft 3. A save/load code is essentially a ton of
values all mashed together. Old save/load systems just put them side
by side, but Encoder uses actual math to mash them together into an
actual number via BigInt so that the code is as small as possible.
QueueQueue hiveworkshop.com/forums/submissions-414/snippet-queuequeue-190890/
A special type of tree structure. This is the thing that makes Encoder
2 so superior to any save/load system ever created before. PipeDream's
save/load system at wc3c.net used a BigInt library, but no save/load
system has ever used a QueueQueue before Encoder 2. This essentially
allows Encoder 2 to build objects rather than just save a list of values.
This means that values may or may not be in a code depending on the
object saved! This demo map has a range of 32 to 57 chars for codes
because of the QueueQueue. The maximal data is 4 chars for security
and the 53 chars of data that is as compressed as possible. This provides
endless possibilities for save/load, like item charges and hero
specific abilities.
Base hiveworkshop.com/forums/jass-functions-413/snippet-base-188814/
This stores character collections. Save/load codes typically aren't
shown in base 10 (0123456789), but in some obscure base.
Ascii hiveworkshop.com/forums/jass-functions-413/snippet-ascii-190746/
Handles ascii (characters like 'c' and 'a'). This is primarily used
by Base to prevent StringHash collisions.
Table hiveworkshop.com/forums/jass-functions-413/snippet-new-table-188084/
1 hashtable for the entire map. Used by Base to handle character to
ordinal value conversion.
These two can be changed (*Advanced*)
These are used within the security functions, which are found in the settings.
Changing these changes how security is done in Encoder.
KnuthChecksum hiveworkshop.com/forums/1846246-post343.html
Generates a checksum for BigInt, which prevents tampering.
You can create your own checksum algorithm if you so desire.
Scrambler hiveworkshop.com/forums/submissions-414/snippet-salt-189766/
Obsfucates a BigInt at the binary level and it makes the BigInt
player unique. You can use your own obsfucation technique if
you desire.
Recommended Systems:
Catalog http://www.hiveworkshop.com/forums/submissions-414/snippet-catalog-192452/
Save/load systems, for the most part, require catalogs. Catalog store things
like raw ids into big tables so that the table ids can be used in the codes instead.
For example, 'hpea', a raw id, is much larger than 3, a possible catalog id. This
is one technique of compression. The Catalog system is the premier system system
for doing catalogs.
UnitStatePercent http://www.hiveworkshop.com/forums/submissions-414/snippet-unitstatepercent-189943/
This retrieves coordinates, xp, life, and mana as percents. Things like xp and
locations have very large ranges. Accuracy doesn't matter as much with them (.01%
xp lost won't even make much of a difference). Because of this, they can use a
type of compression called lossy compression. The technique used in this case to
pull it off is simple percents. The x,y coordinates are percents of the world
bounds (max x,y coords) and xp is a percent of the current level (100/200 -> 50).
Most ORPGs don't even bother saving xp, which is kind of important. I know I'd
be pretty upset to lose 50% xp on a high level character because I had to leave
before I could get the next level.
WorldBounds http://www.hiveworkshop.com/forums/jass-functions-413/snippet-worldbounds-180494/
A script that simply stores the max x,y and min x,y coords of the map. Also
includes a world rect and region. This is used by UnitStatePercent for its
percent coordinates.
Lua scripts-
----------------------------------------------------------
Lua scripts require special installation (not a simple cnp)
LUA_FILE_HEADER http://www.hiveworkshop.com/forums/jass-functions-413/snippet-lua_file_header-186775/
Dynamic script used by UnitStatePercent. Read the mini tut at the top
to learn how to install. This is the framework for all Lua scripts. Mini tut also
includes instructions on how to install other types of Lua scripts running on
this framework.
If you have trouble with the mini tut, you can try Purge's tut (very good)
hiveworkshop.com/forums/tutorial-submission-283/lua-object-generation-191740/
LUA_GET_VAR_OBJECT http://www.hiveworkshop.com/forums/jass-functions-413/snippet-lua_get_var_object-185944/
Generates objects. Used by UnitStatePercent See LUA_FILE_HEADER mini tut or
Purge's tut for instructions on how to install.
*/
//TESH.scrollpos=0
//TESH.alwaysfold=0
library BigInt /* v1.1.4.7
*************************************************************************************
*
* Used for creating very large integers in any base. Stores in linked list.
*
*************************************************************************************
*
* */uses/*
*
* */ Base /* hiveworkshop.com/forums/submissions-414/snippet-base-188814/
*
*************************************************************************************
*
* struct BigInt extends array
*
* Base base
* - The current base of the integer
* - Changing this value will convert the BigInt value into another base
*
* integer digit
* - Specific digit within BigInt
* readonly BigInt next
* - Used for iterating over digits
* - Goes from first placehold to last
* - Looping through 10 would be 0 to 1
* readonly BigInt previous
* - Used for iterating over digits
* - Goes from last placeholder to first
* - Looping through 10 would be 1 to 0
* readonly boolean end
* - The head, the pointer that represents the BigInt
* - Does not store a value, exit loop when this is true
*
* static method create takes Base base returns BigInt
* - Creates a new BigInt in a base
* - Semi small operation
* method destroy takes nothing returns nothing
* - Destroys a BigInt. Must pass in the integer pointer or this
* - will bug the rest of the system.
* - Very small operation.
*
* method add takes integer value, integer extraPower returns nothing
* - Integer will be added as base 10 integers, meaning that they will
* - be converted into the base. If wanting to add integers in the same
* - base, convert it before hand. 0x and 0 notation for hexadecimal
* - and octal are very useful as well as they work with the integers
* - in an already converted state.
* -
* - value and extraPower must be greater than 0
* -
* - extraPower refers to value^(1+extraPower)
* method multiply takes integer value returns nothing
* - Multiplies an integer. Value is treated as a base 10 integer.
* method divide takes integer value returns integer
* - Divides an integer by an integer. Value is treated as a base10 integer.
* -
* - Returns remainder
* method mod takes integer k returns integer
* - Returns the modulo of a BigInt given k as a divisor.
*
* method addBig takes BigInt integerToAdd, integer extraPower returns nothing
* - Adds BigInt integerToAdd to BigInt
* method multiplyBig takes BigInt integerToAdd returns nothing
* - Multiplies BigInt by BigInt integerToAdd
*
* method push takes integer value returns nothing
* - pushes a base 10 integer on to the right side of BigInt
* - and converts that base 10 number into the BigInt's base
* method pop takes nothing returns integer
* - pop does the reverse of push and returns the popped digit
* - (see pop @google)
* method enq takes integer value returns nothing
* - pushes base 10 integer to the left side of the number
* method deq takes nothing returns integer
* - deq does the reverse of enq and returns popped digit
* method rl takes nothing returns nothing
* - Rotates number left
* method rr takes nothing returns nothing
* - Rotates number right
*
* method copy takes nothing returns BigInt
* - Returns a copy of the BigInt
*
* method toString takes nothing returns string
* - converts an integer into a string (extremely useful)
* -
* - if working in hexadecimal and there was a value like
* - C1H4, it'd actually return "C1H4"
* -
* - string conversions use the actual Base to perform the
* - character conversions
* method toInt takes nothing returns integer
* - returns the value stored in the BigInt as an integer.
* - only use when the value can be stored within an integer.
* - one common use might be retrieving the last value in a save/load
* - code.
* static method convertString takes string value, Base base returns BigInt
* - converts a string into an BigInt
* -
* - if working with hexadecimal and inputted "C1H4", it would
* - return an BigInt containing C1H4.
* -
* - Returns 0 if the string value contains invalid characters
*
*************************************************************************************
*
* Error Messages
*
* Thread crash error messages output the trigger that crashed.
* Feel free to post a message up for the resource about the crashed trigger
* including the trigger name.
*
* To find the specific method that crashed, do CTRL+F trigger name two times
* (should be at the onInit method). From there, look at the method that's
* added to the trigger and then CTRL+F that method.
*
* Finding t-
* private trigger t = CreateTrigger()
* call TriggerAddCondition(t, Condition(function thistype.cl))
* private static method cl takes nothing returns boolean
*
* Overflow errors have to do with too many allocated digits. If running into these, the numbers
* are just too large. This has been tested with 61*62^120 (base 62 number) converted to binary and
* back, so it can handle extremely large digits (binary number was over 700 digits)
*
*************************************************************************************/
/************************************************************************************
*
* Code
*
* if you want to read the code, my suggestion is to not do it
* this system performs operations digit by digit, meaning the algorithms
* are ugly
*
* the code is optimized, meaning the variable names aren't descriptive
* the point is that it works and it's optimization is based on a balance
* between minimizing counts towards the op limit and actual speed
*
************************************************************************************/
globals
private integer i=0 //instance count
private integer array n //next
private integer array p //previous
private integer array v //value
private Base array b //base of number
private boolean array e //is last
//bundle of random triggers and trigger args
private trigger j=CreateTrigger()
private trigger x=CreateTrigger()
private trigger x4=CreateTrigger()
private trigger x5=CreateTrigger()
private trigger y0=CreateTrigger()
private trigger y6=CreateTrigger()
private trigger y7=CreateTrigger()
private trigger y8=CreateTrigger()
private trigger y9=CreateTrigger()
private trigger x1=CreateTrigger()
private trigger x2=CreateTrigger()
private integer td=0
private integer my=0
private integer my3=0
private integer td2=0
private string yy=""
private integer dz
endglobals
private module IntMod
private static method onInit takes nothing returns nothing
call TriggerAddCondition(j,Condition(function thistype.ch))
call TriggerAddCondition(x,Condition(function thistype.ml))
call TriggerAddCondition(x4,Condition(function thistype.div))
call TriggerAddCondition(x5,Condition(function thistype.s2))
call TriggerAddCondition(y0,Condition(function thistype.a0))
call TriggerAddCondition(y7,Condition(function thistype.m0))
call TriggerAddCondition(y6,Condition(function thistype.tos))
call TriggerAddCondition(y8,Condition(function thistype.c0))
call TriggerAddCondition(y9,Condition(function thistype.a1))
call TriggerAddCondition(x1,Condition(function thistype.m1))
call TriggerAddCondition(x2,Condition(function thistype.m2))
endmethod
endmodule
struct BigInt extends array
//useful for loading into a buffer
method operator previous takes nothing returns thistype
return p[this]
endmethod
method operator next takes nothing returns thistype
return n[this]
endmethod
method operator digit takes nothing returns integer
return v[this]
endmethod
method operator digit= takes integer y returns nothing
set v[this] = y
endmethod
method operator end takes nothing returns boolean
return e[this]
endmethod
//copy
private static method c0 takes nothing returns boolean
local integer y
local integer z
local integer q
local integer k=td
if (0==n[0]) then
set i=i+1
set z=i
else
set z=n[0]
set n[0]=n[z]
endif
set e[z]=true
set b[z]=b[k]
set v[z]=0
set q=z
loop
set k=n[k]
exitwhen e[k]
if (0==n[0]) then
set i=i+1
set y=i
else
set y=n[0]
set n[0]=n[y]
endif
set n[q]=y
set p[y]=q
set v[y]=v[k]
set q=y
endloop
set p[z]=q
set n[q]=z
set dz=z
return true
endmethod
method copy takes nothing returns thistype
set td=this
//call c0
static if DEBUG_MODE then
if (not TriggerEvaluate(y8)) then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"THREAD CRASH BIG_INT ERROR: y8")
endif
else
call TriggerEvaluate(y8)
endif
return dz
endmethod
//addBig
private static method a1 takes nothing returns boolean
local integer y=td
local integer a
local integer z=b[y].size
local integer q=0
local integer m
local integer g=dz
local integer k=my
loop
if (e[n[y]]) then
if (0==n[0]) then
set i=i+1
set a=i
else
set a=n[0]
set n[0]=n[a]
endif
set p[a]=y
set n[a]=td
set n[y]=a
set p[td]=a
set v[a]=0
endif
set y=n[y]
exitwhen 0==g
set g=g-1
endloop
loop
set k=n[k]
set v[y]=v[y]+v[k]
set m=y
loop
exitwhen z>v[m]
set q=v[m]/z
set v[m]=v[m]-v[m]/z*z
if (e[n[m]]) then
if (0==n[0]) then
set i=i+1
set a=i
else
set a=n[0]
set n[0]=n[a]
endif
set p[a]=m
set n[a]=td
set n[m]=a
set p[td]=a
set v[a]=0
endif
set m=n[m]
set v[m]=v[m]+q
endloop
exitwhen e[n[k]]
if (e[n[y]]) then
if (0==n[0]) then
set i=i+1
set a=i
else
set a=n[0]
set n[0]=n[a]
endif
set p[a]=y
set n[a]=td
set n[y]=a
set p[td]=a
set v[a]=0
endif
set y=n[y]
endloop
return true
endmethod
method addBig takes BigInt k,integer g returns nothing
debug if (0<=g and b[k].size==b[this].size) then
if (0<v[p[k]]) then
set td=this
set my=k
set dz=g
//call a1
static if DEBUG_MODE then
if (not TriggerEvaluate(y9)) then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"THREAD CRASH BIG_INT ERROR: y9")
endif
else
call TriggerEvaluate(y9)
endif
endif
debug else
debug if (b[k].size!=b[this].size) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"BIG_INT ERROR: "+I2S(this)+" base not equal to "+I2S(k))
debug endif
debug if (0>g) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"BIG_INT ERROR: "+I2S(this)+" attempt to add -power "+I2S(g))
debug endif
debug endif
endmethod
private static integer array zs
//multiplyBig
private static method m2 takes nothing returns boolean
local integer q=td2
local integer m=dz
local integer a
local integer k=my3
loop
set q=q-1
if (e[n[m]]) then
if (0==n[0]) then
set i=i+1
set a=i
else
set a=n[0]
set n[0]=n[a]
endif
set p[a]=m
set n[a]=td
set n[m]=a
set p[td]=a
set v[a]=0
endif
set m=n[m]
set v[m]=v[m]+zs[q]*v[k]
exitwhen 0==q
endloop
return true
endmethod
//multiplyBig
private static method m1 takes nothing returns boolean
local integer y=0
local integer q=0
local integer a=td
local integer m=a
local integer w=a
local integer k=my
loop
set a=p[a]
exitwhen e[a]
set zs[y]=v[a]
set y=y+1
endloop
set n[p[a]]=n[0]
set n[0]=n[a]
set n[a]=a
set p[a]=a
loop
set k=n[k]
exitwhen e[k]
set td2=y
set w=n[w]
set dz=w
set my3=k
//call m2
static if DEBUG_MODE then
if (not TriggerEvaluate(x2)) then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"THREAD CRASH BIG_INT ERROR: x2")
endif
else
call TriggerEvaluate(x2)
endif
endloop
set y=0
set a=td
set w=a
set q=a
set k=b[a].size
set m=a
loop
if (e[n[a]]) then
if (0==n[0]) then
set i=i+1
set m=i
else
set m=n[0]
set n[0]=n[m]
endif
set p[m]=a
set n[m]=w
set n[a]=m
set p[w]=m
set v[m]=0
endif
set a=n[a]
set y=y+v[a]
set v[a]=y-y/k*k
set y=y/k
exitwhen e[n[a]] and 0==y
endloop
return true
endmethod
method multiplyBig takes BigInt k returns nothing
debug if (b[k]==b[this]) then
if (0<v[p[k]]) then
set td=this
set my=k
//call m1
static if DEBUG_MODE then
if (not TriggerEvaluate(x1)) then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"THREAD CRASH BIG_INT ERROR: x1")
endif
else
call TriggerEvaluate(x1)
endif
elseif (0==v[p[k]] and not e[p[this]]) then
set n[p[this]]=0
set n[0]=n[this]
set n[this]=this
set p[this]=this
endif
debug elseif (b[k]!=b[this]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"BIG_INT ERROR: "+I2S(this)+" base not equal to "+I2S(k))
debug endif
endmethod
static method create takes Base k returns thistype
local integer y
local integer z
//allocate a head
if (0==n[0]) then
set i=i+1
set z=i
else
set z=n[0]
set n[0]=n[z]
endif
set e[z]=true
set b[z]=k
set n[z]=z
set p[z]=z
set v[z]=0
return z
endmethod
//add
private static method a0 takes nothing returns boolean
local integer y=td
local integer a
local integer z=my3
local integer k=td2
//first go to the correct digit
//z refers to the *extra* g, so just loop from right to left
//until no remaining g
//1 g of 1 in base 10 would actually be 1*10^1, or 10
loop
if (e[n[y]]) then
if (0==n[0]) then
set i=i+1
set a=i
else
set a=n[0]
set n[0]=n[a]
endif
set p[a]=y
set n[a]=td
set n[y]=a
set p[td]=a
set v[a]=0
endif
set y=n[y]
exitwhen 0==z
set z=z-1
endloop
set z=b[td].size
//this will add the digit to the array
//example in base 10 of 10+13
//{1,0}+13p0 (1,0+13) (d being digit to add to)
//{1,13}+0d1 (13/10=1, 13%10=3)
//{1,3}+1d1 (1+1,3)
//{2,3}+0d2 (exit as 2 < 10) -> (exitwhen v[y] < z)
loop
set v[y]=v[y]+k
exitwhen z>v[y]
set k=v[y]/z
set v[y]=v[y]-k*z
if (e[n[y]]) then
if (0==n[0]) then
set i=i+1
set a=i
else
set a=n[0]
set n[0]=n[a]
endif
set p[a]=y
set n[a]=td
set n[y]=a
set p[td]=a
set v[a]=0
endif
set y=n[y]
endloop
return true
endmethod
//adds k to number
//k may be any positive whole number
method add takes integer k,integer g returns nothing
debug if 0<=g then
if (0<k) then
set td=this
set my3=g
set td2=k
static if DEBUG_MODE then
//call a0 (directly above)
if (not TriggerEvaluate(y0)) then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"THREAD CRASH BIG_INT ERROR: y0")
endif
else
call TriggerEvaluate(y0)
endif
endif
debug endif
endmethod
//multiply
private static method ml takes nothing returns boolean
local integer y=td
local integer z=b[td].size
local integer a=0
local integer k=my
local integer q
//first multiply every single digit by the multiplier
loop
set y=n[y]
exitwhen e[y]
set v[y]=v[y]*k
endloop
set y=td
//loop through the number and re add any digits that are >= the base
//efficient adding as the g is already known (g is current node +1)
loop
set y=n[y]
exitwhen e[y]
set q=y
loop
exitwhen z>v[q]
if (e[n[q]]) then
if (0==n[0]) then
set i=i+1
set a=i
else
set a=n[0]
set n[0]=n[a]
endif
set p[a]=q
set n[a]=td
set n[q]=a
set p[td]=a
set v[a]=0
endif
set v[n[q]]=v[n[q]]+v[q]/z
set v[q]=v[q]-v[q]/z*z
endloop
endloop
return true
endmethod
method multiply takes integer k returns nothing
if (0<k) then
if (0<v[p[this]]) then
set td=this
set my=k
//call ml
static if DEBUG_MODE then
if (not TriggerEvaluate(x)) then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"THREAD CRASH BIG_INT ERROR: x")
endif
else
call TriggerEvaluate(x)
endif
endif
elseif (0==k and not e[p[this]]) then
set n[p[this]]=n[0]
set n[0]=n[this]
set n[this]=this
set p[this]=this
endif
endmethod
//adds number to left
method enq takes integer k returns nothing
local integer y=p[this]
local integer z
local integer a=b[this].size
//add the digit to itself, this way it doesn't mix with
//the current number and it is grouped properly into the base
loop
if (0==n[0]) then
set i=i+1
set z=i
else
set z=n[0]
set n[0]=n[z]
endif
set p[z]=y
set n[z]=n[y]
set n[y]=z
set p[n[z]]=z
set v[z]=k
set y=z
exitwhen a>v[y]
set k=v[y]/a
set v[y]=v[y]-k*a
endloop
endmethod
//removes number from left
method deq takes nothing returns integer
local thistype z=p[this]
if (not e[z]) then
set p[this]=p[z]
set n[p[z]]=this
set n[z]=n[0]
set n[0]=z
endif
return v[z]
endmethod
//pushes number on to number
//push(10,10) = 1010
method push takes integer k returns nothing
local integer y=this
local integer z
local integer a=b[this].size
//add the digit to itself, this way it doesn't mix with
//the current number and it is grouped properly into the base
loop
if (0==n[0]) then
set i=i+1
set z=i
else
set z=n[0]
set n[0]=n[z]
endif
set p[z]=y
set n[z]=n[y]
set n[y]=z
set p[n[z]]=z
set v[z]=k
set y=z
exitwhen a>v[y]
set k=v[y]/a
set v[y]=v[y]-k*a
endloop
endmethod
//simply pops off the right most digit and returns it
method pop takes nothing returns integer
local thistype z=n[this]
if (not e[z]) then
set n[this]=n[z]
set p[n[z]]=this
set n[z]=n[0]
set n[0]=z
endif
return v[z]
endmethod
//rotate right
method rr takes nothing returns nothing
local integer z
set z=p[this]
set n[z]=n[this]
set p[n[z]]=z
set p[this]=p[z]
set n[p[z]]=this
set p[z]=this
set n[this]=z
endmethod
//rotate left
method rl takes nothing returns nothing
local integer z
set z=n[this]
set p[z]=p[this]
set n[p[z]]=z
set n[this]=n[z]
set p[n[z]]=this
set n[z]=this
set p[this]=z
endmethod
//mod
private static method m0 takes nothing returns boolean
local integer z=0
local integer q=td
local integer u=b[q].size
local integer k=my
loop
set q=p[q]
exitwhen e[q]
set z=(z*u+v[q])
set z=z-z/k*k
endloop
set dz=z
return true
endmethod
method mod takes integer k returns integer
set td=this
set my=k
//call m0
static if DEBUG_MODE then
if not TriggerEvaluate(y7) then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"THREAD CRASH BIG_INT ERROR: y7")
endif
else
call TriggerEvaluate(y7)
endif
return dz
endmethod
//destroys the entire integer
method destroy takes nothing returns nothing
debug if (e[this]) then
set n[p[this]]=n[0]
set n[0]=this
set e[this]=false
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"BIG_INT ERROR: ATTEMPT TO DESTROY NULL BIG INT "+I2S(this))
debug endif
endmethod
//toString
private static method tos takes nothing returns boolean
local string q=""
local integer y=td
local Base z=b[y]
//loop through the entire number and convert each integer into a
//char
loop
set y=n[y]
exitwhen e[y]
set q=z.char(v[y])+q
endloop
if (q=="") then
set yy=z.char(0)
else
set yy=q
endif
return true
endmethod
method toString takes nothing returns string
set td=this
//call tos
static if DEBUG_MODE then
if not TriggerEvaluate(y6) then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"THREAD CRASH BIG_INT ERROR: y6")
endif
else
call TriggerEvaluate(y6)
endif
return yy
endmethod
method operator base= takes Base k returns nothing
if (b[this].size!=k.size and not e[n[this]]) then
set td=this
set td2=k
//call ch
static if DEBUG_MODE then
if not TriggerEvaluate(j) then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"THREAD CRASH BIG_INT ERROR: j")
endif
else
call TriggerEvaluate(j)
endif
endif
set b[this]=k
static if DEBUG_MODE then
if (8191<i) then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"OVERFLOW BIG_INT ERROR: "+I2S(i))
endif
endif
endmethod
//convert to any base
private static method ch takes nothing returns boolean
local integer q=td
local integer u
local integer k
//first allocate a new big int to perform operations on
if (0==n[0]) then
set i=i+1
set k=i
else
set k=n[0]
set n[0]=n[k]
endif
set e[k]=true
set u=p[q]
set p[q]=p[u]
set p[k]=u
set n[k]=u
set p[u]=k
set n[u]=k
set b[k]=td2
set v[k]=0
set my=Base(b[td]).size
set my3=0
set td=k
set td2=v[u]
set v[u]=0
//loop through the number from left to right
//add current digit to the new big int
//exitwhen out of digits
//multiply new big int by current base of number, not the target base
//no need to allocate new digits as that's done in add/multiply
loop
//call add
static if DEBUG_MODE then
if not TriggerEvaluate(y0) then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"THREAD CRASH BIG_INT ERROR: y0")
endif
else
call TriggerEvaluate(y0)
endif
exitwhen e[p[q]]
//call multiply
static if DEBUG_MODE then
if not TriggerEvaluate(x) then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"THREAD CRASH BIG_INT ERROR: x")
endif
else
call TriggerEvaluate(x)
endif
//go to next digit and deallocate it
set u=p[q]
set p[q]=p[u]
set td2=v[u]
set n[u]=n[0]
set n[0]=u
endloop
//make number point to digits in the new big int that was worked on
//then deallocate the new big int
set n[q]=n[k]
set p[q]=p[k]
set p[n[k]]=q
set n[p[k]]=q
set n[k]=n[0]
set n[0]=k
set e[k]=false
return true
endmethod
//only use when big int is holding value that can fit into an integer
method toInt takes nothing returns integer
local integer k=0
local integer z=b[this].size
loop
set this=p[this]
exitwhen e[this]
set k=k*z
set k=k+v[this]
endloop
return k
endmethod
//divide
//done via long division, but nested loops split into two methods,
//so can't really be commented on in a way that's understandable
//it goes from left to right, just like in long division, dividing
//each digit by w/e and using the remainders in the new number
//returns the last remainder
//does not perform any subtraction! It's all modulos math ;D
private static method div takes nothing returns boolean
local integer z=0
local integer a=td
local integer y=a
local integer h=b[a].size
local integer k=my
set y=p[y]
loop
set z=z*h+v[y]
exitwhen e[p[y]] or z>=k
set n[y]=n[0]
set n[0]=y
set y=p[y]
endloop
set p[a]=y
set n[y]=a
loop
set v[y]=z/k
set z=z-v[y]*k
set y=p[y]
exitwhen e[y]
set z=z*h+v[y]
endloop
set y=a
loop
set y=p[y]
exitwhen 0!=v[y] or e[y]
set n[y]=n[0]
set n[0]=y
endloop
set p[a]=y
set n[y]=a
set my=z
return true
endmethod
//returns remainder
method divide takes integer k returns integer
if (0<k and 0<v[p[this]]) then
set td=this
set my=k
static if DEBUG_MODE then
if not TriggerEvaluate(x4) then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"THREAD CRASH BIG_INT ERROR: x4")
endif
else
call TriggerEvaluate(x4)
endif
else
return 0
endif
return my
endmethod
private static method s2 takes nothing returns boolean
local Base d=td
local string k=yy
local integer y
local integer z
local integer h=StringLength(k)
if (not d.isValid(k)) then
set td=0
return true
endif
if (0==n[0]) then
set i=i+1
set z=i
else
set z=n[0]
set n[0]=n[z]
endif
set e[z]=true
set b[z]=d
set n[z]=z
set p[z]=z
set v[z]=0
loop
set h=h-1
if (0==n[0]) then
set i=i+1
set y=i
else
set y=n[0]
set n[0]=n[y]
endif
set v[y]=d.ord(SubString(k,h,h+1))
set p[y]=p[z]
set n[y]=z
set n[p[z]]=y
set p[z]=y
exitwhen 0==h
endloop
set td=z
return true
endmethod
static method convertString takes string k,Base y returns thistype
set yy=k
set td=y
//call s2
static if DEBUG_MODE then
if not TriggerEvaluate(x5) then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"THREAD CRASH BIG_INT ERROR: x5")
endif
else
call TriggerEvaluate(x5)
endif
return td
endmethod
method operator base takes nothing returns Base
return b[this]
endmethod
implement IntMod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Base /* v1.0.3.1
*************************************************************************************
*
* A script used for base conversion where integers are represented as strings in
* another base.
*
*************************************************************************************
*
* */uses/*
*
* */ Ascii /* wc3c.net/showthread.php?t=110153
* */ Table /* hiveworkshop.com/forums/jass-functions-413/snippet-new-table-188084/
*
************************************************************************************
*
* struct Base extends array
*
* static method operator [] takes string base returns Base
*
* method convertToString takes integer i returns string
* method convertToInteger takes string i returns integer
*
* method ord takes string c returns integer
* method char takes integer i returns string
*
* method isValid takes string value returns boolean
* - determines if all of the characters in the string are valid base character
*
*************************************************************************************/
/*************************************************************************************
*
* Code
*
*************************************************************************************/
globals
private Table gt=0 //stacks of strings with same hashes
private integer array n //next node pointer for gt stack
private string array b //base of string
private Table array t //base character table
private integer c=0 //base instance count
private integer array s //base size
endglobals
private module Init
private static method onInit takes nothing returns nothing
set gt=Table.create()
endmethod
endmodule
struct Base extends array
debug private static boolean array a //is allocated
static method operator [] takes string base returns thistype
local integer value //string hash value
local string char //iterated character
local integer i=0 //this
local integer v //stack of hashes
local integer dv //copy of v
debug if (1<StringLength(base)) then
set value = StringHash(base) //first get the hash
set i = gt[value] //get first node of hash table
set v = i //copy
if (0!=i) then //if stack exists, then loop through
loop
exitwhen 0==i or base==b[i]
set i=n[i]
endloop
endif
//if this still doesn't exist, create it
if (0==i) then
//allocate
set c=c+1
set i=c
set dv=v
debug set a[i]=true
set t[i]=Table.create() //character table
set b[i]=base //base string
//value is now used for iterating through the base string
set value=StringLength(base)
set s[i]=value
loop
set value=value-1
set char=SubString(base,value,value+1)
set v=Char2Ascii(char)
//if the character already exists, stop
//and deallocate (invalid base)
debug if (t[i].has(v)) then
debug call t[i].destroy() //destroy character table
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"BASE CREATION ERROR: "+char+" MULTIPLY DEFINED")
debug set c=c-1
debug set a[i]=false
debug return 0
//character doesn't exist
debug else
set t[i][v]=value
set t[i].string[-value]=char
debug endif
exitwhen 0==value
endloop
//if dv is 0, then allocate dv
if (0==dv) then
set gt[value]=i
//otherwise add i to hash stack
else
set n[i]=n[dv]
set n[dv]=i
endif
endif
return i
debug endif
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"BASE CREATION ERROR: "+base+" IS INVALID")
debug return 0
endmethod
method convertToString takes integer i returns string
local integer k=s[this]
local string n=""
debug if (a[this]) then
debug if (0<=i) then
loop
exitwhen i<k
set n=t[this].string[-(i-i/k*k)]+n
set i=i/k
endloop
return t[this].string[-i]+n
debug endif
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"BASE CONVERSION ERROR: "+I2S(i)+" IS OUT OF BOUNDS")
debug return null
debug endif
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"BASE CONVERSION ERROR: "+I2S(this)+" IS NOT ALLOCATED")
debug return null
endmethod
method convertToInteger takes string i returns integer
local integer n=0
local integer p=StringLength(i)
local integer l=0
local integer k=s[this]
local string char
debug if (a[this]) then
loop
exitwhen 0==p
set p=p-1
set l=l+1
set char=SubString(i,l-1,l)
debug if (t[this].has(Char2Ascii(char))) then
set n=n+t[this][Char2Ascii(char)]*R2I(Pow(k,p))
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"BASE CONVERSION ERROR: "+char+" IS OUT OF BOUNDS")
debug return 0
debug endif
endloop
return n
debug endif
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"BASE CONVERSION ERROR: "+I2S(this)+" IS NOT ALLOCATED")
debug return 0
endmethod
method ord takes string c returns integer
debug if (a[this]) then
debug if (1<StringLength(c) or ""==c or null==c or not (t[this].has(Char2Ascii(c)))) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"BASE ORD ERROR: "+c+" IS OUT OF BOUNDS")
debug return 0
debug endif
return t[this][Char2Ascii(c)]
debug endif
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"BASE ORD ERROR: "+I2S(this)+" IS NOT ALLOCATED")
debug return 0
endmethod
method char takes integer i returns string
debug if (a[this]) then
debug if (i<s[this] and 0<=i) then
return t[this].string[-i]
debug endif
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"BASE CHAR ERROR: "+I2S(i)+" IS OUT OF BOUNDS")
debug return null
debug endif
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"BASE CHAR ERROR: "+I2S(this)+" IS NOT ALLOCATED")
debug return null
endmethod
method isValid takes string s returns boolean
local integer i=StringLength(s)
local string c
if (0<i) then
loop
set c=SubString(s,i-1,i)
if (not t[this].has(Char2Ascii(c))) then
return false
endif
set i=i-1
exitwhen 0==i
endloop
else
return false
endif
return true
endmethod
method operator size takes nothing returns integer
return s[this]
endmethod
implement Init
endstruct
endlibrary
//TESH.scrollpos=1318
//TESH.alwaysfold=0
library Encoder /* v3.0.1.2
*************************************************************************************
*
* Save/Load system
*
*************************************************************************************
* */uses/*
*
* */ BigInt /* hiveworkshop.com/forums/jass-functions-413/system-bigint-188973/
* */ QueueQueue /* hiveworkshop.com/forums/submissions-414/snippet-queuequeue-190890/
*
* These two can be changed (*Advanced*)
* */ KnuthChecksum /* hiveworkshop.com/forums/1846246-post343.html
* */ Scrambler /* hiveworkshop.com/forums/submissions-414/snippet-salt-189766/
*
* Used in settings functions:
* private function Checksum takes BigInt k, integer m returns integer
* private function ApplyScramble takes BigInt k, integer pid returns nothing
* private function UnapplyScramble takes BigInt k, integer pid returns nothing
*
************************************************************************************
*
* SETTINGS
*/
private keyword b10 //base 10
globals
/*************************************************************************************
*
* I suggest permutation of the following base for encoders
*
* 0123456789ABCDEFGHKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@#$%&?
*
*************************************************************************************/
/*************************************************************************************
*
* VER_BASE refers to the base used with encoder.toString()
*
*************************************************************************************/
private constant string VER_BASE="0123456789"
/*************************************************************************************
*
* Coloring Settings
*
*************************************************************************************/
private constant string NUM_COLOR="|cff40e0d0" //what to color numbers
private constant string LOWER_COLOR="|cffff69b4" //what to color lowercase characters
private constant string UPPER_COLOR="|cff00AA00" //what to color uppercase characters
private constant string SPEC_COLOR="|cffffff00" //what to color special characters
private constant string DELIMITER_COLOR="|cffffffff" //what to color DELIMITER characters
/*************************************************************************************
*
* Spacing Settings
*
*************************************************************************************/
private constant string DELIMITER="-" //DELIMITER to make code easier to read
private constant integer DELIMITER_COUNT=4 //how many characters per DELIMITER
/*************************************************************************************
*
* Encryption Settings
*
*************************************************************************************/
/*************************************************************************************
*
* SHUFFLES
*
* How many shuffles to perform in encoder
*
* Nust be greater than 0
*
*************************************************************************************/
private constant integer SHUFFLES=3
/*************************************************************************************
*
* CHECKSUM_VARIANCE
*
* Balanced value: .85
*
* The larger the variance value, the smaller the range of active checksums. A small range
* means that it is more likely for two players to have the same checksums.
*
* Smaller variance increases the range of active checksums, however it also increases the
* range of cehcksum strengths. This means that some checksums may be much weaker than others,
* which increases the chances for those players with weaker checksums to tamper with their
* code.
*
* Checksum strength should be about the same for each checksum and there should be enough
* active checksums that it is unlikely that two players will have te same checksum.
*
* .85 is a rather balanced value, but it can be increased for generally stronger checksums
* with smaller ranges or decreased for weaker checksums with wider ranges.
*
* Ex:
* .85 for a checksum of 238,609,294
*
* min: 202,817,899
* range: 35,791,395
*
* 1 in 35,791,395 checksums will work for a player and checksums will all be around same
* strength.
*
* .99 for a checksum of 238,609,294
*
* min: 236,223,201
* range: 2,386,093
*
* 1 in 2,386,093 checksums will work for a player and checksums will all be around same
* strength.
*
* .01 for a checksum of 238,609,294
*
* min: 2,386,092
* range: 236,223,202
*
* 1 in 236,223,202 will work for a player and checksums will have a wide range of strengths
* from weak to strong.
*
*************************************************************************************/
private constant real CHECKSUM_VARIANCE=.85
/*************************************************************************************
*
* PLAYER_CHECKSUM_SALT
*
* Player checksum salt refers to a value that is appended to a player's name when
* generating player hashes. A player's checksum salt helps determine the player's
* checksum for encoders.
*
* This value can be any string
*
* example: "29a\\~alf1!m~..."
*
*************************************************************************************/
private constant string PLAYER_CHECKSUM_SALT=""
endglobals
/*************************************************************************************
*
* Checksum
*
* This is the Checksum used for code security (makes modifications
* difficult). By default, this uses the Knuth Checksum, but
* that can be changed.
*
* BigInt k: number to get the checksum for
* integer m: dividend for modulos
*
* returns: nothing
*
*************************************************************************************/
private function Checksum takes BigInt k, integer m returns integer
return GetKnuthChecksum(k, m)
endfunction
/*************************************************************************************
*
* ApplyScramble
*
* This is essentially for scrambling the code given a player id.
* By default this uses my own scrambling algorithm.
* Because a player hash based on the player's username is used in my
* scrambling algorithm, this will make it so that a player can't load
* up the code of another player with 0 increase to the code size.
* This security alone is not enough to 100% guarantee the player unique
* codes.
*
* BigInt k: number to be scrambled
* integer pid: player id to scramble for
*
* returns: nothing
*
*************************************************************************************/
private function ApplyScramble takes BigInt k, integer pid returns nothing
call Shuffle(k, pid, SHUFFLES)
endfunction
/*************************************************************************************
*
* UnapplyScramble
*
* This is used to undo the scrambling on a number. This should
* revert the number back to what it was before it was scrambled.
*
* BigInt k: number to be unscrambled
* integer pid: player id to unscramble the number for
*
* returns: nothing
*
*************************************************************************************/
private function UnapplyScramble takes BigInt k, integer pid returns nothing
call Unshuffle(k, pid, SHUFFLES)
endfunction
/*
*******************************************************************
*
* struct CodeRange extends array
*
* - A slot that can store a value. These slots have a range of values they can store. The
* - range is from a low bound value to a high bound value. Slots are added to Encoder objects.
* - Specific ranges of slots can link to other slots (an item with 25 charges for example). Not
* - all slots can store values: some are purely pointers (an inventory slot for example which simply
* - points to 6 items).
*
* static method create takes integer lowBound, integer highBound returns CodeRange
* - Creates a new CodeRange that can be added to an Encoder and linked to. CodeRange objects
* - can be linked to multiple times and can link to as many other CodeRange objects as needed.
* - If the lowBound is equal to the highBound, then the CodeRange object returned is a pointer
* - object that can't store values. This can be useful for things like an inventory that simply
* - points to 6 item slots.
*
* - integer lowBound The minimum value that can be stored in the slot.
* - integer highBound The maximum value that can be stored in the slot.
* method link takes integer lowBound, integer highBound, CodeRange linkTo, integer customLinkId returns nothing
* - Links a CodeRange to another CodeRange. The link is only applied if the value that ends
* - up going into the CodeRange fits the link range. For example, if only heroes from 1 to 5 had
* - an inventory of 6, then the lowBound would be 1 and the highBound would be 5 for that link.
* - Passing in the minimal value and maximal values for a given slot does a link for all possible
* - values that can go into that slot.
*
* - integer lowBound The minimal value that can be in the slot to go into the link
* - integer highBound The maximal value that can be in the slot to go into the link
* - CodeRange linkTo The slot that is to be linked to
* - integer customLinkId A link id that can be used to infer current slot for save/load
* method linka takes CodeRange linkTo returns nothing
* - Links all possible values to a slot. Essentially just calls link with the minimum possible
* - value, maximum possible value, and a custom id of 0.
*
* - CodeRange linkTo The slot that is to be linked to
*
************************************************************************************
*
* struct DataBuffer extends array
*
* - The DataBuffer is used for reading and writing values.
* - When opening an Encoder, it is loaded into the DataBuffer
* - and then values can be read/written. An Encoder may be
* - opened for decompressing a code or for compressing a
* - collection of numbers into a code.
*
* readonly integer id
* - Returns the current custom link id (remember link and linka in CodeRange)
* - As slots inside of links may or may not exist (does value fit?), this is
* - a necessity so that a user can easily determine whether they are in a
* - questionable slot or not.
* - Can be used in read and write mode.
* readonly string code
* - Returns all of the values in the DataBuffer as a save/load code.
* - Can only be used when the DataBuffer is finalized.
* - Can be used in write mode.
*
* method write takes integer value returns nothing
* - Writes a value to the DataBuffer. Order of values is determined by the
* - loaded Encoder. For example, if a Hero, gold, and lumber slots were
* - added to the Encoder in that order, then the DataBuffer would expect
* - values fitting those ranges in that order. When all values are written,
* - the DataBuffer is finalized (meaning can't be written to) and the code
* - can be read.
* - Can be used in write mode.
*
* - integer value The value to write to the DataBuffer.
* method read takes nothing returns integer
* - Reads a value out of the DataBuffer. Value read order is determined by
* - the loaded Encoder.
* - Can be used in read mode.
*
************************************************************************************
*
* struct Encoder extends array
*
* - An Encoder is like a frame for compacting values. It is used
* - for storing base, checksum, player checksum, and CodeRange information.
* - the Encoder determines the order of values in a code for the DataBuffer
* - as well. DataBuffers can only be opened through an Encoder.
*
* static method create takes string base, integer minCodeLength, integer maxCodeLength, integer maxChecksum, integer encoderVersion returns Encoder
* - Creates a new Encoder.
*
* - string base The collection of possible characters that the Encoder can
* - use for its save/load codes. Bigger collection means smaller
* - codes.
* - integer minCodeLength Minimum length a code has to be to be loaded. Useful for blocking
* - small values like 1 or 5. Keeps load codes in bounds.
* - integer maxCodeLength Maximal length a code can be to be loaded. Useful for blocking
* - off random large values. Keeps load codes in bounds.
* - integer maxChecksum The maximum checksum value that can be put into the Encoder.
* - Checksums are used to validate codes (ensure they weren't
* - tampered with and that there are no typos in it). The bigger
* - the checksum value, the more secure the code is, but the longer
* - the code will be. I typically use a 6 digit number like 148292
* - or 559321.
* - Maximum checksum- 238609294
* -
* - integer encoderVersion Used for version control on encoders. toString returns this value and
* - convertString takes the toString value and converts it back into the encoder
* - toString() -> encoderVersion
* - convertString(encoderVersion)
* method toString takes nothing returns string
* - Converts the Encoder into a string that represents it. This can
* - be outputted to players to show the Encoder version that their
* - code was saved for. Players can then possibly type in the Encoder
* - version of older codes so that older codes can be loaded.
* static method convertString takes string encoderId returns Encoder
* - Converts an Encoder string into an Encoder. Used primarily for
* - older save/load codes (player might have inputted Encoder id
* - for their save/load code).
*
* - string encoderId The string that represents the Encoder (toString).
* method add takes CodeRange valueSlot returns nothing
* - Adds a new slot to the Encoder. Value order doesn't matter.
*
* - CodeRange valueSlot The CodeRange to be added to the Encoder.
* method read takes string codeString, integer loadingPlayerId returns DataBuffer
* - Opens a DataBuffer for reading and returns the opened DataBuffer. Loads
* - a code string into the DataBuffer. If this returns 0, the code was invalid.
*
* - string codeString The code to load into the DataBuffer
* - integer loadingPlayerId The player id to load the code for (must
* - be a valid human playing player).
* method write takes integer savingPlayerId returns DataBuffer
* - Opens a DataBuffer for writing and returns the opened DataBuffer. If
* - this returns 0, the Encoder or player id were invalid.
*
* - integer savingPlayerId The player id to save the code for (must
* - be a valid human playing player).
*
************************************************************************************/
/*************************************************************************************
*
* Code
*
*************************************************************************************/
globals
private keyword Link
/*************************************************************************************
*
* Encoder Variables
*
*************************************************************************************/
private Table array eb //encoder base
private string array er //encoder code string
private Table array eh //encoder max hash value
private Base es //encoder base for code string
private Link array el //last range added to encoder
private integer array ec //encoder ver to encoder
private integer array ml //minimum code length
private integer array mx //maximum code length
/*************************************************************************************
*
* Range Variables
*
*************************************************************************************/
private integer array rl //low bound
private integer array rh //high bound
private integer array rsh //shifted high bound
private integer array rf //flag
private constant integer AP=1 //always positive
private constant integer SN=2 //sometimes negative
private constant integer AN=3 //always negative
/*************************************************************************************
*
* Link Variables
*
*************************************************************************************/
private integer array li //link id
private boolean array lb //is link
/*************************************************************************************
*
* Player Variables
*
*************************************************************************************/
private integer array ph //hash of player name + salt
private integer array pn //next player
/*************************************************************************************
*
* Data Buffer Variables
*
*************************************************************************************/
//Base
private Base b10=0 //use for writing
//use encoder base for reading
private Link array dm //data buffer looper
private integer dc=0 //data buffer count
private integer array dn //data buffer next, recycler
private integer array dl //data buffer previous
private integer array dv //data buffer value
private Link array di //data buffer link node id
private integer array dd //data buffer node
private integer array dz //data buffer link id
private integer array de //data buffer encoder
private boolean array df //is data buffer finalized?
private boolean array dw //data buffer open for writing?
private integer array dp //data buffer player
endglobals
/*************************************************************************************
*
* Link
*
* Links values together to form dynamic objects.
*
*************************************************************************************/
private struct Link extends array
implement QueueQueue
implement QueueQueueLoop
endstruct
/*************************************************************************************
*
* CodeRange : Link
*
* Used for manipulating value slots in Encoders and CodeRanges.
*
* Methods
* static method create takes integer l, integer h returns CodeRange
* method link takes integer l, integer h, CodeRange p, integer i returns nothing
* method linka takes CodeRange p returns nothing
*
*************************************************************************************/
struct CodeRange extends array
/*************************************************************************************
*
* create
* Creates a code range given a maximum value and a minimum value. Ranges are slots
* that can be added to encoders and other Ranges.
*
* integer l: low bound
* integer h: high bound
*
* returns: CodeRange
*
*************************************************************************************/
static method create takes integer l,integer h returns CodeRange
local Link t
if (h>l) then
//first ensure that the high bound is greater than the low bound
// if the high bound is greater, then it is a valid range for
// storing actual values
//instantiate
set t=Link.allocate()
set t.skips=false
//store the low bound and the high bound into the properties
set rl[t]=l //low bound
set rh[t]=h //high bound
//now have to determine how to store the value
//the value could be negative, it could always be negative,
//or it could always be positive
if (0>h) then
/**********************************
*
* Flag: AN
* Shifted Low Bound: High Bound
* Shifted High Bound: -Low Bound + High Bound
*
**********************************/
set rf[t]=AN //flag to always negative
//the shifhted high bound is the low bound minus
//the high bound
set rsh[t]=-l+h+1
elseif (0>l) then
/**********************************
*
* Flag: SN
* Shifted Low Bound: low bound
* Shifted High Bound: high bound - low bound
*
**********************************/
set rf[t]=SN //flag to sometimes negative
set rsh[t]=h-l+1
else
/**********************************
*
* Flag: AP
* Shifted Low Bound: lowBound
* Shifted High Bound: highBound-lowBound
*
**********************************/
set rf[t]=AP
set rsh[t]=h-l+1
endif
return t
elseif (h==l) then
//if they are equal, then it is a valid pointer range.
// pointer ranges are used to just point to values. They don't go into the actual code,
// but values they point to do.
/**********************************
*
* Flag: 0
*
**********************************/
//simple instiate it as it is meant only for pointing
return Link.allocate()
debug else
//if the high bound is lower than the low bound, then the range isn't valid
// throw an error
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"CODE RANGE CREATE ERROR: HIGH BOUND LOWER THAN LOW BOUND")
debug return 0
endif
return 0
endmethod
/*************************************************************************************
*
* link
* Links a CodeRange to another CodeRange by adding the later range to the
* first range by a pointer.
*
* integer l: low bound
* integer h: high bound
* integer p: CodeRange to add to CodeRange this
* integer i: a user id for identifying the link
*
* returns: nothing
*
*************************************************************************************/
method link takes integer l,integer h,CodeRange p,integer i returns nothing
local Link t
debug if (h>=l and h<=rh[this] and l>=rl[this]) then
//first ensure that the high bound is greater than the low bound
// if the high bound is greater, then it is a valid range for
// storing actual values
//instantiate via point
set t=Link(this).point(p)
set t.skips=false
set rl[t]=l //link low bound
set rh[t]=h //link high bound
set li[t]=i //link id for identification
set lb[t]=true //is link
debug else
//if the high bound is lower than the low bound, then the range isn't valid
// throw an error
debug if (l>h) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"CODE RANGE CREATE ERROR: HIGH BOUND LOWER THAN LOW BOUND")
debug endif
//range was out of bounds
debug if (h>rh[this] or l<rl[this]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"CODE RANGE CREATE ERROR: LINK RANGE OUT OF BOUNDS")
debug endif
debug endif
endmethod
/*************************************************************************************
*
* linka
* A special link that links all values (lowBound to highBound).
*
* integer p: CodeRange to add to CodeRange this
*
* returns: nothing
*
*************************************************************************************/
method linka takes CodeRange p returns nothing
call link(rl[this],rh[this],p,0)
endmethod
endstruct
/*************************************************************************************
*
* DataBuffer : Queue, Link
*
* Used to read/write code.
*
* Properties
* readonly integer id
*
* Methods
* method write takes integer value returns nothing
* method operator code takes nothing returns string
* method read takes nothing returns integer
* internal method open takes nothing returns nothing
*
*************************************************************************************/
private keyword open
struct DataBuffer extends array
/*************************************************************************************
*
* id
* Retrieves the current open id on the DataBuffer
*
*************************************************************************************/
method operator id takes nothing returns integer
return dz[this]
endmethod
/*************************************************************************************
*
* internal open
* Prepares next slot in DataBuffer
*
* takes: nothing
*
* returns: nothing
*
*************************************************************************************/
method open takes nothing returns nothing
local Link n
local Link y=0
local Link l=0
//retrieve the next node
set n=dm[this].get //node
loop
//if the current node is a pointer, have to determine
// whether to go inside of the pointer or not.
exitwhen not lb[n]
loop
//keep looping until can either go inside of link or the
// node isn't a link
//link ranges of 0 to 0 are pointer links, all values fit into them
exitwhen not lb[n] or (0==rl[n] and 0==rh[n]) or 0==n
//if not a pointer link, then have to retrieve the parent
// node's value
set y=dm[this].depthPointer
loop
exitwhen not lb[y.depthNode]
set y=y.depthPointer
endloop
//the value is stored into the depth pointer's id, check for fit
exitwhen (y.id>=rl[n] and y.id<=rh[n])
set n=dm[this].skip //if value doesn't fit, skip link and all of its contents
endloop
//if the final found node was a pointer (meaning the value fit)
//go inside of it
if (lb[n]) then
//only store link for node ref if the link id isn't 0
if (0!=li[n]) then
set l=n
endif
set n=dm[this].get //go to next node
endif
endloop
//if there is no next node, finalize
if (0==n) then
set df[this]=true
return
endif
//add new node to data buffer
if (0==dn[0]) then
set dc=dc+1
set y=dc
else
set y=dn[0]
set dn[0]=dn[y]
endif
//this buffer is a list because it will eventually have to be looped
//over backwards. The buffer has to be read into the code backwards
//or it will be impossible to read it out because some values exist
//and some don't. Remember integers are written left to right but
//read right to left.
set dl[y]=dl[this]
set dn[y]=this
set dn[dl[y]]=y
set dl[this]=y
//set link id for current node to the node right above it, which
// is always going to be a link
set di[y]=li[l]
set dz[this]=li[l]
//set node for size reference and shifting
set dd[y]=n
endmethod
/*************************************************************************************
*
* write
* Writes a value to the DataBuffer
*
* integer value: value to write
*
* returns: nothing
*
*************************************************************************************/
method write takes integer v returns nothing
local Link y=dl[this]
local Link n=dd[y]
//make sure
// buffer isn't finalized
// buffer is open for writing
// buffer is valid
debug if (not df[this] and dw[this] and 0!=de[this] and v>=rl[n] and v<=rh[n]) then
//store shifted value as current depth pointer id
set dm[this].depthPointer.id=v
//shift the value so that it is smaller
if (rf[n]==AN) then
set v=-v+rh[n]
else
set v=v-rl[n]
endif
//store value
set dv[y]=v
//prepare next slot for writing
call open()
debug else
debug if (v<rl[n] or v>rh[n]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"DATA BUFFER ERROR: VALUE OUT OF BOUNDS\n "+I2S(v)+"-> "+I2S(rl[n])+" ... "+I2S(rh[n]))
debug endif
debug if (df[this]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"DATA BUFFER ERROR: DATA BUFFER FINALIZED")
debug endif
debug if (not dw[this]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"DATA BUFFER ERROR: DATA BUFFER NOT OPEN FOR WRITING")
debug endif
debug if (0==de[this]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"DATA BUFFER ERROR: INVALID ENCODER")
debug endif
debug endif
endmethod
/*************************************************************************************
*
* read
* Reads a value out of the DataBuffer
*
* returns: integer
*
*************************************************************************************/
method read takes nothing returns integer
local Link n
local Link o
//make sure
// buffer isn't finalized
// buffer is open for reading
// buffer is valid
debug if (not dw[this] and 0!=de[this]) then
//retrieve current node
set n=dp[this]
set o=dn[n]
//go to next node
set dp[this]=o
set dz[this]=di[o]
//if no more nodes, deallocate and close
if (o==this) then
set de[this]=0
set dn[dl[this]]=dn[0]
set dn[0]=this
endif
return dv[n]
debug else
debug if (dw[this]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"DATA BUFFER ERROR: DATA BUFFER NOT OPEN FOR READING")
debug endif
debug if (0==de[this]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"DATA BUFFER ERROR: INVALID ENCODER")
debug endif
debug endif
return 0
endmethod
/*************************************************************************************
*
* code
* Converts all values in a finalized DataBuffer that is open for writing
* into a save/load code and returns that code.
*
* returns: string
*
*************************************************************************************/
method operator code takes nothing returns string
local BigInt i //code as a number
local integer h //hash
local integer n //node
local string s="" //colorized code string
local string c //character
local boolean l //lowercase
local Base b
//make sure
// buffer is finalized
// buffer is open for writing
// buffer is valid
debug if (df[this] and dw[this] and 0!=de[this]) then
//create the code integer
set i=BigInt.create(b10)
//compress the values into one value
set n=dl[this]
loop
call i.multiply(rsh[dd[n]])
call i.add(dv[n],0)
set n=dl[n]
exitwhen n==this
endloop
//apply checksum
set h=Checksum(i,eh[de[this]][dp[this]])
//if checksum > last value
// range
if (integer(eh[de[this]][dp[this]])>rsh[dd[dl[this]]]) then
//add to front. Have to rebuild the entire number.
call i.destroy()
set i=BigInt.create(b10)
call i.add(h,0)
//compress the values into one value
set n=dl[this]
loop
call i.multiply(rsh[dd[n]])
call i.add(dv[n],0)
set n=dl[n]
exitwhen n==this
endloop
else
//multiply to back
call i.multiply(eh[de[this]][dp[this]])
call i.add(h,0)
endif
//scramble
call ApplyScramble(i,dp[this])
//colorize
set b=eb[de[this]][dp[this]]
set i.base=b
set h=DELIMITER_COUNT
loop
set i=i.previous
exitwhen i.end
set c=b.char(i.digit)
if (0==h) then
set h=DELIMITER_COUNT
set s=s+DELIMITER_COLOR+DELIMITER
endif
set l=StringCase(c,false)==c
if (c==StringCase(c,true) and l) then
if ("0"==c or 0!=S2I(c)) then
//number
set s=s+NUM_COLOR+c
else
//special
set s=s+SPEC_COLOR+c
endif
elseif (l) then
//lower
set s=s+LOWER_COLOR+c
else
//upper
set s=s+UPPER_COLOR+c
endif
set h=h-1
endloop
//close
call i.destroy()
set df[this]=false
set dw[this]=false
set de[this]=0
//deallocate
set dn[dl[this]]=dn[0]
set dn[0]=this
return s+"|r"
debug else
debug if (not df[this]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"DATA BUFFER ERROR: ATTEMPT TO READ PARTIAL BUFFER")
debug endif
debug if (not dw[this]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"DATA BUFFER ERROR: DATA BUFFER NOT OPEN FOR WRITING")
debug endif
debug if (0==de[this]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"DATA BUFFER ERROR: INVALID ENCODER")
debug endif
debug endif
return null
endmethod
endstruct
/*************************************************************************************
*
* Encoder : Link
*
* Used for forming a frame for generating codes
*
* Methods
* static method create takes string base, integer minCodeLength, integer maxCodeLength, integer maxHash, integer ev returns Encoder
* method toString takes nothing returns string
* static method convertString takes string encoderId returns Encoder
* method add takes CodeRange range returns nothing
* method read takes string s, integer p returns DataBuffer
* method write takes integer p returns DataBuffer
*
*************************************************************************************/
struct Encoder extends array
/*************************************************************************************
*
* create
* Creates a new Encoder given a base (characters used in code), a minimum
* code length, a maximum code length, a maximum hash (unique codes),
* and an encoder version.
*
* string b: The haracters used
* Must exist
* integer u: Min code length
* integer x: Max code length
* integer mh: The maximum hash the Encoder can have. Bigger is more unique
* and secure codes, but longer codes.
* Must be > 1
* integer ev: The version of the encoder object
*
* returns: Encoder
*
*************************************************************************************/
static method create takes string b,integer u,integer x,integer mh,integer ev returns thistype
local integer t=StringLength(b) //the Encoder
local string s //Encoder as a string
local string c //Encoder string character
local integer h //string length of Encoder as string
local boolean l //for colorizing (is lower case?)
local integer i=pn[16] //for looping through players
//checksum values
local integer m //min checksum
local integer r //checksum range
//base values
local Base y //original base
local BigInt q //original base int
local BigInt q2 //new base
//first ensure that the base and max checsum are valid
debug if (1<t and 1<mh and x>=u) then
//checksum values
set m=R2I(mh*CHECKSUM_VARIANCE) //min checksum
set r=mh-m //range
//base values
set y=Base[SubString(b,1,2)+SubString(b,0,1)+SubString(b,2,t)] //original base
set q=BigInt.convertString(b,y) //original base int
//instantiate a new Encoder
set t=Link.allocate() //create encoder
set eh[t]=Table.create() //encoder checksum table (different for each player)
set eb[t]=Table.create() //encoder base table (different for each player)
set ml[t]=u //min code length
set mx[t]=x //max code length
//generate checksums and bases for each player
loop
//generate player base
set q2=q.copy() //copy original base
call Scramble(q2,i,3,y,true) //scramble it
set eb[t][i]=Base[q2.toString()] //give to player
call q2.destroy() //clean
//generate player checksum
//checksum=checksum-checksum/checksumRange*checksumRange+minChecksum
set eh[t][i]=ph[i]-ph[i]/r*r+m
set i=pn[i]
exitwhen -1==i
endloop
call q.destroy() //clean original base int
//convert the encoder version** into a string
set ec[ev]=t
set s=es.convertToString(ev)
set h=StringLength(s)
//colorize the string
loop
set h=h-1
set c=SubString(s,h,h+1)
set l=StringCase(c,false)==c
if (c==StringCase(c,true) and l) then
if ("0"==c or 0!=S2I(c)) then
//number
set er[t]=er[t]+NUM_COLOR+c
else
//special
set er[t]=er[t]+SPEC_COLOR+c
endif
elseif (l) then
//lower
set er[t]=er[t]+LOWER_COLOR+c
else
//upper
set er[t]=er[t]+UPPER_COLOR+c
endif
exitwhen 0==h
endloop
return t
debug else
debug if (x<=u) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0,0,60,"ENCODER ERROR: INVALID VALID CODE RANGE")
debug endif
debug if (1>=t) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(), 0,0,60,"ENCODER ERROR: INVALID BASE")
debug endif
debug if (1>=mh) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"ENCODER ERROR: INVALID MAX HASH")
debug endif
debug endif
return 0
endmethod
/*************************************************************************************
*
* toString
* Returns the Encoder as a colorized string in VER_BASE.
*
* returns: string
*
*************************************************************************************/
method toString takes nothing returns string
debug if (er[this] !=null) then
return er[this]
debug endif
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"ENCODER ERROR: INVALID ENCODER")
debug return null
endmethod
/*************************************************************************************
*
* convertSting
* Returns an Encoder by converting an Encoder string into an Encoder.
*
* string s: Encoder id string
*
* returns: Encoder
*
*************************************************************************************/
static method convertString takes string s returns thistype
return ec[es.convertToInteger(s)]
endmethod
/*************************************************************************************
*
* add
* Adds a CodeRange to an Encoder.
*
* CodeRange r: CodeRange to be added
*
* returns: nothing
*
*************************************************************************************/
method add takes CodeRange r returns nothing
debug if (null!=er[this]) then
call Link(this).point(r)
set el[this]=r
debug else
debug if (null==er[this]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"ENCODER ERROR: INVALID ENCODER")
debug endif
debug endif
endmethod
/*************************************************************************************
*
* read
* Attempts to read values out of a code string.
*
* string s: Code string to read values out of
* integer p: Player id to read code string for
*
* returns: DataBuffer
* 0 means DataBuffer couldn't be openned
*
*************************************************************************************/
method read takes string s,integer p returns DataBuffer
local BigInt i //code integer
local integer k=StringLength(s)
local string c //character
local string b="" //filtered code string
local DataBuffer t //data buffer
local integer v //value
local integer n //node
local integer array o //original values
local boolean f
//first ensure that encoder is valid
if (null!=er[this] and 0!=k) then
//remove all DELIMITERs from code
loop
set k=k-1
set c=SubString(s,k,k+1)
if (c!=DELIMITER) then
set b=c+b
endif
exitwhen 0==k
endloop
set n=StringLength(b)
if (n<ml[this] or n>mx[this]) then
return 0
endif
//convert string into a BigInt
set i=BigInt.convertString(b,eb[this][p])
if (0==i) then
return 0
endif
//unscramble
call UnapplyScramble(i,p)
//retrieve whether the checksum is location at the
//back or the front
// true: front
// false: back
set f=integer(eh[this][p])>rsh[el[this]]
if (not f) then
set i.base=b10
endif
//if the stored checksum wasn't equal to the generated checksum, the
// code isn't valid. This is if the checksum is in the back.
//checksum stored in code //code's actual checksum
if (not f and i.divide(eh[this][p])!=Checksum(i,eh[this][p])) then
call i.destroy()
return 0
endif
//allocate data buffer
if (0==dn[0]) then
set dc=dc+1
set t=dc
else
set t=dn[0]
set dn[0]=dn[t]
endif
set dn[t]=t
set dl[t]=t
//initialize data buffer
set de[t]=this //data buffer encoder
set dm[t]=Link(this).start() //open the loop
loop
//prepare next slot
call t.open()
//exit when there are no slots left (finalized)
exitwhen df[t]
//divide BigInt by shifted high bound of current node of current slot
// this returns the value*
set v=i.divide(rsh[dd[dl[t]]])
//retrieve node
set n=dd[dl[t]]
set o[dl[t]]=v
//shift the value back to what it originally was
if (rf[n]==AN) then
set v=-v+rh[n]
else
set v=v+rl[n]
endif
//store value into depth pointer id
set dm[t].depthPointer.id=v
//store value
set dv[dl[t]]=v
endloop
//unset finalization flag
set df[t]=false
//if the checksum was in the front
if (f) then
//first, retrieve the checksum
set v=i.toInt()
//rebuild the entire number
call i.destroy()
set i=i.create(b10)
set n=dl[t]
loop
call i.multiply(rsh[dd[n]])
call i.add(o[n],0)
set n=dl[n]
exitwhen n==t
endloop
//compare the checksum stored in the number to the checksum
//that the number actually generates
if (v!=Checksum(i,eh[this][p])) then
//if they aren't equal, code wasn't valid
call i.destroy()
set de[t]=0 //data buffer encoder=null
//deallocate data buffer
set dn[dl[t]]=dn[0]
set dn[0]=t
//return null
return 0
endif
endif
call i.destroy()
//code was valid, so return DataBuffer
set dp[t]=dn[t] //current node
set dz[t]=di[dn[t]] //current link id
return t
endif
return 0
endmethod
/*************************************************************************************
*
* write
* Attempts to write value into a code string.
*
* integer p: Player id to write code string for
*
* returns: DataBuffer
* 0 means DataBuffer couldn't be openned
*
*************************************************************************************/
method write takes integer p returns DataBuffer
local integer t
//ensure the player is valid
debug if (0!=ph[p]) then
//ensure the encoder is valid
if (null!=er[this]) then
//allocate data buffer
if (0==dn[0]) then
set dc=dc+1
set t=dc
else
set t=dn[0]
set dn[0]=dn[t]
endif
set dn[t]=t
set dl[t]=t
//initialize the buffer
set dp[t]=p //data buffer player
set de[t]=this //data buffer encoder
set df[t]=false //buffer finalized?
set dw[t]=true //open data buffer for writing
set dm[t]=Link(this).start() //open the loop
//open first buffer slot
call DataBuffer(t).open()
//return the buffer
return t
endif
debug else
debug if (0==ph[p]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"ENCODER ERROR: INVALID PLAYER")
debug endif
debug endif
//returning 0 means something was wrong
return 0
endmethod
endstruct
/*************************************************************************************
*
* Initialization
*
*************************************************************************************/
private module Init
private static method onInit takes nothing returns nothing
//Retrieve all human player hashes (StringHash player name)
local integer i=11
local player p
set pn[16]=-1
loop
set p=Player(i)
if (GetPlayerSlotState(p)==PLAYER_SLOT_STATE_PLAYING and GetPlayerController(p)==MAP_CONTROL_USER) then
set ph[i]=StringHash(StringCase(GetPlayerName(p)+PLAYER_CHECKSUM_SALT,false))
if (0>ph[i]) then
set ph[i]=-ph[i]
endif
set pn[i]=pn[16]
set pn[16]=i
endif
exitwhen 0==i
set i=i-1
endloop
set p=null
//initialize base 10, binary, and the global encoder base
set b10=Base["0123456789"]
set es=Base[VER_BASE]
endmethod
endmodule
private struct Inits extends array
implement Init
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library KnuthChecksum uses BigInt
function GetKnuthChecksum takes BigInt k, integer m returns integer
local BigInt c = k.copy()
local BigInt c2 = k.copy()
call c.add(3,0)
call c2.multiplyBig(c)
call c.destroy()
set c = c2.mod(m)
call c2.destroy()
return c
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Scrambler uses /* v3.0.0.2
*************************************************************************************
*
* Scrambles/Shuffles a BigInt given a player id.
*
* This applies a StringHash to the player, converts that hash into base 8, and
* then uses that as a key. The end result is that each player's code (when
* this is used for save/load) is scrambled/shuffled differently.
*
* Scrambling:
* Shuffles in a specific base a number of times.
* Useful for mixing up save/load keys (the character sets)
* Recommend including front digit as data won't be lost for most uses
* Shuffling:
* Shuffles through a set of prime bases a number of times.
* Useful for mixing up save/load codes
*
*************************************************************************************
*
* REQUIREMENTS
*
* */ BigInt /*hiveworkshop.com/forums/jass-functions-413/system-bigint-188973/
*
************************************************************************************
*
* SETTINGS
*/
globals
/*************************************************************************************
*
* SALT
*
* Refers to what to append to the player's name when generating scrambler keys
* for each player. This is essentially like a password. It's impossible for another
* map to descramble a number without this password.
*
* This password can be any string, such as "7/ah+53~r\\ZZ"
*
*************************************************************************************/
private constant string SALT = ""
endglobals
/*************************************************************************************
*
* SetShuffleOrder
*
* Creates the shuffling algorithm using 5 different prime bases.
*
* Shuffling mixes a number up using a variety of bases to produce results rivaling
* top random number generators.
*
* Different bases ensure better mixes.
*
* Enabled Bases:
*
* 2
* Will shuffle number in groups of 1 bit
* 3
* Will shuffle number in groups of 1.58 bits
* 5
* Will shuffle number in groups of 2.32 bits
* 7
* Will shuffle in groups of 2.81 bits
* 11
* Will shuffle in groups of 3.46 bits
*
* Strategies:
*
* 1.
* shuffle by large1, shuffle by small1, shuffle by large2, etc
* 2.
* shuffle by small1, shuffle by large1, shuffle by small2, etc
* 3.
* shuffle by small1, shuffle by small2, shuffle by large1, shuffle by small3, etc
*
* Keep in mind that as fractional bits are shuffled, bits split/merge, meaning that the number
* can drastically change by becoming much smaller or much larger.
*
*
* Shuffle Array: so
*
* Ex:
*
* set so[0]=3 //first mix by 1.58 bits
* set so[1]=2 //second mix by 1 bit
* set so[2]=7 //third mix by 2.81 bits
* set so[3]=2 //fourth mix by 1 bit
*
* return 4 //return number of mixes
*
*************************************************************************************/
private keyword so
private function SetShuffleOrder takes nothing returns integer
/*************************************************************************************
*
* MIXES
*
* array: so
* bases: 2,3,5,7,11
*
*************************************************************************************/
set so[0]=5
set so[1]=2
set so[2]=3
set so[3]=11
set so[4]=2
set so[5]=7
set so[6]=3
/*************************************************************************************
*
* MIX COUNT
*
*************************************************************************************/
return 7
endfunction
/*
************************************************************************************
*
* function Scramble takes BigInt intToScramble, integer forPlayerId, integer shuffles, Base baseToScrambleIn, boolean includeFront returns nothing
* function Unscramble takes BigInt intToScramble, integer forPlayerId, integer shuffles, Base baseToScrambleIn, boolean includeFront returns nothing
*
* function Shuffle takes BigInt intToScramble, integer forPlayerId, integer shuffles returns nothing
* function Unshuffle takes BigInt intToScramble, integer forPlayerId, integer shuffles returns nothing
*
************************************************************************************
*
* function Scramble takes BigInt intToScramble, integer forPlayerId, integer shuffles, Base baseToScrambleIn, boolean includeFront returns nothing
*
* Scrambles a BigInt at the binary level.
*
* intToScramble: BigInt
* forPlayerId: id of human player*
* shuffles: how many times to shuffle number (must be > 0)
* baseToScrambleIn: what base to scramble number in
*
************************************************************************************
*
* function Unscramble takes BigInt intToScramble, integer forPlayerId, integer shuffles, Base baseToScrambleIn, boolean includeFront returns nothing
*
* Unscrambles a BigInt at the binary level.
*
* intToScramble: BigInt
* forPlayerId: id of human player*
* shuffles: how many times to unshuffle number
* baseToScrambleIn: what base to shuffle number in
* includeFront: this determines whether to include front number or not
*
* including the front number isn't advisable as 0s
* may move to the front, meaning data can be lost
*
* Scramble(1000) -> 0001, or 1
*
************************************************************************************
*
* function Shuffle takes BigInt intToScramble, integer forPlayerId, integer shuffles returns nothing
*
* Scrambles a BigInt using user-defined algorithm.
*
* intToScramble: BigInt
* forPlayerId: id of human player*
* shuffles: how many times to shuffle number (must be > 0)
*
************************************************************************************
*
* function Unshuffle takes BigInt intToScramble, integer forPlayerId, integer shuffles returns nothing
*
* Scrambles a BigInt using user-defined algorithm.
*
* intToScramble: BigInt
* forPlayerId: id of human player*
* shuffles: how many times to unshuffle number
*
************************************************************************************/
globals
private integer array ss
private boolean array se
private BigInt array d
private integer i
private integer dc
private integer k
private integer s1
private integer s2
private integer s3
private integer pid
private trigger mt=CreateTrigger() //mix trigger
private trigger dt=CreateTrigger() //demix trigger
private trigger st=CreateTrigger() //scramble trigger
private trigger ut=CreateTrigger() //unscramble trigger
private BigInt bi
private Base array bs
private integer array so
private integer sc=0
endglobals
private function LNF takes BigInt int,boolean i0 returns nothing
set dc=0
if (i0) then
loop
set int=int.next
exitwhen int.end
set d[dc]=int
set dc=dc+1
endloop
else
loop
set int=int.next
exitwhen int.next.end
set d[dc]=int
set dc=dc + 1
endloop
set int=int.next
endif
endfunction
private function LNB takes BigInt int,boolean i0 returns nothing
set dc=0
if (not i0) then
set int=int.previous
endif
loop
set int=int.previous
exitwhen int.end
set d[dc]=int
set dc=dc+1
endloop
endfunction
private function FLP takes integer id,integer i2 returns nothing
//find last position
loop
exitwhen 0==i2
set s1=dc
loop
exitwhen 0==s1
set s1=s1-1
if (se[k]) then
set k=ss[id]
else
set k=k+1
endif
endloop
set i2=i2-1
endloop
endfunction
function Scramble takes BigInt int,integer id,integer shuffles,Base bb,boolean i0 returns nothing
local Base b=int.base
set pid=id
set k=ss[id]
set i=shuffles
debug if (0!=ss[id]) then
if (b!=bb) then
set int.base=bb
endif
//load number
call LNF(int,i0)
//scramble
call TriggerEvaluate(st)
if (b!=bb) then
set int.base=b
endif
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"SCRAMBLER ERROR: INVALID PLAYER "+I2S(id))
debug endif
endfunction
function Unscramble takes BigInt int,integer id,integer shuffles,integer bb,boolean i0 returns nothing
local Base b=int.base
set i=shuffles
set pid=id
set k=ss[id]
debug if (0!=ss[id]) then
if (b!=bb) then
set int.base=bb
endif
//load number
call LNB(int,i0)
//retrieve last position
call FLP(id,shuffles)
//unscramble
call TriggerEvaluate(ut)
if (b!=bb) then
set int.base=b
endif
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"SCRAMBLER ERROR: INVALID PLAYER "+I2S(id))
debug endif
endfunction
//scramble
private function St takes nothing returns boolean
loop
exitwhen 0==i //exitwhen no more shuffles
set s1=dc //loop through digits from left-1 to right
//don't shuffle left most to save a bit as
//left most must be 1
loop
exitwhen 0==s1 //exitwhen no more digits
set s1=s1-1 //shift down as array ends at n-1
//current digit slot - hash digit (shift right)
set s2=s1-ss[k]
//if s2 is negative, add total digits until positive
loop
exitwhen 0<=s2
set s2=dc+s2
endloop
//swap s2 and s1
set s3=d[s2].digit
set d[s2].digit=d[s1].digit
set d[s1].digit=s3
//if out of digits, go back to first digit on hash
//otherwise, go to next digit
//last existing digit is marked as end
if (se[k]) then
set k=ss[pid]
else
set k=k+1
endif
endloop
set i=i-1
endloop
return false
endfunction
//unscramble
private function Ut takes nothing returns boolean
//go backwards
loop
exitwhen 0==i
set s1 = dc
loop
exitwhen 0==s1
set s1=s1-1
set k=k-1
if (0==ss[k]) then
set k=ss[pid+12]
endif
set s2=s1+ss[k]
loop
exitwhen s2<dc
set s2=s2-dc
endloop
set s3=d[s2].digit
set d[s2].digit=d[s1].digit
set d[s1].digit=s3
endloop
set i=i-1
endloop
return false
endfunction
//shuffle
private function Mt takes nothing returns boolean
local integer sh=0
set k=ss[pid]
loop
exitwhen sh==sc
set i=1
set bi.base=bs[so[sh]]
call LNF(bi,false)
call St()
set sh=sh+1
set k=ss[pid]
endloop
return false
endfunction
//unshuffle
private function Dt takes nothing returns boolean
local integer sh=sc
set k=ss[pid]
loop
exitwhen 0==sh
set sh=sh-1
set i=1
set bi.base=bs[so[sh]]
call LNB(bi,false)
call FLP(pid,1)
call Ut()
set k=ss[pid]
endloop
return false
endfunction
function Shuffle takes BigInt int, integer id, integer h returns nothing
local Base b=int.base
debug if (0!=ss[id]) then
set bi=int
set pid=id
loop
exitwhen 0==h
call TriggerEvaluate(mt)
set h=h-1
endloop
set int.base=b
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"SCRAMBLER ERROR: INVALID PLAYER "+I2S(id))
debug endif
endfunction
function Unshuffle takes BigInt int, integer id, integer h returns nothing
local Base b=int.base
debug if (0!=ss[id]) then
set bi=int
set pid=id
loop
exitwhen 0==h
call TriggerEvaluate(dt)
set h=h-1
endloop
set int.base=b
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"SCRAMBLER ERROR: INVALID PLAYER "+I2S(id))
debug endif
endfunction
private module Init
private static method onInit takes nothing returns nothing
local integer is=11
local integer hh
local integer ks=25
local Base b8=Base["012345678"]
local BigInt bg
call TriggerAddCondition(mt,Condition(function Mt))
call TriggerAddCondition(dt,Condition(function Dt))
call TriggerAddCondition(st,Condition(function St))
call TriggerAddCondition(ut,Condition(function Ut))
set bs[2]=Base["01"]
set bs[3]=Base["012"]
set bs[5]=Base["01234"]
set bs[7]=Base["0123456"]
set bs[11]=Base["0123456789A"]
set sc=SetShuffleOrder()
loop
if (GetPlayerSlotState(Player(is))==PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(is))==MAP_CONTROL_USER) then
set ss[is]=ks
set hh=StringHash(StringCase(GetPlayerName(Player(is))+SALT,false))
if (0>hh) then
set hh=-hh
endif
set bg=BigInt.create(b8)
call bg.add(hh,0)
set bg=bg.previous
loop
set ss[ks]=bg.digit+1
set bg=bg.previous
exitwhen bg.end
set ks=ks+1
endloop
set se[ks]=true
set ss[is+12]=ks
call bg.destroy()
set ks=ks+2
endif
exitwhen 0==is
set is=is-1
endloop
endmethod
endmodule
private struct Inits extends array
implement Init
endstruct
endlibrary
//TESH.scrollpos=95
//TESH.alwaysfold=0
library Catalog /* v1.1.0.3
*************************************************************************************
*
* A system used to generate catalogs of objects by hashing raw code ids into indexed
* ids. Catalogs can be used in save/load systems to save things like units and items.
*
*************************************************************************************
* */uses/*
*
* */ Table /* hiveworkshop.com/forums/jass-functions-413/snippet-new-table-188084/
*
************************************************************************************
*
* Functions
*
* function CatalogCreate takes nothing returns integer
* - Creates a new Catalog
* function CatalogAdd takes integer catalog, integer value returns nothing
* - Adds a value to the catalog
* function CatalogAddCatalog takes integer catalog, integer catalogToAdd returns nothing
* - Adds a catalog to the catalog
* function CatalogId takes integer catalog, integer value returns integer
* - Retrieves catalog id of raw value
* function CatalogRaw takes integer catalog, integer value returns integer
* - Retrieves the raw value given catalog id
* function CatalogCount takes integer catalog returns integer
* - Retrieves total items in catalog (includes added catalogs)
*
************************************************************************************
*
* module Catalog
*
* - Implements a catalog into the struct
*
* readonly static thistype catalog
* - Retrieves the instance id of the catalog. Used for adding it to other
* - catalogs.
* readonly static integer count
* - Retrieves the total amount of values inside of the catalog. Includes totals
* - of added catalogs.
* readonly integer raw
* - Gets the raw value given a catalog value. Raw values are the
* - original values that were added.
*
* - Ex: integer raw = Catalog[1].raw
* readonly integer id
* - Gets the catalog id given a raw value
*
* - Ex: integer id = Catalog['hpea'].id
*
* static method add takes integer value returns nothing
* - Adds a value to the catalog. Values already inside of the catalog
* - or inside of any catalog that it contains are not added.
* static method addCatalog takes integer catalog returns nothing
* - Adds a catalog and all of its inner catalogs to the catalog.
* - Catalogs already inside of the catalog are not added.
*
***********************************************************************************/
globals
private integer w=0 //catalog instance count
private integer array c //catalog count
private Table array i //id given rawcode
private Table array r //rawcode given id
private Table array f //has catalog
private integer array l //last
private integer array e //extends
private integer array p //pointer
endglobals
function CatalogCreate takes nothing returns integer
set w=w+1
set l[w]=w
set p[w]=w
set i[w]=Table.create()
set r[w]=Table.create()
set f[w]=Table.create()
return w
endfunction
function CatalogCount takes integer b returns integer
local integer l=c[b]
loop
set b=e[b]
exitwhen 0==b
set l=l+c[p[b]]
endloop
return l
endfunction
function CatalogRaw takes integer b,integer v returns integer
local integer y
loop
set y=c[p[b]]
exitwhen v<=y
set v=v-y
set b=e[b]
if (0==b) then
return 0
endif
endloop
return r[p[b]][v]
endfunction
function CatalogId takes integer b,integer v returns integer
local integer l=0
loop
exitwhen i[p[b]].has(v)
set l=l+c[p[b]]
set b=e[b]
if (0==b) then
return 0
endif
endloop
return i[p[b]][v]+l
endfunction
function CatalogAdd takes integer y,integer v returns nothing
if (0==CatalogId(y, v)) then
set c[y]=c[y]+1
set i[y][v]=c[y]
set r[y][c[y]]=v
endif
endfunction
function CatalogAddCatalog takes integer y,integer b returns nothing
local integer z=w
loop
if (not f[y].boolean.has(p[b])) then
set z=z+1
set p[z]=p[b]
set f[y].boolean[p[b]]=true
set e[l[y]]=z
set l[y]=z
endif
set b=e[b]
exitwhen 0==b
endloop
set w=z
endfunction
module Catalog
readonly static thistype catalog //catalog instance
method operator raw takes nothing returns integer
return CatalogRaw(catalog,this)
endmethod
static method operator count takes nothing returns integer
return CatalogCount(catalog)
endmethod
method operator id takes nothing returns integer
return CatalogId(catalog,this)
endmethod
static method add takes integer v returns nothing
call CatalogAdd(catalog, v)
endmethod
static method addCatalog takes integer catalog returns nothing
call CatalogAddCatalog(thistype.catalog,catalog)
endmethod
private static method onInit takes nothing returns nothing
set catalog=CatalogCreate()
endmethod
endmodule
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library WorldBounds
private module WorldBoundInit
private static method onInit takes nothing returns nothing
set world=GetWorldBounds()
set maxX=GetRectMaxX(world)
set maxY=GetRectMaxY(world)
set minX=GetRectMinX(world)
set minY=GetRectMinY(world)
set centerX=(maxX+minX)/2
set centerY=(minY+maxY)/2
set worldRegion=CreateRegion()
call RegionAddRect(worldRegion,world)
endmethod
endmodule
struct WorldBounds extends array
readonly static real maxX
readonly static real maxY
readonly static real minX
readonly static real minY
readonly static real centerX
readonly static real centerY
readonly static rect world
readonly static region worldRegion
implement WorldBoundInit
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library QueueQueue /* v2.2.6.5
*******************************************************************
*
* To best understand this data structure, think of a list and then
* imagine that every node on that list can have a list inside of it
* and so on. It's also pretty much a tree.
*
*******************************************************************
*
* API
*
*******************************************************************
*
* module QueueQueue
* readonly thistype parent
* readonly boolean pointer
* boolean skips
*
* static method allocate takes nothing returns thistype
* method deallocate takes nothing returns nothing
*
* method add takes nothing returns thistype
* method point takes integer head returns thistype
* method operator next takes nothing returns thistype
* method operator in takes nothing returns thistype
*
* Loop macros
* //! textmacro QUEUE_QUEUE_HEADER takes STRUCT
* //! textmacro QUEUE_QUEUE_START_LOOP takes THIS
* //! textmacro QUEUE_QUEUE_END_LOOP
* //! textmacro QUEUE_QUEUE_HEADER_B takes STRUCT
* //! textmacro QUEUE_QUEUE_START_LOOP_B takes THIS
* //! textmacro QUEUE_QUEUE_END_LOOP_B
*
* module QueueQueueLoop
* readonly thistype get
* readonly thistype skip
* readonly thistype depthPointer
* readonly thistype depthNode
* integer id
* method start takes nothing returns thistype
* method end takes nothing returns nothing
*
*******************************************************************
*
* module QueueQueue
*
*******************************************************************
*
* readonly thistype next
* - Next node
* readonly thistype in
* - Inner node (any given node can have nodes inside of it)
* readonly thistype parent
* - The node that the node is contained inside of.
* readonly boolean pointer
* - This determines whether the node is a pointer or not. Pointers are
* - the first node on the QueueQueue (a special pointer called a head, only
* - generated with allocate) and nodes made through the point method. Pointers
* - are automatically skipped, however their skip option can be set with the
* - skips property.
* boolean skips
* - This determines whether or not to skip a pointer. Pointers that are skipped
* - are not looped over in loops. This is useful for systems that want to read
* - values inside of pointers to see if a pointer's contents should be skipped
* - over or not.
*
* static method allocate takes nothing returns thistype
* - Returns the head for the entire object.
* method deallocate takes nothing returns nothing
* - Destroys the entire structure given the head
*
* method add takes nothing returns thistype
* - Adds a cell to the cell. Cells generated in this fashion
* - are entirely local to the QueueQueue they were added to, meaninng
* - that they can't be pointed to.
* method point takes integer head returns thistype
* - Points a node to a head. Any node allocated with the allocate
* - method is a head. Pointers can't point to anything other than the head.
*
********************************************************************
*
* Loop macros
*
* A loop macro used for looping through a QueueQueue.
*
*******************************************************************
*
* Regular loop (looped in right order)
* //! textmacro QUEUE_QUEUE_HEADER takes STRUCT
* - Place at top of the method/function.
* -
* - STRUCT: Refers to the struct type to loop for.
* //! textmacro QUEUE_QUEUE_START_LOOP takes THIS
* - Place where the loop should start
* -
* - THIS: Refers to where to start the loop from and also
* - used to store current node inside of for reading.
* - THIS must be a variable, and it is not recommended
* - that the this variable be used.
* //! textmacro QUEUE_QUEUE_END_LOOP
* - Place where the loop should end
*
* Deep first postorder loop macros (inner before outer, backwards)
* //! textmacro QUEUE_QUEUE_HEADER_B takes STRUCT
* //! textmacro QUEUE_QUEUE_START_LOOP_B takes THIS
* //! textmacro QUEUE_QUEUE_END_LOOP_B
*
* ---------------------------------------------------------------------
* -
* - Example
* -
* - //both are used the same way
* - function Test takes QueueQueue q returns nothing
* - //header
* - //! runtextmacro QUEUE_QUEUE_HEADER("QueueQueue")
* -
* - local QueueQueue node = q //make a copy
* -
* - //loop
* - //! runtextmacro QUEUE_QUEUE_START_LOOP("node")
* - //code
* - call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, I2S(node))
* - //endloop
* - //! runtextmacro QUEUE_QUEUE_END_LOOP
* - endfunction
* -
* ---------------------------------------------------------------------
*
*********************************************************************
*
* module QueueQueueLoop
*
* A module that provides methods for looping through a
* QueueQueue given an instanced looper.
*
*******************************************************************
*
* readonly thistype get
* - Retrieves the next value in the QueueQueue given a looper.
* readonly thistype skip
* - Skips inner values of the current node and returns next node.
* readonly thistype depthPointer
* - Returns pointer of current depth of loop that stores node. Depth
* - pointers are a stack, so depthPointer.depthPointer would go up one.
* readonly thistype depthNode
* - Returns the node stored within the depth pointer.
* integer id
* - For referencing a depth pointer to something. Depth pointers can be recycled
* - en masse w/o the user's knowledge, meaning that depth pointers should not be used
* - as references for values. It is best to reference the id of a depth pointer.
*
* method start takes nothing returns thistype
* - Creates a new looper for the QueueQueue.
* method end takes nothing returns nothing
* - Destroys a looper for a QueueQueue. Only used when not looping
* - through the entire QueueQueue. The looper is automatically destroyed
* - if the entire QueueQueue is looped through. This could be useful for value
* - searches where looping through the rest of the QueueQueue is pointles.
*
* ---------------------------------------------------------------------
* -
* - Example
* -
* - function Test takes QueueQueue q returns nothing
* - local QueueQueue looper = q.start() //create a new looper
* - local QueueQueue node
* -
* - loop
* - set node = looper.get //get the next node
* - exitwhen node == 0 //exitwhen the node is null
* -
* - //code
* - call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, I2S(node))
* - endloop
* - endfunction
* -
* ---------------------------------------------------------------------
*
*******************************************************************/
module QueueQueue
private static integer array nc //next column
private static integer array nr //next row
private static integer array lr //last row
private static integer ic=0 //column count
private static integer array rc //position recycler
debug private static boolean array a //is node allocated
debug private static integer array rs //references
private static boolean array h
readonly boolean pointer
readonly thistype parent
private boolean z
method operator skips takes nothing returns boolean
return z
endmethod
method operator skips= takes boolean b returns nothing
debug if (pointer) then
set z=b
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"QUEUE QUEUE ERROR: ATTEMPTED TO MANIPULATE SKIP OPTION FOR NON POINTER")
debug endif
endmethod
//can only add rows to current object
static method allocate takes nothing returns thistype
local thistype this
//allocate
if (0==rc[0]) then
set this=ic+1
set ic=this
else
set this=rc[0]
set rc[0]=rc[this]
endif
debug set a[this]=true
set nc[this]=0 //next column is 0
set nr[this]=0 //next row is 0
set pointer=true //is a pointer
set z=true
set parent=0
//is head
debug set h[this]=true
return this
endmethod
method add takes nothing returns thistype
local thistype n
debug if (a[this] and (not pointer or h[this])) then
//allocate
if (0==rc[0]) then
set n=ic+1
set ic=n
else
set n=rc[0]
set rc[0]=rc[n]
endif
debug set a[n]=true
if (0==nc[this]) then
//if nothing to the right, expand
set nc[this]=n
set lr[this]=n
else
//otherwise, add
set nr[lr[this]]=n
set lr[this]=n
endif
set nr[n]=0 //next row is 0
set nc[n]=0 //next column is 0
set n.parent=this
return n
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"QUEUE QUEUE ERROR: ATTEMPTED TO MANIPULATE NULL NODE")
debug endif
debug return 0
endmethod
//special add that adds an existing cell
method point takes integer p returns thistype
local thistype n
//if allocated and not a shadowed pointer (hidden)
debug if (a[this] and (not pointer or h[this]) and h[p]) then
//allocate
if (0==rc[0]) then
set n=ic+1
set ic=n
else
set n=rc[0]
set rc[0]=rc[n]
endif
debug set a[n]=true
//add
if (0==nc[this]) then
//if nothing to the right, expand
set nc[this]=n
set lr[this]=n
else
//otherwise, add
set nr[lr[this]] = n
set lr[this] = n
endif
//expand and point to p
set nc[n]=p
set nr[n]=0
set n.pointer=true
set n.z=true
set n.parent=this
debug if (h[p]) then
debug set rs[p]=rs[p]+1
debug endif
return n
debug else
debug if (not h[p]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"QUEUE QUEUE ERROR: ATTEMPTED TO POINT TO NON HEAD")
debug elseif (a[this]) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"QUEUE QUEUE ERROR: ATTEMPTED TO MANIPULATE NON HEAD POINTER")
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"QUEUE QUEUE ERROR: ATTEMPTED TO MANIPULATE NULL NODE")
debug endif
debug endif
return 0
endmethod
method operator next takes nothing returns thistype
return nr[this]
endmethod
method operator in takes nothing returns thistype
return nc[this]
endmethod
method deallocate takes nothing returns nothing
local thistype array r //first row on column
local thistype c = -1 //column
local thistype n = this //node
local boolean p = false
debug if (h[n] and 0==rs[n]) then
debug set h[n]=false
debug set a[n]=false
set rc[n]=rc[0]
set rc[0]=n
set pointer=false
set z=false
loop
if (p) then
debug if (h[nc[n]]) then
debug set rs[nc[n]]=rs[nc[n]]-1
debug endif
set n.pointer=false
set n.z=false
loop
//go left until can go down or all the way left
exitwhen 0!=nr[n] or 0==c
set c=c-1
set n=r[c]
endloop
set n=nr[n]
set r[c]=n
else
if (0==nc[n]) then
//if there is nothing to the right, then go down
loop
//go left until can go down or all the way left
exitwhen 0!=nr[n] or 0==c
set c=c-1
set n=r[c]
endloop
set n=nr[n]
set r[c]=n
else
//go right
set c=c+1 //go to next column
set n=nc[n]
set r[c]=n //update next column
endif
endif
exitwhen 0==n
set p=n.pointer
debug set a[n]=false
//destroy
set rc[n]=rc[0]
set rc[0]=n
endloop
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"QUEUE QUEUE ERROR: ATTEMPT TO DESTROY NON HEAD "+I2S(n))
debug endif
endmethod
endmodule
//! textmacro QUEUE_QUEUE_HEADER_B takes STRUCT
local boolean array d_1
local $STRUCT$ array r_1
local $STRUCT$ c_1
local $STRUCT$ n_1
//! endtextmacro
//! textmacro QUEUE_QUEUE_START_LOOP_B takes THIS
set n_1=$THIS$
set c_1=0
if (0!=n_1.in) then
loop
//go to lowest position
loop
exitwhen d_1[c_1] or (0==n_1.next and 0==n_1.in)
set d_1[c_1]=true
//first go down, then right
if (0!=n_1.in) then
set c_1=c_1+1
set r_1[c_1]=n_1
if (0!=n_1.next) then
set c_1=c_1+1
set r_1[c_1]=n_1.in
set n_1=n_1.next
else
set n_1=n_1.in
endif
elseif (0!=n_1.next) then
set c_1=c_1+1
set r_1[c_1]=n_1
set n_1=n_1.next
endif
endloop
if (not n_1.skips) then
set $THIS$=n_1
//! endtextmacro
//! textmacro QUEUE_QUEUE_END_LOOP_B
endif
//go up 1
set d_1[c_1]=false
set n_1=r_1[c_1]
set c_1=c_1-1
exitwhen 0==n_1
endloop
endif
//! endtextmacro
//! textmacro QUEUE_QUEUE_HEADER takes STRUCT
local $STRUCT$ array r_1
local $STRUCT$ c_1
local $STRUCT$ n_1
//! endtextmacro
//! textmacro QUEUE_QUEUE_START_LOOP takes THIS
set n_1=$THIS$
set c_1=-1
loop
if (not n_1.skips) then
set $THIS$=n_1
//! endtextmacro
//! textmacro QUEUE_QUEUE_END_LOOP
endif
if (0==n_1.in) then
//if there is nothing to the right, then go down
loop
//go left until can go down or all the way left
exitwhen 0!=n_1.next or 0==c_1
set c_1=c_1-1
set n_1=r_1[c_1]
endloop
set n_1=n_1.next
set r_1[c_1]=n_1
else
//go right
set c_1=c_1+1 //go to next column
set n_1=n_1.in
set r_1[c_1]=n_1 //update next column
endif
exitwhen 0==n_1
endloop
//! endtextmacro
module QueueQueueLoop
private thistype c
private thistype n
private boolean e
private boolean s
integer id
debug private boolean o
private static thistype array rr //recyler
private static thistype rc=0 //instance count
method operator depthNode takes nothing returns thistype
return n
endmethod
method operator depthPointer takes nothing returns thistype
local thistype h=c
loop
exitwhen not h.n.skips
set h=h.c
endloop
if (h==this) then
return 0
endif
return h
endmethod
method operator skip takes nothing returns thistype
local thistype n=c.n
debug if (o) then
//first, skip the node
loop
//go left until can go down or all the way left
exitwhen 0!=n.next or c.e
//destroy
set rr[c]=rr[0]
set rr[0]=c
set c=c.c
set n=c.n
endloop
set n=n.next
set c.n=n
//then find a node that doesn't skip
loop
exitwhen not n.skips
if (0==n.in) then
//if there is nothing to the right, then go down
loop
//go left until can go down or all the way left
exitwhen 0!=n.next or c.e
//destroy
set rr[c]=rr[0]
set rr[0]=c
set c=c.c
set n=c.n
endloop
set n=n.next
set c.n=n
else
//go right
if (0==rr[0]) then
set rc=rc+1
set rc.c=c
set c=rc
else
set rr[0].c=c
set c=rr[0]
set rr[0]=rr[c]
endif
set c.id=0
set n=n.in
set c.n=n
endif
endloop
if (0==n) then
debug set o=false
set s=false
set e=false
set rr[this]=rr[0]
set rr[0]=this
else
set c.id=0
endif
return n
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"QUEUE QUEUE LOOP ERROR: LOOP NOT OPEN")
debug endif
debug return 0
endmethod
method operator get takes nothing returns thistype
local thistype n=c.n
local string es=""
debug if (o) then
if (s) then
set s=false
if (not n.skips) then
return n
endif
endif
loop
if (0==n.in) then
//if there is nothing to the right, then go down
loop
//go left until can go down or all the way left
exitwhen 0!=n.next or c.e
//destroy
set rr[c]=rr[0]
set rr[0]=c
set c=c.c
set n=c.n
endloop
set n=n.next
set c.n=n
else
//go right
if (0==rr[0]) then
set rc=rc+1
set rc.c=c
set c=rc
else
set rr[0].c=c
set c=rr[0]
set rr[0]=rr[c]
endif
set c.id=0
set n=n.in
set c.n=n
endif
exitwhen not n.skips
endloop
if (0==n) then
debug set o=false
set s=false
set e=false
set rr[this]=rr[0]
set rr[0]=this
else
set c.id=0
endif
return n
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"QUEUE QUEUE LOOP ERROR: LOOP NOT OPEN")
debug endif
debug return 0
endmethod
method start takes nothing returns thistype
local thistype t
if (0==rr[0]) then
set rc=rc+1
set t=rc
else
set t=rr[0]
set rr[0]=rr[t]
endif
set t.id=0
set t.s=true
set t.c=t
set t.e=true
set t.n=this
debug set t.o=true
return t
endmethod
method end takes nothing returns nothing
local thistype c=this.c
debug if (o) then
debug set o=false
loop
exitwhen c.e
set rr[c]=rr[0]
set rr[0]=c
set c=c.c
endloop
set s=false
set e=false
set rr[c]=rr[0]
set rr[0]=c
debug else
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"QUEUE QUEUE LOOP ERROR: LOOP NOT OPEN")
debug endif
endmethod
endmodule
endlibrary
//TESH.scrollpos=30
//TESH.alwaysfold=0
//========================================================
library UnitStatePercent /* v1.0.1.6
// by nes
//========================================================
// UnitStatePercent allows one to deal with Unit States as if they were
// represented by percents instead of literal values. This is very useful
// for Save/Load.
//
// */uses/*
*/ WorldBounds //www.hiveworkshop.com/forums/jass-functions-413/snippet-worldbounds-180494/
//
// FUNCTIONS
// function GetPercentHeroXP takes unit u returns integer
// function AddPercentHeroXP takes unit u, integer p returns nothing
//
// function GetPercentUnitLife takes unit u returns integer
// function SetPercentUnitLife takes unit u, integer p returns nothing
//
// function GetPercentUnitMana takes unit u returns integer
// function SetPercentUnitMana takes unit u, integer p returns nothing
//
// function GetPercentUnitX takes unit u returns integer
// function PercentToX takes integer l returns real
//
// function GetPercentUnitY takes unit u returns integer
// function PercentToY takes integer l returns real
//
// function GetPercentUnitFacing takes unit u returns integer
// function PercentToFacing takes integer f returns real
//
// CREDITS
// tooltiperror -
// For helping with documentation
//
//
globals
private real xl=0
private real yl=0
private unit h=null
endglobals
private module Init
private static method onInit takes nothing returns nothing
set xl=WorldBounds.maxX-WorldBounds.minX
set yl=WorldBounds.maxY-WorldBounds.minY
set h=CreateUnit(Player(15),'H!!!',WorldBounds.maxX,WorldBounds.maxY, 0)
call SetUnitX(h,WorldBounds.maxX)
call SetUnitY(h,WorldBounds.maxY)
call PauseUnit(h,true)
endmethod
endmodule
private struct Inits extends array
implement Init
endstruct
//retrieves how far a hero is into its level as an integer %
//u refers to the hero
function GetPercentHeroXP takes unit u returns integer
local integer l=GetHeroLevel(u)
local integer m=0
if (1<l) then
call SetHeroLevel(h,l,false)
set m=GetHeroXP(h)
endif
call SetHeroLevel(h,l+1,false)
set m=(GetHeroXP(u)-m)*100/(GetHeroXP(h)-m)
call UnitStripHeroLevel(h,l+1)
return m
endfunction
//adds an integer percent xp to a hero
//u refer to hero, p refers to percent
//make sure the hero was its original level before adding
//call SetHeroLevel(u, myLvl, false)
//call AddPercentHeroXP(u, 30) //pushes the hero 30% into the level
function AddPercentHeroXP takes unit u,integer p returns nothing
local integer l
local integer m=0
if (0<p) then
set l=GetHeroLevel(u)
if (1<l) then
call SetHeroLevel(h,l,false)
set m=GetHeroXP(h)
endif
call SetHeroLevel(h,l+1,false)
call AddHeroXP(u,R2I((GetHeroXP(h)-m)*p/100.),false)
call UnitStripHeroLevel(h,l+1)
endif
endfunction
//retrieves a unit's current life as a percent
function GetPercentUnitLife takes unit u returns integer
return R2I((GetWidgetLife(u)/GetUnitState(u,UNIT_STATE_MAX_LIFE))*100+.5)
endfunction
//sets a unit's life given a percent
function SetPercentUnitLife takes unit u, integer p returns nothing
call SetWidgetLife(u,p/100.*GetUnitState(u,UNIT_STATE_MAX_LIFE))
endfunction
//retrieves a unit's current mana as a percent
function GetPercentUnitMana takes unit u returns integer
local real m=GetUnitState(u,UNIT_STATE_MAX_MANA)
if (0==m) then
return 0
endif
return R2I(GetUnitState(u,UNIT_STATE_MANA)/m*100+.5)
endfunction
//sets a unit's mana given a percent
function SetPercentUnitMana takes unit u, integer p returns nothing
call SetUnitState(u,UNIT_STATE_MANA,p/100.*GetUnitState(u,UNIT_STATE_MAX_MANA))
endfunction
function GetPercentUnitX takes unit u returns integer
return R2I((GetWidgetX(u)-WorldBounds.minX)/xl*100+.5)
endfunction
function PercentToX takes integer l returns real
return l/100.*xl+WorldBounds.minX
endfunction
function GetPercentUnitY takes unit u returns integer
return R2I((GetWidgetY(u)-WorldBounds.minY)/yl*100+.5)
endfunction
function PercentToY takes integer l returns real
return l/100.*yl+WorldBounds.minY
endfunction
function GetPercentUnitFacing takes unit u returns integer
local integer i=R2I(GetUnitFacing(u)/360.*100+.5)
if (100==i) then
return 0
endif
return i
endfunction
function PercentToFacing takes integer f returns real
return f/100.*360
endfunction
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Ascii
///////////////////////////////////////////////////////////////////
// function Char2Ascii takes string s returns integer
// integer ascii = Char2Ascii("F")
//
// function Ascii2Char takes integer a returns string
// string char = Ascii2Char('F')
//
// function A2S takes integer a returns string
// string rawcode = A2S('CODE')
//
// function S2A takes string s returns integer
// integer rawcode = S2A("CODE")
//
///////////////////////////////////////////////////////////////////
globals
private integer array i //hash
private string array c //char
endglobals
function Char2Ascii takes string s returns integer
local integer a
if ("\\"==s) then
return 92
endif
set a=i[StringHash(s)/0x1F0748+0x3EA]
if (s!=c[a]) then
debug if (0==a) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"ASCII ERROR: INVALID CHARACTER")
debug return 0
debug endif
return a+32
endif
return a
endfunction
function Ascii2Char takes integer a returns string
return c[a]
endfunction
function A2S takes integer a returns string
local string s=""
loop
set s=c[a-a/256*256]+s
set a=a/256
exitwhen 0==a
endloop
return s
endfunction
function S2A takes string s returns integer
local integer a=0
local integer l=StringLength(s)
local integer j=0
local string m
local integer h
loop
exitwhen j==l
set m=SubString(s,j,j+1)
if ("\\"==m) then
set a=a*256+92
else
set h=i[StringHash(m)/0x1F0748+0x3EA]
if (m!=c[h]) then
debug if (0==a) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"ASCII ERROR: INVALID CHARACTER")
debug return 0
debug endif
set a=a*256+h+32
else
set a=a*256+h
endif
endif
set j=j+1
endloop
return a
endfunction
private module Init
private static method onInit takes nothing returns nothing
set i[931]=8
set i[1075]=9
set i[1586]=10
set i[1340]=12
set i[412]=13
set i[198]=32
set i[1979]=33
set i[1313]=34
set i[1003]=35
set i[1264]=36
set i[983]=37
set i[1277]=38
set i[306]=39
set i[904]=40
set i[934]=41
set i[917]=42
set i[1972]=43
set i[1380]=44
set i[1985]=45
set i[869]=46
set i[1906]=47
set i[883]=48
set i[1558]=49
set i[684]=50
set i[582]=51
set i[668]=52
set i[538]=53
set i[672]=54
set i[1173]=55
set i[71]=56
set i[277]=57
set i[89]=58
set i[1141]=59
set i[39]=60
set i[1171]=61
set i[51]=62
set i[305]=63
set i[0]=64
set i[222]=65
set i[178]=66
set i[236] =67
set i[184]=68
set i[1295]=69
set i[1390]=70
set i[1276]=71
set i[203]=72
set i[1314]=73
set i[209]=74
set i[1315]=75
set i[170]=76
set i[1357]=77
set i[1343]=78
set i[1397]=79
set i[1420]=80
set i[1419]=81
set i[1396]=82
set i[1374]=83
set i[1407]=84
set i[499]=85
set i[1465]=86
set i[736]=87
set i[289]=88
set i[986]=89
set i[38]=90
set i[1230]=91
set i[1636]=93
set i[1416]=94
set i[1917]=95
set i[217]=96
set i[833]=123
set i[1219]=124
set i[553]=125
set i[58]=126
set c[8]="\b"
set c[9]="\t"
set c[10]="\n"
set c[12]="\f"
set c[13]="\r"
set c[32]=" "
set c[33]="!"
set c[34]="\""
set c[35]="#"
set c[36]="$"
set c[37]="%"
set c[38]="&"
set c[39]="'"
set c[40]="("
set c[41]=")"
set c[42]="*"
set c[43]="+"
set c[44]=","
set c[45]="-"
set c[46]="."
set c[47]="/"
set c[48]="0"
set c[49]="1"
set c[50]="2"
set c[51]="3"
set c[52]="4"
set c[53]="5"
set c[54]="6"
set c[55]="7"
set c[56]="8"
set c[57]="9"
set c[58]=":"
set c[59]=";"
set c[60]="<"
set c[61]="="
set c[62]=">"
set c[63]="?"
set c[64]="@"
set c[65]="A"
set c[66]="B"
set c[67]="C"
set c[68]="D"
set c[69]="E"
set c[70]="F"
set c[71]="G"
set c[72]="H"
set c[73]="I"
set c[74]="J"
set c[75]="K"
set c[76]="L"
set c[77]="M"
set c[78]="N"
set c[79]="O"
set c[80]="P"
set c[81]="Q"
set c[82]="R"
set c[83]="S"
set c[84]="T"
set c[85]="U"
set c[86]="V"
set c[87]="W"
set c[88]="X"
set c[89]="Y"
set c[90]="Z"
set c[92]="\\"
set c[97]="a"
set c[98]="b"
set c[99]="c"
set c[100]="d"
set c[101]="e"
set c[102]="f"
set c[103]="g"
set c[104]="h"
set c[105]="i"
set c[106]="j"
set c[107]="k"
set c[108]="l"
set c[109]="m"
set c[110]="n"
set c[111]="o"
set c[112]="p"
set c[113]="q"
set c[114]="r"
set c[115]="s"
set c[116]="t"
set c[117]="u"
set c[118]="v"
set c[119]="w"
set c[120]="x"
set c[121]="y"
set c[122]="z"
set c[91]="["
set c[93]="]"
set c[94]="^"
set c[95]="_"
set c[96]="`"
set c[123]="{"
set c[124]="|"
set c[125]="}"
set c[126]="~"
endmethod
endmodule
private struct Inits extends array
implement Init
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
struct tester extends array
private static method onInit takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0,60,"0=="+I2S(Char2Ascii("")))
endmethod
endstruct
//TESH.scrollpos=9
//TESH.alwaysfold=0
library Table // made by Bribe, special thanks to Nestharus, version 3.0.0.0
/*
API
------------
struct Table
| static method create takes nothing returns Table
| create a new Table
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush all stored values inside of it
|
| method remove takes integer key returns nothing
| remove the value at index "key"
|
| method operator []= takes integer key, $TYPE$ value returns nothing
| assign "value" to index "key"
|
| method operator [] takes integer key returns $TYPE$
| load the value at index "key"
|
| method has takes integer key returns boolean
| whether or not the key was assigned
|
----------------
struct TableArray
| static method operator [] takes integer array_size returns TableArray
| create a new array of Tables of size "array_size"
|
| method destroy takes nothing returns nothing
| destroy it
|
| method flush takes nothing returns nothing
| flush and destroy it
|
| method operator size takes nothing returns integer
| returns the size of the TableArray
|
| method operator [] takes integer key returns Table
| returns a Table accessible exclusively to index "key"
*/
globals
private hashtable ht = InitHashtable() //The last hashtable you need
private integer more = 2 //Index generation for Tables (above 2)
private integer less = 0 //Index generation for TableArrays (below 0)
endglobals
private struct dex extends array
static method operator size takes nothing returns Table
return 1
endmethod
static method operator list takes nothing returns Table
return 2
endmethod
endstruct
private struct handles extends array
method has takes integer key returns boolean
return HaveSavedHandle(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSavedHandle(ht, this, key)
endmethod
endstruct
private struct agents extends array
method operator []= takes integer key, agent value returns nothing
call SaveAgentHandle(ht, this, key, value)
endmethod
endstruct
//! textmacro NEW_ARRAY_BASIC takes SUPER, FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$(ht, this, key, value)
endmethod
method has takes integer key returns boolean
return HaveSaved$SUPER$(ht, this, key)
endmethod
method remove takes integer key returns nothing
call RemoveSaved$SUPER$(ht, this, key)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//! textmacro NEW_ARRAY takes FUNC, TYPE
private struct $TYPE$s extends array
method operator [] takes integer key returns $TYPE$
return Load$FUNC$Handle(ht, this, key)
endmethod
method operator []= takes integer key, $TYPE$ value returns nothing
call Save$FUNC$Handle(ht, this, key, value)
endmethod
endstruct
private module $TYPE$m
method operator $TYPE$ takes nothing returns $TYPE$s
return this
endmethod
endmodule
//! endtextmacro
//! runtextmacro NEW_ARRAY_BASIC("Real", "Real", "real")
//! runtextmacro NEW_ARRAY_BASIC("Boolean", "Boolean", "boolean")
//! runtextmacro NEW_ARRAY_BASIC("String", "Str", "string")
//! runtextmacro NEW_ARRAY("Player", "player")
//! runtextmacro NEW_ARRAY("Widget", "widget")
//! runtextmacro NEW_ARRAY("Destructable", "destructable")
//! runtextmacro NEW_ARRAY("Item", "item")
//! runtextmacro NEW_ARRAY("Unit", "unit")
//! runtextmacro NEW_ARRAY("Ability", "ability")
//! runtextmacro NEW_ARRAY("Timer", "timer")
//! runtextmacro NEW_ARRAY("Trigger", "trigger")
//! runtextmacro NEW_ARRAY("TriggerCondition", "triggercondition")
//! runtextmacro NEW_ARRAY("TriggerAction", "triggeraction")
//! runtextmacro NEW_ARRAY("TriggerEvent", "event")
//! runtextmacro NEW_ARRAY("Force", "force")
//! runtextmacro NEW_ARRAY("Group", "group")
//! runtextmacro NEW_ARRAY("Location", "location")
//! runtextmacro NEW_ARRAY("Rect", "rect")
//! runtextmacro NEW_ARRAY("BooleanExpr", "boolexpr")
//! runtextmacro NEW_ARRAY("Sound", "sound")
//! runtextmacro NEW_ARRAY("Effect", "effect")
//! runtextmacro NEW_ARRAY("UnitPool", "unitpool")
//! runtextmacro NEW_ARRAY("ItemPool", "itempool")
//! runtextmacro NEW_ARRAY("Quest", "quest")
//! runtextmacro NEW_ARRAY("QuestItem", "questitem")
//! runtextmacro NEW_ARRAY("DefeatCondition", "defeatcondition")
//! runtextmacro NEW_ARRAY("TimerDialog", "timerdialog")
//! runtextmacro NEW_ARRAY("Leaderboard", "leaderboard")
//! runtextmacro NEW_ARRAY("Multiboard", "multiboard")
//! runtextmacro NEW_ARRAY("MultiboardItem", "multiboarditem")
//! runtextmacro NEW_ARRAY("Trackable", "trackable")
//! runtextmacro NEW_ARRAY("Dialog", "dialog")
//! runtextmacro NEW_ARRAY("Button", "button")
//! runtextmacro NEW_ARRAY("TextTag", "texttag")
//! runtextmacro NEW_ARRAY("Lightning", "lightning")
//! runtextmacro NEW_ARRAY("Image", "image")
//! runtextmacro NEW_ARRAY("Ubersplat", "ubersplat")
//! runtextmacro NEW_ARRAY("Region", "region")
//! runtextmacro NEW_ARRAY("FogState", "fogstate")
//! runtextmacro NEW_ARRAY("FogModifier", "fogmodifier")
//! runtextmacro NEW_ARRAY("Hashtable", "hashtable")
struct Table extends array
// Implement modules for intuitive type-syntax
implement realm
implement booleanm
implement stringm
implement playerm
implement widgetm
implement destructablem
implement itemm
implement unitm
implement abilitym
implement timerm
implement triggerm
implement triggerconditionm
implement triggeractionm
implement eventm
implement forcem
implement groupm
implement locationm
implement rectm
implement boolexprm
implement soundm
implement effectm
implement unitpoolm
implement itempoolm
implement questm
implement questitemm
implement defeatconditionm
implement timerdialogm
implement leaderboardm
implement multiboardm
implement multiboarditemm
implement trackablem
implement dialogm
implement buttonm
implement texttagm
implement lightningm
implement imagem
implement ubersplatm
implement regionm
implement fogstatem
implement fogmodifierm
implement hashtablem
method operator handle takes nothing returns handles
return this
endmethod
method operator agent takes nothing returns agents
return this
endmethod
// set this = a[GetSpellAbilityId()]
method operator [] takes integer key returns Table
return LoadInteger(ht, this, key)
endmethod
// set a[389034] = 8192
method operator []= takes integer key, Table a returns nothing
call SaveInteger(ht, this, key, a)
endmethod
// set b = a.has(2493223)
method has takes integer key returns boolean
return HaveSavedInteger(ht, this, key)
endmethod
// call a.remove(294080)
method remove takes integer key returns nothing
call RemoveSavedInteger(ht, this, key)
endmethod
// Remove all data from a Table instance
method flush takes nothing returns nothing
call FlushChildHashtable(ht, this)
endmethod
// local Table a = Table.create()
static method create takes nothing returns Table
local Table this = dex.list[0]
if this == 0 then
set more = more + 1
set this = more
else
set dex.list[0] = dex.list[this]
call dex.list.remove(this)
endif
debug set dex.list[this] = -1
return this
endmethod
// Removes all data from a Table instance and recycles its index.
//
// call a.destroy()
//
method destroy takes nothing returns nothing
debug if dex.list[this] != -1 then
debug call BJDebugMsg("Table Error: Tried to double-free instance: " + I2S(this))
debug return
debug endif
call this.flush()
set dex.list[this] = dex.list[0]
set dex.list[0] = this
endmethod
endstruct
struct TableArray extends array
//Returns a new TableArray to do your bidding. Simply use:
//
// local TableArray ta = TableArray[array_size]
//
static method operator [] takes integer array_size returns TableArray
local Table a = dex.size[array_size] //Get the unique recycle list for this array size
local TableArray this = a[0] //The last-destroyed TableArray that had this array size
debug if array_size <= 0 then
debug call BJDebugMsg("TypeError: Invalid specified TableArray size: " + I2S(array_size))
debug return 0
debug endif
if this == 0 then
set less = less - array_size
set this = less
else
set a[0] = a[this] //Set the last destroyed to the last-last destroyed
call a.remove(this) //Clear hash memory
endif
set dex.size[this] = array_size //This remembers the array size
return this
endmethod
//Returns the size of the TableArray
method operator size takes nothing returns integer
return dex.size[this]
endmethod
//da[integer a].unit[integer b] = unit u
//da[integer a][integer c] = integer d
//
//Inline-friendly when not running in debug mode
//
method operator [] takes integer key returns Table
static if DEBUG_MODE then
local integer i = this.size
if i == 0 then
call BJDebugMsg("IndexError: Tried to get key from invalid TableArray instance: " + I2S(this))
return 0
elseif key < 0 or key >= i then
call BJDebugMsg("IndexError: Tried to get key [" + I2S(key) + "] from outside TableArray bounds: " + I2S(i))
return 0
endif
endif
return this + key
endmethod
//Destroys a TableArray without flushing it; assumed you'd call .flush()
//if you want it flushed too. This is public so that if you are flushing
//instances the whole time you don't waste efficiency when disposing the
//TableArray.
//
method destroy takes nothing returns nothing
local Table a = dex.size[this.size]
debug if this.size <= 0 then
debug call BJDebugMsg("TypeError: Tried to destroy an invalid TableArray: " + I2S(this))
debug return
debug endif
if a == 0 then
//Create an array to index recycled instances with their array size
set a = Table.create()
set dex.size[this.size] = a
endif
call dex.size.remove(this) //Clear the array size from hash memory
set a[this] = a[0]
set a[0] = this
endmethod
//All you need to know about this one is that it won't hit the op limit.
private static method clean takes Table a, integer end returns nothing
local integer i = a + 5000
if i < end then
call clean.evaluate(i, end)
set end = i
endif
loop
call a.flush()
set a = a + 1
exitwhen a == end
endloop
endmethod
//Flushes the TableArray and also destroys it. Doesn't get any more
//similar to the FlushParentHashtable native than this.
//
method flush takes nothing returns nothing
local integer end = this.size + this
debug if this == end then
debug call BJDebugMsg("TypeError: Tried to flush an invalid TableArray instance: " + I2S(this))
debug return
debug endif
call clean.evaluate(this, end)
call this.destroy()
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/*
Catalogs are used to convert things like raw object ids into smaller numbers. For example,
the value 'hpea', which is the raw ascii code for a peasant, is much larger than 1. If a catalog
were used, the catalog id (max of total things in catalog) can be used rather than the raw ascii id.
A map with 600 heroes would have a max catalog id of 600 for a hero, which is much smaller than the
unit type ids.
Catalogs are extremely useful.
Catalogs can contain other catalogs as well, which allows a user to more easily do class specific items,
hero specific abilities, and etc.
Item catalogs example
--------------------------------------------------------------------
struct HeroCatalog extends array
//general items that can be used by anyone
implement Catalog
private static method onInit takes nothing returns nothing
call add(POTION)
call add(HOOD)
call add(LEATHER_BOOTS)
call add(LEATHER_GLOVES)
endmethod
endstruct
struct MagicCatalog extends array
//items that can only be used by heroes with magic
implement Catalog
private static method onInit takes nothing returns nothing
call addCatalog(HeroCatalog.catalog)
call add(MAGIC_STAFF)
call add(SPELL_GLOVES)
endmethod
endstruct
--------------------------------------------------------------------
Class specific items are useful for making save/load codes smaller. They might be bleh for
gameplay, but limiting a hero to items that are only useful to that hero makes sense. Why
would a warrior use an item that increases magical power? Class specific items are the way
to go to have smaller save/load codes.
Abilities are rather difficult as every single unit has its own catalog of abilities unique
to it. This means that a catalog has to be made for every single hero in the game and all of
its possible abilities need to be put into that catalog. For hero specific abilities, the catalog
ids are used in a loop (they aren't stored into the code). A level max is associated with each ability
and it is the ability's level that is put into the code. The catalog is looped over to retrieve the ability
ids so that their levels can be set.
More general abilities (abilities that may be on all melee characters, or abilites that are added with
UnitAddAbility) can also have catalogs, but if any general abilities are used, then the ability catalog
id as well as its level must be stored as the ability could be anything from a number of abilities.
Most ORPGs don't deal with saving abilities at all because they are a pain.
See the following script for more information on capturing abilities when dealing with general abilities
hiveworkshop.com/forums/submissions-414/vjass-abilityevent-179642/
*/
//TESH.scrollpos=0
//TESH.alwaysfold=0
//This catalog is a hero catalog. It orders the heroes by how many abilities they have.
//This ordering is done for easier hero specific ability catalogs.
library HeroCatalog uses Catalog
struct HeroCatalog1 extends array
implement Catalog
readonly static integer abil4Min = 0 //the first hero with 4 abilities in the catalog
readonly static integer abil4Max = 0 //the last hero with 4 abilities in the catalog
readonly static integer abil5Min = 0 //the first hero with 5 abilities in the catalog
readonly static integer abil5Max = 0 //the last hero with 5 abilities in the catalog
readonly static integer abil5_2Min = 0 //different 5x ability maxes
readonly static integer abil5_2Max = 0 //different 5x ability maxes
private static method onInit takes nothing returns nothing
//0 abilities
call add('Hapm') //Admiral Proudmoore 0
call add('Ogld') //Gul'dan 0
//4 abilities
set abil4Min = count+1
call add('Hamg') //HeroArchMage 4 AHbz,AHab,AHwe,AHmt
call add('Hblm') //HeroBloodMage 4 AHfs,AHbn,AHdr,AHpx
call add('Hmkg') //HeroMountainKing 4 AHtc,AHtb,AHbh,AHav
call add('Hpal') //HeroPaladin 4 AHhb,AHds,AHre,AHad
call add('Obla') //HeroBladeMaster 4 AOwk,AOcr,AOmi,AOww
call add('Ofar') //HeroFarSeer 4 AOfs,AOsf,AOcl,AOeq
call add('Oshd') //HeroShadowHunter 4 AOhw,AOhx,AOsw,AOvd
call add('Otch') //HeroTaurenChieftain 4 AOsh,AOae,AOre,AOws
call add('Edem') //HeroDemonHunter 4 AEmb,AEim,AEev,AEme
call add('Ekee') //HeroKeeperoftheGrove 4 AEer,AEfn,AEah,AEtq
call add('Emoo') //HeroMoonPriestess 4 AHfa,AEst,AEar,AEsf
call add('Ewar') //HeroWarden 4 AEbl,AEfk,AEsh,AEsv
call add('Ucrl') //HeroCryptLord 4 AUim,AUts,AUcb,AUls
call add('Udea') //HeroDeathKnight 4 AUdc,AUdp,AUau,AUan
call add('Udre') //HeroDreadLord 4 AUav,AUsl,AUcs,AUin
call add('Ulic') //HeroLich 4 AUfn,AUfu,AUdr,AUdd
call add('Nbrn') //HeroBansheeRanger 4 ANsi,ANba,ANdr,ANch
call add('Nbst') //HeroBeastMaster 4 ANsg,ANsq,ANsw,ANst
call add('Nngs') //HeroNagaSeaWitch 4 ANfl,ANfa,ANms,ANto
call add('Npbm') //HeroPandarenBrewmaster 4 ANbf,ANdh,ANdb,ANef
call add('Nalc') //HeroAlchemist 4 ANhs,ANab,ANcr,ANtm
call add('Ntin') //HeroTinker 4 ANsy,ANcs,ANeg,ANrg
call add('Nplh') //HeroPitLord 4 ANrf,ANht,ANca,ANdo
call add('Nfir') //FireLord 4 ANic,ANso,ANlm,ANvc
call add('Ecen') //cenarius 4 AEer,AEfn,AEah,AEtq
call add('Eevi') //evil illidan 4 AEmb,AEim,AEev,AEvi
call add('Efur') //furion 4 AEer,AEfn,AEah,AEtq
call add('Eill') //illidan 4 AEmb,AEim,AEev,AEIl
call add('Ekgg') //keeper ghost 4 AEer,AEfn,AEah,AEtq
call add('Emfr') //Mal'furion 4 AEer,AEfn,AEah,AEtq
call add('Emns') //Mal'furion no stag 4 AEer,AEfn,AEah,AEtq
call add('Etyr') //Tyrande 4 AHfa,AEst,AEar,AEsf
call add('Ewrd') //Maiev 4 AEbl,AEfk,AEsh,AEsv
call add('Hant') //antonidus 4 AHbz,AHab,AHwe,AHmt
call add('Harf') //arthas w/ frostmourne 4 AHhb,AHds,AHre,AHad
call add('Hart') //arthas 4 AHhb,AHds,AHre,AHad
call add('Hdgo') //Dagren the Orcslayer 4 AHhb,AHds,AHre,AHad
call add('Hhkl') //Halahk the Lifebringer 4 AHhb,AHds,AHre,AHad
call add('Hjai') //jaina 4 AHbz,AHab,AHwe,AHmt
call add('Hkal') //Kael 4 AHfs,AHbn,AHdr,AHpx
call add('Hlgr') //Lord Garithos 4 ANsh,AHhb,AHad,ANav
call add('Hmbr') //muradin bronzebeard 4 AHtc,AHtb,AHbh,AHav
call add('Hmgd') //Magroth the Defender 4 AHhb,AHds,AHre,AHad
call add('Hpb1') //Paladin Boss 1 4 AHhb,AHds,AHre,AHad
call add('Huth') //uther 4 AHhb,AHds,AHre,AHad
call add('Hvsh') //Lady Vashj 4 ANfl,ANfa,ANms,ANto
call add('Hvwd') //sylvanus windrunner 4 AHca,AEst,AEar,AEsf
call add('Nbbc') //blackrock blademaster 4 AOwk,AOcr,AOmi,AOww
call add('Nmag') //Magtheridon 4 ANrf,ANht,ANca,ANdo
call add('Nman') //Mannoroth 4 AOsh,AHtc,AOeq,ANrn
call add('Npld') //Pit Lord 4 AOsh,AHtc,AOeq,ANrn
call add('Ocbh') //cairne bloodhoof 4 AOsh,AOae,AOre,AOws
call add('Odrt') //Drek'Thar 4 AOfs,AOsf,AOcl,AOeq
call add('Ogrh') //grom hellscream 4 AOwk,AOcr,AOmi,AOww
call add('Udth') //detheroc 4 AUsl,AEsh,AUcs,AUdd
call add('Uear') //evil arthas 4 AUdc,AUdp,AUau,AUan
call add('Uktl') //kelthuzadlich 4 AUfn,AUfu,AUdr,AUdd
call add('Umal') //malganis 4 AUsl,AUcs,ANsl,ANdc
call add('Usyl') //Evil Sylvanas 4 ANsi,ANba,ANdr,ANch
call add('Utic') //tichondrius 4 AUsl,AUcs,ANrc,ANfd
call add('Uvar') //varimathras 4 AUsl,AUav,ANrf,ANdo
call add('Uvng') //Vengyr 4 AUav,AUsl,AUcs,AUin
call add('Uwar') //archimonde 4 ANrc,ANdp,ANfd,AHbh
call add('Hgam') //ghostly archmage 4 AHbz,AHab,AHwe,AHmt
call add('Naka') //akama 4 ACs7,AOcl,AEsh,ANr2
call add('Osam') //Samuro 4 AOwk,AOcr,AOmi,AOww
call add('Othr') //thrall 4 AOfs,AOsf,AOcl,AOeq
call add('Uanb') //anub'arak 4 AUim,AUts,AUcb,AUls
set abil4Max = count
//5 abilities
set abil5Min = count+1
call add('Nsjs') //Chen Stormstout 5 ANcf,Acdh,Acdb,Acef,Aamk
call add('Ocb2') //cairne bloodhoof (war3x) 5 AOs2,AOr2,AOr3,AOw2,Aamk
call add('Orex') //Rexxar 5 Arsg,Arsq,ANsb,Arsp,Aamk
call add('Orkn') //Rokhan 5 ANhw,ANhx,Arsw,AOls,Aamk
set abil5Max = count
set abil5_2Min = count+1
call add('Ubal') //balnazzar 5_2 AUsl,AUav,ANr3,AOeq,ACf3
set abil5_2Max = count
endmethod
endstruct
endlibrary
//TESH.scrollpos=3
//TESH.alwaysfold=0
//This catalog stores standard units that can act as pets for heroes
//there is no specific order
library PetCatalog uses Catalog
struct PetCatalog1 extends array
implement Catalog
private static method onInit takes nothing returns nothing
call add('hdhw') //blood elf dragon hawk
call add('hfoo') //Footman
call add('hgry') //GryphonRider
call add('hkni') //Knight
call add('hmpr') //Priest
call add('hmtm') //MortarTeam
call add('hrif') //Rifleman
call add('hsor') //Sorceress
call add('hspt') //Blood Elf Spell Breaker
call add('odoc') //WitchDoctor
call add('ogru') //Grunt
call add('ohun') //HeadHunter
call add('okod') //KodoBeast
call add('orai') //WolfRider
call add('oshm') //Shaman
call add('ospw') //spiritwalker
call add('otau') //Tauren
call add('otbk') //Berserker
call add('otbr') //Troll Batrider
call add('owyv') //Wind Rider
call add('earc') //Archer
call add('echm') //Chimaera
call add('edoc') //DruidoftheClaw
call add('edot') //DruidoftheTalon
call add('edry') //Dryad
call add('efdr') //faerie dragon
call add('efon') //Ent
call add('ehip') //Hippogryph
call add('emtg') //Mountain Giant
call add('esen') //Huntress
call add('uabo') //Abomination
call add('uaco') //Acolyte
call add('uban') //Banshee
call add('ucry') //CryptFiend
call add('ufro') //FrostWyrm
call add('ugar') //Gargoyle
call add('ugho') //Ghoul
call add('unec') //Necromancer
call add('uobs') //Obsidian Statue
call add('nadk') //blue drake
call add('nadr') //blue dragon
call add('nadw') //blue dragon whelp
call add('nahy') //ancient hydra
call add('nanb') //barbed arachnathid
call add('nanc') //crystal arachnathid
call add('nane') //arachnathid earth-borer
call add('nano') //arachnathid overlord
call add('nanw') //arachnathid warrior
call add('narg') //battle golem
call add('nass') //assassin
call add('nbal') //Doom Guard
call add('nban') //bandit
call add('nbda') //blue dragonspawn apprentice
call add('nbdk') //black drake
call add('nbdm') //blue dragonspawn meddler
call add('nbdo') //blue dragonspawn overseer
call add('nbdr') //black whelp
call add('nbds') //blue dragonspawn sorceror
call add('nbdw') //blue dragonspawn warrior
call add('nbld') //bandit lord
call add('nbnb') //barbed arachnathid burrowed
call add('nbrg') //brigand
call add('nbwm') //black dragon
call add('nbzd') //bronze dragon
call add('nbzk') //bronze drake
call add('nbzw') //bronze dragon whelp
call add('ncea') //CentaurArcher
call add('ncen') //Centaur outrunner
call add('ncer') //centaur drudge
call add('ncfs') //watery minion cliffrunner
call add('nchp') //chaplain
call add('ncim') //Centaur impaler
call add('ncks') //centaur sorceror
call add('ncnk') //centaur khan
call add('ndqn') //succubus
call add('ndqp') //maiden of pain
call add('ndqs') //queen of suffering
call add('ndqt') //vile temptress
call add('ndqv') //vile tormentor
call add('ndrv') //revenant of the depths
call add('ndtb') //dark troll berserker
call add('ndth') //dark troll high priest
call add('ndtp') //dark troll shadow priest
call add('ndtr') //darkTroll
call add('ndtt') //darkTrollTrapper
call add('ndtw') //darkTrollwarlord
call add('nehy') //elder hydra
call add('nelb') //berserk elemental
call add('nele') //enraged elemental
call add('nenc') //corrupted ent
call add('nenf') //enforcer
call add('nenp') //poison ent
call add('nepl') //plague ent
call add('nerd') //eredar diabolist
call add('ners') //eredar sorceror
call add('nerw') //eredar warlock
call add('nfel') //fel stalker
call add('nfgb') //bloodfiend
call add('nfgu') //felguard
call add('nfod') //faceless one deathbringer
call add('nfor') //faceless one trickster
call add('nfot') //faceless one terror
call add('nfov') //overlord
call add('nfpc') //Polar Furbolg Champion
call add('nfpe') //Polar Furbolg Elder Shaman
call add('nfpl') //Polar Furbolg
call add('nfps') //Polar Furbolg Shaman
call add('nfpt') //Polar Furbolg Tracker
call add('nfpu') //Polar Furbolg Ursa Warrior
call add('nfra') //Furbolg Ursa Warrior
call add('nfrb') //Furbolg Tracker
call add('nfre') //Furbolg Elder Shaman
call add('nfrg') //Furbolg Champion
call add('nfrl') //Furbolg
call add('nfrp') //Furbolg Panda
call add('nfrs') //Furbolg Shaman
call add('nfsh') //forest troll high priest
call add('nfsp') //forest troll shadow priest
call add('nftb') //forest troll berserker
call add('nftk') //ForestTrollKing
call add('nftr') //ForestTroll
call add('nftt') //ForestTrollTrapper
call add('ngdk') //green drake
call add('nggr') //granite golem
call add('ngh1') //ghost
call add('ngh2') //wraith
call add('ngna') //Gnoll Poacher
call add('ngnb') //gnoll brute
call add('ngno') //Gnoll Robber
call add('ngns') //Gnoll Assassin
call add('ngnv') //gnoll king
call add('ngnw') //gnoll warden
call add('ngrd') //green dragon
call add('ngrk') //mud golem
call add('ngrw') //green dragon whelp
call add('ngsp') //GoblinSapper
call add('ngst') //rock golem
call add('ngza') //misha 3
call add('nhar') //Harpy Scout
call add('nhdc') //deceiver
call add('nhfp') //fallen priest
call add('nhhr') //heretic
call add('nhrh') //harpy hag
call add('nhrq') //harpy queen
call add('nhrr') //harpy rogue
call add('nhrw') //harpy witch
call add('nhyc') //campaign turtle
call add('nhyd') //hydra
call add('nhyh') //hydra hatchling
call add('nhym') //hydromancer
call add('nith') //ice troll high priest
call add('nitp') //ice troll shadow priest
call add('nitr') //IceTroll
call add('nits') //ice troll berserker
call add('nitt') //ice troll trapper
call add('nitw') //ice troll warlord
call add('njg1') //Jungle Stalker
call add('njga') //Elder Jungle Stalker
call add('njgb') //Enranged Jungle Stalker
call add('nkob') //Kobold
call add('nkog') //Kobold Geomancer
call add('nkol') //kobold leader
call add('nkot') //kobold tunneler
call add('nlds') //makrura deep seer
call add('nlkl') //makrura tidal lord
call add('nlpd') //makrura pool dweller
call add('nlpr') //makrura prawn
call add('nlps') //makrura prawn summoned
call add('nlrv') //deeplord revenant
call add('nlsn') //makrura snapper
call add('nltc') //makrura tide caller
call add('nltl') //lightning lizard
call add('nmam') //Mammoth
call add('nmbg') //mur'gul blood-gill
call add('nmcf') //mur'gul cliffrunner
call add('nmdr') //Dire Mammoth
call add('nmfs') //murloc flesheater
call add('nmgd') //magnataur destroyer
call add('nmgr') //magnataur reaver
call add('nmgw') //magnataur warrior
call add('nmit') //Icetusk Mammoth
call add('nmmu') //murloc mutant
call add('nmpg') //murloc plaguebearer
call add('nmrl') //murloc fisherman
call add('nmrm') //murloc nightcrawler
call add('nmrr') //murloc huntsman
call add('nmrv') //mur'gul reaver
call add('nmsc') //mur'gul shadowcaster
call add('nmsn') //mur'gul snarecaster
call add('nmtw') //mur'gul tidewarrior
call add('nmyr') //naga myrmidon
call add('nmys') //naga myrmidon submerged
call add('nndk') //nether drake
call add('nndr') //nether dragon
call add('nnht') //nether hatchling
call add('nnmg') //naga mur'gul
call add('nnrg') //naga royal guard
call add('nnrs') //naga royal guard submerged
call add('nnsu') //naga summoner
call add('nnsw') //naga siren
call add('nnwa') //nerubian warrior
call add('nnwl') //nerubian webspinner
call add('nnwq') //nerubian queen
call add('nnwr') //nerubian seer
call add('nnws') //nerubian spider lord
call add('noga') //Stonemaul Warchief
call add('nogl') //ogre lord
call add('nogm') //ogre mauler
call add('nogn') //Stonemaul Magi
call add('nogo') //Stonemaul Ogre
call add('nogr') //Ogre Warrior
call add('nomg') //ogre magi
call add('nowb') //owlbear
call add('nowe') //enraged owlbear
call add('nowk') //berserk owlbear
call add('npfl') //purple felhound
call add('npfm') //purple felhound
call add('nplb') //polar bear
call add('nplg') //giant polar bear
call add('nqbh') //quillboar hunter
call add('nrdk') //Red Dragon Whelp
call add('nrdr') //Red Drake
call add('nrel') //reef elemental
call add('nrog') //rogue
call add('nrvd') //death revenant
call add('nrvf') //fire revenant
call add('nrvi') //ice revenant
call add('nrvl') //lightning revenant
call add('nrvs') //frost revenant
call add('nrwm') //Red Dragon
call add('nrzb') //razormane brute
call add('nrzg') //razormane chieftain
call add('nrzm') //razormane medicine man
call add('nrzs') //razormane scout
call add('nrzt') //quillboar
call add('nsat') //Satyr Trickster
call add('nsbm') //brood mother
call add('nsc2') //spider crab
call add('nsel') //sea elemental
call add('nsgb') //sea giant behemoth
call add('nsgg') //siege golem
call add('nsgh') //sea giant hunter
call add('nsgn') //sea giant
call add('nsgt') //giant spider
call add('nska') //skeletal archer
call add('nske') //SkeletonWarrior
call add('nskf') //burning archer
call add('nskg') //giant SkeletonWarrior
call add('nskm') //skeletal marksman
call add('nsko') //skeletal orc
call add('nslf') //sludge flinger
call add('nslh') //salamander hatchling
call add('nsll') //salamander lord
call add('nslm') //sludge minion
call add('nsln') //sludge monstrosity
call add('nslr') //salamander
call add('nslv') //salamander vizier
call add('nsnp') //snap dragon
call add('nsns') //watery minion snarecaster
call add('nsoc') //skeletal orc champion
call add('nsog') //skeletal orc grunt
call add('nspb') //black spider
call add('nspd') //spiderling
call add('nspg') //green spider
call add('nspp') //spirit pig
call add('nspr') //spider
call add('nsqa') //ancient sasquatch
call add('nsqe') //elder sasquatch
call add('nsqo') //sasquatch oracle
call add('nsqt') //sasquatch
call add('nsra') //stormreaver apprentice
call add('nsrh') //stormreaver hermit
call add('nsrn') //stormreaver necrolyte
call add('nsrv') //revenant of the seas
call add('nsrw') //stormreaver warlock
call add('nssp') //spitting spider
call add('nsth') //satyr hellcaller
call add('nstl') //satyr soulstealer
call add('nsts') //satyr shadowdancer
call add('nstw') //storm wyrm
call add('nsty') //satyr
call add('nthl') //thunder lizard
call add('ntka') //tuskarr spearman
call add('ntkc') //tuskarr chieftain
call add('ntkf') //tuskarr fighter
call add('ntkh') //tuskarr healer
call add('ntks') //tuskarr sorceror
call add('ntkt') //tuskarr trapper
call add('ntkw') //tuskarr warrior
call add('ntrd') //dragon turtle
call add('ntrg') //gargantuan sea turtle
call add('ntrh') //sea turtle hatchling
call add('ntrs') //sea turtle
call add('ntrt') //giant sea turtle
call add('ntrv') //revenant of the tides
call add('ntws') //watery minion tidewarrior
call add('nubk') //unbroken darkhunter
call add('nubr') //unbroken rager
call add('nubw') //unbroken darkweaver
call add('nvde') //elder voidwalker
call add('nvdg') //greater voidwalker
call add('nvdl') //lesser voidwalker
call add('nvdw') //voidwalker
call add('nwen') //Wendigo
call add('nwgs') //naga coutl
call add('nwiz') //wizard
call add('nwld') //dire wolf
call add('nwlg') //giant wolf
call add('nwlt') //timber wolf
call add('nwna') //ancient wendigo
call add('nwnr') //elder wendigo
call add('nwns') //wendigo shaman
call add('nwrg') //war golem
call add('nws1') //dragon hawk
call add('nwwd') //white dire wolf
call add('nwwf') //white wolf
call add('nwwg') //giant white wolf
call add('nwzd') //dark wizard
call add('nwzg') //renegade wizard
call add('nwzr') //rogue wizard
call add('nzom') //Zombie
call add('nalb') //Albatross
call add('ncrb') //Crab
call add('nder') //deer
call add('ndog') //Dog
call add('ndwm') //Dune Worm
call add('nech') //Chicken
call add('necr') //Rabbit
call add('nfbr') //Felboar
call add('nfro') //Frog
call add('nhmc') //Hermit Crab
call add('nowl') //owlscout
call add('npig') //Pig
call add('npng') //Penguin
call add('nrac') //Raccoon
call add('nrat') //Rat
call add('nsea') //Seal
call add('nshe') //Sheep
call add('nshf') //Flying Sheep
call add('nskk') //Skink
call add('nsno') //Snowy Owl
call add('nvul') //Vulture
call add('enec') //night elf courier
call add('ensh') //Naisha
call add('eshd') //shandris
call add('hcth') //the captain
call add('hhdl') //headless rider
call add('hhes') //high elven swordsman
call add('nbee') //blood elf engineer
call add('nbel') //blood elf lieutenant
call add('nchg') //chaos grunt
call add('nchr') //ChaosWolfRider
call add('nchw') //ChaosWarlock
call add('nckb') //Chaos Kodo Beast
call add('ncpn') //Chaos Peon
call add('ndmu') //dalaran mutant
call add('ndrd') //draenei darkslayer
call add('ndrf') //draenei guardian
call add('ndrh') //draenei harbinger
call add('ndrj') //dalaran reject
call add('ndrl') //draenei laborer
call add('ndrm') //draenei disciple
call add('ndrn') //draenei vindicator
call add('ndrp') //draenei protector
call add('ndrs') //draenei seer
call add('ndrt') //draenei stalker
call add('ndrw') //draenei watcher
call add('ndsa') //draenei salamander
call add('negz') //engineer gazlowe
call add('nemi') //emissary
call add('nfgl') //flesh golem
call add('ngbl') //goblin blaster
call add('njks') //jailor kassan
call add('nmed') //medivh
call add('nmsh') //misha the bear
call add('nser') //searinox
call add('nssn') //night elf assassin
call add('nthr') //tharifas
call add('nw2w') //War2Warlock
call add('nwat') //watcher
call add('odkt') //Drak'Thul
call add('ogrk') //Gar'thok
call add('omtg') //mathog
call add('onzg') //nazgrel
call add('oosc') //kodo beast (riderless)
call add('oswy') //spirit wyvern
call add('ovlj') //vol'jin
call add('owar') //orc warchief
call add('ownr') //wyvern
call add('uswb') //sylvanus banshee
call add('zcso') //chaos space orc
call add('zhyd') //hydralisk
call add('zmar') //Marine
call add('zzrg') //zergling
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//This is the item catalog. The items are ordered from smallest charges to highest charges.
//Items that are perishable with only 1 charge are treated as items with 0 charges.
//
library ItemCatalog uses Catalog
struct ItemCatalog1 extends array
implement Catalog
readonly static integer charge2Min = 0 //the first item with 2 charges in the catalog
readonly static integer charge2Max = 0 //the last item with 2 charges in the catalog
readonly static integer charge3Min = 0 //the first item with 3 charges in the catalog
readonly static integer charge3Max = 0 //the last item with 3 charges in the catalog
readonly static integer charge4Min = 0 //the first item with 4 charges in the catalog
readonly static integer charge4Max = 0 //the last item with 4 charges in the catalog
readonly static integer charge5Min = 0 //the first item with 5 charges in the catalog
readonly static integer charge5Max = 0 //the last item with 5 charges in the catalog
readonly static integer charge6Min = 0 //the first item with 6 charges in the catalog
readonly static integer charge6Max = 0 //the last item with 6 charges in the catalog
readonly static integer charge10Min = 0 //the first item with 10 charges in the catalog
readonly static integer charge10Max = 0 //the last item with 10 charges in the catalog
private static method onInit takes nothing returns nothing
call add('ckng') //Crown of Kings +5
call add('modt') //mask of death
call add('ratf') //Claws of Attack +15
call add('rde4') //Ring of Protection +5
call add('ofro') //Orb of Frost
call add('fgdg') //Demonic Figurine
call add('infs') //Inferno Stone
call add('shar') //Ice Shard
call add('sand') //Scroll of Animate Dead
call add('sres') //Scroll of Restoration
call add('wild') //Amulet of the Wild
call add('srrc') //Scroll of Resurrection
call add('rej6') //Greater Scroll of Replenishment
call add('odef') //Orb of Darkness
call add('rde3') //Ring of Protection +4
call add('pmna') //Pendant of Mana
call add('rhth') //Khadgar's Gem of Health
call add('ssil') //Staff of Silence
call add('spsh') //Amulet of Spell Shield
call add('desc') //Dagger of Escape
call add('ankh') //Ankh of Reincarnation
call add('pdiv') //Potion of Divinity
call add('pres') //Potion of Restoration
call add('rej5') //Lesser Scroll of Replenishment
call add('hcun') //Hood of Cunning
call add('hval') //Helm of Valor
call add('mcou') //Medallion of Courage
call add('belv') //Boots of Quel'Thalas +6
call add('bgst') //Belt of Giant Strength +6
call add('ciri') //Robe of the Magi +6
call add('ajen') //Ancient Janggo of Endurance
call add('clfm') //Cloak of Flames
call add('ratc') //Claws of Attack +12
call add('ward') //Warsong Battle Drums
call add('kpin') //Khadgar's Pipe of Insight
call add('crys') //Crystal Ball
call add('fgfh') //Spiked Collar
call add('fgrg') //Stone Token
call add('fgsk') //Book of the Dead
call add('hlst') //Health Stone
call add('mnst') //Mana Stone
call add('rej4') //Greater Replenishment Potion
call add('ram4') //Fourth Ring of the Archmagi
call add('lhst') //Lion Horn of Stormwind
call add('afac') //Alleria's Flute of Accuracy
call add('lgdh') //Legion Doom-Horn
call add('sbch') //Scourge Bone Chimes
call add('brac') //Runed Bracers
call add('rwiz') //Sobi Mask
call add('dsum') //Diamond of Summoning
call add('pghe') //potion of greater healing
call add('pgma') //Potion of Greater Mana
call add('pnvu') //potion of invulnerability
call add('sror') //Scroll of the Beast
call add('rej3') //Replenishment Potion
call add('ofir') //Orb of Fire
call add('ocor') //Orb of Corruption
call add('oli2') //Orb of Lightning
call add('oven') //Orb of Venom
call add('ram3') //Third Ring of the Archmagi
call add('evtl') //Talisman of Evasion
call add('penr') //Pendant of Energy
call add('prvt') //Periapt of Vitality
call add('rat9') //Claws of Attack +9
call add('rde2') //Ring of Protection +3
call add('rlif') //Ring of regeneration
call add('tgrh') //Tiny Great Hall
call add('rej2') //Lesser Replenishment
call add('gemt') //Gem of True Seeing
call add('ram2') //Second Ring of the Archmagi
call add('stel') //Staff of Teleportation
call add('cnob') //Circlet of Nobility
call add('gcel') //Gloves of Haste
call add('rat6') //Claws of Attack +6
call add('rde1') //Ring of Protection +2
call add('bspd') //Boots of Speed
call add('pnvl') //Potion of Lesser Invulnerability
call add('stwp') //Scroll of Town Portal
call add('sneg') //Staff of Negation
call add('shea') //Scroll of Healing
call add('sman') //Scroll of Mana
call add('rej1') //Minor Replenishment
call add('pspd') //Potion of Speed
call add('ram1') //First Ring of the Archmagi
call add('clsd') //Cloak of Shadows
call add('rag1') //Slippers of Agility +3
call add('rin1') //Mantle of Intelligence +3
call add('rst1') //Gauntlets of Ogre Strength +3
call add('pinv') //potion of invisibility
call add('phea') //potion of healing
call add('pman') //Potion of Mana
call add('spro') //Scroll of Protection
call add('moon') //Moonstone
call add('shas') //Scroll of Speed
call add('skul') //Sacrificial Skull
call add('mcri') //Mechanical Critter
call add('tsct') //Ivory Tower
call add('azhr') //Heart of Aszune
call add('bzbe') //Empty Vial
call add('bzbf') //Full Vial
call add('ches') //Cheese
call add('cnhn') //Horn of Cenarius
call add('glsk') //Guldan's Skull
call add('k3m1') //Key of 3 Moons - 1
call add('k3m2') //Key of 3 Moons - 2
call add('k3m3') //Key of 3 Moons - 3
call add('ktrm') //Urn of Kel'Thuzad
call add('kybl') //bloody key
call add('kygh') //ghost key
call add('kymn') //moon key
call add('kysn') //sun key
call add('ledg') //Gerard's Lost Ledger
call add('phlt') //Phat Lewt
call add('sehr') //Searinox's Heart
call add('engs') //Enchanted Gemstone
call add('jpnt') //note to jaina proudmoore
call add('skrt') //Skeletal Artifact
call add('pomn') //Potion of Omniscience
call add('lure') //Monster Lure
call add('olig') //Orb of Lightning(old)
call add('amrc') //Amulet of Recall
call add('flag') //human flag
call add('gsou') //Soul Gem
call add('nflg') //NightElf flag
call add('nspi') //Necklace of Spell Immunity
call add('oflg') //Orc flag
call add('pams') //Anti-Magic Potion
call add('pgin') //potion of greater invisibility
call add('rat3') //Claws of Attack +3
call add('rde0') //Ring of Protection +1
call add('rnsp') //Ring of Superiority
call add('soul') //Soul
call add('tels') //Goblin Night Scope
call add('uflg') //Undead flag
call add('anfg') //Ancient Figurine
call add('brag') //Bracer of Agility
call add('drph') //Druid Pouch
call add('iwbr') //Ironwood Branch
call add('jdrn') //Jade Ring
call add('lnrn') //Lion's Ring
call add('mlst') //Maul of Strength
call add('oslo') //Orb of Slow
call add('sbok') //Spell Book
call add('sksh') //Skull Shield
call add('sprn') //Spider Ring
call add('tmmt') //Totem of Might
call add('vddl') //Voodoo Doll
call add('spre') //Staff of Preservation
call add('sfog') //Horn of the Clouds
call add('sor1') //Shadow Orb +1
call add('sor2') //Shadow Orb +2
call add('sor3') //Shadow Orb +3
call add('sor4') //Shadow Orb +4
call add('sor5') //Shadow Orb +5
call add('sor6') //Shadow Orb +6
call add('sor7') //Shadow Orb +7
call add('sor8') //Shadow Orb +8
call add('sor9') //Shadow Orb +9
call add('sora') //Shadow Orb +10
call add('fwss') //Frostwyrm Skull Shield
call add('shtm') //Shamanic Totem
call add('esaz') //Essence of Aszune
call add('btst') //orcish battle standard
call add('pclr') //Clarity Potion
call add('plcl') //Lesser Clarity Potion
call add('vamp') //Potion of Vampirism
call add('sreg') //Scroll of Regeneration
call add('ssan') //Staff of Sanctuary
call add('tcas') //Tiny Castle
call add('tbsm') //Tiny Blacksmith
call add('tfar') //Tiny Farm
call add('tlum') //Tiny Lumber Mill
call add('tbar') //Tiny Barracks
call add('tbak') //Tiny Altar of Kings
call add('gldo') //Orb of Kil'jaeden
call add('wtlg') //Wirt's Leg
call add('wolg') //Wirt's Other Leg
call add('mgtk') //Magtheridon's Keys
call add('stre') //Staff of Reanimation
call add('horl') //Holy Relic
call add('hbth') //Helm of Battlethirst
call add('blba') //Bladebane Armor
call add('rugt') //Runed Gauntlets
call add('frhg') //Firehand Gauntlets
call add('gvsm') //Gloves of Spell Mastery
call add('crdt') //Crown of the Deathlord
call add('arsc') //Arcane Scroll
call add('scul') //Scroll of the Unholy Legion
call add('tmsc') //Tome of Sacrifices
call add('dtsb') //Drek'thar's Spellbook
call add('arsh') //Arcanite Shield
call add('shdt') //Shield of the Deathlord
call add('shhn') //Shield of Honor
call add('shen') //Enchanted Shield
call add('thdm') //Thunderlizard Diamond
call add('stpg') //Stuffed Penguin
call add('bfhr') //Bloodfeather's Heart
call add('cosl') //Celestial Orb of Souls
call add('shcw') //Shaman Claws
call add('srbd') //Searing Blade
call add('frgd') //Frostguard
call add('rump') //Rusty Mining Pick
call add('mort') //Mogrin's Report
call add('srtl') //Serathil
call add('stwa') //Sturdy War Axe
call add('klmm') //Killmaim
call add('axas') //Ancestral Staff
call add('mnsf') //Mindstaff
call add('schl') //Scepter of Healing
call add('asbl') //Assassin's Blade
call add('kgal') //Keg of Ale
set charge2Min = count+1
call add('wshs') //Wand of Shadowsight 2
call add('dust') //Dust of Appearance 2
call add('woms') //Wand of Mana Stealing 2
set charge2Max = count
set charge3Min = count+1
call add('whwd') //Healing Wards 3
call add('fgun') //Flare Gun 3
call add('ccmd') //Scepter of Mastery 3
call add('gobm') //Goblin Land Mine 3
call add('will') //Wand of Illusion 3
call add('wlsd') //Wand of Lightning Shield 3
call add('wswd') //Sentry Wards 3
call add('wneg') //Wand of Negation 3
call add('hslv') //Healing Salve 3
call add('totw') //talisman of the wild 3
call add('wcyc') //Wand of the Wind 3
set charge3Max = count
set charge4Min = count+1
call add('silk') //Spider Silk 4
call add('rnec') //Rod of Necromancy 4
call add('wneu') //Wand of Neutralization 4
set charge4Max = count
set charge5Min = count+1
call add('rots') //Rod of the Sea 5
call add('envl') //Enchanted Vial 5
set charge5Max = count
set charge6Min = count+1
call add('shrs') //Shimmerglaze Roast 6
set charge6Max = count
set charge10Min = count+1
call add('grsl') //Grimoire of Souls 10
set charge10Max = count
endmethod
endstruct
endlibrary
//TESH.scrollpos=1
//TESH.alwaysfold=0
library AbilityCatalog uses Catalog
struct AbilityCatalog1 extends array
private static Table catalog
static method operator [] takes integer index returns thistype
return catalog[index]
endmethod
method raw takes integer va returns integer
return CatalogRaw(this, va)
endmethod
method id takes integer va returns integer
return CatalogId(this, va)
endmethod
method operator count takes nothing returns integer
return CatalogCount(this)
endmethod
private static method onInit takes nothing returns nothing
local integer i
set catalog = Table.create()
/*
max abil levels (wc3 follows this pattern for abilities)
if a unit has 4 abilities
abil levels: 3 3 3 1
if a unit has 5 abilities
abil levels: 4 4 4 2 4
if a unit has special 5 abils
abil levels: 3 3 3 1 1
*/
//for general abilities done with UnitAddAbility, create a
//general ability catalog and add it to all of the hero specific
//ability catalogs
//'Hamg' HeroArchMage 4 AHbz,AHab,AHwe,AHmt
set i = CatalogCreate()
set catalog['Hamg'] = i
call CatalogAdd(i, 'AHbz')
call CatalogAdd(i, 'AHab')
call CatalogAdd(i, 'AHwe')
call CatalogAdd(i, 'AHmt')
//'Hblm' HeroBloodMage 4 AHfs,AHbn,AHdr,AHpx
set i = CatalogCreate()
set catalog['Hblm'] = i
call CatalogAdd(i, 'AHfs')
call CatalogAdd(i, 'AHbn')
call CatalogAdd(i, 'AHdr')
call CatalogAdd(i, 'AHpx')
//'Hmkg' HeroMountainKing 4 AHtc,AHtb,AHbh,AHav
set i = CatalogCreate()
set catalog['Hmkg'] = i
call CatalogAdd(i, 'AHtc')
call CatalogAdd(i, 'AHtb')
call CatalogAdd(i, 'AHbh')
call CatalogAdd(i, 'AHav')
//'Hpal' HeroPaladin 4 AHhb,AHds,AHre,AHad
set i = CatalogCreate()
set catalog['Hpal'] = i
call CatalogAdd(i, 'AHhb')
call CatalogAdd(i, 'AHds')
call CatalogAdd(i, 'AHad')
call CatalogAdd(i, 'AHre')
//'Obla' HeroBladeMaster 4 AOwk,AOcr,AOmi,AOww
set i = CatalogCreate()
set catalog['Obla'] = i
call CatalogAdd(i, 'AOwk')
call CatalogAdd(i, 'AOcr')
call CatalogAdd(i, 'AOmi')
call CatalogAdd(i, 'AOww')
//'Ofar' HeroFarSeer 4 AOfs,AOsf,AOcl,AOeq
set i = CatalogCreate()
set catalog['Ofar'] = i
call CatalogAdd(i, 'AOfs')
call CatalogAdd(i, 'AOsf')
call CatalogAdd(i, 'AOcl')
call CatalogAdd(i, 'AOeq')
//'Oshd' HeroShadowHunter 4 AOhw,AOhx,AOsw,AOvd
set i = CatalogCreate()
set catalog['Oshd'] = i
call CatalogAdd(i, 'AOhw')
call CatalogAdd(i, 'AOhx')
call CatalogAdd(i, 'AOsw')
call CatalogAdd(i, 'AOvd')
//'Otch' HeroTaurenChieftain 4 AOsh,AOae,AOre,AOws
set i = CatalogCreate()
set catalog['Otch'] = i
call CatalogAdd(i, 'AOsh')
call CatalogAdd(i, 'AOae')
call CatalogAdd(i, 'AOws')
call CatalogAdd(i, 'AOre')
//'Edem' HeroDemonHunter 4 AEmb,AEim,AEev,AEme
set i = CatalogCreate()
set catalog['Edem'] = i
call CatalogAdd(i, 'AEmb')
call CatalogAdd(i, 'AEim')
call CatalogAdd(i, 'AEev')
call CatalogAdd(i, 'AEme')
//'Ekee' HeroKeeperoftheGrove 4 AEer,AEfn,AEah,AEtq
set i = CatalogCreate()
set catalog['Ekee'] = i
call CatalogAdd(i, 'AEer')
call CatalogAdd(i, 'AEfn')
call CatalogAdd(i, 'AEah')
call CatalogAdd(i, 'AEtq')
//'Emoo' HeroMoonPriestess 4 AHfa,AEst,AEar,AEsf
set i = CatalogCreate()
set catalog['Emoo'] = i
call CatalogAdd(i, 'AHfa')
call CatalogAdd(i, 'AEst')
call CatalogAdd(i, 'AEar')
call CatalogAdd(i, 'AEsf')
//'Ewar' HeroWarden 4 AEbl,AEfk,AEsh,AEsv
set i = CatalogCreate()
set catalog['Ewar'] = i
call CatalogAdd(i, 'AEbl')
call CatalogAdd(i, 'AEfk')
call CatalogAdd(i, 'AEsh')
call CatalogAdd(i, 'AEsv')
//'Ucrl' HeroCryptLord 4 AUim,AUts,AUcb,AUls
set i = CatalogCreate()
set catalog['Ucrl'] = i
call CatalogAdd(i, 'AUim')
call CatalogAdd(i, 'AUts')
call CatalogAdd(i, 'AUcb')
call CatalogAdd(i, 'AUls')
//'Udea' HeroDeathKnight 4 AUdc,AUdp,AUau,AUan
set i = CatalogCreate()
set catalog['Udea'] = i
call CatalogAdd(i, 'AUdc')
call CatalogAdd(i, 'AUdp')
call CatalogAdd(i, 'AUau')
call CatalogAdd(i, 'AUan')
//'Udre' HeroDreadLord 4 AUav,AUsl,AUcs,AUin
set i = CatalogCreate()
set catalog['Udre'] = i
call CatalogAdd(i, 'AUav')
call CatalogAdd(i, 'AUsl')
call CatalogAdd(i, 'AUcs')
call CatalogAdd(i, 'AUin')
//'Ulic' HeroLich 4 AUfn,AUfu,AUdr,AUdd
set i = CatalogCreate()
set catalog['Ulic'] = i
call CatalogAdd(i, 'AUfn')
call CatalogAdd(i, 'AUfu')
call CatalogAdd(i, 'AUdr')
call CatalogAdd(i, 'AUdd')
//'Nbrn' HeroBansheeRanger 4 ANsi,ANba,ANdr,ANch
set i = CatalogCreate()
set catalog['Nbrn'] = i
call CatalogAdd(i, 'ANsi')
call CatalogAdd(i, 'ANba')
call CatalogAdd(i, 'ANdr')
call CatalogAdd(i, 'ANch')
//'Nbst' HeroBeastMaster 4 ANsg,ANsq,ANsw,ANst
set i = CatalogCreate()
set catalog['Nbst'] = i
call CatalogAdd(i, 'ANsg')
call CatalogAdd(i, 'ANsq')
call CatalogAdd(i, 'ANsw')
call CatalogAdd(i, 'ANst')
//'Nngs' HeroNagaSeaWitch 4 ANfl,ANfa,ANms,ANto
set i = CatalogCreate()
set catalog['Nngs'] = i
call CatalogAdd(i, 'ANfl')
call CatalogAdd(i, 'ANfa')
call CatalogAdd(i, 'ANms')
call CatalogAdd(i, 'ANto')
//'Npbm' HeroPandarenBrewmaster 4 ANbf,ANdh,ANdb,ANef
set i = CatalogCreate()
set catalog['Npbm'] = i
call CatalogAdd(i, 'ANbf')
call CatalogAdd(i, 'ANdh')
call CatalogAdd(i, 'ANdb')
call CatalogAdd(i, 'ANef')
//'Nalc' HeroAlchemist 4 ANhs,ANab,ANcr,ANtm
set i = CatalogCreate()
set catalog['Nalc'] = i
call CatalogAdd(i, 'ANhs')
call CatalogAdd(i, 'ANab')
call CatalogAdd(i, 'ANcr')
call CatalogAdd(i, 'ANtm')
//'Ntin' HeroTinker 4 ANsy,ANcs,ANeg,ANrg
set i = CatalogCreate()
set catalog['Ntin'] = i
call CatalogAdd(i, 'ANsy')
call CatalogAdd(i, 'ANcs')
call CatalogAdd(i, 'ANeg')
call CatalogAdd(i, 'ANrg')
//'Nplh' HeroPitLord 4 ANrf,ANht,ANca,ANdo
set i = CatalogCreate()
set catalog['Nplh'] = i
call CatalogAdd(i, 'ANrf')
call CatalogAdd(i, 'ANht')
call CatalogAdd(i, 'ANca')
call CatalogAdd(i, 'ANdo')
//'Nfir' FireLord 4 ANic,ANso,ANlm,ANvc
set i = CatalogCreate()
set catalog['Nfir'] = i
call CatalogAdd(i, 'ANic')
call CatalogAdd(i, 'ANso')
call CatalogAdd(i, 'ANlm')
call CatalogAdd(i, 'ANvc')
//'Ecen' cenarius 4 AEer,AEfn,AEah,AEtq
set i = CatalogCreate()
set catalog['Ecen'] = i
call CatalogAdd(i, 'AEer')
call CatalogAdd(i, 'AEfn')
call CatalogAdd(i, 'AEah')
call CatalogAdd(i, 'AEtq')
//'Eevi' evil illidan 4 AEmb,AEim,AEev,AEvi
set i = CatalogCreate()
set catalog['Eevi'] = i
call CatalogAdd(i, 'AEmb')
call CatalogAdd(i, 'AEim')
call CatalogAdd(i, 'AEev')
call CatalogAdd(i, 'AEvi')
//'Efur' furion 4 AEer,AEfn,AEah,AEtq
set i = CatalogCreate()
set catalog['Efur'] = i
call CatalogAdd(i, 'AEer')
call CatalogAdd(i, 'AEfn')
call CatalogAdd(i, 'AEah')
call CatalogAdd(i, 'AEtq')
//'Eill' illidan 4 AEmb,AEim,AEev,AEIl
set i = CatalogCreate()
set catalog['Eill'] = i
call CatalogAdd(i, 'AEmb')
call CatalogAdd(i, 'AEim')
call CatalogAdd(i, 'AEev')
call CatalogAdd(i, 'AEIl')
//'Ekgg' keeper ghost 4 AEer,AEfn,AEah,AEtq
set i = CatalogCreate()
set catalog['Ekgg'] = i
call CatalogAdd(i, 'AEer')
call CatalogAdd(i, 'AEfn')
call CatalogAdd(i, 'AEah')
call CatalogAdd(i, 'AEtq')
//'Emfr' Mal'furion 4 AEer,AEfn,AEah,AEtq
set i = CatalogCreate()
set catalog['Emfr'] = i
call CatalogAdd(i, 'AEer')
call CatalogAdd(i, 'AEfn')
call CatalogAdd(i, 'AEah')
call CatalogAdd(i, 'AEtq')
//'Emns' Mal'furion no stag 4 AEer,AEfn,AEah,AEtq
set i = CatalogCreate()
set catalog['Emns'] = i
call CatalogAdd(i, 'AEer')
call CatalogAdd(i, 'AEfn')
call CatalogAdd(i, 'AEah')
call CatalogAdd(i, 'AEtq')
//'Etyr' Tyrande 4 AHfa,AEst,AEar,AEsf
set i = CatalogCreate()
set catalog['Etyr'] = i
call CatalogAdd(i, 'AHfa')
call CatalogAdd(i, 'AEst')
call CatalogAdd(i, 'AEar')
call CatalogAdd(i, 'AEsf')
//'Ewrd' Maiev 4 AEbl,AEfk,AEsh,AEsv
set i = CatalogCreate()
set catalog['Ewrd'] = i
call CatalogAdd(i, 'AEbl')
call CatalogAdd(i, 'AEfk')
call CatalogAdd(i, 'AEsh')
call CatalogAdd(i, 'AEsv')
//'Hant' antonidus 4 AHbz,AHab,AHwe,AHmt
set i = CatalogCreate()
set catalog['Hant'] = i
call CatalogAdd(i, 'AHbz')
call CatalogAdd(i, 'AHab')
call CatalogAdd(i, 'AHwe')
call CatalogAdd(i, 'AHmt')
//'Harf' arthas w/ frostmourne 4 AHhb,AHds,AHre,AHad
set i = CatalogCreate()
set catalog['Harf'] = i
call CatalogAdd(i, 'AHhb')
call CatalogAdd(i, 'AHds')
call CatalogAdd(i, 'AHad')
call CatalogAdd(i, 'AHre')
//'Hart' arthas 4 AHhb,AHds,AHre,AHad
set i = CatalogCreate()
set catalog['Hart'] = i
call CatalogAdd(i, 'AHhb')
call CatalogAdd(i, 'AHds')
call CatalogAdd(i, 'AHad')
call CatalogAdd(i, 'AHre')
//'Hdgo' Dagren the Orcslayer 4 AHhb,AHds,AHre,AHad
set i = CatalogCreate()
set catalog['Hdgo'] = i
call CatalogAdd(i, 'AHhb')
call CatalogAdd(i, 'AHds')
call CatalogAdd(i, 'AHad')
call CatalogAdd(i, 'AHre')
//'Hhkl' Halahk the Lifebringer 4 AHhb,AHds,AHre,AHad
set i = CatalogCreate()
set catalog['Hhkl'] = i
call CatalogAdd(i, 'AHhb')
call CatalogAdd(i, 'AHds')
call CatalogAdd(i, 'AHad')
call CatalogAdd(i, 'AHre')
//'Hjai' jaina 4 AHbz,AHab,AHwe,AHmt
set i = CatalogCreate()
set catalog['Hjai'] = i
call CatalogAdd(i, 'AHbz')
call CatalogAdd(i, 'AHab')
call CatalogAdd(i, 'AHwe')
call CatalogAdd(i, 'AHmt')
//'Hkal' Kael 4 AHfs,AHbn,AHdr,AHpx
set i = CatalogCreate()
set catalog['Hkal'] = i
call CatalogAdd(i, 'AHfs')
call CatalogAdd(i, 'AHbn')
call CatalogAdd(i, 'AHdr')
call CatalogAdd(i, 'AHpx')
//'Hlgr' Lord Garithos 4 ANsh,AHhb,AHad,ANav
set i = CatalogCreate()
set catalog['Hlgr'] = i
call CatalogAdd(i, 'ANsh')
call CatalogAdd(i, 'AHhb')
call CatalogAdd(i, 'AHad')
call CatalogAdd(i, 'ANav')
//'Hmbr' muradin bronzebeard 4 AHtc,AHtb,AHbh,AHav
set i = CatalogCreate()
set catalog['Hmbr'] = i
call CatalogAdd(i, 'AHtc')
call CatalogAdd(i, 'AHtb')
call CatalogAdd(i, 'AHbh')
call CatalogAdd(i, 'AHav')
//'Hmgd' Magroth the Defender 4 AHhb,AHds,AHre,AHad
set i = CatalogCreate()
set catalog['Hmgd'] = i
call CatalogAdd(i, 'AHhb')
call CatalogAdd(i, 'AHds')
call CatalogAdd(i, 'AHad')
call CatalogAdd(i, 'AHre')
//'Hpb1' Paladin Boss 1 4 AHhb,AHds,AHre,AHad
set i = CatalogCreate()
set catalog['Hpb1'] = i
call CatalogAdd(i, 'AHhb')
call CatalogAdd(i, 'AHds')
call CatalogAdd(i, 'AHad')
call CatalogAdd(i, 'AHre')
//'Huth' uther 4 AHhb,AHds,AHre,AHad
set i = CatalogCreate()
set catalog['Huth'] = i
call CatalogAdd(i, 'AHhb')
call CatalogAdd(i, 'AHds')
call CatalogAdd(i, 'AHad')
call CatalogAdd(i, 'AHre')
//'Hvsh' Lady Vashj 4 ANfl,ANfa,ANms,ANto
set i = CatalogCreate()
set catalog['Hvsh'] = i
call CatalogAdd(i, 'ANfl')
call CatalogAdd(i, 'ANfa')
call CatalogAdd(i, 'ANms')
call CatalogAdd(i, 'ANto')
//'Hvwd' sylvanus windrunner 4 AHca,AEst,AEar,AEsf
set i = CatalogCreate()
set catalog['Hvwd'] = i
call CatalogAdd(i, 'AHca')
call CatalogAdd(i, 'AEst')
call CatalogAdd(i, 'AEar')
call CatalogAdd(i, 'AEsf')
//'Nbbc' blackrock blademaster 4 AOwk,AOcr,AOmi,AOww
set i = CatalogCreate()
set catalog['Nbbc'] = i
call CatalogAdd(i, 'AOwk')
call CatalogAdd(i, 'AOcr')
call CatalogAdd(i, 'AOmi')
call CatalogAdd(i, 'AOww')
//'Nmag' Magtheridon 4 ANrf,ANht,ANca,ANdo
set i = CatalogCreate()
set catalog['Nmag'] = i
call CatalogAdd(i, 'ANrf')
call CatalogAdd(i, 'ANht')
call CatalogAdd(i, 'ANca')
call CatalogAdd(i, 'ANdo')
//'Nman' Mannoroth 4 AOsh,AHtc,AOeq,ANrn
set i = CatalogCreate()
set catalog['Nman'] = i
call CatalogAdd(i, 'AOsh')
call CatalogAdd(i, 'AHtc')
call CatalogAdd(i, 'AOeq')
call CatalogAdd(i, 'ANrn')
//'Npld' Pit Lord 4 AOsh,AHtc,AOeq,ANrn
set i = CatalogCreate()
set catalog['Npld'] = i
call CatalogAdd(i, 'AOsh')
call CatalogAdd(i, 'AHtc')
call CatalogAdd(i, 'AOeq')
call CatalogAdd(i, 'ANrn')
//'Ocbh' cairne bloodhoof 4 AOsh,AOae,AOre,AOws
set i = CatalogCreate()
set catalog['Ocbh'] = i
call CatalogAdd(i, 'AOsh')
call CatalogAdd(i, 'AOae')
call CatalogAdd(i, 'AOws')
call CatalogAdd(i, 'AOre')
//'Odrt' Drek'Thar 4 AOfs,AOsf,AOcl,AOeq
set i = CatalogCreate()
set catalog['Odrt'] = i
call CatalogAdd(i, 'AOfs')
call CatalogAdd(i, 'AOsf')
call CatalogAdd(i, 'AOcl')
call CatalogAdd(i, 'AOeq')
//'Ogrh' grom hellscream 4 AOwk,AOcr,AOmi,AOww
set i = CatalogCreate()
set catalog['Ogrh'] = i
call CatalogAdd(i, 'AOwk')
call CatalogAdd(i, 'AOcr')
call CatalogAdd(i, 'AOmi')
call CatalogAdd(i, 'AOww')
//'Osam' Samuro 4 AOwk,AOcr,AOmi,AOww
set i = CatalogCreate()
set catalog['Osam'] = i
call CatalogAdd(i, 'AOwk')
call CatalogAdd(i, 'AOcr')
call CatalogAdd(i, 'AOmi')
call CatalogAdd(i, 'AOww')
//'Othr' thrall 4 AOfs,AOsf,AOcl,AOeq
set i = CatalogCreate()
set catalog['Othr'] = i
call CatalogAdd(i, 'AOfs')
call CatalogAdd(i, 'AOsf')
call CatalogAdd(i, 'AOcl')
call CatalogAdd(i, 'AOeq')
//'Uanb' anub'arak 4 AUim,AUts,AUcb,AUls
set i = CatalogCreate()
set catalog['Uanb'] = i
call CatalogAdd(i, 'AUim')
call CatalogAdd(i, 'AUts')
call CatalogAdd(i, 'AUcb')
call CatalogAdd(i, 'AUls')
//'Udth' detheroc 4 AUsl,AEsh,AUcs,AUdd
set i = CatalogCreate()
set catalog['Udth'] = i
call CatalogAdd(i, 'AUsl')
call CatalogAdd(i, 'AEsh')
call CatalogAdd(i, 'AUcs')
call CatalogAdd(i, 'AUdd')
//'Uear' evil arthas 4 AUdc,AUdp,AUau,AUan
set i = CatalogCreate()
set catalog['Uear'] = i
call CatalogAdd(i, 'AUdc')
call CatalogAdd(i, 'AUdp')
call CatalogAdd(i, 'AUau')
call CatalogAdd(i, 'AUan')
//'Uktl' kelthuzadlich 4 AUfn,AUfu,AUdr,AUdd
set i = CatalogCreate()
set catalog['Uktl'] = i
call CatalogAdd(i, 'AUfn')
call CatalogAdd(i, 'AUfu')
call CatalogAdd(i, 'AUdr')
call CatalogAdd(i, 'AUdd')
//'Umal' malganis 4 AUsl,AUcs,ANsl,ANdc
set i = CatalogCreate()
set catalog['Umal'] = i
call CatalogAdd(i, 'AUsl')
call CatalogAdd(i, 'AUcs')
call CatalogAdd(i, 'ANsl')
call CatalogAdd(i, 'ANdc')
//'Usyl' Evil Sylvanas 4 ANsi,ANba,ANdr,ANch
set i = CatalogCreate()
set catalog['Usyl'] = i
call CatalogAdd(i, 'ANsi')
call CatalogAdd(i, 'ANba')
call CatalogAdd(i, 'ANdr')
call CatalogAdd(i, 'ANch')
//'Utic' tichondrius 4 AUsl,AUcs,ANrc,ANfd
set i = CatalogCreate()
set catalog['Utic'] = i
call CatalogAdd(i, 'AUsl')
call CatalogAdd(i, 'AUcs')
call CatalogAdd(i, 'ANrc')
call CatalogAdd(i, 'ANfd')
//'Uvar' varimathras 4 AUsl,AUav,ANrf,ANdo
set i = CatalogCreate()
set catalog['Uvar'] = i
call CatalogAdd(i, 'AUsl')
call CatalogAdd(i, 'AUav')
call CatalogAdd(i, 'ANrf')
call CatalogAdd(i, 'ANdo')
//'Uvng' Vengyr 4 AUav,AUsl,AUcs,AUin
set i = CatalogCreate()
set catalog['Uvng'] = i
call CatalogAdd(i, 'AUav')
call CatalogAdd(i, 'AUsl')
call CatalogAdd(i, 'AUcs')
call CatalogAdd(i, 'AUin')
//'Uwar' archimonde 4 ANrc,ANdp,ANfd,AHbh
set i = CatalogCreate()
set catalog['Uwar'] = i
call CatalogAdd(i, 'ANrc')
call CatalogAdd(i, 'ANdp')
call CatalogAdd(i, 'AHbh')
call CatalogAdd(i, 'ANfd')
//'Hgam' ghostly archmage 4 AHbz,AHab,AHwe,AHmt
set i = CatalogCreate()
set catalog['Hgam'] = i
call CatalogAdd(i, 'AHbz')
call CatalogAdd(i, 'AHab')
call CatalogAdd(i, 'AHwe')
call CatalogAdd(i, 'AHmt')
//'Naka' akama 4 ACs7,AOcl,AEsh,ANr2
set i = CatalogCreate()
set catalog['Naka'] = i
call CatalogAdd(i, 'ACs7')
call CatalogAdd(i, 'AOcl')
call CatalogAdd(i, 'AEsh')
call CatalogAdd(i, 'ANr2')
//'Nsjs' Chen Stormstout 5 ANcf,Acdh,Acdb,Acef,Aamk
set i = CatalogCreate()
set catalog['Nsjs'] = i
call CatalogAdd(i, 'ANcf')
call CatalogAdd(i, 'Acdh')
call CatalogAdd(i, 'Acdb')
call CatalogAdd(i, 'Acef')
call CatalogAdd(i, 'Aamk')
//'Ocb2' cairne bloodhoof (war3x) 5 AOs2,AOr2,AOr3,AOw2,Aamk
set i = CatalogCreate()
set catalog['Ocb2'] = i
call CatalogAdd(i, 'AOs2')
call CatalogAdd(i, 'AOr2')
call CatalogAdd(i, 'AOw2')
call CatalogAdd(i, 'AOr3')
call CatalogAdd(i, 'Aamk')
//'Orex' Rexxar 5 Arsg,Arsq,ANsb,Arsp,Aamk
set i = CatalogCreate()
set catalog['Orex'] = i
call CatalogAdd(i, 'Arsg')
call CatalogAdd(i, 'Arsq')
call CatalogAdd(i, 'ANsb')
call CatalogAdd(i, 'Arsp')
call CatalogAdd(i, 'Aamk')
//'Orkn' Rokhan 5 ANhw,ANhx,Arsw,AOls,Aamk
set i = CatalogCreate()
set catalog['Orkn'] = i
call CatalogAdd(i, 'ANhw')
call CatalogAdd(i, 'ANhx')
call CatalogAdd(i, 'Arsw')
call CatalogAdd(i, 'AOls')
call CatalogAdd(i, 'Aamk')
//'Ubal' balnazzar 5_2 AUsl,AUav,ANr3,AOeq,ACf3
set i = CatalogCreate()
set catalog['Ubal'] = i
call CatalogAdd(i, 'AUsl') //3
call CatalogAdd(i, 'AUav') //3
call CatalogAdd(i, 'ANr3') //3
call CatalogAdd(i, 'AOeq') //1
call CatalogAdd(i, 'ACf3') //1
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
//use catalogs
library Catalogs uses HeroCatalog, PetCatalog, ItemCatalog, AbilityCatalog
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/*
An Encoder is a frame that generates a save/load code. This frame contains slots that can hold values.
A save/load code is just a collection of values compressed into one huge number.
Building an Encoder object is a lot like building a clump of structs.
Each Encoder object is a set of dynamic objects. All of an objects properties are linked
to that object and all of the objects are linked to the Encoder.
Hero -> loc -> x
y
facing
Each object consists of slots that can store values. Each slot can hold a range of values (a minimum
value to a maximum value). For example, a slot for gold might hold 0 to 1000000.
Slots are called CodeRanges and they can be used. An example of resource slots (gold/lumber)
CodeRange resource = CodeRange.create(0,1000000)
The object they are added to is the Encoder object. The encoder objects store 6 things-
the slots
minimum code size (bounds)
maximum code size (bounds)
the maximum checksum (to prevent tampering)
the base (characters used in code)
encoder version (used for backwards compatibility
The create method takes the last five parameters.
Encoder encoder = Encoder.create(base,minCodeSize,maxCodeSize,checksum,version)
An example call using an alphanumeric base (0-9, a-z, A-Z), min code size of 12,
max code size of 24, a hash of 148194, and a version of 1
Encoder encoder = Encoder.create("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",12,24,148194,1)
From here, slots are added to the encoder with the add method.
call encoder.add(resource) //adding slot for storing lumber to the encoder
call encoder.add(resource) //adding slot for storing gold to the encoder
Recall that each slot can represent an object because slots can be linked to. This means that rather than
just adding quick value ranges to encoders, objects can be added, like a hero object.
Recall that heroes have xp, level, stats, an inventory, life, mana, and a location.
First, the slots need to be created. I will be using UnitStatePercent for this example, so my ranges
for xp, life, mana, and coordinates will be percents (0 to 100).
*/
//ids are used for slots that may or may not exist (like item charges for items)
//recall that not all items have item charges. This can tell whether on an item charge
//slot or not and moreover, can tell exactly how many max item charges the slot refers to.
//for saving and loading, not really building encoders =).
//constant integer ITEM_CHARGE_2 = 1 //item charge 2 id
//constant integer ITEM_CHARGE_6 = 2 //item charge 6 id
//constant integer ITEM_CHARGE_15 = 3 //item charge 15 id
//if you don't care about how many item charges you have, you just want to know whether the
//slot is an item charge slot, you can just use the value 1
//I will be using the value 1 in this example since I don't really care exactly how
//many item charges an item has, hence why the above is commented out. The above would
//also be globals.
Encoder encoder = Encoder.create("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",12,24,148194,1)
CodeRange hero = CodeRange.create(0,10) //10 heroes in the map, may not have a hero
CodeRange xp = CodeRange.create(0,99) //recall that 100% xp is next lvl and max lvl is 0% xp
CodeRange lvl = CodeRange.create(1,10) //recall hero lvls start at 1
CodeRange stat = CodeRange.create(1,256) //each stat has a max of 256
CodeRange coord = CodeRange.create(0,100) //x,y coord and facing as a percent of max
CodeRange item = Coderange.create(0,100) //100 items in the map, may not have an item
CodeRange itemCharge2 = CodeRange.create(1,2) //2 max item charges, perishable (notice 0 not min)
CodeRange itemCharge6 = CodeRange.create(0,6) //6 max item charge, permanent (notice 0 min)
CodeRange itemCharge15 = CodeRange.create(1,15) //15 max item charge, perishable
CodeRange states = CodeRange.create(0,0) //mana,life
CodeRange resource = CodeRange.create(0,0) //gold, lumber
CodeRange inventory = CodeRange.create(0,0) //0,0 means that the thing is just a pointer*
//pointers don't store values, they just point to
//something : ). Can be useful.
CodeRange location = CodeRange.create(0,0)
//linka is link all values
//link normally links a range of values*
//build the location object (x,y,facing)
call location.linka(coord) //give location an x coordinate
call location.linka(coord) //give location a y coordinate
call location.linka(coord) //give location a facing
//build the item object (item charges?)
call item.link(30,60,itemCharge2,1) //give items from 30 to 60 an item charge slot\
call item.link(31,60,itemCharge6,1) //give items from 61 to 70 an item charge slot
call item.link(61,100,itemCharge15,1) //give items from 61 to 100 an item charge slot
//build the inventory object (6 items)
//for our purposes, every hero will have an inventory of 6 items
call inventory.linka(item)
call inventory.linka(item)
call inventory.linka(item)
call inventory.linka(item)
call inventory.linka(item)
call inventory.linka(item)
//build the stats object (str, agi, int)
call stats.linka(stat) //str
call stats.linka(stat) //agi
call stats.linka(stat) //int
//build the stats object (life, mana)
call states.linka(coord) //life
//coord has same range as life range, so just reuse it
call states.linka(coord) //mana
//don't link null heros to have properties :P
//I use 0 hero because it is known whether the hero is null or not
//upon saving/loading it. The id doesn't matter in this case.
call hero.link(1,10,location,0) //I link the location first because when a hero is created, the
//id, x, y, and facing are needed in that order
call hero.link(1,10,stats,0) //give hero stats. I link stats before inventory because when loading,
//items may change a hero's stats.
call hero.link(1,10,inventory,0) //give hero an inventory
call hero.link(1,10,states,0) //i link states last since a hero's life%/mana% can change if loading
//stats, items, and etc after setting the unit's life/mana.
//at this point, the objects are all built.
//in Encoder, the last range added to the Encoder can't be an object, it has to just be
//a range. This is because of an efficiency perk. This is the reason I didn't create
//a resource pointer and link it to gold/lumber ranges.
//The last range added to the Encoder should be the largest range that typically
//contains the largest values (to ensure smaller codes). For this reason, I will add
//gold to the Encoder last.
call encoder.add(hero) //add the hero
call encoder.add(resource) //add lumber
call encoder.add(resource) //add gold
/*
And that is all there is to creating an Encoder object. See code in the Encoders trigger to see a more
complicated example.
*/
//TESH.scrollpos=21
//TESH.alwaysfold=0
//this is where Encoder objects are formed up and managed
//the template allows a map to have 9 Encoder objects at one time, meaning
//that a map can load up a save/load code from 9 versions ago.
library Encoders uses Catalogs
globals
private constant integer CUR_ENC_VER = 1
private Encoder array encoders
endglobals
function GetEncoder takes nothing returns Encoder
return encoders[CUR_ENC_VER]
endfunction
private struct Encoder1 extends array
//the encoder version associated with this module
private static constant integer ENC_VER = 1
//the characters that can be used in the save/load code
//more characters means smaller codes
private static constant string ENCODER_BASE = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
//the maximum security checksum that can be used in the save/load code
//bigger means more secure, but longer code. Smaller means less secure (easier to
//tamper code or let typos go by w/o noticing them), but smaller codes. I suggest
//6 digits.
private static constant integer ENCODER_HASH = 148194
private static constant integer MIN_CODE_SIZE = 20
private static constant integer MAX_CODE_SIZE = 65
private static method onInit takes nothing returns nothing
//code ranges are local because of links*
//a code range in an earlier version may not link to the same things
//as the same code range from a later version
local Encoder encoder = Encoder.create(ENCODER_BASE,MIN_CODE_SIZE,MAX_CODE_SIZE,ENCODER_HASH,1)
//hero code range
local CodeRange hero = CodeRange.create(1,HeroCatalog1.count)
local CodeRange lvl = CodeRange.create(1,10) //level
local CodeRange xp = CodeRange.create(0,99) //xp
local CodeRange stats = CodeRange.create(0,0) //stats (str, agi, int)
local CodeRange stat = CodeRange.create(1,256)
//inventory code range
local CodeRange inv6 = CodeRange.create(0,0)
local CodeRange it = CodeRange.create(0,ItemCatalog1.count) //item
//life, mana
local CodeRange state = CodeRange.create(0,0)
//location code range
local CodeRange loc = CodeRange.create(0,0)
//pet code range
local CodeRange pet = CodeRange.create(0,PetCatalog1.count)
//4 pets
local CodeRange pet4 = CodeRange.create(0,0)
//percent code range
local CodeRange perc = CodeRange.create(0,100)
//ability levels
local CodeRange a1 = CodeRange.create(0,1)
local CodeRange a2 = CodeRange.create(0,2)
local CodeRange a3 = CodeRange.create(0,3)
local CodeRange a4 = CodeRange.create(0,4)
//item charges
local CodeRange c2 = CodeRange.create(1,2)
local CodeRange c3 = CodeRange.create(1,3)
local CodeRange c4 = CodeRange.create(1,4)
local CodeRange c5 = CodeRange.create(1,5)
local CodeRange c6 = CodeRange.create(1,6)
local CodeRange c10 = CodeRange.create(1,10)
//abilities
local CodeRange abil4 = CodeRange.create(0,0)
local CodeRange abil5 = CodeRange.create(0,0)
local CodeRange abil5_2 = CodeRange.create(0,0)
//gold and lumber code range
local CodeRange resource = CodeRange.create(0,1000000)
//item charges
call it.link(ItemCatalog1.charge2Min, ItemCatalog1.charge2Max, c2, 1)
call it.link(ItemCatalog1.charge3Min, ItemCatalog1.charge3Max, c3, 1)
call it.link(ItemCatalog1.charge4Min, ItemCatalog1.charge4Max, c4, 1)
call it.link(ItemCatalog1.charge5Min, ItemCatalog1.charge5Max, c5, 1)
call it.link(ItemCatalog1.charge6Min, ItemCatalog1.charge6Max, c6, 1)
call it.link(ItemCatalog1.charge10Min, ItemCatalog1.charge10Max, c10, 1)
//life,mana
call state.linka(perc) //life
call state.linka(perc) //mana
//ability levels: 3,3,3,1
call abil4.linka(a3)
call abil4.linka(a3)
call abil4.linka(a3)
call abil4.linka(a1)
//ability levels: 4,4,4,2,4
call abil5.linka(a4)
call abil5.linka(a4)
call abil5.linka(a4)
call abil5.linka(a2)
call abil5.linka(a4)
call abil5_2.linka(abil4)
call abil5_2.linka(a1)
//link 3 percents to location (x,y, facing)
call loc.linka(perc) //x
call loc.linka(perc) //y
call loc.linka(xp) //facing
//link 5 stats to stat
call stats.linka(lvl) //level
call stats.linka(xp) //xp%
call stats.linka(stat) //str
call stats.linka(stat) //agi
call stats.linka(stat) //int
//link 6 items to inventory
call inv6.linka(it) //item 1
call inv6.linka(it) //item 2
call inv6.linka(it) //item 3
call inv6.linka(it) //item 4
call inv6.linka(it) //item 5
call inv6.linka(it) //item 6
//give all existing pets a location and life,mana
//if the pet is null, then the data is not linked to.
call pet.link(1, PetCatalog1.count, loc, 0) //x,y,facing
call pet.link(1, PetCatalog1.count, state, 0) //life,mana
//it may be true that not all units have mana, but keep in mind
//that a unit may be upgraded to have mana*, so it's typically a
//good idea to save states.
//link 4 pets to pet4
call pet4.linka(pet) //pet 1
call pet4.linka(pet) //pet 2
call pet4.linka(pet) //pet 3
call pet4.linka(pet) //pet 4
call hero.linka(loc) //x,y,facing
call hero.linka(stats) //stats
call hero.linka(inv6) //6 slot inventory
//heroes that have 4 abilities will have 4 places to store abilities
call hero.link(HeroCatalog1.abil4Min, HeroCatalog1.abil4Max, abil4, 0)
//heroes that have 5 abilities will have 5 places to store abilities
call hero.link(HeroCatalog1.abil5Min, HeroCatalog1.abil5Max, abil5, 0)
//heroes with special 5 abils
call hero.link(HeroCatalog1.abil5_2Min, HeroCatalog1.abil5_2Max, abil5_2, 0)
call hero.linka(state) //life,mana
//heroes with 0 abilities will have no places to store abilities
call hero.linka(pet4) //4 pets
call encoder.add(hero) //hero
call encoder.add(resource) //lumber
call encoder.add(resource) //gold
set encoders[ENC_VER] = encoder
endmethod
endstruct
private struct Encoder2 extends array
private static constant integer ENC_VER = 2
private static constant string ENCODER_BASE = ""
private static constant integer ENCODER_HASH = 0
private static constant integer ENCODER_PLAYER_HASH = 0
private static method onInit takes nothing returns nothing
local Encoder encoder = 0
set encoders[ENC_VER] = encoder
endmethod
endstruct
private struct Encoder3 extends array
private static constant integer ENC_VER = 3
private static constant string ENCODER_BASE = ""
private static constant integer ENCODER_HASH = 0
private static constant integer ENCODER_PLAYER_HASH = 0
private static method onInit takes nothing returns nothing
local Encoder encoder = 0
set encoders[ENC_VER] = encoder
endmethod
endstruct
private struct Encoder4 extends array
private static constant integer ENC_VER = 4
private static constant string ENCODER_BASE = ""
private static constant integer ENCODER_HASH = 0
private static constant integer ENCODER_PLAYER_HASH = 0
private static method onInit takes nothing returns nothing
local Encoder encoder = 0
set encoders[ENC_VER] = encoder
endmethod
endstruct
private struct Encoder5 extends array
private static constant integer ENC_VER = 5
private static constant string ENCODER_BASE = ""
private static constant integer ENCODER_HASH = 0
private static constant integer ENCODER_PLAYER_HASH = 0
private static method onInit takes nothing returns nothing
local Encoder encoder = 0
set encoders[ENC_VER] = encoder
endmethod
endstruct
private struct Encoder6 extends array
private static constant integer ENC_VER = 6
private static constant string ENCODER_BASE = ""
private static constant integer ENCODER_HASH = 0
private static constant integer ENCODER_PLAYER_HASH = 0
private static method onInit takes nothing returns nothing
local Encoder encoder = 0
set encoders[ENC_VER] = encoder
endmethod
endstruct
private struct Encoder7 extends array
private static constant integer ENC_VER = 7
private static constant string ENCODER_BASE = ""
private static constant integer ENCODER_HASH = 0
private static constant integer ENCODER_PLAYER_HASH = 0
private static method onInit takes nothing returns nothing
local Encoder encoder = 0
set encoders[ENC_VER] = encoder
endmethod
endstruct
private struct Encoder8 extends array
private static constant integer ENC_VER = 8
private static constant string ENCODER_BASE = ""
private static constant integer ENCODER_HASH = 0
private static constant integer ENCODER_PLAYER_HASH = 0
private static method onInit takes nothing returns nothing
local Encoder encoder = 0
set encoders[ENC_VER] = encoder
endmethod
endstruct
private struct Encoder9 extends array
private static constant integer ENC_VER = 9
private static constant string ENCODER_BASE = ""
private static constant integer ENCODER_HASH = 0
private static constant integer ENCODER_PLAYER_HASH = 0
private static method onInit takes nothing returns nothing
local Encoder encoder = 0
set encoders[ENC_VER] = encoder
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Random uses Catalogs
//gives player gold, lumber, hero with items, and 4 pets
// -random
globals
boolean array pdata
unit array hero
integer array petCount
unit array pet1
unit array pet2
unit array pet3
unit array pet4
endglobals
struct Random extends array
static method remove takes player p, integer pid returns nothing
local integer i
if (pdata[pid]) then
set i = UnitInventorySize(hero[pid])
loop
exitwhen i == 0
set i = i - 1
call RemoveItem(UnitItemInSlot(hero[pid], i))
endloop
call RemoveUnit(hero[pid])
if (petCount[pid] > 0) then
call RemoveUnit(pet1[pid])
set pet1[pid] = null
if (petCount[pid] > 1) then
call RemoveUnit(pet2[pid])
set pet2[pid] = null
if (petCount[pid] > 2) then
call RemoveUnit(pet3[pid])
set pet3[pid] = null
if (petCount[pid] > 3) then
call RemoveUnit(pet4[pid])
set pet4[pid] = null
endif
endif
endif
set petCount[pid] = 0
endif
set hero[pid] = null
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, 0)
call SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, 0)
set pdata[pid] = false
endif
endmethod
private static method run takes nothing returns boolean
local player p = GetTriggerPlayer()
local integer pid = GetPlayerId(p)
local integer i
call remove(p, pid)
set hero[pid] = CreateUnit(p, HeroCatalog1[GetRandomInt(1, HeroCatalog1.count)].raw, 2400, -100, 0)
set i = UnitInventorySize(hero[pid])
loop
exitwhen i == 0
set i = i - 1
call UnitAddItem(hero[pid], CreateItem(ItemCatalog1[GetRandomInt(1, ItemCatalog1.count)].raw, 300, 500))
endloop
call AddHeroXP(hero[pid], GetRandomInt(1, 5400), false)
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, GetRandomInt(0, 1000000))
call SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, GetRandomInt(0, 1000000))
set petCount[pid] = GetRandomInt(0, 4)
if (petCount[pid] > 0) then
set pet1[pid] = CreateUnit(p, PetCatalog1[GetRandomInt(1, PetCatalog1.count)].raw, 2400, -100, 0)
if (petCount[pid] > 1) then
set pet2[pid] = CreateUnit(p, PetCatalog1[GetRandomInt(1, PetCatalog1.count)].raw, 2400, -100, 0)
if (petCount[pid] > 2) then
set pet3[pid] = CreateUnit(p, PetCatalog1[GetRandomInt(1, PetCatalog1.count)].raw, 2400, -100, 0)
if (petCount[pid] > 3) then
set pet4[pid] = CreateUnit(p, PetCatalog1[GetRandomInt(1, PetCatalog1.count)].raw, 2400, -100, 0)
endif
endif
endif
endif
set pdata[pid] = true
return false
endmethod
private static method onInit takes nothing returns nothing
local integer i = 11
local trigger t = CreateTrigger()
loop
if (GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(i)) == MAP_CONTROL_USER) then
call TriggerRegisterPlayerChatEvent(t, Player(i), "-random", true)
endif
exitwhen i == 0
set i = i - 1
endloop
call TriggerAddCondition(t, function thistype.run)
endmethod
endstruct
endlibrary
//TESH.scrollpos=3
//TESH.alwaysfold=0
library Min uses Random
// -min
private struct Min extends array
private static method run takes nothing returns boolean
local player p = GetTriggerPlayer()
local integer pid = GetPlayerId(p)
local integer i
call Random.remove(p, pid)
set hero[pid] = CreateUnit(p, HeroCatalog1[1].raw, 0, 0, 0)
call PauseUnit(hero[pid], true)
call SetWidgetLife(hero[pid], GetUnitState(hero[pid], UNIT_STATE_MAX_LIFE)*.01)
call SetUnitState(hero[pid], UNIT_STATE_MANA, 0)
call SetUnitX(hero[pid], WorldBounds.minX)
call SetUnitY(hero[pid], WorldBounds.minY)
set pdata[pid] = true
return false
endmethod
private static method onInit takes nothing returns nothing
local integer i = 11
local trigger t = CreateTrigger()
loop
if (GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(i)) == MAP_CONTROL_USER) then
call TriggerRegisterPlayerChatEvent(t, Player(i), "-min", true)
endif
exitwhen i == 0
set i = i - 1
endloop
call TriggerAddCondition(t, function thistype.run)
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
library Max uses Random
// -max
private struct Max extends array
private static method run takes nothing returns boolean
local player p = GetTriggerPlayer()
local integer pid = GetPlayerId(p)
local integer i
call Random.remove(p, pid)
set hero[pid] = CreateUnit(p, HeroCatalog1[HeroCatalog1.count].raw, 0, 0, 356.4)
call SetUnitX(hero[pid], WorldBounds.maxX)
call SetUnitY(hero[pid], WorldBounds.maxY)
call AddHeroXP(hero[pid], 5399, true)
set i = UnitInventorySize(hero[pid])
loop
exitwhen i == 0
set i = i - 1
call UnitAddItem(hero[pid], CreateItem(ItemCatalog1[ItemCatalog1.count].raw, 300, 500))
endloop
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, 1000000)
call SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, 1000000)
set petCount[pid] = 4
set pet1[pid] = CreateUnit(p, PetCatalog1[PetCatalog1.count].raw, 2400, -100, 0)
set pet2[pid] = CreateUnit(p, PetCatalog1[PetCatalog1.count].raw, 2400, -100, 0)
set pet3[pid] = CreateUnit(p, PetCatalog1[PetCatalog1.count].raw, 2400, -100, 0)
set pet4[pid] = CreateUnit(p, PetCatalog1[PetCatalog1.count].raw, 2400, -100, 0)
call SetUnitX(pet1[pid], WorldBounds.maxX)
call SetUnitY(pet1[pid], WorldBounds.maxY)
call SetUnitX(pet2[pid], WorldBounds.maxX)
call SetUnitY(pet2[pid], WorldBounds.maxY)
call SetUnitX(pet3[pid], WorldBounds.maxX)
call SetUnitY(pet3[pid], WorldBounds.maxY)
call SetUnitX(pet4[pid], WorldBounds.maxX)
call SetUnitY(pet4[pid], WorldBounds.maxY)
set pdata[pid] = true
return false
endmethod
private static method onInit takes nothing returns nothing
local integer i = 11
local trigger t = CreateTrigger()
loop
if (GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(i)) == MAP_CONTROL_USER) then
call TriggerRegisterPlayerChatEvent(t, Player(i), "-max", true)
endif
exitwhen i == 0
set i = i - 1
endloop
call TriggerAddCondition(t, function thistype.run)
endmethod
endstruct
endlibrary
//TESH.scrollpos=0
//TESH.alwaysfold=0
/*
Old save/load systems were pretty easy to handle when it came to saving and loading. Every value
was always in the code, so it was simply about writing the values to the code and reading them out.
What happens if a value may or may not be in a code? How do you know how to treat the value you read out?
In Encoder, you assign custom ids to the links you create, that way you know precisely where you are. Rather
than loading components of the code, objects are loaded.
loadHero()
The loadHero might then read a hero out and load an inventory (based on hero).
Inventory may then load up items, and those items would read items and then possibly load up item charges.
--------------------------------------------------------------------
private static method saveItem takes DataBuffer db, item i returns nothing
call db.write(ItemCatalog[GetItemTypeId(i)].id) //item catalog id
//if item has charges
if (db.id == CHARGE_25 or db.id == CHARGE_10) then
call db.write(GetItemCharges(i))
endif
endmethod
//save inventory with 6 slots
private static method saveInventory6 takes DataBuffer db, unit u returns nothing
call saveItem(db, UnitItemInSlot(u, 0)) //save item
call saveItem(db, UnitItemInSlot(u, 1)) //save item
call saveItem(db, UnitItemInSlot(u, 2)) //save item
call saveItem(db, UnitItemInSlot(u, 3)) //save item
call saveItem(db, UnitItemInSlot(u, 4)) //save item
call saveItem(db, UnitItemInSlot(u, 5)) //save item
endmethod
--------------------------------------------------------------------
Notice how first the inventory is saved and in there it just calls saveItem 6 times. saveItem then always writes
the item into the Encoder because the item slot is assuredly there, but afterwards it checks* for an item charge
slot.
The same deal occurs when loading.
Another interesting note: because slots may or may not exist, cracking the code is virtually impossible. Changing
one value could possibly change which slots are used and which aren't, meaning the entire structure of the code
is changed.
The first step is to collect all of the information. Note that I retrieved link ids for slots that may
or may not exist.
--------------------------------------------------------------------
inv6
item
item
item
item
item
item
item
ItemCatalog1.CHARGE_2
ItemCatalog1.CHARGE_3
ItemCatalog1.CHARGE_4
ItemCatalog1.CHARGE_5
ItemCatalog1.CHARGE_6
state
life%
mana%
ability levels
HeroCatalog1.ABILITY_4: 3,3,3,1
HeroCatalog1.ABILITY_5: 4,4,4,2,4
loc
x%
y%
facing%
pet
loc
state
pet4
pet
pet
pet
pet
stats
lvl
xp%
str
agi
int
hero
loc
stats
inv6
abilities
state
pet4
lumber
gold
--------------------------------------------------------------------
After this, rearrange the data so that it is more readable. Start with things that are actually added
to the Encoder.
--------------------------------------------------------------------
hero
lumber
gold
--------------------------------------------------------------------
Now just fill in all of the links
--------------------------------------------------------------------
hero
x%
y%
facing%
lvl
xp%
str
agi
int
item
ItemCatalog1.CHARGE_2
ItemCatalog1.CHARGE_3
ItemCatalog1.CHARGE_4
ItemCatalog1.CHARGE_5
ItemCatalog1.CHARGE_6
item
ItemCatalog1.CHARGE_2
ItemCatalog1.CHARGE_3
ItemCatalog1.CHARGE_4
ItemCatalog1.CHARGE_5
ItemCatalog1.CHARGE_6
item
ItemCatalog1.CHARGE_2
ItemCatalog1.CHARGE_3
ItemCatalog1.CHARGE_4
ItemCatalog1.CHARGE_5
ItemCatalog1.CHARGE_6
item
ItemCatalog1.CHARGE_2
ItemCatalog1.CHARGE_3
ItemCatalog1.CHARGE_4
ItemCatalog1.CHARGE_5
ItemCatalog1.CHARGE_6
item
ItemCatalog1.CHARGE_2
ItemCatalog1.CHARGE_3
ItemCatalog1.CHARGE_4
ItemCatalog1.CHARGE_5
ItemCatalog1.CHARGE_6
item
ItemCatalog1.CHARGE_2
ItemCatalog1.CHARGE_3
ItemCatalog1.CHARGE_4
ItemCatalog1.CHARGE_5
ItemCatalog1.CHARGE_6
HeroCatalog1.ABILITY_4|HeroCatalog1.ABILITY_5|HeroCatalog1.ABILITY_5_2
life%
mana%
pet
x%
y%
facing%
life%
mana%
pet
x%
y%
facing%
life%
mana%
pet
x%
y%
facing%
life%
mana%
pet
x%
y%
facing%
life%
mana%
lumber
gold
--------------------------------------------------------------------
And now it is clear what order to save and load in.
You can also format it to make it a bit easier to read
--------------------------------------------------------------------
hero
x%,y%,facing%
lvl,xp%,str,agi,int
item x6
ItemCatalog1.CHARGE_2
ItemCatalog1.CHARGE_3
ItemCatalog1.CHARGE_4
ItemCatalog1.CHARGE_5
ItemCatalog1.CHARGE_6
HeroCatalog1.ABILITY_4|HeroCatalog1.ABILITY_5|HeroCatalog1.ABILITY_5_2
life%,mana%
pet x4
x%,y%,facing%
life%,mana%
lumber
gold
--------------------------------------------------------------------
After this, you need to figure out which objects you are actually saving/loading. The above
format actually splits it up pretty well.
--------------------------------------------------------------------
Hero
Location
Stats
Inventory
Item (6)
Item Charge?
Abilities 4|5|5_2
States
Pets
Pet (4)
Location
States
lumber
gold
--------------------------------------------------------------------
The above clearly shows the objects-
Hero, Location, Stats, Inventory, Item, Abilities, States, Pets, Pet, Location, States, Lumber, Gold
You could go a bit further and say Item Charge is an object, but it's by itself and is only used by items,
so it's a bit overkill.
Every object that points to a lot of things or is pointed to by a lot of things gets a method.
->Hero, Location, Stats, Inventory, Item, Abilities, States, Pets, Pet
So 8 methods are needed
private static method saveAbilities takes DataBuffer buffer, unit hero returns nothing
private static method saveItem takes DataBuffer buffer, item i returns nothing
private static method saveInventory takes DataBuffer buffer, unit u returns nothing
private static method saveStates takes DataBuffer buffer, unit u returns nothing
private static method saveStats takes DataBuffer buffer, unit hero returns nothing
private static method saveLocation takes DataBuffer buffer, unit u returns nothing
private static method savePet takes DataBuffer buffer, unit u returns nothing
private static method savePets takes DataBuffer buffer, integer pid returns nothing
private static method saveHero takes DataBuffer buffer, unit hero, integer pid returns nothing
Note that I always pass in the DataBuffer as the methods need that in order to write values. I also pass
in any needed information.
Order of the methods matters! No method should be calling a method under it.
The final results are in the saving and loading triggers.
*/
//TESH.scrollpos=0
//TESH.alwaysfold=0
//enable this trigger and disable the Saving trigger to see all the data being saved
struct Saver extends array
//HeroCatalog1.ABILITY_4,5
private static method saveAbilities takes DataBuffer buffer, unit hero returns nothing
local AbilityCatalog1 i = AbilityCatalog1[GetUnitTypeId(hero)]
local integer c = i.count
local integer o = 0
loop
exitwhen o == c
set o = o + 1
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Ability Level: " + I2S(GetUnitAbilityLevel(hero, i.raw(o))))
call buffer.write(GetUnitAbilityLevel(hero, i.raw(o)))
endloop
endmethod
//ItemCatalog1.CHARGE_2,3,4,5,6
private static method saveItem takes DataBuffer buffer, item i returns nothing
if (i == null) then
call buffer.write(0)
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Item: " + I2S(ItemCatalog1[GetItemTypeId(i)].id))
call buffer.write(ItemCatalog1[GetItemTypeId(i)].id)
if (/*
*/buffer.id == ItemCatalog1.CHARGE_2 /*
*/or buffer.id == ItemCatalog1.CHARGE_3 /*
*/or buffer.id == ItemCatalog1.CHARGE_4 /*
*/or buffer.id == ItemCatalog1.CHARGE_5 /*
*/or buffer.id == ItemCatalog1.CHARGE_6 /*
*/or buffer.id == ItemCatalog1.CHARGE_10/*
*/) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Item Charges: " + I2S(GetItemCharges(i)))
call buffer.write(GetItemCharges(i))
endif
endif
endmethod
//item x6
private static method saveInventory takes DataBuffer buffer, unit u returns nothing
call saveItem(buffer, UnitItemInSlot(u, 0))
call saveItem(buffer, UnitItemInSlot(u, 1))
call saveItem(buffer, UnitItemInSlot(u, 2))
call saveItem(buffer, UnitItemInSlot(u, 3))
call saveItem(buffer, UnitItemInSlot(u, 4))
call saveItem(buffer, UnitItemInSlot(u, 5))
endmethod
//life%,mana%
private static method saveStates takes DataBuffer buffer, unit u returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Life: " + I2S(GetPercentUnitLife(u)))
call buffer.write(GetPercentUnitLife(u))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Mana: " + I2S(GetPercentUnitMana(u)))
call buffer.write(GetPercentUnitMana(u))
endmethod
//lvl,xp%,str,agi,int
private static method saveStats takes DataBuffer buffer, unit hero returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Level: " + I2S(GetHeroLevel(hero)))
call buffer.write(GetHeroLevel(hero))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "xp: " + I2S(GetPercentHeroXP(hero)))
call buffer.write(GetPercentHeroXP(hero))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Strength: " + I2S(GetHeroStr(hero, false)))
call buffer.write(GetHeroStr(hero, false))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Agility: " + I2S(GetHeroAgi(hero, false)))
call buffer.write(GetHeroAgi(hero, false))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Intelligence: " + I2S(GetHeroInt(hero, false)))
call buffer.write(GetHeroInt(hero, false))
endmethod
//x%,y%,facing%
private static method saveLocation takes DataBuffer buffer, unit u returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "x: " + I2S(GetPercentUnitX(u)))
call buffer.write(GetPercentUnitX(u))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "y: " + I2S(GetPercentUnitY(u)))
call buffer.write(GetPercentUnitY(u))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "facing: " + I2S(GetPercentUnitFacing(u)))
call buffer.write(GetPercentUnitFacing(u))
endmethod
private static method savePet takes DataBuffer buffer, unit u returns nothing
if (u == null) then
call buffer.write(0)
else
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Pet: " + I2S(PetCatalog1[GetUnitTypeId(u)].id))
call buffer.write(PetCatalog1[GetUnitTypeId(u)].id)
call saveLocation(buffer, u)
call saveStates(buffer, u)
endif
endmethod
//pets x4
private static method savePets takes DataBuffer buffer, integer pid returns nothing
call savePet(buffer, pet1[pid])
call savePet(buffer, pet2[pid])
call savePet(buffer, pet3[pid])
call savePet(buffer, pet4[pid])
endmethod
//hero
private static method saveHero takes DataBuffer buffer, unit hero, integer pid returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Hero: " + I2S(HeroCatalog1[GetUnitTypeId(hero)].id))
call buffer.write(HeroCatalog1[GetUnitTypeId(hero)].id)
call saveLocation(buffer, hero)
call saveStats(buffer, hero)
call saveInventory(buffer, hero)
call saveAbilities(buffer, hero)
call saveStates(buffer, hero)
call savePets(buffer, pid)
endmethod
private static method run takes nothing returns boolean
local player p = GetTriggerPlayer()
local integer pid = GetPlayerId(p)
local Encoder encoder
local DataBuffer buffer
if (pdata[pid]) then
set encoder = GetEncoder()
set buffer = encoder.write(pid)
//now write to it in order that the data was added to it
/*
hero
x%,y%,facing%
lvl,xp%,str,agi,int
item x6
ItemCatalog1.CHARGE_2
ItemCatalog1.CHARGE_3
ItemCatalog1.CHARGE_4
ItemCatalog1.CHARGE_5
ItemCatalog1.CHARGE_6
life%,mana%
HeroCatalog1.ABILITY_4
HeroCatalog1.ABILITY_5
pet x4
x%,y%,facing%
life%,mana%
lumber
gold
*/
call saveHero(buffer, hero[pid], pid)
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Lumber: " + I2S(GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER)))
call buffer.write(GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Gold: " + I2S(GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD)))
call buffer.write(GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD))
//display the encoder version and code
call DisplayTimedTextToPlayer(p, 0, 0, 60, "Encoder Version: " + encoder.toString())
call DisplayTimedTextToPlayer(p, 0, 0, 60, buffer.code)
endif
return false
endmethod
private static method onInit takes nothing returns nothing
local integer i = 11
local trigger t = CreateTrigger()
loop
if (GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(i)) == MAP_CONTROL_USER) then
call TriggerRegisterPlayerChatEvent(t, Player(i), "-save", true)
endif
exitwhen i == 0
set i = i - 1
endloop
call TriggerAddCondition(t, function thistype.run)
endmethod
endstruct
//TESH.scrollpos=99
//TESH.alwaysfold=0
//enable this trigger and disable the Loading trigger to see all the data being loaded
struct Loader extends array
private static constant string INVALID_CODE = "|cffff0000Invalid Code"
private static constant string DELIMITER = ","
//HeroCatalog1.ABILITY_4,5
private static method loadAbilities takes DataBuffer buffer, unit hero returns nothing
local AbilityCatalog1 i = AbilityCatalog1[GetUnitTypeId(hero)]
local integer c = i.count
local integer o = 0
local integer h
loop
exitwhen o == c
set o = o + 1
set h = buffer.read()
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Ability Level: " + I2S(h))
if (h > 0) then
call UnitAddAbility(hero, i.raw(o))
call SetUnitAbilityLevel(hero, i.raw(o), h)
call UnitModifySkillPoints(hero, -h)
endif
endloop
endmethod
//ItemCatalog1.CHARGE_2,3,4,5,6
private static method loadItem takes DataBuffer buffer, unit u returns nothing
local integer id = buffer.read()
local item i
if (id != 0) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Item Id: " + I2S(id))
set i = CreateItem(ItemCatalog1[id].raw, 0, 0)
call UnitAddItem(u, i)
if (/*
*/buffer.id == ItemCatalog1.CHARGE_2 /*
*/or buffer.id == ItemCatalog1.CHARGE_3 /*
*/or buffer.id == ItemCatalog1.CHARGE_4 /*
*/or buffer.id == ItemCatalog1.CHARGE_5 /*
*/or buffer.id == ItemCatalog1.CHARGE_6 /*
*/or buffer.id == ItemCatalog1.CHARGE_10/*
*/) then
set id = buffer.read()
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Item Charges: " + I2S(id))
call SetItemCharges(i, id)
endif
endif
set i = null
endmethod
//item x6
private static method loadInventory takes DataBuffer buffer, unit u returns nothing
call loadItem(buffer, u)
call loadItem(buffer, u)
call loadItem(buffer, u)
call loadItem(buffer, u)
call loadItem(buffer, u)
call loadItem(buffer, u)
endmethod
//life%,mana%
private static method loadStates takes DataBuffer buffer, unit u returns nothing
local integer l = buffer.read()
local integer m = buffer.read()
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Life: " + I2S(l))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Mana: " + I2S(m))
call SetPercentUnitLife(u, l)
call SetPercentUnitMana(u, m)
endmethod
//lvl,xp%,str,agi,int
private static method loadStats takes DataBuffer buffer, unit hero returns nothing
local integer lvl = buffer.read()
local integer xp = buffer.read()
local integer str = buffer.read()
local integer agi = buffer.read()
local integer int = buffer.read()
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Level: " + I2S(lvl))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Xp: " + I2S(xp))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Strength: " + I2S(str))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Agility: " + I2S(agi))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Intelligence: " + I2S(int))
if (lvl > 1) then
call SetHeroLevel(hero, lvl, false)
endif
call AddPercentHeroXP(hero, xp)
call SetHeroStr(hero, str, true)
call SetHeroAgi(hero, agi, true)
call SetHeroInt(hero, int, true)
endmethod
private static method loadPet takes DataBuffer buffer, player p, integer pid returns unit
local integer i = buffer.read()
local integer x
local integer y
local integer f
local unit u = null
if (i != 0) then
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Pet: " + I2S(i))
set x = buffer.read()
set y = buffer.read()
set f = buffer.read()
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "x: " + I2S(x))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "y: " + I2S(y))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Facing: " + I2S(f))
set u = CreateUnit(p, PetCatalog1[i].raw, PercentToX(x), PercentToY(y), PercentToFacing(f))
call loadStates(buffer, u)
set petCount[pid] = petCount[pid] + 1
endif
return u
endmethod
//pets x4
private static method loadPets takes DataBuffer buffer, player p, integer pid returns nothing
set pet1[pid] = loadPet(buffer, p, pid)
set pet2[pid] = loadPet(buffer, p, pid)
set pet3[pid] = loadPet(buffer, p, pid)
set pet4[pid] = loadPet(buffer, p, pid)
endmethod
//hero
private static method loadHero takes DataBuffer buffer, player p, integer pid returns nothing
local integer h = buffer.read()
local integer x = buffer.read()
local integer y = buffer.read()
local integer f = buffer.read()
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Hero: " + I2S(h))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "x: " + I2S(x))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "y: " + I2S(y))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Facing: " + I2S(f))
set hero[pid] = CreateUnit(p, HeroCatalog1[h].raw, PercentToX(x), PercentToY(y), PercentToFacing(f))
call loadStats(buffer, hero[pid])
call loadInventory(buffer, hero[pid])
call loadAbilities(buffer, hero[pid])
call loadStates(buffer, hero[pid])
call loadPets(buffer, p, pid)
endmethod
private static method load takes nothing returns DataBuffer
local string s = GetEventPlayerChatString()
local string c = ""
local integer i
local integer q
local string s2
set s = SubString(s, 6, StringLength(s))
set q = StringLength(s)
if (q > 0) then
set s2 = ""
set i = 0
loop
exitwhen i == q
set c = SubString(s, i, i+1)
exitwhen c == DELIMITER
if (c != " ") then
set s2 = s2 + c
endif
set i = i + 1
endloop
if (i < q) then
return Encoder.convertString(SubString(s2, 0, i)).read(SubString(s, i+1, StringLength(s)), GetPlayerId(GetTriggerPlayer()))
endif
return GetEncoder().read(s2, GetPlayerId(GetTriggerPlayer()))
endif
return 0
endmethod
private static method run takes nothing returns boolean
local player p = GetTriggerPlayer()
local integer pid = GetPlayerId(p)
local DataBuffer buffer = load()
local integer g
local integer l
if (buffer == 0) then
call DisplayTimedTextToPlayer(p, 0, 0, 60, INVALID_CODE)
else
call Random.remove(p, pid)
set pdata[pid] = true
/*
hero
x%,y%,facing%
lvl,xp%,str,agi,int
item x6
ItemCatalog1.CHARGE_2
ItemCatalog1.CHARGE_3
ItemCatalog1.CHARGE_4
ItemCatalog1.CHARGE_5
ItemCatalog1.CHARGE_6
life%,mana%
HeroCatalog1.ABILITY_4
HeroCatalog1.ABILITY_5
pet x4
x%,y%,facing%
life%,mana%
lumber
gold
*/
call loadHero(buffer, p, pid)
set g = buffer.read()
set l = buffer.read()
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Gold: " + I2S(g))
call SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, g)
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "Lumber: " + I2S(l))
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, l)
endif
return false
endmethod
private static method onInit takes nothing returns nothing
local integer i = 11
local trigger t = CreateTrigger()
loop
if (GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(i)) == MAP_CONTROL_USER) then
call TriggerRegisterPlayerChatEvent(t, Player(i), "-load ", false)
endif
exitwhen i == 0
set i = i - 1
endloop
call TriggerAddCondition(t, function thistype.run)
endmethod
endstruct
//TESH.scrollpos=206
//TESH.alwaysfold=0
//first read
// private static method run takes nothing returns boolean
/*
Layout:
onInit -save command registration
run runs on -save
saveHero
saveLocation
save x
save y
save facing
saveStats
save level
save xp
save str
save agi
save int
saveInventory
saveItem x6
save item
save item charges?
saveAbilities
save ability x?
saveStates
save life
save mana
savePets
savePet x4
saveLocation?
saveStates?
save lumber
save gold
output code
*/
struct Saver extends array
private static multiboard displayCode
private static multiboarditem saveCode
private static multiboarditem encoderVersion
private static dialog array displayDialogs
//HeroCatalog1.ABILITY_4,5
private static method saveAbilities takes DataBuffer buffer, unit hero returns nothing
local AbilityCatalog1 i = AbilityCatalog1[GetUnitTypeId(hero)]
local integer c = i.count
local integer o = 0
loop
exitwhen o == c
set o = o + 1
call buffer.write(GetUnitAbilityLevel(hero, i.raw(o)))
endloop
endmethod
//ItemCatalog1.CHARGE_2,3,4,5,6
private static method saveItem takes DataBuffer buffer, item i returns nothing
if (i == null) then
call buffer.write(0)
else
call buffer.write(ItemCatalog1[GetItemTypeId(i)].id)
if (buffer.id == 1) then //has item charges
call buffer.write(GetItemCharges(i))
endif
endif
endmethod
//item x6
private static method saveInventory takes DataBuffer buffer, unit u returns nothing
call saveItem(buffer, UnitItemInSlot(u, 0))
call saveItem(buffer, UnitItemInSlot(u, 1))
call saveItem(buffer, UnitItemInSlot(u, 2))
call saveItem(buffer, UnitItemInSlot(u, 3))
call saveItem(buffer, UnitItemInSlot(u, 4))
call saveItem(buffer, UnitItemInSlot(u, 5))
endmethod
//life%,mana%
private static method saveStates takes DataBuffer buffer, unit u returns nothing
call buffer.write(GetPercentUnitLife(u))
call buffer.write(GetPercentUnitMana(u))
endmethod
//lvl,xp%,str,agi,int
private static method saveStats takes DataBuffer buffer, unit hero returns nothing
call buffer.write(GetHeroLevel(hero))
call buffer.write(GetPercentHeroXP(hero))
call buffer.write(GetHeroStr(hero, false))
call buffer.write(GetHeroAgi(hero, false))
call buffer.write(GetHeroInt(hero, false))
endmethod
//x%,y%,facing%
private static method saveLocation takes DataBuffer buffer, unit u returns nothing
call buffer.write(GetPercentUnitX(u))
call buffer.write(GetPercentUnitY(u))
call buffer.write(GetPercentUnitFacing(u))
endmethod
private static method savePet takes DataBuffer buffer, unit u returns nothing
if (u == null) then
call buffer.write(0)
else
call buffer.write(PetCatalog1[GetUnitTypeId(u)].id)
call saveLocation(buffer, u)
call saveStates(buffer, u)
endif
endmethod
//pets x4
private static method savePets takes DataBuffer buffer, integer pid returns nothing
call savePet(buffer, pet1[pid])
call savePet(buffer, pet2[pid])
call savePet(buffer, pet3[pid])
call savePet(buffer, pet4[pid])
endmethod
//hero
private static method saveHero takes DataBuffer buffer, unit hero, integer pid returns nothing
call buffer.write(HeroCatalog1[GetUnitTypeId(hero)].id)
call saveLocation(buffer, hero)
call saveStats(buffer, hero)
call saveInventory(buffer, hero)
call saveAbilities(buffer, hero)
call saveStates(buffer, hero)
call savePets(buffer, pid)
endmethod
private static method run takes nothing returns boolean
local player p = GetTriggerPlayer()
local integer pid = GetPlayerId(p)
local Encoder encoder
local DataBuffer buffer
local string s
local string s2
if (pdata[pid]) then
//retrieve the latest encoder version
set encoder = GetEncoder()
//open a buffer for writing
set buffer = encoder.write(pid)
//now write to it in order that the data was added to it
/*
hero
x%,y%,facing%
lvl,xp%,str,agi,int
item x6
ItemCatalog1.CHARGE_2
ItemCatalog1.CHARGE_3
ItemCatalog1.CHARGE_4
ItemCatalog1.CHARGE_5
ItemCatalog1.CHARGE_6
life%,mana%
HeroCatalog1.ABILITY_4
HeroCatalog1.ABILITY_5
pet x4
x%,y%,facing%
life%,mana%
lumber
gold
*/
call saveHero(buffer, hero[pid], pid)
call buffer.write(GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER))
call buffer.write(GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD))
//display the encoder version and code
set s = "Encoder Version: " + encoder.toString()
set s2 = buffer.code
if (GetLocalPlayer() == p) then
call MultiboardSetItemValue(encoderVersion, s)
call MultiboardSetItemValue(saveCode, s2)
call MultiboardDisplay(displayCode, true)
endif
call DialogDisplay(p, displayDialogs[pid], true)
endif
return false
endmethod
private static method hideDialog takes nothing returns boolean
local player p = GetTriggerPlayer()
local integer i = GetPlayerId(p)
call DialogDisplay(p, displayDialogs[i], false)
if (GetLocalPlayer() == p) then
call MultiboardDisplay(displayCode, false)
endif
return false
endmethod
private static method runs takes nothing returns nothing
local integer i = 11
local trigger t = CreateTrigger()
local trigger t2 = CreateTrigger()
call DestroyTimer(GetExpiredTimer())
loop
if (GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(i)) == MAP_CONTROL_USER) then
call TriggerRegisterPlayerChatEvent(t, Player(i), "-save", true)
set displayDialogs[i] = DialogCreate()
call DialogSetMessage(displayDialogs[i], "Press Done When Finished")
call DialogAddButton(displayDialogs[i], "Done", ' ')
call TriggerRegisterDialogEvent(t2, displayDialogs[i])
endif
exitwhen i == 0
set i = i - 1
endloop
set displayCode = CreateMultiboard()
call MultiboardSetTitleText(displayCode, "Save/Load Code")
call MultiboardMinimize(displayCode, false)
call MultiboardSetItemsWidth(displayCode, 1)
call MultiboardSetRowCount(displayCode, 2)
call MultiboardSetColumnCount(displayCode, 1)
call MultiboardSetItemsStyle(displayCode, true, false)
set encoderVersion = MultiboardGetItem(displayCode, 0, 0)
set saveCode = MultiboardGetItem(displayCode, 1, 0)
call TriggerAddCondition(t, function thistype.run)
call TriggerAddCondition(t2, function thistype.hideDialog)
endmethod
private static method onInit takes nothing returns nothing
call TimerStart(CreateTimer(), 0, false, function thistype.runs)
endmethod
endstruct
//TESH.scrollpos=111
//TESH.alwaysfold=0
//first read
// private static method run takes nothing returns boolean
/*
Layout:
onInit -load command registration
run runs on -load
load parses load string (encoder id?, code)
IF valid code
loadHero
loadLocation
load x
load y
load facing
loadStats
load level
load xp
load str
load agi
load int
loadInventory
loadItem x6
load item?
load item charges?
loadAbilities
load ability x?
loadStates
load life
load mana
loadPets
loadPet x4?
loadLocation?
loadStates?
load lumber
load gold
*/
struct Loader extends array
private static constant string INVALID_CODE = "|cffff0000Invalid Code"
private static constant string DELIMITER = ","
//HeroCatalog1.ABILITY_4,5
private static method loadAbilities takes DataBuffer buffer, unit hero returns nothing
local AbilityCatalog1 i = AbilityCatalog1[GetUnitTypeId(hero)]
local integer c = i.count
local integer o = 0
local integer h
loop
exitwhen o == c
set o = o + 1
set h = buffer.read()
if (h > 0) then
call UnitAddAbility(hero, i.raw(o))
call SetUnitAbilityLevel(hero, i.raw(o), h)
call UnitModifySkillPoints(hero, -h)
endif
endloop
endmethod
//ItemCatalog1.CHARGE_2,3,4,5,6
private static method loadItem takes DataBuffer buffer, unit u returns nothing
local integer id = buffer.read()
local item i
if (id != 0) then
set i = CreateItem(ItemCatalog1[id].raw, 0, 0)
call UnitAddItem(u, i)
if (buffer.id == 1) then //has item charges
call SetItemCharges(i, buffer.read())
endif
set i = null
endif
endmethod
//item x6
private static method loadInventory takes DataBuffer buffer, unit u returns nothing
call loadItem(buffer, u)
call loadItem(buffer, u)
call loadItem(buffer, u)
call loadItem(buffer, u)
call loadItem(buffer, u)
call loadItem(buffer, u)
endmethod
//life%,mana%
private static method loadStates takes DataBuffer buffer, unit u returns nothing
call SetPercentUnitLife(u, buffer.read())
call SetPercentUnitMana(u, buffer.read())
endmethod
//lvl,xp%,str,agi,int
private static method loadStats takes DataBuffer buffer, unit hero returns nothing
local integer lvl = buffer.read()
if (lvl > 1) then
call SetHeroLevel(hero, lvl, false)
endif
call AddPercentHeroXP(hero, buffer.read())
call SetHeroStr(hero, buffer.read(), true)
call SetHeroAgi(hero, buffer.read(), true)
call SetHeroInt(hero, buffer.read(), true)
endmethod
private static method loadPet takes DataBuffer buffer, player p, integer pid returns unit
local integer i = buffer.read()
local unit u = null
if (i != 0) then
set u = CreateUnit(p, PetCatalog1[i].raw, PercentToX(buffer.read()), PercentToY(buffer.read()), PercentToFacing(buffer.read()))
call loadStates(buffer, u)
set petCount[pid] = petCount[pid] + 1
endif
return u
endmethod
//pets x4
private static method loadPets takes DataBuffer buffer, player p, integer pid returns nothing
set pet1[pid] = loadPet(buffer, p, pid)
set pet2[pid] = loadPet(buffer, p, pid)
set pet3[pid] = loadPet(buffer, p, pid)
set pet4[pid] = loadPet(buffer, p, pid)
endmethod
//hero
private static method loadHero takes DataBuffer buffer, player p, integer pid returns nothing
set hero[pid] = CreateUnit(p, HeroCatalog1[buffer.read()].raw, PercentToX(buffer.read()), PercentToY(buffer.read()), PercentToFacing(buffer.read()))
call loadStats(buffer, hero[pid])
call loadInventory(buffer, hero[pid])
call loadAbilities(buffer, hero[pid])
call loadStates(buffer, hero[pid])
call loadPets(buffer, p, pid)
endmethod
//this just does parsing
//-load encoderId,code or -load code could be the input with any number of spaces
//between encoderId and , and , and code.
private static method load takes nothing returns DataBuffer
local string s = GetEventPlayerChatString()
local string c = ""
local integer i
local integer q
local string s2
set s = SubString(s, 6, StringLength(s))
set q = StringLength(s)
if (q > 0) then
set s2 = ""
set i = 0
//find the comma and remove spaces
loop
exitwhen i == q
set c = SubString(s, i, i+1)
exitwhen c == DELIMITER
if (c != " ") then
set s2 = s2 + c
endif
set i = i + 1
endloop
//if a comma was found
if (i < q) then
set q = i
//remove more spaces ;D
loop
set q = q + 1
set c = SubString(s, q, q+1)
exitwhen c != " "
endloop
//open buffer for reading with encoder specified by encoder id and return it
return Encoder.convertString(SubString(s2, 0, i)).read(SubString(s, q, StringLength(s)), GetPlayerId(GetTriggerPlayer()))
endif
//open buffer for reading with latest encoder
return GetEncoder().read(s2, GetPlayerId(GetTriggerPlayer()))
endif
return 0
endmethod
private static method run takes nothing returns boolean
local player p = GetTriggerPlayer()
local integer pid = GetPlayerId(p)
local DataBuffer buffer = load() //first load the buffer
//if the buffer is 0, then the code was invalid
if (buffer == 0) then
call DisplayTimedTextToPlayer(p, 0, 0, 60, INVALID_CODE)
else
call Random.remove(p, pid)
set pdata[pid] = true
/*
hero
x%,y%,facing%
lvl,xp%,str,agi,int
item x6
ItemCatalog1.CHARGE_2
ItemCatalog1.CHARGE_3
ItemCatalog1.CHARGE_4
ItemCatalog1.CHARGE_5
ItemCatalog1.CHARGE_6
life%,mana%
HeroCatalog1.ABILITY_4
HeroCatalog1.ABILITY_5
pet x4
x%,y%,facing%
life%,mana%
lumber
gold
*/
call loadHero(buffer, p, pid)
call SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, buffer.read())
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, buffer.read())
endif
return false
endmethod
private static method onInit takes nothing returns nothing
local integer i = 11
local trigger t = CreateTrigger()
loop
if (GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(i)) == MAP_CONTROL_USER) then
call TriggerRegisterPlayerChatEvent(t, Player(i), "-load ", false)
endif
exitwhen i == 0
set i = i - 1
endloop
call TriggerAddCondition(t, function thistype.run)
endmethod
endstruct
//TESH.scrollpos=8
//TESH.alwaysfold=0
//type -random to get a random hero with 4 pets and some items as well as some gold and lumber.
//The hero xp will be set to random as well. Move them around.
//type -save to save this information. Outputs encoder id used to make the code as well as the save/load code.
//Encoder id is used for backwards compatability.
/*
hero
x%,y%,facing%
lvl,xp%,str,agi,int
item x6
itemCharge?
life%,mana%
abilities x4|x5?
pet x4
x%,y%,facing%
life%,mana%
lumber
gold
*/
//type -load code to load up the code under the current Encoder.
//type -load encoder,code to load up a code under the chosen encoder id.
//Average code size: 32 to 57 characters
//Average code size for other save/load systems: 106-125 characters
struct Welcome extends array
private static method onInit takes nothing returns nothing
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "type -random, -min, or -max for hero. Move it around")
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "type -save to save the hero. Encoder id and save/load code outputted.")
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60, "type -load code to load up the code under the current Encoder.\ntype -load encoder,code to load up a code under the chosen encoder id.")
endmethod
endstruct