Skip to content

Commit

Permalink
Save custom mode (#1007)
Browse files Browse the repository at this point in the history
* first step to save custom game

* localize various settings in custom game

* rename fields to lower cases

* fix many bugs

* fixes #1014
  • Loading branch information
ImpleLee authored Oct 19, 2023
1 parent 7ac2c28 commit 90c428c
Show file tree
Hide file tree
Showing 13 changed files with 240 additions and 158 deletions.
24 changes: 0 additions & 24 deletions main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -376,30 +376,6 @@ then
MES.new('error',"An error occured during loading, and some data was lost.")
end

-- Initialize fields, sequence, missions, gameEnv for cutsom game
local fieldData=loadFile('conf/customBoards','-string -canSkip')
if fieldData then
fieldData=STRING.split(fieldData,"!")
for i=1,#fieldData do
DATA.pasteBoard(fieldData[i],i)
end
else
FIELD[1]=DATA.newBoard()
end
local sequenceData=loadFile('conf/customSequence','-string -canSkip')
if sequenceData then
DATA.pasteSequence(sequenceData)
end
local missionData=loadFile('conf/customMissions','-string -canSkip')
if missionData then
DATA.pasteMission(missionData)
end
local customData=loadFile('conf/customEnv','-canSkip')
if customData and customData['version']==VERSION.code then
TABLE.complete(customData,CUSTOMENV)
end
TABLE.complete(require"parts.customEnv0",CUSTOMENV)

-- Update data
do
if type(STAT.version)~='number' then
Expand Down
105 changes: 51 additions & 54 deletions parts/data.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ local floor=math.floor
local char,byte=string.char,string.byte
local ins=table.insert

local BAG,FIELD,MISSION,CUSTOMENV,GAME=BAG,FIELD,MISSION,CUSTOMENV,GAME
local GAME=GAME

local DATA={}
-- Sep symbol: 33 (!)
Expand All @@ -13,13 +13,13 @@ local DATA={}
Encode: A[B] sequence, A = block ID, B = repeat times, no B means do not repeat.
Example: "abcdefg" is [SZJLTOI], "a^aDb)" is [Z*63,Z*37,S*10]
]]
function DATA.copySequence()
function DATA.copySequence(bag)
local str=""

local count=1
for i=1,#BAG+1 do
if BAG[i+1]~=BAG[i] or count==64 then
str=str..char(96+BAG[i])
for i=1,#bag+1 do
if bag[i+1]~=bag[i] or count==64 then
str=str..char(96+bag[i])
if count>1 then
str=str..char(32+count)
count=1
Expand All @@ -32,7 +32,7 @@ function DATA.copySequence()
return str
end
function DATA.pasteSequence(str)
TABLE.cut(BAG)
local bag={}
local b,reg
for i=1,#str do
b=byte(str,i)
Expand All @@ -44,20 +44,20 @@ function DATA.pasteSequence(str)
end
else
if b>=97 and b<=125 then
ins(BAG,reg)
ins(bag,reg)
reg=b-96
elseif b>=34 and b<=96 then
for _=1,b-32 do
ins(BAG,reg)
ins(bag,reg)
end
reg=false
end
end
end
if reg then
ins(BAG,reg)
ins(bag,reg)
end
return true
return true,bag
end

local fieldMeta={__index=function(self,h)
Expand All @@ -69,8 +69,7 @@ end}
function DATA.newBoard(f)-- Generate a new board
return setmetatable(f and TABLE.shift(f) or{},fieldMeta)
end
function DATA.copyBoard(page)-- Copy the [page] board
local F=FIELD[page or 1]
function DATA.copyBoard(F)-- Copy the [page] board
local str=""

-- Encode field
Expand All @@ -84,21 +83,15 @@ function DATA.copyBoard(page)-- Copy the [page] board
end
return STRING.packBin(str)
end
function DATA.copyBoards()
function DATA.copyBoards(field)
local out={}
for i=1,#FIELD do
out[i]=DATA.copyBoard(i)
for i=1,#field do
out[i]=DATA.copyBoard(field[i])
end
return table.concat(out,"!")
end
function DATA.pasteBoard(str,page)-- Paste [str] data to [page] board
if not page then
page=1
end
if not FIELD[page] then
FIELD[page]=DATA.newBoard()
end
local F=FIELD[page]
function DATA.pasteBoard(str)-- Paste [str] data to [page] board
local F=DATA.newBoard()

