Name | Type | is_array | initial_value |
HeroXPConstant | integer | No | |
HeroXPLevelFactor | integer | No | |
HeroXPPrevLevelFactor | integer | No | |
HeroXPRequired | integer | No | |
LocalFiles_WarningMessage | string | No | |
MapName | string | No | |
SaveAbilityType | abilcode | Yes | |
SaveAbilityTypeMax | integer | No | |
SaveCodeColored | string | No | |
SaveCount | integer | No | |
SaveCurrentSlot | integer | Yes | |
SaveHeroName | boolean | No | |
SaveItemType | itemcode | Yes | |
SaveItemTypeMax | integer | No | |
SaveLoad_HeroName | boolean | No | |
SaveLoad_Slot | integer | No | |
SaveLoad_TriggerName | string | No | |
SaveLoadEvent | real | No | |
SaveLoadEvent_Code | string | No | |
SaveLoadEvent_Player | player | No | |
SaveLoadMaxLength | integer | No | |
SaveMaxValue | integer | Yes | |
SaveNameList | string | Yes | |
SaveNameMax | integer | No | |
SavePlayerHero | unit | Yes | |
SavePlayerLoading | boolean | Yes | |
SaveShowCode | boolean | No | |
SaveTempInt | integer | No | |
SaveTempReal | real | No | |
SaveTempString | string | No | |
SaveTempUnit | unit | No | |
SaveUnitMaxStat | integer | No | |
SaveUnitType | unitcode | Yes | |
SaveUnitTypeMax | integer | No | |
SaveUseGUI | boolean | No | |
SaveValue | integer | Yes |
scope SampleDialogSystem initializer Init
globals
private dialog array Dialog
private button array Button
private button array PlayerButton[25][10]
private trigger T=CreateTrigger()
endglobals
private function GetTitle takes player p, integer slot returns string
local string s = SaveFile(slot).getTitle()
if (s == null or s == "") then
return "Empty"
endif
if (StringLength(s) > 32) then
set s = SubString(s, 0, 26) + "...)"
endif
return s
endfunction
private function OnButtonClick takes nothing returns boolean
local button b = GetClickedButton()
local player p = GetTriggerPlayer()
local string s = ""
local integer pid = GetPlayerId(p)
local boolean safe = (File.ReadEnabled and GetLocalPlayer() == p)
local User u = User(pid)
local integer curSlot = SaveHelper.GetSaveSlot(u)
if (b == Button[(u.id*12)+0]) then // save char
if (curSlot == 0) then
call DialogClear(Dialog[(u.id*12)+2])
call DialogSetMessage(Dialog[(u.id*12)+2], "|cffff8000Save Character|r")
if (not safe) then
call ClearTextMessages()
call DisplayTimedTextToPlayer(p, 0, 0, 60000, udg_LocalFiles_WarningMessage)
endif
set PlayerButton[pid][10] = DialogAddButton(Dialog[(u.id*12)+2], "|cffffcc00[1] |cffffffff" + GetTitle(p, 1) + "|r", 0)
set PlayerButton[pid][11] = DialogAddButton(Dialog[(u.id*12)+2], "|cffffcc00[2] |cffffffff" + GetTitle(p, 2), 0)
set PlayerButton[pid][12] = DialogAddButton(Dialog[(u.id*12)+2], "|cffffcc00[3] |cffffffff" + GetTitle(p, 3), 0)
set PlayerButton[pid][13] = DialogAddButton(Dialog[(u.id*12)+2], "|cffffcc00[4] |cffffffff" + GetTitle(p, 4), 0)
set PlayerButton[pid][14] = DialogAddButton(Dialog[(u.id*12)+2], "|cffffcc00[5] |cffffffff" + GetTitle(p, 5), 0)
call DialogAddButton(Dialog[(u.id*12)+2], "|cffff8000Close", 0)
call DialogDisplay(GetLocalPlayer(), Dialog[(u.id*12)+2], safe)
else
call SaveCharToSlot(udg_SavePlayerHero[pid], curSlot, GetHeroSaveCode(SaveHelper.GetUserHero(u)))
call DisplayTextToPlayer(u.toPlayer(), 0, 0, "|cffffcc00[" + I2S(curSlot) + "]|r " + SaveHelper.GetUnitTitle(SaveHelper.GetUserHero(u)))
endif
elseif(b == Button[(u.id*12)+1]) then // load char
if (not safe) then
call ClearTextMessages()
call ClearTextMessages()
call DisplayTimedTextToPlayer(p, 0, 0, 60000, udg_LocalFiles_WarningMessage)
endif
call DialogClear(Dialog[(u.id*12)+1])
call DialogSetMessage(Dialog[(u.id*12)+1], "|cffff8000Load Character|r")
set PlayerButton[pid][20] = DialogAddButton(Dialog[(u.id*12)+1], "|cffffcc00Autosave - |cffffffff" + GetTitle(p, 10), 0)
set PlayerButton[pid][0] = DialogAddButton(Dialog[(u.id*12)+1], "|cffffcc00[1] |cffffffff" + GetTitle(p, 1), 0)
set PlayerButton[pid][1] = DialogAddButton(Dialog[(u.id*12)+1], "|cffffcc00[2] |cffffffff" + GetTitle(p, 2), 0)
set PlayerButton[pid][2] = DialogAddButton(Dialog[(u.id*12)+1], "|cffffcc00[3] |cffffffff" + GetTitle(p, 3), 0)
set PlayerButton[pid][3] = DialogAddButton(Dialog[(u.id*12)+1], "|cffffcc00[4] |cffffffff" + GetTitle(p, 4), 0)
set PlayerButton[pid][4] = DialogAddButton(Dialog[(u.id*12)+1], "|cffffcc00[5] |cffffffff" + GetTitle(p, 5), 0)
call DialogAddButton(Dialog[(u.id*12)+1], "|cffff8000Close", 0)
call DialogDisplay(p, Dialog[(u.id*12)+1], safe)
elseif(b == Button[(u.id*12)+2]) then // load char
if (not safe) then
call ClearTextMessages()
call DisplayTimedTextToPlayer(p,0,0,60000, udg_LocalFiles_WarningMessage)
endif
call DialogClear(Dialog[(u.id*12)+3])
call DialogSetMessage(Dialog[(u.id*12)+3], "|cffff8000Delete Character|r")
set PlayerButton[pid][5] = DialogAddButton(Dialog[(u.id*12)+3], "|cffff0000[X] - |cffffffff" + GetTitle(p, 1), 0)
set PlayerButton[pid][6] = DialogAddButton(Dialog[(u.id*12)+3], "|cffff0000[X] - |cffffffff" + GetTitle(p, 2), 0)
set PlayerButton[pid][7] = DialogAddButton(Dialog[(u.id*12)+3], "|cffff0000[X] - |cffffffff" + GetTitle(p, 3), 0)
set PlayerButton[pid][8] = DialogAddButton(Dialog[(u.id*12)+3], "|cffff0000[X] - |cffffffff" + GetTitle(p, 4), 0)
set PlayerButton[pid][9] = DialogAddButton(Dialog[(u.id*12)+3], "|cffff0000[X] - |cffffffff" + GetTitle(p, 5), 0)
call DialogAddButton(Dialog[(u.id*12)+3], "|cffff8000Close", 0)
call DialogDisplay(p, Dialog[(u.id*12)+3], safe)
elseif(b == PlayerButton[pid][0]) then
call LoadSaveSlot(p, 1)
elseif(b == PlayerButton[pid][1]) then
call LoadSaveSlot(p, 2)
elseif(b == PlayerButton[pid][2]) then
call LoadSaveSlot(p, 3)
elseif(b == PlayerButton[pid][3]) then
call LoadSaveSlot(p, 4)
elseif(b == PlayerButton[pid][4]) then
call LoadSaveSlot(p, 5)
elseif(b == PlayerButton[pid][20]) then
call LoadSaveSlot(p, 10)
elseif(b == PlayerButton[pid][5]) then
call DeleteCharSlot(p, 1)
elseif(b == PlayerButton[pid][6]) then
call DeleteCharSlot(p, 2)
elseif(b == PlayerButton[pid][7]) then
call DeleteCharSlot(p, 3)
elseif(b == PlayerButton[pid][8]) then
call DeleteCharSlot(p, 4)
elseif(b == PlayerButton[pid][9]) then
call DeleteCharSlot(p, 5)
elseif(b == PlayerButton[pid][10]) then
call SaveCharToSlot(udg_SavePlayerHero[pid], 1, GetHeroSaveCode(SaveHelper.GetUserHero(u)))
elseif(b == PlayerButton[pid][11]) then
call SaveCharToSlot(udg_SavePlayerHero[pid], 2, GetHeroSaveCode(SaveHelper.GetUserHero(u)))
elseif(b == PlayerButton[pid][12]) then
call SaveCharToSlot(udg_SavePlayerHero[pid], 3, GetHeroSaveCode(SaveHelper.GetUserHero(u)))
elseif(b == PlayerButton[pid][13]) then
call SaveCharToSlot(udg_SavePlayerHero[pid], 4, GetHeroSaveCode(SaveHelper.GetUserHero(u)))
elseif(b == PlayerButton[pid][14]) then
call SaveCharToSlot(udg_SavePlayerHero[pid], 5, GetHeroSaveCode(SaveHelper.GetUserHero(u)))
endif
return false
endfunction
private function ShowMenu takes nothing returns boolean
local player p = GetTriggerPlayer()
local integer i = GetPlayerId(p)
if (GetLocalPlayer() == p) then
call DialogSetMessage(Dialog[(i*12)+0], "|cffff8000Main Menu|r")
call DialogDisplay(p, Dialog[(i*12)+0], true)
endif
return false
endfunction
private function InitDialog takes nothing returns nothing
local integer i = 0
local trigger t = CreateTrigger()
local User u
loop
exitwhen i == User.AmountPlaying
set u = User.fromPlaying(i)
set Dialog[(u.id*12)+0] = DialogCreate()
set Button[(u.id*12)+0] = DialogAddButton(Dialog[(u.id*12)+0], "|cffffcc00Save Character", 0)
set Button[(u.id*12)+1] = DialogAddButton(Dialog[(u.id*12)+0], "|cffffcc00Load Character", 0)
set Button[(u.id*12)+2] = DialogAddButton(Dialog[(u.id*12)+0], "|cffffcc00Delete Character", 0)
call DialogAddButton(Dialog[(u.id*12)+0], "|cffff8000Close", 0)
set Dialog[(u.id*12)+1] = DialogCreate()
set Dialog[(u.id*12)+2] = DialogCreate()
set Dialog[(u.id*12)+3] = DialogCreate()
call TriggerRegisterDialogEvent(t, Dialog[(u.id*12)+0])
call TriggerRegisterDialogEvent(t, Dialog[(u.id*12)+1])
call TriggerRegisterDialogEvent(t, Dialog[(u.id*12)+2])
call TriggerRegisterDialogEvent(t, Dialog[(u.id*12)+3])
set i = i + 1
endloop
call TriggerAddCondition(t, Filter(function OnButtonClick))
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
loop
//set CurrentCharSaveSlot[i] = -1
call TriggerRegisterPlayerEvent(t, Player(i), EVENT_PLAYER_END_CINEMATIC)
set i = i + 1
exitwhen i == bj_MAX_PLAYER_SLOTS
endloop
call TriggerAddCondition(t, Filter(function ShowMenu))
call TimerStart(CreateTimer(), 0, false, function InitDialog)
endfunction
endscope
function Trig_HeroNames_Actions takes nothing returns nothing
set udg_SaveNameList[0] = null
// Blood Mage
set udg_SaveNameList[72] = "Eldin Sunstrider"
set udg_SaveNameList[1] = "Tanin Hawkwing"
set udg_SaveNameList[2] = "Lorn Bloodseeker"
set udg_SaveNameList[3] = "Aldos Firestar"
set udg_SaveNameList[4] = "Gilaras Drakeson"
set udg_SaveNameList[5] = "Hale Magefire"
set udg_SaveNameList[6] = "Kath'ranis Remar"
set udg_SaveNameList[7] = "Tyoril Sunchaser"
set udg_SaveNameList[8] = "Sylvos Windrunner"
set udg_SaveNameList[9] = "Tenris Mirkblood"
set udg_SaveNameList[10] = "Marakanis Starfury"
set udg_SaveNameList[11] = "Geldor Earthfire"
set udg_SaveNameList[12] = "Halendor Burnkin"
set udg_SaveNameList[13] = "Kelen the Destroyer"
// Tauren Chieften
set udg_SaveNameList[14] = "Marn Thunderhorn"
set udg_SaveNameList[15] = "Tygore Dusthoof"
set udg_SaveNameList[16] = "Tam Windtotem"
set udg_SaveNameList[17] = "Durn Harpyslayer"
set udg_SaveNameList[18] = "Kam Ghoststeer"
set udg_SaveNameList[19] = "Kel Stonebull"
set udg_SaveNameList[20] = "Mull Stormhoof"
set udg_SaveNameList[21] = "Grok Bloodhorn"
set udg_SaveNameList[22] = "Malar Plainstrider"
set udg_SaveNameList[23] = "Taur Runetotem"
// Lich
set udg_SaveNameList[24] = "Ordin Frostbane"
set udg_SaveNameList[25] = "Ras Splinterspine"
set udg_SaveNameList[26] = "Morbent Fell"
set udg_SaveNameList[27] = "Rage Winterchill"
set udg_SaveNameList[28] = "Araj the Summoner"
set udg_SaveNameList[29] = "Kali'naj Dethknell"
set udg_SaveNameList[30] = "Rak Coldskull"
set udg_SaveNameList[31] = "Din Frostfire"
set udg_SaveNameList[32] = "Calis Wraithson"
set udg_SaveNameList[33] = "Venim Iceblade"
set udg_SaveNameList[34] = "Naze the Eternal"
set udg_SaveNameList[35] = "Ras Frostwhisper"
set udg_SaveNameList[36] = "Coldreaver"
set udg_SaveNameList[37] = "Cho'Nammoth"
set udg_SaveNameList[38] = "Kryptikk Soulslayer"
set udg_SaveNameList[39] = "Alandil Lieng"
// Demon Hunter
set udg_SaveNameList[40] = "Shadowsong"
set udg_SaveNameList[41] = "Shadowfury"
set udg_SaveNameList[42] = "Shadowstalker"
set udg_SaveNameList[43] = "Flameseeker"
set udg_SaveNameList[44] = "Darkweaver"
set udg_SaveNameList[45] = "Darkterror"
set udg_SaveNameList[46] = "Darksorrow"
set udg_SaveNameList[47] = "Sindweller"
set udg_SaveNameList[48] = "Painkiller"
set udg_SaveNameList[49] = "Hellbourne"
set udg_SaveNameList[50] = "Wrathbringer"
set udg_SaveNameList[51] = "Ragerunner"
set udg_SaveNameList[52] = "Firebrand"
set udg_SaveNameList[53] = "Bloodwrath"
set udg_SaveNameList[54] = "Terrorblade"
// Naga Sea Witch
set udg_SaveNameList[55] = "Anna Kondra"
set udg_SaveNameList[56] = "Scilla Murkshadow"
set udg_SaveNameList[57] = "Ursula Snakemane"
set udg_SaveNameList[58] = "Lady Venomtongue"
set udg_SaveNameList[59] = "Lady Serpentra"
set udg_SaveNameList[60] = "Lady Darkscale"
set udg_SaveNameList[61] = "Serena Scarscale"
set udg_SaveNameList[62] = "Asprah Serpus"
set udg_SaveNameList[63] = "Venna Seastorm"
set udg_SaveNameList[64] = "Charib'dishal"
// Beastmaster
set udg_SaveNameList[65] = "Mag Bearmaul"
set udg_SaveNameList[66] = "Tagar Bearclaw"
set udg_SaveNameList[67] = "Gorsh Talonfang"
set udg_SaveNameList[68] = "Maxx Rocmane"
set udg_SaveNameList[69] = "Gaz Boartusk"
set udg_SaveNameList[70] = "Mok Rocksnout"
set udg_SaveNameList[71] = "Gish Eagle Eye"
endfunction
//===========================================================================
function InitTrig_HeroNames takes nothing returns nothing
set gg_trg_HeroNames = CreateTrigger( )
call TriggerAddAction( gg_trg_HeroNames, function Trig_HeroNames_Actions )
endfunction
library SaveHelperLib initializer Init requires SyncHelper, PlayerUtils, SaveFile
// Uses GUI variables from the "Save Init" trigger. You can modify these functions to use your own variables.
private keyword SaveHelperInit
struct SaveHelper extends array
static constant hashtable Hashtable = InitHashtable()
static constant integer KEY_ITEMS = 1
static constant integer KEY_UNITS = 2
static constant integer KEY_NAMES = 3
static method MaxCodeSyncLength takes nothing returns integer
return udg_SaveLoadMaxLength
endmethod
static method GetUserHero takes User user returns unit
return udg_SavePlayerHero[user.id]
endmethod
static method RemoveUserHero takes User user returns nothing
call RemoveUnit(udg_SavePlayerHero[user.id])
set udg_SavePlayerHero[user.id] = null
endmethod
static method SetUserHero takes User user, unit u returns nothing
set udg_SavePlayerHero[user.id] = u
endmethod
static method IsUserLoading takes User user returns boolean
return udg_SavePlayerLoading[user.id]
endmethod
static method SetUserLoading takes User user, boolean flag returns nothing
set udg_SavePlayerLoading[user.id] = flag
endmethod
static method SetSaveSlot takes User user, integer slot returns nothing
set udg_SaveCurrentSlot[user.id] = slot
endmethod
static method GetSaveSlot takes User user returns integer
return udg_SaveCurrentSlot[user.id]
endmethod
static method GetUnitTitle takes unit u returns string
return GetObjectName(GetUnitTypeId(u)) + " (" + GetHeroProperName(u) + ")"
endmethod
static method GetMapName takes nothing returns string
return udg_MapName
endmethod
static method MaxAbilityLevel takes nothing returns integer
return 10
endmethod
static method MaxAbilities takes nothing returns integer
return udg_SaveAbilityTypeMax
endmethod
static method MaxItems takes nothing returns integer
return udg_SaveItemTypeMax
endmethod
static method MaxUnits takes nothing returns integer
return udg_SaveUnitTypeMax
endmethod
static method MaxNames takes nothing returns integer
return udg_SaveNameMax
endmethod
static method MaxHeroStat takes nothing returns integer
return udg_SaveUnitMaxStat
endmethod
static method GetAbility takes integer index returns integer
return udg_SaveAbilityType[index]
endmethod
static method GetItem takes integer index returns integer
return udg_SaveItemType[index]
endmethod
static method GetUnit takes integer index returns integer
return udg_SaveUnitType[index]
endmethod
static method ConvertItemId takes integer itemId returns integer
return LoadInteger(thistype.Hashtable, KEY_ITEMS, itemId)
endmethod
static method ConvertUnitId takes integer unitId returns integer
return LoadInteger(thistype.Hashtable, KEY_UNITS, unitId)
endmethod
static method GetHeroNameFromID takes integer id returns string
return udg_SaveNameList[id]
endmethod
static method GetHeroNameID takes string name returns integer
return LoadInteger(thistype.Hashtable, KEY_NAMES, StringHash(name))
endmethod
static method ConvertHeroName takes string name returns string
return udg_SaveNameList[GetHeroNameID(name)]
endmethod
static method GUILoadNext takes nothing returns nothing
set udg_SaveValue[udg_SaveCount] = Savecode(udg_SaveTempInt).Decode(udg_SaveMaxValue[udg_SaveCount])
endmethod
static method GetLevelXP takes integer level returns real
local real xp = udg_HeroXPLevelFactor // level 1
local integer i = 1
loop
exitwhen i > level
set xp = (xp*udg_HeroXPPrevLevelFactor) + (i+1) * udg_HeroXPLevelFactor
set i = i + 1
endloop
return xp-udg_HeroXPLevelFactor
endmethod
static method Init takes nothing returns nothing // called at the end of "Save Init" trigger
local integer i = 0
loop
exitwhen i >= thistype.MaxItems() //or udg_SaveItemType[i] == 0
call SaveInteger(thistype.Hashtable, KEY_ITEMS, udg_SaveItemType[i], i)
set i = i + 1
endloop
set i = 0
loop
exitwhen i >= thistype.MaxUnits() //or udg_SaveUnitType[i] == 0
call SaveInteger(thistype.Hashtable, KEY_UNITS, udg_SaveUnitType[i], i)
set i = i + 1
endloop
set i = 1
loop
exitwhen i >= SaveHelper.MaxNames() or udg_SaveNameList[i] == "" or udg_SaveNameList[i] == null
call SaveInteger(thistype.Hashtable, KEY_NAMES, StringHash(udg_SaveNameList[i]), i)
set i = i + 1
endloop
endmethod
endstruct
function GetHeroSaveCode takes unit u returns string
if (udg_SaveUseGUI) then
call TriggerExecute(gg_trg_Save_GUI)
return udg_SaveTempString
endif
return ""
endfunction
private function LoadSaveSlot_OnLoad takes nothing returns nothing
local player p = GetTriggerPlayer()
local string prefix = BlzGetTriggerSyncPrefix()
local string data = BlzGetTriggerSyncData()
local User user = User[p]
call SaveHelper.SetUserLoading(user, false)
if (udg_SaveUseGUI) then
set udg_SaveLoadEvent_Code = data
set udg_SaveLoadEvent_Player = p
set udg_SaveLoadEvent = 1.
set udg_SaveLoadEvent = -1
endif
endfunction
function LoadSaveSlot takes player p, integer slot returns nothing
local SaveFile savefile = SaveFile(slot)
local string s
local User user = User[p]
if (not SaveFile.exists(slot)) then
call DisplayTextToPlayer(p, 0, 0, "Did not find any save data.")
return
elseif (SaveHelper.IsUserLoading(user)) then
call DisplayTextToPlayer(p, 0, 0, "Please wait while your character synchronizes.")
else
set s = savefile.getData()
if (GetLocalPlayer() == p) then
call SyncString(s)
endif
call ClearTextMessages()
call DisplayTimedTextToPlayer(p, 0, 0, 15, "Synchronzing with other players...")
call SaveHelper.SetSaveSlot(user, slot)
endif
endfunction
function DeleteCharSlot takes player p, integer slot returns nothing
if (GetLocalPlayer() == p) then
call SaveFile(slot).clear(p, slot)
endif
endfunction
function SaveCharToSlot takes unit u, integer slot, string s returns nothing
local player p = GetOwningPlayer(u)
if (GetLocalPlayer() == p) then
call SaveFile(slot).create(p, SaveHelper.GetUnitTitle(u), slot, s)
endif
call SaveHelper.SetSaveSlot(User[p], slot)
endfunction
private function Init takes nothing returns nothing
call OnSyncString(function LoadSaveSlot_OnLoad)
endfunction
endlibrary
library SyncHelper
globals
public constant string SYNC_PREFIX = "S"
endglobals
private keyword INITS
private struct Sync extends array
static trigger Trigger = CreateTrigger()
implement INITS
endstruct
function SyncString takes string s returns boolean
return BlzSendSyncData(SYNC_PREFIX, s)
endfunction
function OnSyncString takes code func returns triggeraction
return TriggerAddAction(Sync.Trigger, func)
endfunction
function RemoveSyncString takes triggeraction t returns nothing
call TriggerRemoveAction(Sync.Trigger, t)
endfunction
private module INITS
private static method onInit takes nothing returns nothing
local integer i = 0
loop
call BlzTriggerRegisterPlayerSyncEvent(.Trigger, Player(i), SYNC_PREFIX, false)
set i = i + 1
exitwhen i == bj_MAX_PLAYER_SLOTS
endloop
endmethod
endmodule
endlibrary
library SaveFile requires FileIO
private keyword SaveFileInit
struct SaveFile extends array
static constant string ManualPath = "Manual"
static constant string InvalidPath = "Unknown"
static constant integer MIN = 1
static constant integer MAX = 10
private File file
static method operator Folder takes nothing returns string
return udg_MapName
endmethod
static method getPath takes integer slot returns string
if (slot == 0) then
return .Folder + "\\SaveSlot_" + .InvalidPath + ".pld"
elseif (slot > 0 and (slot < .MIN or slot > .MAX)) then
return .Folder + "\\SaveSlot_" + .InvalidPath + ".pld"
elseif (slot < 0) then
return .Folder + "\\SaveSlot_" + .ManualPath + ".pld"
endif
return .Folder + "\\SaveSlot_" + I2S(slot) + ".pld"
endmethod
static method create takes player p, string title, integer slot, string data returns thistype
if (GetLocalPlayer() == p) then
call FileIO_Write(.getPath(slot), title + "\n" + data)
endif
return slot
endmethod
static method clear takes player p, integer slot returns thistype
if (GetLocalPlayer() == p) then
call FileIO_Write(.getPath(slot), "")
endif
return slot
endmethod
static method exists takes integer slot returns boolean // async
return StringLength(FileIO_Read(.getPath(slot))) > 1
endmethod
method getLines takes integer line, boolean includePrevious returns string // async
local string contents = FileIO_Read(.getPath(this))
local integer len = StringLength(contents)
local string char = null
local string buffer = ""
local integer curLine = 0
local integer i = 0
loop
exitwhen i > len
set char = SubString(contents, i, i + 1)
if (char == "\n") then
set curLine = curLine + 1
if (curLine > line) then
return buffer
endif
if (not includePrevious) then
set buffer = ""
endif
else
set buffer = buffer + char
endif
set i = i + 1
endloop
if (curLine == line) then
return buffer
endif
return null
endmethod
method getLine takes integer line returns string // async
return .getLines(line, false)
endmethod
method getTitle takes nothing returns string // async
return .getLines(0, false)
endmethod
method getData takes nothing returns string // async
return .getLines(1, false)
endmethod
implement SaveFileInit
endstruct
private module SaveFileInit
private static method onInit takes nothing returns nothing
//set thistype.Folder = udg_MapName
endmethod
endmodule
endlibrary
library FileIO
/***************************************************************
*
* v1.1.0, by TriggerHappy
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
*
* Provides functionality to read and write files.
* _________________________________________________________________________
* 1. Requirements
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* - Patch 1.29 or higher.
* - JassHelper (vJASS)
* _________________________________________________________________________
* 2. Installation
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* Copy the script to your map and save it.
* _________________________________________________________________________
* 3. API
* ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
* struct File extends array
*
* static constant integer AbilityCount
* static constant integer PreloadLimit
*
* readonly static boolean ReadEnabled
* readonly static integer Counter
* readonly static integer array List
*
* static method open takes string filename returns File
* static method create takes string filename returns File
*
* ---------
*
* method write takes string value returns File
* method read takes nothing returns string
*
* method readEx takes boolean close returns string
* method readAndClose takes nothing returns string
* method readBuffer takes nothing returns string
* method writeBuffer takes string contents returns nothing
* method appendBuffer takes string contents returns nothing
*
* method close takes nothing returns nothing
*
* public function Write takes string filename, string contents returns nothing
* public function Read takes string filename returns string
*
***************************************************************/
globals
// Enable this if you want to allow the system to read files generated in patch 1.30 or below.
// NOTE: For this to work properly you must edit the 'Amls' ability and change the levels to 2
// as well as typing something in "Level 2 - Text - Tooltip - Normal" text field.
//
// Enabling this will also cause the system to treat files written with .write("") as empty files.
//
// This setting is really only intended for those who were already using the system in their map
// prior to patch 1.31 and want to keep old files created with this system to still work.
private constant boolean BACKWARDS_COMPATABILITY = true
endglobals
private keyword FileInit
struct File extends array
static constant integer AbilityCount = 10
static constant integer PreloadLimit = 200
readonly static integer Counter = 0
readonly static integer array List
readonly static integer array AbilityList
readonly static boolean ReadEnabled = false
readonly string filename
private string buffer
static method open takes string filename returns thistype
local thistype this = .List[0]
if (this == 0) then
set this = Counter + 1
set Counter = this
else
set .List[0] = .List[this]
endif
set this.filename = filename
set this.buffer = null
debug if (this >= JASS_MAX_ARRAY_SIZE) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0, 120, "FileIO(" + filename + ") WARNING: Maximum instance limit " + I2S(JASS_MAX_ARRAY_SIZE) + " reached.")
debug endif
return this
endmethod
// This is used to detect invalid characters which aren't supported in preload files.
static if (DEBUG_MODE) then
private static method validateInput takes string contents returns string
local integer i = 0
local integer l = StringLength(contents)
local string ch = ""
loop
exitwhen i >= l
set ch = SubString(contents, i, i + 1)
if (ch == "\\") then
return ch
elseif (ch == "\"") then
return ch
endif
set i = i + 1
endloop
return null
endmethod
endif
method write takes string contents returns thistype
local integer i = 0
local integer c = 0
local integer len = StringLength(contents)
local integer lev = 0
local string prefix = "-" // this is used to signify an empty string vs a null one
local string chunk
debug if (.validateInput(contents) != null) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0, 120, "FileIO(" + filename + ") ERROR: Invalid character |cffffcc00" + .validateInput(contents) + "|r")
debug return this
debug endif
set this.buffer = null
// Check if the string is empty. If null, the contents will be cleared.
if (contents == "") then
set len = len + 1
endif
// Begin to generate the file
call PreloadGenClear()
call PreloadGenStart()
loop
exitwhen i >= len
debug if (c >= .AbilityCount) then
debug call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0, 120, "FileIO(" + filename + ") ERROR: String exceeds max length (" + I2S(.AbilityCount * .PreloadLimit) + ").|r")
debug endif
set lev = 0
static if (BACKWARDS_COMPATABILITY) then
if (c == 0) then
set lev = 1
set prefix = ""
else
set prefix = "-"
endif
endif
set chunk = SubString(contents, i, i + .PreloadLimit)
call Preload("\" )\ncall BlzSetAbilityTooltip(" + I2S(.AbilityList[c]) + ", \"" + prefix + chunk + "\", " + I2S(lev) + ")\n//")
set i = i + .PreloadLimit
set c = c + 1
endloop
call Preload("\" )\nendfunction\nfunction a takes nothing returns nothing\n //")
call PreloadGenEnd(this.filename)
return this
endmethod
method clear takes nothing returns thistype
return this.write(null)
endmethod
private method readPreload takes nothing returns string
local integer i = 0
local integer lev = 0
local string array original
local string chunk = ""
local string output = ""
loop
exitwhen i == .AbilityCount
set original[i] = BlzGetAbilityTooltip(.AbilityList[i], 0)
set i = i + 1
endloop
// Execute the preload file
call Preloader(this.filename)
// Read the output
set i = 0
loop
exitwhen i == .AbilityCount
set lev = 0
// Read from ability index 1 instead of 0 if
// backwards compatability is enabled
static if (BACKWARDS_COMPATABILITY) then
if (i == 0) then
set lev = 1
endif
endif
// Make sure the tooltip has changed
set chunk = BlzGetAbilityTooltip(.AbilityList[i], lev)
if (chunk == original[i]) then
if (i == 0 and output == "") then
return null // empty file
endif
return output
endif
// Check if the file is an empty string or null
static if not (BACKWARDS_COMPATABILITY) then
if (i == 0) then
if (SubString(chunk, 0, 1) != "-") then
return null // empty file
endif
set chunk = SubString(chunk, 1, StringLength(chunk))
endif
endif
// Remove the prefix
if (i > 0) then
set chunk = SubString(chunk, 1, StringLength(chunk))
endif
// Restore the tooltip and append the chunk
call BlzSetAbilityTooltip(.AbilityList[i], original[i], lev)
set output = output + chunk
set i = i + 1
endloop
return output
endmethod
method close takes nothing returns nothing
if (this.buffer != null) then
call .write(.readPreload() + this.buffer)
set this.buffer = null
endif
set .List[this] = .List[0]
set .List[0] = this
endmethod
method readEx takes boolean close returns string
local string output = .readPreload()
local string buf = this.buffer
if (close) then
call this.close()
endif
if (output == null) then
return buf
endif
if (buf != null) then
set output = output + buf
endif
return output
endmethod
method read takes nothing returns string
return .readEx(false)
endmethod
method readAndClose takes nothing returns string
return .readEx(true)
endmethod
method appendBuffer takes string contents returns thistype
set .buffer = .buffer + contents
return this
endmethod
method readBuffer takes nothing returns string
return .buffer
endmethod
method writeBuffer takes string contents returns nothing
set .buffer = contents
endmethod
static method create takes string filename returns thistype
return .open(filename).write("")
endmethod
implement FileInit
endstruct
private module FileInit
private static method onInit takes nothing returns nothing
local string originalTooltip
// We can't use a single ability with multiple levels because
// tooltips return the first level's value if the value hasn't
// been set. This way we don't need to edit any object editor data.
set File.AbilityList[0] = 'Amls'
set File.AbilityList[1] = 'Aroc'
set File.AbilityList[2] = 'Amic'
set File.AbilityList[3] = 'Amil'
set File.AbilityList[4] = 'Aclf'
set File.AbilityList[5] = 'Acmg'
set File.AbilityList[6] = 'Adef'
set File.AbilityList[7] = 'Adis'
set File.AbilityList[8] = 'Afbt'
set File.AbilityList[9] = 'Afbk'
// Backwards compatability check
static if (BACKWARDS_COMPATABILITY) then
static if (DEBUG_MODE) then
set originalTooltip = BlzGetAbilityTooltip(File.AbilityList[0], 1)
call BlzSetAbilityTooltip(File.AbilityList[0], SCOPE_PREFIX, 1)
if (BlzGetAbilityTooltip(File.AbilityList[0], 1) == originalTooltip) then
call DisplayTimedTextToPlayer(GetLocalPlayer(),0,0, 120, "FileIO WARNING: Backwards compatability enabled but \"" + GetObjectName(File.AbilityList[0]) + "\" isn't setup properly.|r")
endif
endif
endif
// Read check
set File.ReadEnabled = File.open("FileTester.pld").write(SCOPE_PREFIX).readAndClose() == SCOPE_PREFIX
endmethod
endmodule
public function Write takes string filename, string contents returns nothing
call File.open(filename).write(contents).close()
endfunction
public function Read takes string filename returns string
return File.open(filename).readEx(true)
endfunction
endlibrary
library PlayerUtils
/**************************************************************
*
* v1.2.9 by TriggerHappy
*
* This library provides a struct which caches data about players
* as well as provides functionality for manipulating player colors.
*
* Constants
* ------------------
*
* force FORCE_PLAYING - Player group of everyone who is playing.
*
* Struct API
* -------------------
* struct User
*
* static method fromIndex takes integer i returns User
* static method fromLocal takes nothing returns User
* static method fromPlaying takes integer id returns User
*
* static method operator [] takes integer id returns User
* static method operator count takes nothing returns integer
*
* method operator name takes nothing returns string
* method operator name= takes string name returns nothing
* method operator color takes nothing returns playercolor
* method operator color= takes playercolor c returns nothing
* method operator defaultColor takes nothing returns playercolor
* method operator hex takes nothing returns string
* method operator nameColored takes nothing returns string
*
* method toPlayer takes nothing returns player
* method colorUnits takes playercolor c returns nothing
*
* readonly string originalName
* readonly boolean isPlaying
* readonly static player Local
* readonly static integer LocalId
* readonly static integer AmountPlaying
* readonly static playercolor array Color
* readonly static player array PlayingPlayer
*
**************************************************************/
globals
// automatically change unit colors when changing player color
private constant boolean AUTO_COLOR_UNITS = true
// use an array for name / color lookups (instead of function calls)
private constant boolean ARRAY_LOOKUP = false
// this only applies if ARRAY_LOOKUP is true
private constant boolean HOOK_SAFETY = false // disable for speed, but only use the struct to change name/color safely
constant force FORCE_PLAYING = CreateForce()
private string array Name
private string array Hex
private string array OriginalHex
private playercolor array CurrentColor
endglobals
private keyword PlayerUtilsInit
struct User extends array
static constant integer NULL = bj_MAX_PLAYER_SLOTS
readonly player handle
readonly integer id
readonly thistype next
readonly thistype prev
readonly string originalName
readonly boolean isPlaying
readonly static thistype first
readonly static thistype last
readonly static player Local
readonly static integer LocalId
readonly static integer AmountPlaying = 0
readonly static playercolor array Color
static if not (LIBRARY_GroupUtils) then
readonly static group ENUM_GROUP = CreateGroup()
endif
private static thistype array PlayingPlayer
private static integer array PlayingPlayerIndex
// similar to Player(#)
static method fromIndex takes integer i returns thistype
return thistype(i)
endmethod
// similar to GetLocalPlayer
static method fromLocal takes nothing returns thistype
return thistype(thistype.LocalId)
endmethod
// access active players array
static method fromPlaying takes integer index returns thistype
return PlayingPlayer[index]
endmethod
static method operator [] takes player p returns thistype
return thistype(GetPlayerId(p))
endmethod
method toPlayer takes nothing returns player
return this.handle
endmethod
method operator name takes nothing returns string
static if (ARRAY_LOOKUP) then
return Name[this]
else
return GetPlayerName(this.handle)
endif
endmethod
method operator name= takes string newName returns nothing
call SetPlayerName(this.handle, newName)
static if (ARRAY_LOOKUP) then
static if not (HOOK_SAFETY) then
set Name[this] = newName
endif
endif
endmethod
method operator color takes nothing returns playercolor
static if (ARRAY_LOOKUP) then
return CurrentColor[this]
else
return GetPlayerColor(this.handle)
endif
endmethod
method operator hex takes nothing returns string
return OriginalHex[GetHandleId(this.color)]
endmethod
method operator color= takes playercolor c returns nothing
call SetPlayerColor(this.handle, c)
static if (ARRAY_LOOKUP) then
set CurrentColor[this] = c
static if not (HOOK_SAFETY) then
static if (AUTO_COLOR_UNITS) then
call this.colorUnits(color)
endif
endif
endif
endmethod
method operator defaultColor takes nothing returns playercolor
return Color[this]
endmethod
method operator nameColored takes nothing returns string
return hex + this.name + "|r"
endmethod
method colorUnits takes playercolor c returns nothing
local unit u
call GroupEnumUnitsOfPlayer(ENUM_GROUP, this.handle, null)
loop
set u = FirstOfGroup(ENUM_GROUP)
exitwhen u == null
call SetUnitColor(u, c)
call GroupRemoveUnit(ENUM_GROUP, u)
endloop
endmethod
static method onLeave takes nothing returns boolean
local thistype p = thistype[GetTriggerPlayer()]
local integer i = .PlayingPlayerIndex[p.id]
// clean up
call ForceRemovePlayer(FORCE_PLAYING, p.toPlayer())
// recycle index
set .AmountPlaying = .AmountPlaying - 1
set .PlayingPlayerIndex[i] = .PlayingPlayerIndex[.AmountPlaying]
set .PlayingPlayer[i] = .PlayingPlayer[.AmountPlaying]
if (.AmountPlaying == 1) then
set p.prev.next = User.NULL
set p.next.prev = User.NULL
else
set p.prev.next = p.next
set p.next.prev = p.prev
endif
set .last = .PlayingPlayer[.AmountPlaying]
set p.isPlaying = false
return false
endmethod
implement PlayerUtilsInit
endstruct
private module PlayerUtilsInit
private static method onInit takes nothing returns nothing
local trigger t = CreateTrigger()
local integer i = 0
local thistype p
set thistype.Local = GetLocalPlayer()
set thistype.LocalId = GetPlayerId(thistype.Local)
set OriginalHex[0] = "|cffff0303"
set OriginalHex[1] = "|cff0042ff"
set OriginalHex[2] = "|cff1ce6b9"
set OriginalHex[3] = "|cff540081"
set OriginalHex[4] = "|cfffffc01"
set OriginalHex[5] = "|cfffe8a0e"
set OriginalHex[6] = "|cff20c000"
set OriginalHex[7] = "|cffe55bb0"
set OriginalHex[8] = "|cff959697"
set OriginalHex[9] = "|cff7ebff1"
set OriginalHex[10] = "|cff106246"
set OriginalHex[11] = "|cff4e2a04"
if (bj_MAX_PLAYERS > 12) then
set OriginalHex[12] = "|cff9B0000"
set OriginalHex[13] = "|cff0000C3"
set OriginalHex[14] = "|cff00EAFF"
set OriginalHex[15] = "|cffBE00FE"
set OriginalHex[16] = "|cffEBCD87"
set OriginalHex[17] = "|cffF8A48B"
set OriginalHex[18] = "|cffBFFF80"
set OriginalHex[19] = "|cffDCB9EB"
set OriginalHex[20] = "|cff282828"
set OriginalHex[21] = "|cffEBF0FF"
set OriginalHex[22] = "|cff00781E"
set OriginalHex[23] = "|cffA46F33"
endif
set thistype.first = User.NULL
loop
exitwhen i == bj_MAX_PLAYERS
set p = User(i)
set p.handle = Player(i)
set p.id = i
set thistype.Color[i] = GetPlayerColor(p.handle)
set CurrentColor[i] = thistype.Color[i]
if (GetPlayerController(p.handle) == MAP_CONTROL_USER and GetPlayerSlotState(p.handle) == PLAYER_SLOT_STATE_PLAYING) then
set .PlayingPlayer[AmountPlaying] = p
set .PlayingPlayerIndex[i] = .AmountPlaying
set .last = i
if (.first == User.NULL) then
set .first = i
set User(i).next = User.NULL
set User(i).prev = User.NULL
else
set User(i).prev = PlayingPlayer[AmountPlaying-1].id
set PlayingPlayer[AmountPlaying-1].next = User(i)
set User(i).next = User.NULL
endif
set p.isPlaying = true
call TriggerRegisterPlayerEvent(t, p.handle, EVENT_PLAYER_LEAVE)
call ForceAddPlayer(FORCE_PLAYING, p.handle)
set Hex[p] = OriginalHex[GetHandleId(thistype.Color[i])]
set .AmountPlaying = .AmountPlaying + 1
endif
set Name[p] = GetPlayerName(p.handle)
set p.originalName=Name[p]
set i = i + 1
endloop
call TriggerAddCondition(t, Filter(function thistype.onLeave))
endmethod
endmodule
//===========================================================================
static if (ARRAY_LOOKUP) then
static if (HOOK_SAFETY) then
private function SetPlayerNameHook takes player whichPlayer, string name returns nothing
set Name[GetPlayerId(whichPlayer)] = name
endfunction
private function SetPlayerColorHook takes player whichPlayer, playercolor color returns nothing
local User p = User[whichPlayer]
set Hex[p] = OriginalHex[GetHandleId(color)]
set CurrentColor[p] = color
static if (AUTO_COLOR_UNITS) then
call p.colorUnits(color)
endif
endfunction
hook SetPlayerName SetPlayerNameHook
hook SetPlayerColor SetPlayerColorHook
endif
endif
endlibrary
library Savecode requires BigNum
private constant function uppercolor takes nothing returns string
return "|cffff0000"
endfunction
private constant function lowercolor takes nothing returns string
return "|cff00ff00"
endfunction
private constant function numcolor takes nothing returns string
return "|cff0000ff"
endfunction
private function player_charset takes nothing returns string
return "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
endfunction
private function player_charsetlen takes nothing returns integer
return StringLength(player_charset())
endfunction
private function charset takes nothing returns string
return "!#$%&'()*+,-.0123456789:;=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_abcdefghijklmnopqrstuvwxyz{|}`"
endfunction
private function charsetlen takes nothing returns integer
return StringLength(charset())
endfunction
private function BASE takes nothing returns integer
return charsetlen()
endfunction
private constant function HASHN takes nothing returns integer
return 5000 //1./HASHN() is the probability of a random code being valid
endfunction
private constant function MAXINT takes nothing returns integer
return 2147483647
endfunction
private function player_chartoi takes string c returns integer
local integer i = 0
local string cs = player_charset()
local integer len = player_charsetlen()
loop
exitwhen i>=len or c == SubString(cs,i,i+1)
set i = i + 1
endloop
return i
endfunction
private function chartoi takes string c returns integer
local integer i = 0
local string cs = charset()
local integer len = charsetlen()
loop
exitwhen i>=len or c == SubString(cs,i,i+1)
set i = i + 1
endloop
return i
endfunction
private function itochar takes integer i returns string
return SubString(charset(),i,i+1)
endfunction
//You probably want to use a different char set for this
//Also, use a hash that doesn't suck so much
private function scommhash takes string s returns integer
local integer array count
local integer i = 0
local integer len = StringLength(s)
local integer x
set s = StringCase(s,true)
loop
exitwhen i >= len
set x = player_chartoi(SubString(s,i,i+1))
set count[x] = count[x] + 1
set i = i + 1
endloop
set i = 0
set len = player_charsetlen()
set x = 0
loop
exitwhen i>= len
set x = count[i]*count[i]*i+count[i]*x+x+199
// call BJDebugMsg(I2S(x)+" "+I2S(count[i]))
// call TriggerSleepAction(0.)
set i = i + 1
endloop
if x < 0 then
set x = -x
endif
return x
endfunction
private function modb takes integer x returns integer
if x >= BASE() then
return x - BASE()
elseif x < 0 then
return x + BASE()
else
return x
endif
endfunction
struct Savecode
real digits //logarithmic approximation
BigNum bignum
static method create takes nothing returns Savecode
local Savecode sc = Savecode.allocate()
set sc.digits = 0.
set sc.bignum = BigNum.create(BASE())
return sc
endmethod
method onDestroy takes nothing returns nothing
call .bignum.destroy()
endmethod
method Encode takes integer val, integer max returns nothing
set .digits = .digits + log(max+1,BASE())
call .bignum.MulSmall(max+1)
call .bignum.AddSmall(val)
endmethod
method Decode takes integer max returns integer
return .bignum.DivSmall(max+1)
endmethod
method IsEmpty takes nothing returns boolean
return .bignum.IsZero()
endmethod
method Length takes nothing returns real
return .digits
endmethod
method Clean takes nothing returns nothing
call .bignum.Clean()
endmethod
//These functions get too intimate with BigNum_l
method Pad takes nothing returns nothing
local BigNum_l cur = .bignum.list
local BigNum_l prev
local integer maxlen = R2I(1.0 + .Length())
loop
exitwhen cur == 0
set prev = cur
set cur = cur.next
set maxlen = maxlen - 1
endloop
loop
exitwhen maxlen <= 0
set prev.next = BigNum_l.create()
set prev = prev.next
set maxlen = maxlen - 1
endloop
endmethod
method ToString takes nothing returns string
local BigNum_l cur = .bignum.list
local string s = ""
loop
exitwhen cur == 0
set s = itochar(cur.leaf) + s
set cur = cur.next
endloop
return s
endmethod
method FromString takes string s returns nothing
local integer i = StringLength(s)-1
local BigNum_l cur = BigNum_l.create()
set .bignum.list = cur
loop
set cur.leaf = chartoi(SubString(s,i,i+1))
exitwhen i <= 0
set cur.next = BigNum_l.create()
set cur = cur.next
set i = i - 1
endloop
endmethod
method Hash takes nothing returns integer
local integer hash = 0
local integer x
local BigNum_l cur = .bignum.list
loop
exitwhen cur == 0
set x = cur.leaf
set hash = ModuloInteger(hash+79*hash/(x+1) + 293*x/(1+hash - (hash/BASE())*BASE()) + 479,HASHN())
set cur = cur.next
endloop
return hash
endmethod
//this is not cryptographic which is fine for this application
//sign = 1 is forward
//sign = -1 is backward
method Obfuscate takes integer key, integer sign returns nothing
local integer seed = GetRandomInt(0,MAXINT())
local integer advance
local integer x
local BigNum_l cur = .bignum.list
if sign == -1 then
call SetRandomSeed(.bignum.LastDigit())
set cur.leaf = modb(cur.leaf + sign*GetRandomInt(0,BASE()-1))
set x = cur.leaf
endif
call SetRandomSeed(key)
loop
exitwhen cur == 0
if sign == -1 then
set advance = cur.leaf
endif
set cur.leaf = modb(cur.leaf + sign*GetRandomInt(0,BASE()-1))
if sign == 1 then
set advance = cur.leaf
endif
set advance = advance + GetRandomInt(0,BASE()-1)
call SetRandomSeed(advance)
set x = cur.leaf
set cur = cur.next
endloop
if sign == 1 then
call SetRandomSeed(x)
set .bignum.list.leaf = modb(.bignum.list.leaf + sign*GetRandomInt(0,BASE()-1))
endif
call SetRandomSeed(seed)
endmethod
method Dump takes nothing returns nothing
local BigNum_l cur = .bignum.list
local string s = ""
set s = "max: "+R2S(.digits)
loop
exitwhen cur == 0
set s = I2S(cur.leaf)+" "+s
set cur = cur.next
endloop
call BJDebugMsg(s)
endmethod
method Save takes player p, integer loadtype returns string
local integer key = scommhash(GetPlayerName(p))+loadtype*73
local string s
local integer hash
call .Clean()
set hash = .Hash()
call .Encode(hash,HASHN())
call .Clean()
/////////////////////// Save code information. Comment out next two lines in implementation
//call BJDebugMsg("Expected length: " +I2S(R2I(1.0+.Length())))
//call BJDebugMsg("Room left in last char: "+R2S(1.-ModuloReal((.Length()),1)))
///////////////////////
call .Pad()
call .Obfuscate(key,1)
return .ToString()
endmethod
method Load takes player p, string s, integer loadtype returns boolean
local integer ikey = scommhash(GetPlayerName(p))+loadtype*73
local integer inputhash
call .FromString(s)
call .Obfuscate(ikey,-1)
set inputhash = .Decode(HASHN())
call .Clean()
return inputhash == .Hash()
endmethod
endstruct
private function isupper takes string c returns boolean
return c == StringCase(c,true)
endfunction
private function ischar takes string c returns boolean
return S2I(c) == 0 and c!= "0"
endfunction
private function chartype takes string c returns integer
if(ischar(c)) then
if isupper(c) then
return 0
else
return 1
endif
else
return 2
endif
endfunction
private function testchar takes string c returns nothing
if(ischar(c)) then
if isupper(c) then
call BJDebugMsg(c+" isupper")
else
call BJDebugMsg(c+" islower")
endif
else
call BJDebugMsg(c+ " isnumber")
endif
endfunction
public function colorize takes string s returns string
local string out = ""
local integer i = 0
local integer len = StringLength(s)
local integer ctype
local string c
loop
exitwhen i >= len
set c = SubString(s,i,i+1)
set ctype = chartype(c)
if ctype == 0 then
set out = out + uppercolor()+c+"|r"
elseif ctype == 1 then
set out = out + lowercolor()+c+"|r"
else
set out = out + numcolor()+c+"|r"
endif
set i = i + 1
endloop
return out
endfunction
private function prop_Savecode takes nothing returns boolean
local string s
local Savecode loadcode
//--- Data you want to save ---
local integer medal1 = 10
local integer medal2 = 3
local integer medalmax = 13
local integer XP = 1337
local integer XPmax = 1000000
local Savecode savecode = Savecode.create()
call SetPlayerName(Player(0),"yomp")
call SetPlayerName(Player(1),"fruitcup")
call savecode.Encode(medal1,medalmax)
call savecode.Encode(medal2,medalmax)
call savecode.Encode(XP,XPmax)
//--- Savecode_save generates the savecode for a specific player ---
set s = savecode.Save(Player(0),1)
call savecode.destroy()
// call BJDebugMsg("Savecode: " + Savecode_colorize(s))
//--- User writes down code, inputs again ---
set loadcode = Savecode.create()
if loadcode.Load(Player(0),s,1) then
// call BJDebugMsg("load ok")
else
call BJDebugMsg("load failed")
return false
endif
//Must decode in reverse order of encodes
// load object : max value that data can take
if XP != loadcode.Decode(XPmax) then
return false
elseif medal2 != loadcode.Decode(medalmax) then
return false
elseif medal1 != loadcode.Decode(medalmax) then
return false
endif
call loadcode.destroy()
return true
endfunction
endlibrary
//===========================================================================
function InitTrig_save_system takes nothing returns nothing
endfunction
library BigNum
//prefer algebraic approach because of real subtraction issues
function log takes real y, real base returns real
local real x
local real factor = 1.0
local real logy = 0.0
local real sign = 1.0
if(y < 0.) then
return 0.0
endif
if(y < 1.) then
set y = 1.0/y
set sign = -1.0
endif
//Chop out powers of the base
loop
exitwhen y < 1.0001 //decrease this ( bounded below by 1) to improve precision
if(y > base) then
set y = y / base
set logy = logy + factor
else
set base = SquareRoot(base) //If you use just one base a lot, precompute its squareroots
set factor = factor / 2.
endif
endloop
return sign*logy
endfunction
struct BigNum_l
integer leaf
BigNum_l next
debug static integer nalloc = 0
static method create takes nothing returns BigNum_l
local BigNum_l bl = BigNum_l.allocate()
set bl.next = 0
set bl.leaf = 0
debug set BigNum_l.nalloc = BigNum_l.nalloc + 1
return bl
endmethod
method onDestroy takes nothing returns nothing
debug set BigNum_l.nalloc = BigNum_l.nalloc - 1
endmethod
//true: want destroy
method Clean takes nothing returns boolean
if .next == 0 and .leaf == 0 then
return true
elseif .next != 0 and .next.Clean() then
call .next.destroy()
set .next = 0
return .leaf == 0
else
return false
endif
endmethod
method DivSmall takes integer base, integer denom returns integer
local integer quotient
local integer remainder = 0
local integer num
if .next != 0 then
set remainder = .next.DivSmall(base,denom)
endif
set num = .leaf + remainder*base
set quotient = num/denom
set remainder = num - quotient*denom
set .leaf = quotient
return remainder
endmethod
endstruct
struct BigNum
BigNum_l list
integer base
static method create takes integer base returns BigNum
local BigNum b = BigNum.allocate()
set b.list = 0
set b.base = base
return b
endmethod
method onDestroy takes nothing returns nothing
local BigNum_l cur = .list
local BigNum_l next
loop
exitwhen cur == 0
set next = cur.next
call cur.destroy()
set cur = next
endloop
endmethod
method IsZero takes nothing returns boolean
local BigNum_l cur = .list
loop
exitwhen cur == 0
if cur.leaf != 0 then
return false
endif
set cur = cur.next
endloop
return true
endmethod
method Dump takes nothing returns nothing
local BigNum_l cur = .list
local string s = ""
loop
exitwhen cur == 0
set s = I2S(cur.leaf)+" "+s
set cur = cur.next
endloop
call BJDebugMsg(s)
endmethod
method Clean takes nothing returns nothing
local BigNum_l cur = .list
call cur.Clean()
endmethod
//fails if bignum is null
//BASE() + carry must be less than MAXINT()
method AddSmall takes integer carry returns nothing
local BigNum_l next
local BigNum_l cur = .list
local integer sum
if cur == 0 then
set cur = BigNum_l.create()
set .list = cur
endif
loop
exitwhen carry == 0
set sum = cur.leaf + carry
set carry = sum / .base
set sum = sum - carry*.base
set cur.leaf = sum
if cur.next == 0 then
set cur.next = BigNum_l.create()
endif
set cur = cur.next
endloop
endmethod
//x*BASE() must be less than MAXINT()
method MulSmall takes integer x returns nothing
local BigNum_l cur = .list
local integer product
local integer remainder
local integer carry = 0
loop
exitwhen cur == 0 and carry == 0
set product = x * cur.leaf + carry
set carry = product/.base
set remainder = product - carry*.base
set cur.leaf = remainder
if cur.next == 0 and carry != 0 then
set cur.next = BigNum_l.create()
endif
set cur = cur.next
endloop
endmethod
//Returns remainder
method DivSmall takes integer denom returns integer
return .list.DivSmall(.base,denom)
endmethod
method LastDigit takes nothing returns integer
local BigNum_l cur = .list
local BigNum_l next
loop
set next = cur.next
exitwhen next == 0
set cur = next
endloop
return cur.leaf
endmethod
endstruct
private function prop_Allocator1 takes nothing returns boolean
local BigNum b1
local BigNum b2
set b1 = BigNum.create(37)
call b1.destroy()
set b2 = BigNum.create(37)
call b2.destroy()
return b1 == b2
endfunction
private function prop_Allocator2 takes nothing returns boolean
local BigNum b1
local boolean b = false
set b1 = BigNum.create(37)
call b1.AddSmall(17)
call b1.MulSmall(19)
debug if BigNum_l.nalloc < 1 then
debug return false
debug endif
call b1.destroy()
debug set b = BigNum_l.nalloc == 0
return b
endfunction
private function prop_Arith takes nothing returns boolean
local BigNum b1
set b1 = BigNum.create(37)
call b1.AddSmall(73)
call b1.MulSmall(39)
call b1.AddSmall(17)
//n = 2864
if b1.DivSmall(100) != 64 then
return false
elseif b1.DivSmall(7) != 0 then
return false
elseif b1.IsZero() then
return false
elseif b1.DivSmall(3) != 1 then
return false
elseif b1.DivSmall(3) != 1 then
return false
elseif not b1.IsZero() then
return false
endif
return true
endfunction
endlibrary
//===========================================================================
function InitTrig_bignum_lib takes nothing returns nothing
endfunction