Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
Have alot save-load code stuff, maybe this is just +1 but maybe someone like it, please read the Features!
Last changes:
1.24
-rewrote, now 1-2 character is the what tell the length, exp/gold/lumer not save if 0, if gold is example 1 then save only 1 char not 3/5
function/variable renameing, other reorganised stuff
1.21
- custom value save test demonstration added to map
1.2
- custom value save added (able save any integer [below than 2kkk])
Code:
[b]Features:[/b]
- can save custom value too
- Code saved to file directly, user need only copy from txt file and paste into warcraft chat, don't need type anything manually to player except "-save"
- useable with normal wc3 WE - easy to gui users too
- Dynamic code length
- Protected vs changeing values
- you choose if you want save: stat, hero coordinate, gold, lumber, items
* item saved with item slot position and charge
- allow bind code to player name
- very easy to import
- flexible if you want change
JASS:
function Colorized_Code takes string s, string numColor, string lowerColor, string upperColor, string specColor, integer start returns string
local string ns = ""
local string c
local integer m = StringLength(s)
local integer i = start
local boolean l
loop
exitwhen m == i
set c = SubString(s, i, i + 1)
if (c!=" ") then
set l = StringCase(c, false) == c
//special or number
if (c == StringCase(c, true) and l) then
//number character coloring
if ("0" == c or 0 != S2I(c)) then
set ns = ns + "|cff" + numColor + c
//special character coloring
else
set ns = ns + "|cff" + specColor + c
endif
//lowercase character coloring
elseif (l) then
set ns = ns + "|cff" + lowerColor + c
//uppercase character coloring
else
set ns = ns + "|cff" + upperColor + c
endif
else
set ns = ns + " "
endif
set i = i + 1
endloop
return ns
endfunction
function SL_IntegerToCode takes integer i, integer len returns string
local string s = ""
local integer m = 0
local integer c
local integer l = StringLength(udg_SL_STRING)
local boolean e = false
if l < 36 then
set c = 7
elseif l < 74 then
set c = 6
else
set c = 5
endif
if i <= Pow(l, c - 1) then
loop
set c = c - 1
if c > 0 then
if not e and i >= Pow(l, c) then
set e = true
endif
set m = i / R2I(Pow(l, c))
set i = i - m * R2I(Pow(l, c))
if not e and m == 0 then
else
set s = s + SubString(udg_SL_STRING, m, m + 1)
endif
else
set m = ModuloInteger(i, l)
set s = s + SubString(udg_SL_STRING, m, m + 1)
set i = 0
endif
exitwhen c == 0
endloop
endif
if len != - 1 then
loop
exitwhen StringLength(s) >= len
set s = SubString(udg_SL_STRING, 0, 1) + s
endloop
endif
return s
endfunction
function SL_CodeToInteger takes string c returns integer
local integer l = StringLength(c)
local integer m = StringLength(udg_SL_STRING)
local integer i = 0
local integer char
local string s
local integer int = 0
if l > 0 then
loop
exitwhen i == l
set s = SubString(c, i, i + 1)
if s != StringCase(s, true) then
set char = LoadInteger(udg_SL_HASHTABLE, StringHash(s), 2)
else
set char = LoadInteger(udg_SL_HASHTABLE, StringHash(s), 1)
endif
if char !=0 or i > 0 then
set int = int + R2I(Pow(m, l - i - 1)) * char
endif
set i = i + 1
endloop
endif
set s = null
return int
endfunction
function SL_GetIntegerSize takes integer a returns integer
local integer base = StringLength(udg_SL_STRING)
local integer max = 4
local integer i = 0
if base < 64 then
set max = 6
elseif base < 74 then
set max = 5
endif
loop
set i = i + 1
exitwhen i > max
if a < R2I(Pow(base,i)) then
return i
endif
endloop
endfunction
function SL_CodeCheckSum takes string c, player p returns string
local string EC = udg_SL_STRING
local integer MaxV = R2I(Pow(StringLength(EC), udg_SL_CRC_LEN))
local integer i
if udg_SL_BIND_TO_PLAYER then
set i = StringHash(c + StringCase(GetPlayerName(p), false))
else
set i = StringHash(c)
endif
if i < 0 then
set i = i * - 1
endif
if i > MaxV then
set i = ModuloInteger(i, MaxV)
endif
return SL_IntegerToCode(i, udg_SL_CRC_LEN)
endfunction
function SL_CodeValidation takes player p, string c returns boolean
local integer l = StringLength(c)
if StringLength(c) < (2+udg_SL_CRC_LEN) then
return false
else
return SL_CodeCheckSum(SubString(c, 0, l-udg_SL_CRC_LEN), p) == SubString(c, l-udg_SL_CRC_LEN, l)
endif
endfunction
function SL_LoadDataFromLoadCode takes player p, string CODE returns nothing
local integer l = StringLength(udg_SL_STRING) //get the string length of the alphabet string
local integer i = 0
local integer i2
local integer MinExp
local integer array Pow2
local integer CLASS // the hero unit type index in SL_HERO_TYPE array
local integer LV // hero level
local integer EXP // hero exp
local integer STR // hero strength
local integer AGI // hero agility
local integer INT // hero intelligence
local integer GOLD // player gold
local integer LUMBER // player lumber
local integer ITEM_SLOT
local integer MAX_X = R2I(GetRectMaxX(bj_mapInitialPlayableArea)) //highest X coordinate on map
local integer MAX_Y = R2I(GetRectMaxY(bj_mapInitialPlayableArea)) //highest Y coordinate on map
local integer COORD_LEN_X = SL_GetIntegerSize(MAX_X * 2) // how much character needed for save hero location
local integer COORD_LEN_Y = SL_GetIntegerSize(MAX_Y * 2) // how much character needed for save hero location
local integer X // hero x coordinate
local integer Y // hero y coordinate
local item itm
local integer a1
local integer a2
local integer a3
local integer a4
local integer c
local string Key
local string s
local location loc
local unit u
//----------- just preload the 2 bases, like 1,2,4,8,16,32 ----------------------
set i = 0
loop
set Pow2[i] = R2I(Pow(2, i))
set i = i + 1
exitwhen i > 6
endloop
//-------------------------------------------------------------------------------
set i = 0
//lets check 1st the custom values
if udg_SL_CUSTOM_VALUE_ON then
set a4 = 0
loop
set a1 = SL_CodeToInteger(SubString(CODE, i, i + 1)) //this say how much the next 2 data size
set i = i + 1
if a1 > 0 then
set a2 = a1 / 10
set a4 = a4 + 1
set a3 = SL_CodeToInteger(SubString(CODE, i, i + a2)) //1st piece
set udg_SL_CV_ARRAY[a4] = a3
set i = i + a2
set a1 = a1 - (a2 * 10)
if a1 > 0 then
set a4 = a4 + 1
set a3 = SL_CodeToInteger(SubString(CODE, i, i + a1)) //2nd piece
set udg_SL_CV_ARRAY[a4] = a3
set i = i + a1
endif
endif
exitwhen a4 == udg_SL_CV_MAX
endloop
endif
//don't forget i keep the position where ended the custom value and start the hero data
// we do several check
if udg_SL_SAVE_HERO then
set loc = GetStartLocationLoc(GetPlayerStartLocation(Player(0)))
set X = R2I(GetLocationX(loc))
set Y = R2I(GetLocationY(loc))
call RemoveLocation(loc)
set a1 = StringLength(SubString(CODE, i, StringLength(CODE)))
//if have remaining code then its mean we can read foward
if a1 > 0 then
//we get 1st the Key string, this string contain the lv,exp,str,int,agi,gold and lumber length
//the udg_SL_VAR array containing the data and we saved into code the array index
//we get 1st how much char needed for saveing the array index
set a1 = SL_GetIntegerSize(udg_SL_MAX_VAR)
set a2 = SL_CodeToInteger(SubString(CODE, i , i + a1))
set i = i + a1
set Key = udg_SL_VAR[a2]
set a1 = SL_GetIntegerSize(udg_SL_MAX_HERO)
set CLASS = SL_CodeToInteger(SubString(CODE, i, i + a1)) //after the key we read out the class
set i = i + a1
//we get the level from code
set a2 = S2I(SubString(Key, 0, 1))
if a2 > 0 then
set LV = SL_CodeToInteger(SubString(CODE, i, i + a2))
set i = i + a2
else
set LV = 0
endif
//we get exp from code
set a2 = S2I(SubString(Key, 1, 2))
if a2 > 0 then
set EXP = SL_CodeToInteger(SubString(CODE, i, i + a2))
set i = i + a2
else
set EXP = 0
endif
//we create the hero
set u = CreateUnit(p, udg_SL_HERO_TYPE[CLASS], X, Y, 0)
//we set hero exp & level
if LV == 0 and EXP > 0 then
call AddHeroXP (u, EXP, false)
else
if LV > 1 then
call SetHeroLevel(u, LV, false)
endif
if EXP > 0 then
call AddHeroXP (u, EXP, false)
endif
endif
if udg_SL_SAVE_STAT then
set a1 = S2I(SubString(Key, 2, 3))
set STR = SL_CodeToInteger(SubString(CODE, i, i + a1))
set i = i + a1
set a1 = S2I(SubString(Key, 3, 4))
set AGI = SL_CodeToInteger(SubString(CODE, i, i + a1))
set i = i + a1
set a1 = S2I(SubString(Key, 4, 5))
set INT = SL_CodeToInteger(SubString(CODE, i, i + a1))
set i = i + a1
call SetHeroStr(u, STR, true)
call SetHeroAgi(u, AGI, true)
call SetHeroInt(u, INT, true)
endif
if udg_SL_SAVE_GOLD then
set a1 = S2I(SubString(Key, 5, 6))
if a1 > 0 then
set GOLD = SL_CodeToInteger(SubString(CODE, i, i + a1))
set i = i + a1
else
set GOLD = 0
endif
call SetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD, GOLD)
endif
if udg_SL_SAVE_LUMBER then
set a1 = S2I(SubString(Key, 6, 7))
if a1 > 0 then
set LUMBER = SL_CodeToInteger(SubString(CODE, i, i + a1))
set i = i + a1
else
set LUMBER = 0
endif
call SetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER, LUMBER)
endif
if udg_SL_SAVE_COORD then
set X = SL_CodeToInteger(SubString(CODE, i, i + COORD_LEN_X)) - MAX_X
set i = i + COORD_LEN_X
set Y = SL_CodeToInteger(SubString(CODE, i, i + COORD_LEN_Y)) - MAX_Y
set i = i + COORD_LEN_Y
call SetUnitX(u, X)
call SetUnitY(u, Y)
endif
if udg_SL_SAVE_ITEMS then
// we get the item slot, this number is between 0-63 and tell what slot empty or no
set ITEM_SLOT = SL_CodeToInteger(SubString(CODE, i, i + 1))
set i = i + 1
if ITEM_SLOT > 0 then
set a3 = 1
set a3 = SL_GetIntegerSize(udg_SL_MAX_ITEM) //we get the length what need save the items
set a2 = 'flag' //dummy item raw code
set a1 = - 1
loop
set a1 = a1 + 1
if ITEM_SLOT >= Pow2[5 - a1] then
set ITEM_SLOT = ITEM_SLOT - Pow2[5 - a1]
set i2 = SL_CodeToInteger(SubString(CODE, i, i + a3)) //ITEM_TYPE array index
set i = i + a3
set i2 = udg_SL_ITEM_TYPE[i2]
if i2 == 0 then
set i2 = a2
endif
set itm = CreateItem(i2, X, Y)
call UnitAddItem(u, itm)
set c = GetItemCharges(itm)
if c > 1 then
set a4 = SL_GetIntegerSize (c)
set c = SL_CodeToInteger(SubString(CODE, i, i + a4))
set i = i + a4
if c > 0 then
call SetItemCharges(itm, c)
endif
endif
else
set itm = CreateItem(a2, X, Y)
call UnitAddItem(u, itm)
endif
exitwhen a1 == 5
endloop
endif
set a1 = 0
loop
exitwhen a1 == 6
set itm = UnitItemInSlot(u, a1)
if itm != null then
if GetItemTypeId(itm) == a2 then
call RemoveItem(itm)
endif
endif
set a1 = a1 + 1
endloop
endif
call DisplayTextToPlayer ( p, 0, 0, "|cffffff00 Load System:|r Loading completed without error." )
endif
set loc = null
endif
set itm = null
endfunction
function CreateSaveLoadCode takes player p, unit u returns nothing
local string CODE = "" // final code will be stored to this variable
local integer l = StringLength(udg_SL_STRING) //get the string length of the alphabet string
local integer i
local integer array Pow2
local integer array PowL
local integer MinExp // that exp what was needed for your hero current level
local integer MaxExp // that exp what needed for your hero for level up
local integer CurExp // with how much exp hero passed the last level up
local integer CLASS // the hero unit type index in SL_HERO_TYPE array
local integer LV // hero level
local integer EXP // hero exp
local integer STR // hero strength
local integer AGI // hero agility
local integer INT // hero intelligence
local integer GOLD // player gold
local integer LUMBER // player lumber
local integer X // hero x coordinate
local integer Y // hero y coordinate
local integer COORD_LEN_X // how much character needed for save hero location
local integer COORD_LEN_Y // how much character needed for save hero location
local boolean ERROR = true
local string CV_CODE = "" //custom value code
local string H_CODE = "" //hero value code
local integer MAX_X = R2I(GetRectMaxX(bj_mapInitialPlayableArea)) //highest X coordinate on map
local integer MAX_Y = R2I(GetRectMaxY(bj_mapInitialPlayableArea)) //highest Y coordinate on map
local integer ITEM_SLOT
local item itm
local item itm2
local unit d //dummy unit
local location loc //just for location
local string Key = "" //this is a key for saveing lv, exp, stats into 1 character, we will search thsi string in VAR array for get a index
local string s1
local string s2
local string s3
local integer a1
local integer a2
local integer a3
local integer a4
local string PATH
local string HERO_NAME
local string HERO_LV
//----------- just preload the 2 bases, like 1,2,4,8,16,32 ----------------------
set i = 0
loop
set Pow2[i] = R2I(Pow(2, i))
set i = i + 1
exitwhen i > 6
endloop
//-------------------------------------------------------------------------------
//----------- just preload the Alpahabet string bases with max values like 1char length till length-1 ----
set i = 1
loop
set PowL[i] = R2I(Pow(l, i)) - 1
set i = i + 1
exitwhen i == 5
endloop
//-------------------------------------------------------------------------------
//---------- check if 2 character length would be sufficient for hero coord or no ----
set COORD_LEN_X = SL_GetIntegerSize(MAX_X * 2)
set COORD_LEN_Y = SL_GetIntegerSize(MAX_Y * 2)
//------------------------------------------------------------------------------------
// ------ why save custom values to 1st place? because its optional
// if i let custom value first then probabil resource could be lower by 1
if udg_SL_CUSTOM_VALUE_ON then
set i = 1
loop
//we form then variables to avoid the higher numbers then the limit
set a3 = ModuloInteger(udg_SL_CV_ARRAY[i], PowL[4] + 1)
set a4 = ModuloInteger(udg_SL_CV_ARRAY[i + 1], PowL[4] + 1)
set s1 = SL_IntegerToCode(a3, - 1)
set a1 = StringLength(s1)
set s2 = ""
set a2 = 0
if i < udg_SL_CV_MAX then
set s2 = SL_IntegerToCode(a4, - 1)
set a2 = StringLength(s2)
set i = i + 1
endif
set CV_CODE = CV_CODE + SL_IntegerToCode((a1 * 10 + a2), 1) + s1 + s2
set i = i + 1
exitwhen i > udg_SL_CV_MAX
endloop
if not (udg_SL_SAVE_HERO and u != null) then
set ERROR = false
set HERO_NAME = "No hero"
set HERO_LV = "-"
endif
endif
if udg_SL_SAVE_HERO and u != null then
// ----- we get the hero index from hashtable, if it will be 0, then not found
set CLASS = LoadInteger(udg_SL_HASHTABLE, 2, GetUnitTypeId(u))
// --- if isn't 0 then Hero was stored into array and we continue -----
if CLASS != 0 then
// --- we get every data, what we will use that not sure yet ----
set LV = GetHeroLevel(u)
set EXP = GetHeroXP(u)
set STR = GetHeroStr (u, false)
set AGI = GetHeroAgi (u, false)
set INT = GetHeroInt (u, false)
set GOLD = GetPlayerState(p, PLAYER_STATE_RESOURCE_GOLD)
set LUMBER = GetPlayerState(p, PLAYER_STATE_RESOURCE_LUMBER)
//formating the stuff to max value if maybe it is higher
set LV = ModuloInteger(LV, PowL[2] + 1)
set EXP = ModuloInteger(EXP, PowL[4] + 1)
set STR = ModuloInteger(STR, PowL[2] + 1)
set AGI = ModuloInteger(AGI, PowL[2] + 1)
set INT = ModuloInteger(INT, PowL[2] + 1)
set GOLD = ModuloInteger(GOLD, udg_SL_MAX_GOLD + 1)
set LUMBER = ModuloInteger(LUMBER, udg_SL_MAX_GOLD + 1)
//if your hero not maxed level then
if udg_SL_MAX_HERO_LEVEL != LV then
// -- we get the MinExp, MaxExp, CurExp with createing a dummy unit at player 1 start location
set loc = GetStartLocationLoc(GetPlayerStartLocation(Player(0)))
set d = CreateUnit(Player(0), GetUnitTypeId(u), GetLocationX(loc), GetLocationY(loc), 0)
call RemoveLocation(loc)
if LV == 1 then
set MinExp = 0
else
call SetHeroLevel(d, LV, false)
set MinExp = GetHeroXP(d)
endif
call SetHeroLevel(d, LV + 1, false)
set MaxExp = GetHeroXP(d) - 1
call RemoveUnit(d)
set CurExp = EXP - MinExp
else
set MinExp = EXP
set MaxExp = EXP
set CurExp = 0
endif
//lets start build the H_CODE with class then with level
//lets check if max class is higher than the Alpahabet string base
set a1 = 1
if udg_SL_MAX_HERO > PowL[1] then
set a1 = 2
endif
set H_CODE = SL_IntegerToCode(CLASS, a1)
//we check if the SMART_LV was on or off
//if off then easily save the
if not udg_SL_SAVE_SMART_LV or CurExp == 0 or EXP == 0 then
set s1 = SL_IntegerToCode(LV, - 1)
set Key = I2S(StringLength(s1)) + "0"
set H_CODE = H_CODE + s1
else
//we must figure out what better, if we save LV+CurExp or total EXP
set s1 = SL_IntegerToCode(LV, - 1) + SL_IntegerToCode(CurExp, - 1)
set s2 = SL_IntegerToCode(EXP, - 1)
set a1 = StringLength(s1)
set a2 = StringLength(s2)
if a1 > a2 then
set Key = "0" + I2S(a2)
set H_CODE = H_CODE + s2
else
set Key = I2S(StringLength(SL_IntegerToCode(LV, - 1))) + I2S(StringLength(SL_IntegerToCode(CurExp, - 1)))
set H_CODE = H_CODE + s1
endif
endif
//next piece what we save is the stats
if udg_SL_SAVE_STAT then
set s1 = SL_IntegerToCode(STR, - 1)
set s2 = SL_IntegerToCode(AGI, - 1)
set s3 = SL_IntegerToCode(INT, - 1)
set a1 = StringLength(s1)
set a2 = StringLength(s2)
set a3 = StringLength(s3)
set H_CODE = H_CODE + s1 + s2 + s3
set Key = Key + I2S(a1) + I2S(a2) + I2S(a3)
else
//its just a 1st record in array, doesn't matter too much
set Key = Key + "111"
endif
//saveing resource part: gold and lumber
if udg_SL_SAVE_GOLD and udg_SL_SAVE_LUMBER then
if not (GOLD == 0 and LUMBER == 0) then
set s1 = SL_IntegerToCode(GOLD, - 1)
set s2 = SL_IntegerToCode(LUMBER, - 1)
set a1 = StringLength(s1)
set a2 = StringLength(s2)
set H_CODE = H_CODE + SL_IntegerToCode((a1 * 10 + a2), - 1) + s1 + s2
set Key = Key + I2S(a1)
set Key = Key + I2S(a2)
else
set Key = Key + "00"
endif
elseif udg_SL_SAVE_GOLD then
if GOLD > 0 then
set H_CODE = H_CODE + SL_IntegerToCode(GOLD, - 1)
set Key = Key + I2S(StringLength(SL_IntegerToCode(GOLD, - 1)))
else
set Key = Key + "0"
endif
set Key = Key + "0"
elseif udg_SL_SAVE_LUMBER then
set Key = Key + "0"
if LUMBER > 0 then
set H_CODE = H_CODE + SL_IntegerToCode(LUMBER, - 1)
set Key = Key + I2S(StringLength(SL_IntegerToCode(LUMBER, - 1)))
else
set Key = Key + "0"
endif
else
set Key = Key + "00"
endif
//we save hero coordinates (X,Y) with shift
if udg_SL_SAVE_COORD then
set a1 = R2I(GetUnitX(u)) + MAX_X //x coordinate with shift for don't be negative number
set a2 = R2I(GetUnitY(u)) + MAX_Y //y coordinate with shift for don't be negative number
set H_CODE = H_CODE + SL_IntegerToCode(a1, COORD_LEN_X) + SL_IntegerToCode(a2, COORD_LEN_Y)
endif
//--------------------------- Item save -----------------------
// now coming the harder part :D
// saveing the items
if udg_SL_SAVE_ITEMS then
// let's see how much item got the hero
set ITEM_SLOT = 0
set i = 0
set a1 = 0
set s1 = ""
set a2 = SL_GetIntegerSize(udg_SL_MAX_ITEM) //Get how much character long the last items when saved
loop
set itm = UnitItemInSlot(u, i)
if itm != null then
set a1 = LoadInteger(udg_SL_HASHTABLE, 3, GetItemTypeId(itm))
if a1 != 0 then //so item was found from item data base
set ITEM_SLOT = ITEM_SLOT + Pow2[5 - i]
//reminder a1 = item type index, a2 = how much character needed for item type index
set s1 = s1 + SL_IntegerToCode(a1, a2)
if GetItemCharges(itm) != 0 then
//we handle item charges like if it is 1 then not save
//we create a clone item for check how much charge got default
set loc = GetStartLocationLoc(GetPlayerStartLocation(Player(0)))
set itm2 = CreateItem(GetItemTypeId(itm), GetLocationX(loc), GetLocationY(loc))
set a4 = GetItemCharges(itm2)
call RemoveItem(itm2)
call RemoveLocation(loc)
//if charge is too high for able write out with 1 char we use 2
set a4 = ModuloInteger(a4, PowL[4] + 1) //only for avoid a crap if have huge charge number like 2bil
set a3 = SL_GetIntegerSize(a4) //get how much char needed for save charge
if a4 != 1 then
//a4 = item charge, a3=how much char needed for save this item
set s1 = s1 + SL_IntegerToCode(a4, a3)
endif
endif
endif
set itm = null
endif
set i = i + 1
exitwhen i == 6
endloop
set H_CODE = H_CODE + SL_IntegerToCode(ITEM_SLOT, 1) + s1
endif
//we search after Key index in VAR array, when Key == VAR[index] then we save index
set a1 = SL_GetIntegerSize(udg_SL_MAX_VAR)
set a2 = - 1
set i = 0
loop
exitwhen i > udg_SL_MAX_VAR or a2 != - 1
if udg_SL_VAR[i] == Key then
set a2 = i
endif
set i = i + 1
endloop
if a2 != - 1 then
set s1 = SL_IntegerToCode(a2, a1)
set H_CODE = s1 + H_CODE
set ERROR = false
else
call DisplayTextToPlayer ( p, 0, 0, "|cffffff00Warning:|r something went wrong." )
endif
endif
set HERO_NAME = GetUnitName(u)
set HERO_LV = I2S(LV)
endif
if not ERROR then
set CODE = CV_CODE + H_CODE
set CODE = CODE + SL_CodeCheckSum(CODE, p)
set PATH = udg_SL_FOLDER + "\\" + HERO_NAME + " - " + HERO_LV + " by " + GetPlayerName(p) + ".txt"
if StringLength(CODE) < 60 then
call DisplayTextToPlayer ( p, 0, 0, "|cffffff00Code:|r -Load " + Colorized_Code(CODE, "00FF00", "FFFF00", "00FFFF", "FF00FF", 0) )
else
call DisplayTextToPlayer ( p, 0, 0, "|cffffff00Code:|r -Load " + CODE )
endif
call DisplayTextToPlayer ( p, 0, 0, "|cff7777ffNote:|r Code saved into |cffff8888" + PATH + "|r")
if GetLocalPlayer() == p then
call PreloadGenClear()
call PreloadGenStart()
call Preload("\r\n\t\t\t\tHero: " + HERO_NAME + "\r\n\t\t\t\t" + "Level: " + HERO_LV + "\t\t\r\n\t\t\t\t" + "Name: " + GetPlayerName(p) + "\t\t\r\n" + "Code: -Load " + CODE )
call PreloadGenEnd(PATH)
endif
else
call DisplayTextToPlayer ( p, 0, 0, "|cffff7777Warning:|r something went wrong." )
endif
set itm = null
set itm2 = null
set p = null
set loc = null
set d = null
endfunction
Settings
Events
Map initialization
Conditions
Actions
-------- -save:this save exp, items with slot and charge, hero location, gold and lumber, str, agi, int stat --------
Set SL_STRING = 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$&/+-=[]^_`{}~()*
-------- SAVEHERO on/off, if it is off then save only data from custom value's --------
Set SL_SAVE_HERO = True
-------- If false then its only level without exp --------
-------- if SMART_LV is true then calculate the shortest way for save lv and exp --------
Set SL_SAVE_SMART_LV = True
-------- enable custom value what allow you save more info into code --------
Set SL_CUSTOM_VALUE_ON = False
-------- This say how much custom value you want save (btw custom values must be integer and max 2kkk and no negative value) --------
-------- if CV_MAX is 3 then index will be 1, 2, 3 to array what u save, so allways same than last index from CV_ARRAY in save trigger --------
-------- if you change then previous load code will be useless with different CV_MAX than current one, so be wise --------
Set SL_CV_MAX = 4
-------- Save the hero position in map --------
Set SL_SAVE_COORD = False
-------- Bind to player the code so only that player can use his own code --------
Set SL_BIND_TO_PLAYER = True
-------- enable saveing gold and lumber and max gold/lumber (used max gold value for both) --------
Set SL_MAX_GOLD = 1000000
Set SL_SAVE_GOLD = True
Set SL_SAVE_LUMBER = False
-------- save HERO (Str, Agi, Int) stat or don't save? --------
Set SL_SAVE_STAT = False
-------- Save Hero items? --------
Set SL_SAVE_ITEMS = False
-------- Folder where we save, its look like: ....wc3\FOLDER\*HeroName* - *Level* ver*.txt --------
Set SL_FOLDER = SaveLoad Code
-------- Declare the Heroes what we use on map --------
Set SL_HERO_TYPE[1] = Archmage
Set SL_HERO_TYPE[2] = Mountain King
Set SL_HERO_TYPE[3] = Blood Mage
Set SL_HERO_TYPE[4] = Blademaster
Set SL_HERO_TYPE[5] = Far Seer
Set SL_HERO_TYPE[6] = Tauren Chieftain
Set SL_HERO_TYPE[7] = Shadow Hunter
Set SL_HERO_TYPE[8] = Death Knight
Set SL_HERO_TYPE[9] = Priestess of the Moon
Set SL_HERO_TYPE[10] = Dreadlord
Set SL_HERO_TYPE[11] = Crypt Lord
Set SL_HERO_TYPE[12] = Keeper of the Grove
Set SL_HERO_TYPE[13] = Priestess of the Moon
Set SL_HERO_TYPE[14] = Demon Hunter
Set SL_HERO_TYPE[15] = Warden
Set SL_HERO_TYPE[16] = Paladin
Set SL_MAX_HERO = 16
-------- we set the items to variable but we doing this with jass, in header u can find the function --------
-------- if you easily want change the saveable items (currently 73 item type) --------
-------- then use http://www.hiveworkshop.com/forums/spells-569/save-load-tools-get-raw-code-file-randomiz-257133/ --------
-------- and replace the current once but dont forget change the MAX_ITEM variable too --------
-------- The crc code length, if 1=less accurate, 2=more accurate, 3=more accurate ...5=highest --------
-------- Default is 4 --------
Set SL_CRC_LEN = 2
-------- List here the items what you want use --------
-------- and Max item at end --------
Set SL_ITEM_TYPE[1] = Bladebane Armor
Set SL_ITEM_TYPE[2] = Potion of Healing
Set SL_ITEM_TYPE[3] = Potion of Invisibility
Set SL_ITEM_TYPE[4] = Wand of Lightning Shield
Set SL_ITEM_TYPE[5] = Wand of Illusion
Set SL_ITEM_TYPE[6] = Killmaim
Set SL_MAX_ITEM = 6
-------- Don't need to change these below --------
Trigger - Add to Auto Settings <gen> the event (Time - Elapsed game time is 1.00 seconds)
Hashtable - Create a hashtable
Set SL_HASHTABLE = (Last created hashtable)
-------- don't need touch, will be loaded somewhere else --------
-------- this will automaticall updated in Load table and data trigger --------
Set SL_MAX_HERO_LEVEL = 100
Set SL_MAX_VAR = 2
Set SL_VAR[1] = <Empty String>
JASS:
function Trig_Loading_table_Actions takes nothing returns nothing
//"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$&/+-=[]^_`{}~()*"
//local string ENCODE = "@rh4[N{ym9MlT/Qc1LI2Ja^$5x60_CFdjDqARs=n3+E~(eY}gXuGw`)pSU8WHz#-*kB]!Zv&t7OiPoKbfV"
//local string ENCODE = "@h0oj]LH)!+bAcQtWMr_3#fDR&g1$Cq-uUTXvx5zsYIk4iONEFew^Vm(/86}l9[dna{~J=S*Pp2G7Z`yBK"
local integer i = 0
local integer i2 = 0
local integer l = StringLength(udg_SL_STRING)
local location loc
local string array Key
local string s
local unit u
local integer MaxExp
local integer MaxLvExp
local integer a1 //lv
local integer a2 //exp
local integer a3 //str
local integer a4 //agi
local integer a5 //int
local integer a6 //gold
local integer a7 //lumber
local integer b1 = 0 //minimum lv code length
local integer b2 = 0 //minimum exp code length
local integer b3 = 1 //minimum str code length
local integer b4 = 1 //minimum agi code length
local integer b5 = 1 //minimum int code length
local integer b6 = 0 //minimum gold code length
local integer b7 = 0 //minimum lumber code length
local integer c1 = 2 //maximum lv code length
local integer c2 = 4 //maximum exp code length
local integer c3 = 2 //maximum str code length
local integer c4 = 2 //maximum agi code length
local integer c5 = 2 //maximum int code length
local integer c6 = 4 //maximum gold code length
local integer c7 = 4 //maximum lumber code length
local integer c2_1
set i = 0
loop
exitwhen i == l
set s = SubString(udg_SL_STRING, i, i + 1)
if s != StringCase(s, true) then
call SaveInteger(udg_SL_HASHTABLE, StringHash(s), 2, i)
else
call SaveInteger(udg_SL_HASHTABLE, StringHash(s), 1, i)
endif
//call SaveStr(h, 2, i, s)
set i = i + 1
endloop
set i = 1
loop
exitwhen i > udg_SL_MAX_HERO
call SaveInteger(udg_SL_HASHTABLE, 2, udg_SL_HERO_TYPE[i], i)
set i = i + 1
endloop
set i = 1
loop
exitwhen i > udg_SL_MAX_ITEM
call SaveInteger(udg_SL_HASHTABLE, 3, udg_SL_ITEM_TYPE[i], i)
set i = i + 1
endloop
set loc = GetStartLocationLoc(GetPlayerStartLocation(Player(0)))
set u = CreateUnit(Player(15), 'Hpal', GetLocationX(loc), GetLocationY(loc), 0)
call AddHeroXP(u,2147483647,false)
set MaxExp = GetHeroXP(u)
set i = GetHeroLevel(u)
set udg_SL_MAX_HERO_LEVEL = i
if i > 1 then
call UnitStripHeroLevel(u, -i)
call SetHeroLevel(u, i - 1,false)
endif
set MaxLvExp = MaxExp - GetHeroXP(u) - 1
call RemoveLocation(loc)
call RemoveUnit(u)
//checking if max gold could be lower code length than max
set i = 1
set c1 = SL_GetIntegerSize(udg_SL_MAX_HERO_LEVEL)
set c2 = SL_GetIntegerSize(MaxExp)
set c2_1 = SL_GetIntegerSize(MaxLvExp)
set c6 = SL_GetIntegerSize(udg_SL_MAX_GOLD)
set c7 = SL_GetIntegerSize(udg_SL_MAX_GOLD)
//if something turned off then we dont need loop over all variations
if not udg_SL_SAVE_SMART_LV then
set c2 = b2
endif
if not udg_SL_SAVE_GOLD then
set c6 = b6
endif
if not udg_SL_SAVE_LUMBER then
set c7 = b7
endif
if not udg_SL_SAVE_STAT then
set c3 = b3
set c4 = b4
set c5 = b5
endif
// we make a huge crap :D
set i = (c1+1-b1)*(c2+1-b2)*(c3+1-b3)*(c4+1-b4)*(c5+1-b5)*(c6+1-b6)*(c7+1-b7)
if (i > (l*l-1)) or i > 8191 then
call DisplayTextToPlayer ( GetLocalPlayer(), 0, 0, "|cffff7777Warning:|r too huge max numbers in system." )
else
//call PreloadGenClear()
//call PreloadGenStart()
set i = -1
set a1 = b1
loop
set a2 = b2
if a1 > b1 then
set c2 = c2_1
endif
set Key[1] = I2S(a1)
loop
set a3 = b3
set Key[2] = I2S(a2)
loop
set a4 = b4
set Key[3] = I2S(a3)
loop
set a5 = b5
set Key[4] = I2S(a4)
loop
set a6 = b6
set Key[5] = I2S(a5)
loop
set a7 = b7
set Key[6] = I2S(a6)
loop
set Key[7] = I2S(a7)
set s = Key[1] + Key[2] + Key[3] + Key[4] + Key[5] + Key[6] + Key[7]
set i = i + 1
set udg_SL_VAR[i] = s
//call Preload(s+" i:"+I2S(i))
set a7 = a7 + 1
exitwhen a7 > c7
endloop
set a6 = a6 + 1
exitwhen a6 > c6
endloop
set a5 = a5 + 1
exitwhen a5 > c5
endloop
set a4 = a4 + 1
exitwhen a4 > c4
endloop
set a3 = a3 + 1
exitwhen a3 > c3
endloop
set a2 = a2 +1
exitwhen a2 > c2
endloop
set a1 = a1 + 1
exitwhen a1 > c1
endloop
set udg_SL_MAX_VAR = i
//call PreloadGenEnd("log_shadow.txt")
endif
call DisplayTextToPlayer ( GetLocalPlayer(), 0, 0, "|cffffff00Notice:|r Loading save-load system done." )
set u = null
set loc = null
set s = null
endfunction
//===========================================================================
function InitTrig_Auto_Settings takes nothing returns nothing
set gg_trg_Auto_Settings = CreateTrigger( )
call TriggerAddAction( gg_trg_Auto_Settings, function Trig_Loading_table_Actions )
endfunction
Save
Events
Player - Player 1 (Red) types a chat message containing -save as An exact match
Player - Player 2 (Blue) types a chat message containing -save as An exact match
Player - Player 3 (Teal) types a chat message containing -save as An exact match
Player - Player 4 (Purple) types a chat message containing -save as An exact match
Player - Player 5 (Yellow) types a chat message containing -save as An exact match
Player - Player 6 (Orange) types a chat message containing -save as An exact match
Player - Player 7 (Green) types a chat message containing -save as An exact match
Player - Player 8 (Pink) types a chat message containing -save as An exact match
Player - Player 9 (Gray) types a chat message containing -save as An exact match
Player - Player 10 (Light Blue) types a chat message containing -save as An exact match
Player - Player 11 (Dark Green) types a chat message containing -save as An exact match
Player - Player 12 (Brown) types a chat message containing -save as An exact match
Conditions
Actions
Set SL_CV_ARRAY[1] = 76
Set SL_CV_ARRAY[2] = 35
Set SL_CV_ARRAY[3] = 15
Set SL_CV_ARRAY[4] = 64
Set SL_CV_ARRAY[5] = 444
Set SL_CV_ARRAY[6] = 5673
Set SL_CV_ARRAY[7] = 63
Set Player = (Triggering player)
Custom script: set bj_wantDestroyGroup = true
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
SL_SAVE_HERO Equal to True
Then - Actions
Unit Group - Pick every unit in (Units currently selected by (Triggering player)) and do (Actions)
Loop - Actions
If (All Conditions are True) then do (Then Actions) else do (Else Actions)
If - Conditions
(Owner of (Picked unit)) Equal to (Triggering player)
12th Dec 2015
IcemanBo: For long time as NeedsFix. Rejected.
IcemanBo:
TriggerHappy's critiqute is still not solved. Also look for posts by Nestharus in this thread.
09:31, 19th Sep 2014
TriggerHappy:
Nestharus' post covered most of it...
tbh it seems to be a pain to use since you need to add every single item. There should be a boolean that you can set to true if you want every single item to be saved.
tbh it seems to be a pain to use since you need to add every single item. There should be a boolean that you can set to true if you want every single item to be saved.
do u mean saved to variable and that pain?
its a copy a copy paste and maybe change the index...
if you readed the map init trigger and the link there then you also understand what u say takes maximum 1 minute if you want different item...
also map include every normal item code at disable trigger so if dont want use my other map for save items and copy here then just copy from that trigger and change index... so what is pain in that?
other side could work without saveing any item to variable ofc, cost of 4 char instead of the 1-2 char length
I still don't get why these save load codes need to have Long arse codes
its dynamic, u can save a simple hero and check then the code length, other side since code saved directly into file i think its a select+copy+paste is fine, are anyone said to you type manually the code? lol
so if i understand instead store 70-80 item to variable better save 200 what i don't save?
in game have around that much and in this map for example i used 73 item type
other side you don't need other system except if u want do it fastest way (also need use only 1X with that system too, not bigger difference than implent a dd's to your map except this isn't required and have other way also here need copy-paste and not add more trigger), like said above there a disabled trigger what i isn't copied here, where was saved every item with id and raw code and that direct form, what u can simple copy past from that trigger to header and change item index, that isn't pain really.
since to every item on list in disabled trigger also got name u easily select what u want save or what not, really copy pasteing dont make bigger effort like example create variable if at settings was disabled the create unknow variable.
about item saveing:
1 character tell where is the 0-6 item, like 1-slot 1 item filled, 0 if slot1 empty, 2 if slot2 filled and 0 if empty, 4 if slot 3 filled and 0 if empty.... 32 if slot6 filled 0 if empty and add to each other, so if each slot filled it is 63 what is 1 character length in base 73 and from that number we can know each item position because work like 6 boolean in 1 number
if this not 0 then next 1 character tell the item type via give index in item type array, if this is a charged item type and max charge for item not 1 then next char tell the charge amount, next char tell the 2nd item index in array this till 6th item.
so basically if u got no item then in save load code u have 1 charater, if u have 6 normal item then 7 character totally the item part, if u have 6 item with all charged and 2-3 charge then it is 13 character, if u save raw code then it is 4 character each, 6 item became 24 character and 1 who say the slot so 25 then if u add charge to each then 31 character, i hope u got it why i used item array.
(btw if u disable with boolean in map init the item saveing then 0 character )
if someone experienceing the simple save load could be around 3x less than if u enable everything and got high amount from everything, thats why code length dynamic. btw only the crc code is 4 character long to be more sure peoples can touch it too easy
No it just happens so many make the same mistake although I should make a file so I can copy and paste it. It would be easier for me.
Any of the red text is a BJ function call there are a few in your system that should be removed.
Custom resources should be able to be saved because several maps have them. Why should they use your system if you don't make it work for almost everyone ?
No it just happens so many make the same mistake although I should make a file so I can copy and paste it. It would be easier for me.
Any of the red text is a BJ function call there are a few in your system that should be removed.
Custom resources should be able to be saved because several maps have them. Why should they use your system if you don't make it work for almost everyone ?
(about red text, yes have few, like moduloint but since rarly used i let it there, why? because if someone who not expert easier understand the that than if i replace with a math formula what maybe peoples dont understand why i do that) so let that stuff what dosn't do too much system call but alot help to understand why it is there.
but what u mean under custom resource? still isn't clear to me, saveing custom integer?
(about red text, yes have few, like moduloint but since rarly used i let it there, why? because if someone who not expert easier understand the that than if i replace with a math formula what maybe peoples dont understand why i do that) so let that stuff what dosn't do too much system call but alot help to understand why it is there.
but what u mean under custom resource? still isn't clear to me, saveing custom integer?
because don't really change on anything these function since they isnt spammed or something and improve more on understanding for very very minor cost
(GetPlayableMapRect(), moduloint)
i added into map a demonstration about how to use 2 number (each +1char and value each max 63) for handle 6 quest if they are discovered or no, completed or no etc.
changed but to be honest, this have absolute 0 importance if someone use it in gui, do you think its speed up atleast with 0.0000000000001sec? i am not sure
3. With the names of the variables and the convoluted process, I can barely even tell what this does
4.
function ItoS takes integer i, integer len, string t returns string
It appears to just convert each integer into the base of the alphabet, which is really, really bad, lol. TriggerHappy's does it better.
It also has a bunch of extra stuff. The function is way too heavy weight. You need to represent your data as a number, it'll make everything so much easier. Either that, or you need to convert a number into a string and return it given an alphabet or something. This just does way too much. You need to split it up a lot.
5. function SPos takes string s, string t returns integer
No idea what this does from the function name and don't care. I'm assuming that it is a string search function that returns the index of the first instance of the character/string.
6. There's this thing called the hashtable. O(n) loops over strings are so damn old school, lmao.
function StoI takes string c, string t returns integer
7. Why is this in your save/load system?!
function GetItemMaxCharges takes integer id returns integer
8. And this..
function HeroDatabase takes integer id, integer index returns integer
9. This too ...
function DeclareItems takes nothing returns nothing
10. -.-
function ItemDatabase takes integer id, integer index returns integer
11. All of the if-statements in this... jeezes, and it does so much extra crap that it shouldn't be doing... what if they don't have a hero, or don't care about stats, etc? You ganna save that stuff anyways?
function MakeSaveLoadCode takes player p returns nothing
Conclusion:
I can see why this produces hellishly long codes now compared to other systems. It isn't flexible, it isn't scalable, it isn't modular, it's extremely difficult to maintain and is very difficult to read, and it's a very heavy weight resource. It essentially fails to meet any of the requirements of MEDA, which defines what good quality software is ^)^. Even the usability is negative because this can't really be configured unless you modify the actual code. If you have to modify the system to use it, that's bad = P.
Considering all of this, I would honestly trash it and start over. You need to break the problem up into pieces. How are you going to handle the data? Make a resource for that. You can either do bits or arbitrary bases, both are legit. You also need to consider save/load techniques. Rather than include a bunch of stuff in your system to make it super heavy weight, rip them out and make them standalone resources. Someone may want your database thing, but they may not want to use your actual encoding algorithm, etc.
There is a lot, but I think this is a good learning experience ; ).
This is an all in one package, and that isn't good at all. The bigger something is, the more likely it is to fail and the more likely that it is going to suck. It's difficult to maintain the quality of something enormous. That's why things are broken down into small pieces and put together like a puzzle.
Right now, i'd give it a 1/10, but nice effort ; ). I can tell this is your first attempt.
I'm a harsh reviewer, I get that, but I'm also honest and upfront. I really recommend you just start over from scratch and use what you learned in the previous attempt to make something better. When I code something that bad, I just start over =). Some things may be able to be salvaged, this line of code or that, but yea.
Think more generic. It's not about what you are going to save, it's about what you might save and what you might not save. Save/load systems are all about producing small codes. The smaller the code, the better. You don't want to pack a user's code up with a bunch of extra fluff that they are never going to use, do you?
Go away from options and configurables and go more to making your system adapt to anything. It's not about including 1001 things and 1001 booleans to enable/disable those things, it's about making a skeleton that people can plug things into.
When I first started out, I was just like you. It took many, many years to get to where I am now, so don't be demoralized by this ; ).
Also, when you use JASS, you need to consider encapsulation. You should prefix your variables with like LIBRARYNAME_.
Fix your variable names. Your code is practically impossible to read because they give no insight as to what they do.
Comment your code. If you have a huge block of code that does something, put a little note at the top of it that says what it does, this way someone doesn't have to trace your algorithm to figure out what it's purpose is. You don't need to comment every single little line (unless there is a good reason too, like an operation that might seem strange), but you should definitely comment algorithms and explain why you are doing them. Keep them short and simple, don't get carried away like some people and write huge novels, lol. It's faster to read the code than to read a huge 1000-line novel : P.
Those are my tips. To anyone thinking of using this, just use TriggerHappy's ; ). It's very GUI friendly and is much better.
Also, about the only way you are going to bring something new to the table with save/load is to do a good GUI save/load system, meaning arbitrary bases. There are some out there, like Neostorm's, that use bits. Pipedream's uses arbitrary bases and has GUI support (go go), but it has a few ... errors. You can actually start from his code and fix the errors if you want ; ), but I warn you, the errors are not so easily fixed =).
Nice attempt, but this is definitely not useful at the moment. It probably wasn't the right time to submit it ^)^. We do have a place called The Lab.
I'll rate this 1/5 for now to let people know to stay away. I'll update the rating to reflect your changes in the future.
Keep in mind, this isn't about you. This isn't about stroking your ego or being nice to you and approving it. This is about the users. Do we really want to mislead the userbase into using this when there are much better systems out there? Take this opportunity to improve yourself ^_^.
I'm also about the harshest review on the site, so this is about as bad as it's ganna get ; P.
edit
Here is a bit manipulation library that is practically raw JASS.
You can remove the module initializer and initialize the system yourself and remove the library wrappers and you'll have plain JASS. You can also change the single global to a udg_.
That will drastically reduce the size of your codes. The system isn't difficult to use either ^)^.
Test it out a bit to see how the functions work.
If that is too much, there are bitwise operator libraries in the JASS section.
i agree with my jass style is kinda chaotic, and few place maybe needed few label but one reason was i dont wrote label because if someone use in gui dont need touch there.
my english also not the best like my creativity with names, thats why there CodeTypes[/s] what for me a function where have more randomized numericalphabet with syntax so string what i use for encode.
during time few function i dont used anymore but still not removed like ColorCodeString,GetMaxItemCharge - i not was sure if remove definitly or no
There's this thing called the hashtable. O(n) loops over strings are so damn old school, lmao.
i tryed make the system with if posible the low amount of variables also if posible avoid the hashtable if not needed, since saveing not periodic thing i am well with old stuff methode
BTW. Spos coming from string position what often used in php, basic etc
in every language similiar methode, a function where have a big string, a string what we search, starting place
11. All of the if-statements in this... jeezes, and it does so much extra crap that it shouldn't be doing... what if they don't have a hero, or don't care about stats, etc? You ganna save that stuff anyways?
.....................................
It isn't flexible, it isn't scalable, it isn't modular, it's extremely difficult to maintain and is very difficult to read, and it's a very heavy weight resource
why flexible?
u set in gui if want save the hero stat[3stat],resource[gold,lumber],coordinate, items and all with boolean in init and you can add your own custom value (0-2kkk) in save trigger, you set the verification code size and the player name binding to code also boolean[yes or no], the custom value amount what want save
yes that point right it's allways save the hero exp and class type.
after that still why flexible? you can change the "encrypting" string (add or decrease the length), system save a 50000 level hero,200mil str/agi, 2kkk exp hero without touching/changing anything to gui users, basically with custom values can save any other thing aswell, and that also could be 0-2kkk, could be used for save other stuff like in demonstartion i save 6 quest stuff.
how flexible more?
the code included the version number, what if someone want edit the jass core loading part then just make example a if VERSION == 2 then and organise how he want anything and still old codes useable too because they are loaded with VERSION==1 way...
i know wouold be change the how organised the function, i will do it, but i can't call this trash only because maybe this way for save load code outdated (its my 2nd try, 1st was make Aceheart save load code in ~2004 from thehelper in jass around alot year ago )
btw i know about percentage stuff and compress int function but both inaccurate, lets say if someone want make a rpg where hereo could be high level and need alot exp for level but exp gaining slow then annoying that also i dont save level just exp and if i same percentage than need save level too, what in result same in length.
later if have time check ur link
[update]
i made that, i puted function to header and map init the array, but honestly no ideea what it must do or what it do?
i thougth it compress the number, but only read bits give shorter result rest of stuff what i tryed did a 2 based string
to be honest what you talk about?
- don't save the item position and item charge
- save the level only and no exp, if i was at 98% close to next level still lower level
- don't save to file, i really don't want anymore typeing codes, atleast this can copy under sec without bluring my eyes
- with same save option[no coord, lumber save, less crc code length] that generate similiar and sometimes his longer length without the "-"'s (except if we don't count 2 char in mine what both could be removed - version number, encodeing string identifier)
only pro is in functions and not in output, and that is he wrote organised the save load and workk without hero
01001001100101100000001011010010 would be the number in binary (base 2)
If you work with bits instead of your huge characters, you have a lot less space in between your information, which makes your codes much smaller.
If you wanted to save a 1 in base 63, that would take up a full base 63 digit. 63 happens to be 6 bits. That value, 1, could be saved using only 1 bit. That's 5 bits of empty space.
You end up with this
000001
Instead of
1
So what if you wanted to save two 1's? Now you get this.
000001000001
Instead of
11
Do you see where I'm going with this?
Binary still has empty space between values. Unless a value is a power of 2, there is going to be empty space. This space is in fractions of digits.
For example, something may be able to be stored with a max value of 5
101
That would be your max value in binary. Notice how you aren't utilizing all of the bits? If you were, your max value would be
111
With arbitrary bases, any given value takes up a single digit in a target base, that base being 1 higher than the value.
Want to have a max value of 9? Use base 10
9999999
0 space in between the values
Want a max value of 2? Use base 3
222222
Want a max value of 5, then 3, then 9?
5, 3, 9 (not base 10, 3 numbers in base 6, 4, and 10)
In base 10, the above would be
239 (a bit smaller than 539, this is because there is 0 space in between the values)
Binary would have much less space in between your values and has nice/easy math that goes with it. If you want to reduce your code sizes w/o a ton of overhead, binary is the way to go. If your final output base is a power of 2, converting between binary and it is trivial.
For example, base 16 is a group of 4 binary digits
In this regard, using this system, an integer is a 32 slot array. Each slot holds either a 0 or a 1. You can combine these slots together to form bigger values.
If you want to store up to 5, you can take 3 array slots, similarly to how you would take several characters in your code to store a number.
Feel free to use these functions to pack your data more tightly ^)^.
ReadBits - reads values in the array from a start position to an end position, similarly to SubString. Returns everything as 1 value.
GetBitNumber - 2^n, where n is your input. If you give it 0, it'll give you 1. If you give it 31, it'll give you 2^31.
There is also WriteBits, which writes to the end of your array. You just tell it how many slots to take up and then what to plug into those slots. It'll return the number with the written bits. There isn't a function that'll write at an arbitrary position atm.
PopBits will remove either the first bits or the last bits from the array. I don't remember which, you can test it.
These functions transform an integer into an array of size 32, where each slot can hold either a 0 or a 1. Use it how you will ^)^.
i undersand the binary, hexadecimal numbers but no ideea this how to help on me, i mean i got the 74 in base 73 is waste in ur binary view point but no ideea how its became string or and from binary functions i understanded only few, the storeing 5 to 3 slot i understand because used it, i know 1st char have 0/1 next 2 or 0 then 4 or 0 etc so 2^position or 0 depend it is 1 or 0.
bit2string is okey, its convert decimal to binary, readbit i understand read/calculate a part of the string but i dont see where its became needed, same the shift and rotate or pop bits, it is only just tool? because if i converted my decimal to binary i dont know why would swap 2 index in array.
read bit i noticed give back the input value
JASS:
call DisplayTextToForce( GetPlayersAll(), I2S(ReadBits (1234567890,0,31)) ) //1234567890
call DisplayTextToForce( GetPlayersAll(), I2S(ReadBits (1234567890,0,10)) ) //588
call DisplayTextToForce( GetPlayersAll(), I2S(ReadBits (4,0,31)) ) //4
call DisplayTextToForce( GetPlayersAll(), I2S(ReadBits (4,28,31)) ) //4
call DisplayTextToForce( GetPlayersAll(), I2S(ReadBits (4,0,31)) ) //10
//i guess the bits counted from right to left and read bits work from left to right thats why need to be 31 the value
call DisplayTextToForce( GetPlayersAll(), I2S(GetBitNumber(1) )) //1
call DisplayTextToForce( GetPlayersAll(), I2S(GetBitNumber(2) )) //2
call DisplayTextToForce( GetPlayersAll(), I2S(GetBitNumber(3) )) //4
call DisplayTextToForce( GetPlayersAll(), I2S(GetBitNumber(8) )) //128
//so this simple like u wrote put 2^(input integer-1)
call DisplayTextToForce( GetPlayersAll(), I2S(GetBitSize(3) )) //2 because in binary 11
call DisplayTextToForce( GetPlayersAll(), I2S(GetBitSize(8) )) //4 because in binary 1000
call DisplayTextToForce( GetPlayersAll(), I2S(GetBitSize(9) )) //4 because in binary 1001
//so its like if binary would be string then this give the StringLength of binary string i guess GetFreeBits=32-GetBitSize(n)
call DisplayTextToForce( GetPlayersAll(), I2S(GetFreeBits(GetBitSize(9)) )) //29 no ideea how not 28 if 32-4 could be 28
call DisplayTextToForce( GetPlayersAll(), I2S(GetFreeBits(GetBitSize(1)) )) //31 that i got, 32-1
call DisplayTextToForce( GetPlayersAll(), I2S(PopBitsFront (64,3) )) //8
call DisplayTextToForce( GetPlayersAll(), I2S(PopBitsFront (64,2) )) //16
//no ideea what/why this do that but look like if 1st input is 2^x then its give back the 2^(x-2nd input number[what was 3,2]) so 64 is 2^6 and 2nd input 3 => 2^(6-3)=8, 64 is 2^6 => 2^(6-2) = 16
//for be look like work same way the back and front too
set n = 64
call DisplayTextToForce( GetPlayersAll(), I2S(ReadBits (n,31-GetBitSize(n),31)) ) //64
//i just tested :)
would be nice see how u convert example 45 to string step by step?
btw what u do if u have 2 number? like 8 and 8? u put this 10001000 like string then code this string somehow and compress? then how to make difference between where its start and end?(i mean how much space takes) since i guess u dont save delimiter or character (like me) what tell the next number length in code? about arbitrate there is no enough alphabet or syntax for use it, i was able to use only ~80ish string so i am a bit confused how became binary at end a short string
The next step is to take a set of integers. We'll slowly build upon this set of integers. It can be a linked list.
Each integer can store a total of 32 bits. In this case, we only have 30 bits, but if we had more, we'd have to add more bits as we ran out of room.
So, first you take your number
75000
next you get bits it requires
17
now you make room for 17 bits in your code
(if no room in current integer, add another)
now you write to your integers (1-2). If you are writing to two, you'll write a portion of the bits to the first integer, and the rest to the second. In this case, it's just one.
code = WriteBits(code, gold, 17)
Now for the next number, 60 and 6 bits. There is enough room in your integer to store it.
code = WriteBits(code, heroLevel, 6)
last one
code = WriteBits(code, customValue, 7)
Now we have the integer formed.
When checking to see if you have room in the 32-bit integer, you will use GetFreeBits(code)
Assume that we have base 64, so a 64-character string to output data in. Each character can hold 6 bits. This means you will take 6 bits at a time and turn it into a character.
Taking our original data
00000000000000000 000000 0000000
We now partition it like this using PopBits (this gets from the back!)
[000000][000000][00000 0][00000 0][000000]
just have an array like array[value] = character. The values are the things between the [ ]. That will be 5 characters.
Let's assume that they are
aaaaa
To go back, just convert the characters into values and you will have your data back.
LoadInteger(table, StringHash("a")) -> value
Keep in mind that you want to read from the last character to the first. PopBits or w/e will give you the last thing you wrote first.
ReadBits is a very inefficient function. You want to convert this into pops (front pops).
Front pops will take off of the end and return the front. Back pops will take off of the front and return the end... I named them wrong ; p, was naming by how the operation/numbers actually work, not how the function seems to behave : ).
You always write to the right and it goes left. Pop front would pop the stuff at the front of the array (the right) and shift everything down to fill it up. It returns the remaining bits. This is why PopFront(64, 2) gives you 16, because it takes off the 0's. It's the same as 64/2/2, which is 16.
This gives 29 because you are using it wrong -> GetFreeBits(GetBitSize(9))
It should be GetFreeBits(9), which is 28. You were doing GetFreeBits(4), because GetBitSize(9) gives 4. GetFreeBits(4) is indeed 29.
You keep saying that this is compression. This is not compression.
edit
I would just allocate a chunk of 24 integers and then use what you use. That's the number of integers you need to display any amount of data in wc3. If you are doing codeless, then there is no limit, but still, I'd prob cap it at 500 for codeless.
the 3rd value could be anything or u added only for show save 3 value, or it make something and its value important? or could swap it to exp?
this is currently and //the displayed result after the displaytext
JASS:
local integer MaxGold = 75000
local integer MaxLv = 60
local integer MaxAr = 95
local integer Gold = 72000 //current gold
local integer Lv = 55 //current level
local integer Ar = 80 //curent idk what :D
local integer LGold = GetBitSize(MaxGold) //max gold space in binary
local integer LLv = GetBitSize(MaxLv) //max level space in binary
local integer LAr = GetBitSize(MaxAr) //max ar. space in binary
local integer code1 = WriteBits(2, Gold, LGold)
local integer code2 = WriteBits(2, Lv, LLv)
local integer code3 = WriteBits(2, Ar, LAr)
local integer rc1 = ReadBits (code1,31-LGold,31)
local integer rc2 = ReadBits (code2,31-LLv,31)
local integer rc3 = ReadBits (code3,31-LAr,31)
local string rs1 = ItoS (code1, -1)
local string rs2 = ItoS (code2, -1)
local string rs3 = ItoS (code3, -1) //converted to string, based on 64 length string
curious how to compress it because till now the code longer than with normal methode
oh and how to merge the numbers (gold,lv and ar merge into 1 number? in save load tutorial was something stack and 3 number into 1 but that became huge)
it was good till now?
[topic off] same time i check ur interactive save load and there at 48 where save unit and get 2 string piece (exk) when i load multiple time sometimes it is full hp and 0 mana instead 50-50% hp and mp
in 53 if i use twice the load same code give several item only and have bounds error
So first, some function updates and 2 new functions. I did this to drastically increase performance and add some new functionality ^)^.
Functions
JASS:
function Bits2String32 takes integer num returns string
local string str0 = "00000000000000000000000000000000"
local string str = ""
local integer bit0 = 0
if (num < 0) then
set bit0 = 1
set num = -2147483648 + num
endif
loop
exitwhen 0 == num
set str = I2S(num - num/2*2) + str
set num = num/2
endloop
return I2S(bit0) + SubString(str0, 0, 31 - StringLength(str)) + str
endfunction
function Bits2String takes integer num returns string
local string str0 = "00000000000000000000000000000000"
local string str = ""
local integer bit0 = 0
if (num < 0) then
set bit0 = 1
set num = -2147483648 + num
endif
loop
exitwhen 0 == num
set str = I2S(num - num/2*2) + str
set num = num/2
endloop
if (0 == bit0) then
return str
endif
return I2S(bit0) + SubString(str0, 0, 31 - StringLength(str)) + str
endfunction
function GetBitSize takes integer bits returns integer
local integer low = 0
local integer high = 31
local integer mid = 15
if (0 == bits) then
return 0
elseif (0 > bits) then
return 32
endif
loop
if (bits < udg_powArr[mid - 1]) then
set high = mid - 1
else
set low = mid + 1
endif
set mid = (high + low)/2
exitwhen high < low
endloop
return mid
endfunction
function GetFreeBits takes integer bits returns integer
return 32 - GetBitSize(bits)
endfunction
function WriteBits takes integer bits, integer bitsToWrite, integer bitsToOccupy returns integer
return bits*udg_powArr[bitsToOccupy] + bitsToWrite
endfunction
function ReadBitsBack takes integer bits, integer bitCount returns integer
if (bits < 0) then
return (bits - 2147483648)/udg_powArr[32 - bitCount] + udg_powArr[bitCount - 1]
else
return bits/udg_powArr[32 - bitCount]
endif
endfunction
function ReadBitsFront takes integer bits, integer bitCount returns integer
if (bits < 0) then
if (bitCount == 32) then
return bits
endif
set bits = bits - 2147483648
endif
return bits - bits/udg_powArr[bitCount]*udg_powArr[bitCount]
endfunction
function PopBitsFront takes integer bits, integer bitsToPop returns integer
if (bits < 0) then
return (bits - 2147483648)/udg_powArr[bitsToPop] + udg_powArr[31 - bitsToPop]
else
return bits/udg_powArr[bitsToPop]
endif
endfunction
function PopBitsBack takes integer bits, integer bitsToPop returns integer
if (bits < 0) then
if (bitsToPop == 0) then
return bits
endif
set bits = bits - 2147483648
return bits - bits/udg_powArr[32 - bitsToPop]*udg_powArr[32 - bitsToPop]
else
return bits - bits/udg_powArr[31 - bitsToPop]*udg_powArr[31 - bitsToPop]
endif
endfunction
function ReadBits takes integer bits, integer bitStart, integer bitEnd returns integer
return ReadBitsFront(PopBitsFront(bits, bitStart), bitEnd - bitStart + 1)
endfunction
function GetBitNumber takes integer bits returns integer
return udg_powArr[bits - 1]
endfunction
function ShiftLeft takes integer bits, integer shift returns integer
return bits*udg_powArr[shift]
endfunction
function ShiftRight takes integer bits, integer shift returns integer
return PopBitsFront(bits, shift)
endfunction
function RotateLeft takes integer bits, integer shift returns integer
return ShiftLeft(bits, shift) + ReadBits(bits, 0, shift - 1)
endfunction
function RotateRight takes integer bits, integer shift returns integer
return ShiftRight(bits, shift) + ReadBits(bits, 32 - shift, 31)*udg_powArr[32 - shift]
endfunction
Init
JASS:
function InitTrig_Bitmanip_library takes nothing returns nothing
local integer i = 1
set udg_powArr[0] = 1
loop
set udg_powArr[i] = udg_powArr[i - 1]*2
set i = i + 1
exitwhen i == 32
endloop
set udg_powArr[32] = -2147483648
endfunction
I also changed a couple of functions around. The front is always the right side of the number. The back is always the left side. You read it from right to left, always.
The new functions are
JASS:
function ReadBitsFront takes integer bits, integer bitCount returns integer
function ReadBitsBack takes integer bits, integer bitCount returns integer
The fast functions are
JASS:
function WriteBits takes integer bits, integer bitsToWrite, integer bitsToOccupy returns integer
function ReadBitsBack takes integer bits, integer bitCount returns integer
function PopBitsFront takes integer bits, integer bitsToPop returns integer
ReadBitsFront just reads the front x bits. ReadBitsBack reads the back x bits.
Here is a fully working example that supports a single 32-bit integer.
If you want something that's really usable, you're going to have to have an array of 32-bit integers that you write to. If you only have 2 bits left or something and want to write a value that takes 6 bits, write 2 bits to your first integer, then get a new integer and write the remaining 4 bits to it. When you read back, read out the 4 bits and then read out the next 2 bits and put them together.
JASS:
function Trig_Untitled_Trigger_001_Actions takes nothing returns nothing
local integer maxGold = GetBitSize(75000)
local integer maxLevel = GetBitSize(60)
local integer maxAr = GetBitSize(95)
local integer currentGold = 72000
local integer currentLevel = 55
local integer currentAr = 80
local integer data = 0
local integer v1
local integer v2
local integer v3
local string ALPHABET = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-+="
local string array char
local string s
local hashtable table = InitHashtable()
local string encoded
local integer i
local integer i2
local integer stringHash
call DestroyTimer(GetExpiredTimer())
/*
* initialize alphabet
*/
set i = StringLength(ALPHABET)
loop
set i = i - 1
set s = SubString(ALPHABET, i, i + 1)
set char[i] = s
set stringHash = StringHash(s)
set i2 = 0
loop
exitwhen not HaveSavedInteger(table, stringHash, i2)
set i2 = i2 + 1
endloop
call SaveInteger(table, stringHash, i2, i)
exitwhen 0 == i
endloop
/*
* write values to 32-bit integer
*/
set data = WriteBits(data, currentGold, maxGold)
set data = WriteBits(data, currentLevel, maxLevel)
set data = WriteBits(data, currentAr, maxAr)
/*
* display raw data
*/
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "Raw: " + Bits2String32(data))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "Data: " + I2S(data))
/*
* store bits into characters, 6 bits per character
*/
set encoded = ""
loop
exitwhen 0 == data
set encoded = encoded + char[ReadBitsFront(data, 6)]
set data = PopBitsFront(data, 6)
endloop
/*
* output characters holding bits
*/
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "Code: " + encoded)
/*
* put bits back into 32-bit integer
*/
set i = StringLength(encoded)
loop
exitwhen 0 == i
set i = i - 1
set s = SubString(encoded, i, i + 1)
set stringHash = StringHash(s)
set i2 = 0
loop
exitwhen char[LoadInteger(table, stringHash, i2)] == s
set i2 = i2 + 1
endloop
set data = WriteBits(data, LoadInteger(table, stringHash, i2), 6)
endloop
/*
* output data
*/
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "Raw: " + Bits2String32(data))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, "Data: " + I2S(data))
set v3 = ReadBitsFront(data, maxAr)
set data = PopBitsFront(data, maxAr)
set v2 = ReadBitsFront(data, maxLevel)
set data = PopBitsFront(data, maxLevel)
set v1 = ReadBitsFront(data, maxGold)
set data = PopBitsFront(data, maxGold)
/*
* output written values
*/
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, I2S(v1) + " == " + I2S(currentGold))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, I2S(v2) + " == " + I2S(currentLevel))
call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 60000, I2S(v3) + " == " + I2S(currentAr))
endfunction
//===========================================================================
function InitTrig_Test takes nothing returns nothing
call TimerStart(CreateTimer(), 0, false, function Trig_Untitled_Trigger_001_Actions)
endfunction
Reading values back out of the number may seem confusing to you. Let me explain what's going on.
When you write to the array, it pushes all of the elements currently in it over to the left to make room for what you're writing, then it puts in the new data.
The top 3 bits were dropped like before, but everything moved to the left 3. In the pop version, the last 3 bits were just dropped.
The pop function in BitManip pushes everything as right as it can go. If you pop at the right, it does right shift. If you pop at the left, it does nothing.
Integers in warcaft 3 are signed, meaning that reading from left to write is much more expensive than from right to left. You want that last bit to be filled with a 0 as much as possible. When it's filled with a 1, it's hell to get the one out. Here's what happens in a right shift with the following assuming that the highest bit (leftmost) is signed.
That's right, it fills the entire number up with 1's. The only way to get rid of the dern'd thing is to specifically remove it.
Anyways, hopefully you understand a bit more about numbers ^)^. This is true for all bases btw, not just binary. However, a change of base is some pretty ugly math. When you have several digits in your number from several different bases, you have to do that ugly math. As long as you only work in one base, the math is simple. Binary is the smallest base that exists, so you'll minimize the fluff in your code by using it. Now, of course, you can go with a set of arbitrary bases, but then we get into ugly math ^)^.
One cool thing I did in the past was a library called Scrambler. It just changed the base of a number over and over again, mixing up the digits each time. Resulted in seemingly random numbers that varied in even their lengths o-o. The reason numbers can vary in lengths as a result of this is of course the fractions.
Remember values like 1001? They are stored in fractions of bits.
Suppose you have 10011001
If you rearrange them just right, you can get
00001111
Which is just 1111. That is half the size of the original.
That is the number 153 turned into 15
If you keep changing bases, going from like base 2 to base 3 to base 5, etc, you can end up with some really interesting results.
1111 is 120 in ternary. Let's rearrange again to give us 012. This gives us 101 in binary, rearranged to 011 we get 10 in ternary, and so forth. We can eventually go down to just 1.
As we change between bases, we get more and more fractions. It's possible to reduce a number from 153 to 1. However, we should never drop the leading place, or we lose information (the placeholders). Just showing that it's possible.
That is as packed as the number can get while losing 0 information. If we know our sequence to get back, we can then unscramble it and get all of our information back.
Once again, 153 -> 35.
Of course, numbers can also get bigger. If we scramble in the other direction to maximize the size of the number, we can figure out the range that 153, when scrambled, can become.
In binary, our number is 100011
Compare
10011001
100011
Cut off 2 full bits. This is still still has fractions of a bit in it, but notice that the fraction is very, very small. We know this because it is extremely close to a power of 2
100011
100000
The fraction is higher in ternay
1022
But there's nothing we can do to eliminate it. The number is too small to go to a larger prime base like 5, 7, or 11 to try and find more stuff that can be dropped out. The bigger the number, the bigger the range it has.
Oh well, that's just Scrambler ^)^.
If you want to see the fractions for yourself
ln(number - 1)/ln(base)
This will give you how many digits the number in base 10 will take up in a target base.
If we look back at 153, it takes up 7.257 digits in binary. 0b10000111 takes up 7.077 digits.
The closer you are to a whole number (not rounding down, rounding up), the better. If you are at like 7.99, you've practically maxed out capacity.
Now, this of course refers to bases. For example, 8 returns 3, but it actually takes up 4 binary digits. What this actually means is that a base 8 digit in binary will take up exactly 3 digits. Recall that base 8 goes from 0 to 7.
You can use this to determine how well your max values fit into binary (max value + 1), or any base for that matter. For example, a max value of 75,000 (75,001) will take up 16.19 binary digits, which is pretty bad. In base 84 (you were using this earlier right?), it would take up 2.53 digits.That seems like less wasted space, but let's convert that .47 in base 84 to binary to see how much extra space is wasted. .47*ln(84)/ln(2) = 3.004389 digits, which is way more than .81 digits from binary. Now keep in mind that a binary digit is small, these digits add up and generate a lot of code bloat. Certainly, fractions will still add up, but you may only be adding 3-5 binary digits over all instead of 20-40.
Let's see what would happen with arbitrary bases now.
75000
300
200
100
let's assume all at max
This gives us a value of 458301185600 when all packed together. In base 84, this is 6.06 digits.
Now using only binary, we get 1258301056100
458301185600
1258301056100
already we can see a bit of bloat as compared to the arbitrary base method. In base 84, it's 6.28795656 digits
6.06
6.29
So our code won't have gone up at all, but we do have some more empty space in there. Now for the final method, the method you were using.
So the naive method made the code 2 characters longer.
I hope you can see why it might be worth it to go for, at the bare minimum, binary ; P. Binary also normally outputs in base 64, so the reality is...
Binary = 6.699 = 7 digits
Binary will probably be 1-2 characters higher than arbitrary as the code grows in size. Naive will be way higher than both of them.
The formula, once again, is Ln(max value + 1)/Ln(base), or Ln(base1)/Ln(base2). You can use this equation to calculate the efficiency of your codes. There is an Ln function in the JASS section.
Also, if using arbitrary bases has 0 space in between the values, why was it 6.06 instead of 6? The space is at the very end of the number, when converting to base 84. Arbitrary bases won't necessarily fit nicely into the output base. That's where your space comes from. Arbitrary will never go above 1 extra character. They have the capability of going 0 extra characters, but that's terribly rare. It'll pretty much always be 1 extra character that has mostly space in it.
The space in binary and naive are spread between each of the values. This space grows as you add more values. Arbitrary has 0 space between the values, so the space won't grow, the space is only a result of the final output not being a power of the target base. This is why I personally use arbitrary. However, binary does have minimal space, so if you are going to stick with only 1 base, go with binary for sure.
Btw, base 128 will only drop binary to 5.74 digits. The benefit of increasing the size of your base goes down as the base grows in size. Base 256 is 5.02 digits. Base 1024 is 4.02 digits. Arbitrary in base 1024 is 3.87 digits. Naive in base 1024 is 5 digits, most of which is empty space. Why did the gap between naive and arbitrary lower?
The naive approach with this particular set of values is pretty much maximized at base 301. As it goes farther away from base 301, it will diverge from the other methods. Let's say that the base is now 75,001.
The very best naive is ever going to get to is 4 digits. The others will continue to drop.
There is another form of naive that tries to pack as much data as possible into a single value (Acehart's does 1,000,000) and then converts that value into a character. This reduces space a bit, but is still way worse than binary.
i am not in home but i will check if i going back till that a question about in fucntion, why do u use stringhas like key1? its made if someone use hastable for something then never overwrite the user data in hashtable because stringhash is ~unique?
to be honest, this function description was really nice and understandable, its like a nice tutorial.
a easy example to Arbitrary math stuff?
btw have something trick about storeing set (i mean like agi/str/int what have same max value) or need write each with function like any 3 number like was gold,lv,ar?
For here stats, look at save/load with snipets at save stats or something. That map has a lot of resources in it. You can look at them to see how to do things well.
StringHash is just a hash function that takes a string. There are collisions. Wc3 is also not case sensitive.
Lots of examples for arbitrary bases in the interactive save/load tutorial. The bad part is that you need to represent all of yout data as one number and then do the math operations on that. Do you know how to do division one digit at a time?
For here stats, look at save/load with snipets at save stats or something. That map has a lot of resources in it. You can look at them to see how to do things well.
StringHash is just a hash function that takes a string. There are collisions. Wc3 is also not case sensitive.
Lots of examples for arbitrary bases in the interactive save/load tutorial. The bad part is that you need to represent all of yout data as one number and then do the math operations on that. Do you know how to do division one digit at a time?
a question, if current gold is 1 but max is 75k, then here the ReadBitsFront(data, maxGold) is same 5 char long than 72k so if i save a minimum value and max value is high then isnt waste of space, like example when example if i use in my own map allways 2 char length for stat so '0Z' if less than stringth len, and '11' if higher by 1,if this put to each other then 2+2+2char for the 3 stat where max value is 5300 what takes 13 bit what is after 3 value its 39 reserved space in 32 digit long binary what is 7 char not 6 if i divide 39/6. i missunderstanded something?
btw i asked about hastable because was created locally and lost the reference out of that function and table isnt destroyed or moved to global (or u just dont stored because was non important)?
also why call DestroyTimer(GetExpiredTimer())?
a question, if current gold is 1 but max is 75k, then here the ReadBitsFront(data, maxGold) is same 5 char long than 72k so if i save a minimum value and max value is high then isnt waste of space
It's 3 characters, not 5 characters, but yea, it'll always take up that space regardless of the value. There are ways to actually make it take up less space, but then the worst case scenario is worse.
You can reduce the max value with tricks. For example, level 17 hero of type warrior has 173 strength with no modifications, when you save strength, you can subtract 173 from that hero's strength and max strength. The max strength would be the culmination of possible bonuses that hero can have at that level. If your normal max strength is 1024, but at level 17 with a warrior, it's only 218, then your actual max for your code is 218 - 173.
if this put to each other then 2+2+2char for the 3 stat where max value is 5300 what takes 13 bit what is after 3 value its 39 reserved space in 32 digit long binary what is 7 char not 6 if i divide 39/6. i missunderstanded something?
btw i asked about hastable because was created locally and lost the reference out of that function and table isnt destroyed or moved to global (or u just dont stored because was non important)?
It's 3 characters, not 5 characters, but yea, it'll always take up that space regardless of the value. There are ways to actually make it take up less space, but then the worst case scenario is worse.
You can reduce the max value with tricks. For example, level 17 hero of type warrior has 173 strength with no modifications, when you save strength, you can subtract 173 from that hero's strength and max strength. The max strength would be the culmination of possible bonuses that hero can have at that level. If your normal max strength is 1024, but at level 17 with a warrior, it's only 218, then your actual max for your code is 218 - 173.
basically, then where better to store in binary compared with my map except the 1-2 char less maybe because don't need to store the length of the gold (well this case depend because my code shorter in minimum case and maximum case a bit longer until ur is same length, because i think the difference is when we work in normal numbers)
don't missunderstand me, i love ur help because ~learned this too, this way is another view point about save load code mechanism and i like to learn new stuff
Ahem, 1-2 characters less *per* value. Why do you think your current codes are abnormally large? Try doing the math on your current data to see how much bloat there is in just your example code. Do minimum to maximum to find a range.
Also keep in mind that there are GUI save/load systems that use binary or arbitrary bases, so how, i ask, can yours currently compete with them. Why should a user use your system when there are several vastly superior systems out there? This, and your attitude about it, can be the basis for rejection. There is no need for a resource that only lowers the quality of a map compared to other resources that do the same exact thing. Do you not agree?
Ahem, 1-2 characters less *per* value. Why do you think your current codes are abnormally large? Try doing the math on your current data to see how much bloat there is in just your example code. Do minimum to maximum to find a range.
Also keep in mind that there are GUI save/load systems that use binary or arbitrary bases, so how, i ask, can yours currently compete with them. Why should a user use your system when there are several vastly superior systems out there? This, and your attitude about it, can be the basis for rejection. There is no need for a resource that only lowers the quality of a map compared to other resources that do the same exact thing. Do you not agree?
i dont said per value, i said overall few character difference but i got different ideea, i just noticed what u adviced gui saveload code generate long or same length code in same situation (if save same thing) but not less length code, atleast that one what i checked so thats why dont uinderstand that "lower" quality thing, well ofc chaos in names in stuff ofc understandable, but like i said mine did few character less in minimal case and 1-2 more compared with binary trying (i not regreted trying same with binary system too )
atm i think on something i will upgrade later
btw have conflict if i save StringHash("string letters/syntax/numbers 1by1") and GetUnitTypeId() and Getitemtypeid? any of them can be same than another?
This needs to be rewritten entirely. You have a bundle of extra useless variables.
function SL_IntegerToCode takes integer i, integer len returns string
Converting to a string is as simple as this
JASS:
loop
set myString = myString + characterSet[(i - i/base*base)]
set i = i/base
set length = length + 1
exitwhen i == 0
endloop
set myString = myString + characterSet[length]
Your algorithm is just way too convoluted. Also, you are going to have code bloat because you convert each integer independently rather than together. I've mentioned this before. If you want to store them as compactly as possible using your current algorithm, which has a much worse worst case scenario, you want to store them in binary (won't be exact space, so will still have code bloat) and then store the number of bits that it takes up in front of it. If you want to take up the minimal space possible, then you want to have maximum values and you don't want to store lengths in your code. TriggerHappy's resource has the same issues.
The loop here isn't necessary
JASS:
function SL_CodeToInteger takes string c returns integer
local integer l = StringLength(c)
local integer m = StringLength(udg_SL_STRING)
local integer i = 0
local integer char
local string s
local integer int = 0
if l > 0 then
loop
exitwhen i == l
set s = SubString(c, i, i + 1)
if s != StringCase(s, true) then
set char = LoadInteger(udg_SL_HASHTABLE, StringHash(s), 2)
else
set char = LoadInteger(udg_SL_HASHTABLE, StringHash(s), 1)
endif
if char !=0 or i > 0 then
set int = int + R2I(Pow(m, l - i - 1)) * char
endif
set i = i + 1
endloop
endif
set s = null
return int
endfunction
This isn't required...
JASS:
function SL_GetIntegerSize takes integer a returns integer
local integer base = StringLength(udg_SL_STRING)
local integer max = 4
local integer i = 0
if base < 64 then
set max = 6
elseif base < 74 then
set max = 5
endif
loop
set i = i + 1
exitwhen i > max
if a < R2I(Pow(base,i)) then
return i
endif
endloop
endfunction
Your checksum is not as good as Knuth.
JASS:
function SL_CodeCheckSum takes string c, player p returns string
local string EC = udg_SL_STRING
local integer MaxV = R2I(Pow(StringLength(EC), udg_SL_CRC_LEN))
local integer i
if udg_SL_BIND_TO_PLAYER then
set i = StringHash(c + StringCase(GetPlayerName(p), false))
else
set i = StringHash(c)
endif
if i < 0 then
set i = i * - 1
endif
if i > MaxV then
set i = ModuloInteger(i, MaxV)
endif
return SL_IntegerToCode(i, udg_SL_CRC_LEN)
endfunction
You are still hard coding what will be saved and loaded while just using a bunch of flags. This is no good. You need to be able to save or load anything.
JASS:
local integer l = StringLength(udg_SL_STRING) //get the string length of the alphabet string
local integer i = 0
local integer i2
local integer MinExp
local integer array Pow2
local integer CLASS // the hero unit type index in SL_HERO_TYPE array
local integer LV // hero level
local integer EXP // hero exp
local integer STR // hero strength
local integer AGI // hero agility
local integer INT // hero intelligence
local integer GOLD // player gold
local integer LUMBER // player lumber
local integer ITEM_SLOT
local integer MAX_X = R2I(GetRectMaxX(bj_mapInitialPlayableArea)) //highest X coordinate on map
local integer MAX_Y = R2I(GetRectMaxY(bj_mapInitialPlayableArea)) //highest Y coordinate on map
local integer COORD_LEN_X = SL_GetIntegerSize(MAX_X * 2) // how much character needed for save hero location
local integer COORD_LEN_Y = SL_GetIntegerSize(MAX_Y * 2) // how much character needed for save hero location
local integer X // hero x coordinate
local integer Y // hero y coordinate
local item itm
local integer a1
local integer a2
local integer a3
local integer a4
local integer c
local string Key
local string s
local location loc
local unit u
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.