-- Decode
str=STRING.unpackBin(str)
Expand Down Expand Up @@ -133,7 +126,7 @@ function DATA.pasteBoard(str,page)-- Paste [str] data to [page] board
p=p+1
end

return true
return true, F
end

--[[
Expand All @@ -152,14 +145,14 @@ end
O1=61,O2=62,O3=63,O4=64,
I1=71,I2=72,I3=73,I4=74,
]]
function DATA.copyMission()
function DATA.copyMission(mission)
local _
local str=""

local count=1
for i=1,#MISSION+1 do
if MISSION[i+1]~=MISSION[i] or count==13 then
_=33+MISSION[i]
for i=1,#mission+1 do
if mission[i+1]~=mission[i] or count==13 then
_=33+mission[i]
str=str..char(_)
if count>1 then
str=str..char(113+count)
Expand All @@ -174,7 +167,7 @@ function DATA.copyMission()
end
function DATA.pasteMission(str)
local b
TABLE.cut(MISSION)
local mission={}
local reg
for i=1,#str do
b=byte(str,i)
Expand All @@ -187,28 +180,28 @@ function DATA.pasteMission(str)
else
if b>=34 and b<=114 then
if ENUM_MISSION[reg] then
ins(MISSION,reg)
ins(mission,reg)
reg=b-33
else
TABLE.cut(MISSION)
TABLE.cut(mission)
return
end
elseif b>=115 and b<=126 then
for _=1,b-113 do
ins(MISSION,reg)
ins(mission,reg)
end
reg=false
end
end
end
if reg then
ins(MISSION,reg)
ins(mission,reg)
end
return true
return true,mission
end

function DATA.copyQuestArgs()
local ENV=CUSTOMENV
function DATA.copyQuestArgs(custom_env)
local ENV=custom_env
local str=""..
ENV.holdCount..
(ENV.ospin and "O" or "Z")..
Expand All @@ -218,12 +211,12 @@ function DATA.copyQuestArgs()
end
function DATA.pasteQuestArgs(str)
if #str<4 then return end
local ENV=CUSTOMENV
local ENV={}
ENV.holdCount= str:byte(1)-48
ENV.ospin= str:byte(2)~=90
ENV.missionKill=str:byte(3)~=90
ENV.sequence= str:sub(4)
return true
return true,ENV
end

local function _encode(t)
Expand Down Expand Up @@ -309,7 +302,6 @@ function DATA.pumpRecording(str,L)
end
end
do-- function DATA.saveReplay()
local noRecList={"custom","solo","round","techmino"}
local function _getModList()
local res={}
for number,sel in next,GAME.mod do
Expand All @@ -321,28 +313,30 @@ do-- function DATA.saveReplay()
end
function DATA.saveReplay()
-- Filtering modes that cannot be saved
for _,v in next,noRecList do
if GAME.curModeName:find(v) then
MES.new('error',"Cannot save recording of this mode now!")
return
end
if GAME.initPlayerCount~=1 then
MES.new('error',"Cannot save recording of more than 1 player now!")
return
end

-- Write file
local fileName=os.date("replay/%Y_%m_%d_%H%M%S.rep")
if not love.filesystem.getInfo(fileName) then
local metadata={
date=os.date("%Y/%m/%d %H:%M:%S"),
mode=GAME.curModeName,
version=VERSION.string,
player=USERS.getUsername(USER.uid),
seed=GAME.seed,
setting=GAME.setting,
mod=_getModList(),
tasUsed=GAME.tasUsed,
}
if GAME.curMode.savePrivate then
metadata.private=GAME.curMode.savePrivate()
end
love.filesystem.write(fileName,
love.data.compress('string','zlib',
JSON.encode{
date=os.date("%Y/%m/%d %H:%M:%S"),
mode=GAME.curModeName,
version=VERSION.string,
player=USERS.getUsername(USER.uid),
seed=GAME.seed,
setting=GAME.setting,
mod=_getModList(),
tasUsed=GAME.tasUsed,
}.."\n"..
JSON.encode(metadata).."\n"..
DATA.dumpRecording(GAME.rep)
)
)
Expand Down Expand Up @@ -397,6 +391,9 @@ function DATA.parseReplayData(fileName,fileData,ifFull)
tasUsed=metaData.tasUsed,
}
if ifFull then rep.data=fileData end
if metaData.private then
rep.private=metaData.private
end
return rep
end
return DATA
2 changes: 1 addition & 1 deletion parts/eventsets/checkClearBoard.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ return {
for i=#P.field,1,-1 do
P.field[i],P.visTime[i]=nil
end
setField(P,D.finished+1)
setField(P,FIELD[D.finished+1])
SYSFX.newShade(1.4,P.absFieldX,P.absFieldY,300*P.size,610*P.size,.6,.8,.6)
SFX.play('warn_1')
else
Expand Down
9 changes: 2 additions & 7 deletions parts/gameFuncs.lua
Original file line number Diff line number Diff line change
Expand Up @@ -424,8 +424,7 @@ function notEmptyLine(L)
end
end
end
function setField(P,page)
local F=FIELD[page]
function setField(P,F)
local height=0
for y=#F,1,-1 do
if notEmptyLine(F[y]) then
Expand Down Expand Up @@ -1228,22 +1227,18 @@ do-- function pressKey(k)
return cache[k]
end
end
do-- CUS/SETXXX(k)
local CUSTOMENV=CUSTOMENV
do-- SETXXX(k)
local warnList={
'das','arr','dascut','dropcut','sddas','sdarr',
'ihs','irs','ims','RS',
'frameMul','highCam',
'VKSwitch','VKIcon','VKTrack','VKDodge',
'simpMode',
}
function CUSval(k) return function() return CUSTOMENV[k] end end
function ROOMval(k) return function() return ROOMENV[k] end end
function SETval(k) return function() return SETTING[k] end end
function CUSrev(k) return function() CUSTOMENV[k]=not CUSTOMENV[k] end end
function ROOMrev(k) return function() ROOMENV[k]=not ROOMENV[k] end end
function SETrev(k) return function() if TABLE.find(warnList,k) then trySettingWarn() end SETTING[k]=not SETTING[k] end end
function CUSsto(k) return function(i) CUSTOMENV[k]=i end end
function ROOMsto(k) return function(i) ROOMENV[k]=i end end
function SETsto(k) return function(i) if TABLE.find(warnList,k) then trySettingWarn() end SETTING[k]=i end end
end
16 changes: 15 additions & 1 deletion parts/modes/custom_clear.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,21 @@ return {
end

for _,P in next,PLY_ALIVE do
setField(P,1)
setField(P,FIELD[1])
end
end,
savePrivate=function()
return {
FIELD=FIELD,
BAG=BAG,
MISSION=MISSION,
CUSTOMENV=CUSTOMENV,
}
end,
loadPrivate=function(private)
FIELD=private.FIELD
BAG=private.BAG
MISSION=private.MISSION
CUSTOMENV=private.CUSTOMENV
end,
}
14 changes: 14 additions & 0 deletions parts/modes/custom_puzzle.lua
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,18 @@ return {
PLY.newAIPlayer(2,BOT.template{type='CC',speedLV=2*AIlevel-1,next=math.floor(AIlevel*.5+1),hold=GAME.modeEnv.holdCount,node=20000+5000*AIlevel})
end
end,
savePrivate=function()
return {
FIELD=FIELD,
BAG=BAG,
MISSION=MISSION,
CUSTOMENV=CUSTOMENV,
}
end,
loadPrivate=function(private)
FIELD=private.FIELD
BAG=private.BAG
MISSION=private.MISSION
CUSTOMENV=private.CUSTOMENV
end,
}
Loading

0 comments on commit 90c428c

Please sign in to comment.