# Mini Fast Food Restaurant

return (function()


	local IDs = {--Ingame items and blocks
		sceneBlk1Id = 100,  --Scene block
		sceneBlk2Id = 667,  --Scene block
		storeBoxIdx = 2001, --Box block
	
		contTableId = 1123, --Dirty tray tableID
		washTableId = 219,  --Wash TableID
		waterTapxId = 258,  --Water tapID
		funnelBlkId = 1105, --Deliver blockID
		arrowheadId = 3941, --Deliver arrowsID
	
		cookinBlkId = 2018, --Cooking blockID
		cutBoardxId = 218,  --Cutting board blockID
		checkBlkIdx = 3950, --Check blockID
		musicBlkIdx = 415,  --MusicblockID
	
		emptyDishId = 3997, --Empty dish blockID
		dirtyDishId = 3999, --Dirty dishblockID
	}
	
	-- Hand held food item
	local FoodIDs = {
		[1] = 12502, --Toest
		[2] = 12519, --Roasted Chicken Leg
		[3] = 12512, --Roasted Potato
		[4] = 12517, --Roasted Beef
	}
	
	-- Conversion between Deliver blocks
	local FinalIDs = {
		[FoodIDs[1]] = { --Hand held toast
			[3997] = 4000, --10->block1
			[4000] = 3991, --11->block11
			[3982] = 3972, --12->block12
			[3980] = 3973, --13->block13
			[3976] = 3971, --14->block14
	
			[3991] = 3985, --111->111
			[3972] = 3964, --112->112
			[3973] = 3961, --113->113
			[3971] = 3960, --114->114
	
			[3981] = 3965, --122->122
			[3970] = 3967, --123->123
			[3968] = 3966, --124->124
			[3979] = 3963, --133->133
			[3969] = 3962, --134->134
			[3975] = 3959, --144->144
		},
		[FoodIDs[2]] = { --Hand held Roasted Chicken Leg
			[3997] = 3982, --20->block2
			[4000] = 3972, --21->block12
			[3982] = 3981, --22->block22
			[3980] = 3970, --23->block23
			[3976] = 3968, --24->block24
	
			[3991] = 3964, --211->112
			[3972] = 3965, --212->122
			[3973] = 3967, --213->123
			[3971] = 3966, --214->124
	
			[3981] = 3977, --222->222
			[3970] = 3958, --223->223
			[3968] = 3956, --224->224
			[3979] = 3955, --233->233
			[3969] = 3957, --234->234
			[3975] = 3954, --244->244
		},
		[FoodIDs[3]] = { --Hand held Roasted Potato
			[3997] = 3980, --30->block3
			[4000] = 3973, --31->block13
			[3982] = 3970, --32->block23
			[3980] = 3979, --33->block33
			[3976] = 3969, --34->block34
	
			[3991] = 3961, --311->113
			[3972] = 3967, --312->123
			[3973] = 3963, --313->133
			[3971] = 3962, --314->134
	
			[3981] = 3958, --322->223
			[3970] = 3955, --323->233
			[3968] = 3957, --324->234
			[3979] = 3978, --333->333
			[3969] = 3952, --334->334
			[3975] = 3953, --344->344
		},
		[FoodIDs[4]] = { --Hand held Roasted Beef
			[3997] = 3976, --40->block4
			[4000] = 3971, --41->block14
			[3982] = 3968, --42->block24
			[3980] = 3969, --43->block34
			[3976] = 3975, --44->block44
	
			[3991] = 3960, --411->114
			[3972] = 3966, --412->124
			[3973] = 3962, --413->134
			[3971] = 3959, --414->144
	
			[3981] = 3956, --422->224
			[3970] = 3957, --423->234
			[3968] = 3954, --424->244
			[3979] = 3952, --433->334
			[3969] = 3953, --434->344
			[3975] = 3974, --444->444
		},
	}
	
	--Clock ID:Right/Left half
	local ClockNumIDs = {
		-- right --
		[0] = 3909,
		[1] = 3923,
		[2] = 3925,
		[3] = 3920,
		[4] = 3918,
		[5] = 3916,
		[6] = 3915,
		[7] = 3913,
		[8] = 3929,
		[9] = 3911,
	
		-- lelf --
		[10] = 3908,
		[11] = 3922,
		[12] = 3924,
		[13] = 3921,
		[14] = 3919,
		[15] = 3917,
		[16] = 3914,
		[17] = 3912,
		[18] = 3943,
		[19] = 3910,
	}
	
	local GameSData = {--Level content
		[1] = { --Level 1
			score = 5, --Score
			dtime = 3*60, --Time
			pos = { --Spawn Point
				[1] = {x=21.5, y=7, z=14.5},
				[2] = {x=22.5, y=7, z=14.5},
				[3] = {x=23.5, y=7, z=14.5},
			},
			fpos = { --funnel Level delivery point
				[1] = {x=22, y=7, z=26},
				[2] = {x=23, y=7, z=26},
			},
			dpos = { --Dirty position
				[1] = {x=18, y=7, z=26},
				[2] = {x=19, y=7, z=26},
			},
			mpos = { --Welcome music POS
				[1] = {x=23, y=14, z=20},
				[2] = {x=18, y=14, z=21},
			},
			tools = { --Item conversion type
				[IDs.cutBoardxId] = {--cut board
					[1] = {[241] = 12512},
				},
				[IDs.washTableId] = {--wash table
					[1] = {[3999] = 3997},
				},
				[IDs.waterTapxId] = {--water tap
					[1] = {[3999] = 3997},
				},
			},
			goals = {3973, 3979}, --Score block
			target = {{3907, 3884}, {3884, 3884}},
			clocks = { --Clock information
				{x=21, y=9, z=27, time=45, stop=false, fdir=1},
				{x=24, y=9, z=19, time=45, stop=false, fdir=2},
				{x=20, y=9, z=13, time=45, stop=false, fdir=3},
				{x=17, y=9, z=21, time=45, stop=false, fdir=4},
			},
		},
		[2] = { --Level 2
			score = 9, --Level Score
			dtime = 4*60, --Level Time
			pos = {
				[1] = {x=20.5-27, y=7, z=26.5},
				[2] = {x=21.5-27, y=7, z=26.5},
				[3] = {x=22.5-27, y=7, z=26.5},
			},
			fpos = { --funnel Level delivery point
				[1] = {x=-9, y=7, z=14},
				[2] = {x=-10, y=7, z=14},
			},
			dpos = { --Dirty position
				[1] = {x=-4, y=7, z=18},
				[2] = {x=-4, y=7, z=17},
			},
			mpos = { --Welcome music POS
				[1] = {x=-4, y=14, z=25},
				[2] = {x=-4, y=14, z=20},
			},
			tools = { --Food/Item conversion type
				[IDs.cookinBlkId] = {--cooking block
					[1] = {[12516] = 12517},
					[2] = {[12518] = 12519},
				},
				[IDs.washTableId] = {--wash the dishes
					[1] = {[3999] = 3997},
				},
				[IDs.waterTapxId] = {--wash the dishes
					[1] = {[3999] = 3997},
				},
			},
			goals = {3972, 3971, 3968, 3981, 3975}, --Scoreblock
			target = {{3907, 3926}, {3907, 3880}, {3926, 3880}, {3926, 3926}, {3880, 3880}},
			clocks = { --Clock information
				{x=-7, y=9, z=27, time=60, stop=false, fdir=1},
				{x=-3, y=9, z=19, time=60, stop=false, fdir=2},
				{x=-7, y=9, z=13, time=60, stop=false, fdir=3},
				{x=-11, y=9, z=21, time=60, stop=false, fdir=4},
			},
		},
		[3] = { --Level 3
			score = 12, --Level Score
			dtime = 5*60,--Level Time
			pos = {
				[1] = {x=20.5-15, y=7, z=16.5},
				[2] = {x=21.5-15, y=7, z=16.5},
				[3] = {x=22.5-15, y=7, z=16.5},
			},
			fpos = { --funnel Level delivery point
				[1] = {x=6, y=7, z=25},
				[2] = {x=7, y=7, z=25},
				[3] = {x=8, y=7, z=25},
			},
			dpos = { --Dirty position
				[1] = {x=1, y=7, z=24},
				[2] = {x=2, y=7, z=24},
			},
			mpos = { --Welcome music POS
				[1] = {x=2, y=14, z=24},
				[2] = {x=6, y=14, z=16},
			},
			tools = { --Food/Item conversion type
				[IDs.cutBoardxId] = {--cut board
					[1] = {[241] = 12512},
				},
				[IDs.cookinBlkId] = {--cooking block
					[1] = {[12516] = 12517},
					[2] = {[12518] = 12519},
				},
				[IDs.washTableId] = {--wash the dishes
					[1] = {[3999] = 3997},
				},
				[IDs.waterTapxId] = {--wash the dishes
					[1] = {[3999] = 3997},
				},
			},
			goals = {3967, 3966, 3962, 3957, 3955, 3952, 3958, 3956, 3953, 3954}, --Scoreblock
			target = {{3907, 3926, 3884}, {3907, 3926, 3880}, {3907, 3880, 3884}, {3880, 3926, 3884},
					  {3926, 3884, 3884}, {3880, 3884, 3884}, {3884, 3926, 3926}, {3880, 3926, 3926},
					  {3884, 3880, 3880}, {3926, 3880, 3880}},
			clocks = { --Clock information
				{x=12, y=9, z=25, time=80, stop=false, fdir=1},
				{x=2, y=9, z=25, time=80, stop=false, fdir=1},
				{x=10, y=9, z=15, time=80, stop=false, fdir=3},
				{x=2, y=9, z=15, time=80, stop=false, fdir=3},
			},
		},
	}

-- Game Tips
local GameTips = {
	NewTips = 'Customers are on the way..',
	NewStage = '#GSuccessfully, you will enter the new level!#n',
	CountTip = 'Level %d#Y', -- Timer Tips

	windStage = '#YMini Restaurant-Level %d#n',
	chatStage = 'Successfully entered level %d:#R Get %d points in %d minutes to enter the next level!#nGo!',
	chatNewIn = 'Tips: Get score by puting the food into the plate or the dish according to the guest.',

	windScore1 = 'OK.#YGot 1 point#n',
	windScore2 = 'Well done!#YGot 2 points#n',
	windScore0 = 'Sorry, this does not match the guest request.',
	windComes = 'Welcome <%d> to Mini Fast Food Restaurant',
	windLeave = 'Guest <%d> left…',

	chatLast30 = '#RLast 30 seconds! #n to end the level.',
	chatLast10 = '#RLast 10 seconds! #n to end the level.',
}

local chatType = 1
local tickCount = 0
local newTicker = 20
local IsGameEnded = false --Game over
local IsGRuleInit = false --Set rules
local BattleResult = 0 --Game result Tag
local runTime = 0
local teamIdx = 1--Set team ID
local customers = 0 --Number of Guest
local DishBlks = {IDs.dirtyDishId}

local miniTimer1 = -1 --Level timer
local miniTimer2 = -1 --Reset timing

--Store level data
local CurrStage = {
	stage = 1, --Default 1st level
	score = 0, --score
	clocks = {},--Demand module
	seqids = {},--delayFuncID
}

function EasyCopy(dtab)
	local newtab = {}
	for k, v in pairs(dtab) do newtab[k]=v end
	return newtab
end

-- Clock = {x, y, z, time=30, fdir=1, stop=false, target={t1,t2,t3}}
function GetRandomClock(stage)
	stage = stage or CurrStage.stage
	sdata = GameSData[stage]
	
	if sdata ~= nil then
		local randIdx = 0 --random ID
		local randClock = nil -- New clock
		
		local clocks = GameSData[stage].clocks
		randIdx = math.random(1, #clocks)
		randClock = EasyCopy(clocks[randIdx])

		local target = GameSData[stage].target
		randIdx = math.random(1, #target)
		randClock['target'] = target[randIdx]

		local goals = GameSData[stage].goals
		randClock['goal'] = goals[randIdx]
		-- Save data
		CurrStage.tgIdx = randIdx
		return randClock
	end
end

-- Clock = {x, y, z, time=30, fdir=1, stop=false, target={t1,t2,t3}}
-- Add or cut customer demand timer
function ClockCrtOrDel(clock, dodel)
	local xPos, yPos, zPos = 0, 0, 0
	
	local faceDir = -1 --Block orientation
	local xdiv,zdiv = 0, 0 --X,Z Coordinate offset
	local txdiv,tzdiv = 0, 0 --Position offset
	if clock.fdir==1 then faceDir=2;xdiv=1;tzdiv=1; end --Z axis reverse direction
	if clock.fdir==2 then faceDir=4;zdiv=-1;txdiv=1; end --Y axis reverse direction
	if clock.fdir==3 then faceDir=3;xdiv=-1;tzdiv=-1; end --Z-axis square
	if clock.fdir==4 then faceDir=5;zdiv=1;txdiv=-1; end --Y-axis square

	local headId = 3946 -- Set the head of guest
	xPos, yPos, zPos = clock.x, clock.y+1, clock.z
	if dodel then Block:destroyBlock(xPos, yPos, zPos)
	else Block:setBlockAll(xPos, yPos, zPos, headId, faceDir) end

	local flagId = 3932 --Tips
	local clockId = 3947 -- Left half clock ID
	local drinkId = 3945 -- drink in the right side ID
	local tsize = #clock.target --Required quantity
	local lPanId,mPanId,rPanId = 3883,3882,3881 --L/R Whiteboard

	-- add Tips
	xPos, yPos, zPos = clock.x-xdiv, clock.y+1, clock.z-zdiv
	if dodel then Block:destroyBlock(xPos, yPos, zPos)
	else Block:setBlockAll(xPos, yPos, zPos, flagId, faceDir) end

	-- add L/R Whiteboard or Required
	xPos, yPos, zPos = clock.x-xdiv, clock.y+2, clock.z-zdiv
	if dodel then Block:destroyBlock(xPos, yPos, zPos) --WhiteboardL
	else Block:setBlockAll(xPos, yPos, zPos, lPanId, faceDir) end
	if dodel then Block:destroyBlock(xPos-txdiv, yPos, zPos-tzdiv) --Required L
	else Block:setBlockAll(xPos-txdiv, yPos, zPos-tzdiv, clock.target[1], faceDir) end
	if tsize <= 2 then
		xPos, yPos, zPos = clock.x, clock.y+2, clock.z
		if dodel then Block:destroyBlock(xPos, yPos, zPos) --WhiteboardR
		else Block:setBlockAll(xPos, yPos, zPos, rPanId, faceDir) end
		if dodel then Block:destroyBlock(xPos-txdiv, yPos, zPos-tzdiv) --Required M
		else Block:setBlockAll(xPos-txdiv, yPos, zPos-tzdiv, clock.target[2], faceDir) end
	else -- Required parts more than 2
		xPos, yPos, zPos = clock.x, clock.y+2, clock.z
		if dodel then Block:destroyBlock(xPos, yPos, zPos) --WhiteboardM
		else Block:setBlockAll(xPos, yPos, zPos, mPanId, faceDir) end

		if dodel then Block:destroyBlock(xPos-txdiv, yPos, zPos-tzdiv) --RequiredM
		else Block:setBlockAll(xPos-txdiv, yPos, zPos-tzdiv, clock.target[2], faceDir) end
		
		xPos, yPos, zPos = clock.x+xdiv, clock.y+2, clock.z+zdiv
		if dodel then Block:destroyBlock(xPos, yPos, zPos) --WhiteboardR
		else Block:setBlockAll(xPos, yPos, zPos, rPanId, faceDir) end

		if dodel then Block:destroyBlock(xPos-txdiv, yPos, zPos-tzdiv) --RequiredR
		else Block:setBlockAll(xPos-txdiv, yPos, zPos-tzdiv, clock.target[3], faceDir) end
	end

	-- addLeft half clock
	xPos, yPos, zPos = clock.x-xdiv*2, clock.y, clock.z-zdiv*2
	if dodel then Block:destroyBlock(xPos, yPos, zPos)
	else Block:setBlockAll(xPos, yPos, zPos, clockId, faceDir) end

	-- add drink in the right side
	xPos, yPos, zPos = clock.x+xdiv, clock.y, clock.z+zdiv
	if dodel then Block:destroyBlock(xPos, yPos, zPos)
	else Block:setBlockAll(xPos, yPos, zPos, drinkId, faceDir) end
	
	local status = dodel and 'destroy' or 'count'
	ClockCounted(clock, status)
end

-- Guest required starts to count down
function ClockCounted(clock, status)
	status = status and status or 'count'
	-- Return if it is timed and stopped
	if status=='count' and clock.stop then return end

	local faceDir = -1 -- Block orientation
	local xdiv,zdiv = 0, 0 -- X,Z Coordinate offset
	if clock.fdir==1 then faceDir=2;xdiv=1 end --Z axis reverse direction
	if clock.fdir==2 then faceDir=4;zdiv=-1 end --Y axis reverse direction
	if clock.fdir==3 then faceDir=3;xdiv=-1 end --Z-axis square
	if clock.fdir==4 then faceDir=5;zdiv=1 end --Y-axis square

	if status == 'destroy' then
		Block:destroyBlock(clock.x, clock.y, clock.z)
		Block:destroyBlock(clock.x-xdiv, clock.y, clock.z-zdiv)
		return
	end

	-- Timing or initialization status
	local strTime = tostring(clock.time)
	local left = #strTime>1 and strTime:sub(1,1) or 0--Ten digits
	local right = #strTime>1 and strTime:sub(2) or strTime:sub(1)

	local leftId = ClockNumIDs[tonumber(left)+10]
	local rightId = ClockNumIDs[tonumber(right)]
	if not leftId or not rightId then return end

	-- Set left and right timer
	Block:setBlockAll(clock.x-xdiv, clock.y, clock.z-zdiv, leftId, faceDir)
	Block:setBlockAll(clock.x, clock.y, clock.z, rightId, faceDir)

	if clock.time == 10 then --10 seconds left
		local tsize = #clock.target
		local lPanId,mPanId,rPanId = 3906,3905,3934
		Block:setBlockAll(clock.x-xdiv, clock.y+2, clock.z-zdiv, lPanId, faceDir)
		if tsize <= 2 then
			Block:setBlockAll(clock.x, clock.y+2, clock.z, rPanId, faceDir)
		else -- more than 2 Target
			Block:setBlockAll(clock.x, clock.y+2, clock.z, mPanId, faceDir)
			Block:setBlockAll(clock.x+xdiv, clock.y+2, clock.z+zdiv, rPanId, faceDir)
		end

		local headId = 3940 --Head change
		Block:setBlockAll(clock.x, clock.y+1, clock.z, headId, faceDir)
	end
end

local TargetHited = function(clock)
	local xPos, yPos, zPos = 0, 0, 0
	
	local faceDir = -1 --Block orientation
	local xdiv,zdiv = 0, 0 --X,Z Coordinate offset
	local txdiv,tzdiv = 0, 0 --Required part Position offset
	if clock.fdir==1 then faceDir=2;xdiv=1;tzdiv=1; end --Z axis reverse direction
	if clock.fdir==2 then faceDir=4;zdiv=-1;txdiv=1; end --Y axis reverse direction
	if clock.fdir==3 then faceDir=3;xdiv=-1;tzdiv=-1; end --Z-axis square
	if clock.fdir==4 then faceDir=5;zdiv=1;txdiv=-1; end --Y-axis square

	local checkId = IDs.checkBlkIdx
	local tsize = #clock.target --Required Quantity
	-- set Required part complete the mark
	xPos, yPos, zPos = clock.x-xdiv, clock.y+2, clock.z-zdiv --RequiredL
	Block:setBlockAll(xPos-txdiv, yPos, zPos-tzdiv, checkId, faceDir)
	if tsize <= 2 then
		xPos, yPos, zPos = clock.x, clock.y+2, clock.z --RequiredR
		Block:setBlockAll(xPos-txdiv, yPos, zPos-tzdiv, checkId, faceDir)
	else -- More than 2 Required parts
		xPos, yPos, zPos = clock.x, clock.y+2, clock.z --RequiredM
		Block:setBlockAll(xPos-txdiv, yPos, zPos-tzdiv, checkId, faceDir)
		
		xPos, yPos, zPos = clock.x+xdiv, clock.y+2, clock.z+zdiv --RequiredR
		Block:setBlockAll(xPos-txdiv, yPos, zPos-tzdiv, checkId, faceDir)
	end
end

-- Refresh guest Required part 
local TargetRefresh = function(cInfo)
	local csize = #CurrStage.seqids
	if cInfo~=nil and csize>0 then
		for idx = 1, csize do --Delete from line
			local seqId = CurrStage.seqids[idx]
			if cInfo.seq == seqId then
				table.remove(CurrStage.seqids, idx)
				break
			end
		end
	end

	-- create a Required part 
	customers = customers + 1
	local stage = CurrStage.stage
	local clock = GetRandomClock(stage)

	local csize = #CurrStage.clocks
	CurrStage.clocks[csize+1] = clock
	print('Frt===>>', csize, CurrStage.clocks)

	ClockCrtOrDel(clock, false)
	local chatTips = string.format(GameTips.windComes, customers)
	Chat:sendSystemMsg(chatTips)

	-- Reflesh the guest requiredX,Z Coordinate offset
	local mPos = GameSData[stage].mpos[1]
	Block:destroyBlock(mPos.x, mPos.y, mPos.z)
	local createBlock = function()
		Block:setBlockAll(mPos.x, mPos.y, mPos.z, IDs.musicBlkIdx)	
	end
	threadpool:delay(1, createBlock)
end

-----Generate tray after delivery-----
local GensDirtyDish = function(cInfo)
	local csize = #CurrStage.seqids
	for idx = 1, csize do --Delete from line
		local seqId = CurrStage.seqids[idx]
		if cInfo.seq == seqId then
			table.remove(CurrStage.seqids, idx)
			break
		end
	end

	local cur_stage = CurrStage.stage
	local dpos = GameSData[cur_stage].dpos

	local yOffset = 2
	local isSucc = false
	
	for jdx = 1, yOffset do --Up to two layers
		for idx = 1, #dpos do --if the layer has no blocks
			local x, y, z = dpos[idx].x,dpos[idx].y,dpos[idx].z
			local ret, blockId = Block:getBlockID(x, y+jdx, z)
			if ret==ErrorCode.OK and blockId==0 then
				if cur_stage == 1 then --The first level is generated by a clean plate.
					Block:setBlockAll(x, y+jdx, z, IDs.emptyDishId)
				else --Other levels generate dirty dishes
					Block:setBlockAll(x, y+jdx, z, IDs.dirtyDishId)
				end
				return
			end
		end
	end
end

--if table have key
local function KeyInTable(key, ctab)
	for idx, val in ipairs(ctab) do
		if val==key then return true end
	end
	return false
end

--Replace tick times
local function IsCanTick()
	tickCount = tickCount+1

	if tickCount>=newTicker then 
		tickCount = 0		
		return true
	end

	return false
end

-- Initialize game data
local function InitGameData()
	--Initialize the dish class block DishBlks
	for key, dict in pairs(FinalIDs) do
    	for ckey, cval in pairs(dict) do
    		if not KeyInTable(ckey, DishBlks) then DishBlks[#DishBlks+1] = ckey end
    		if not KeyInTable(cval, DishBlks) then DishBlks[#DishBlks+1] = cval end
    	end
    end
end

--Game rulemaking
local function InitGameRule()
	IsGRuleInit = true -- Initialization target
	GameRule.CameraDir = 1       --Default positive angle
	GameRule.StartMode = 0       --Open mode
	GameRule.StartPlayers = 1    --Minimum player amount:1
	GameRule.DisplayScore = 1    --Display score:1
	GameRule.BlockDestroy = 0    --Blocks cannot be destroyed

	GameRule.WinLoseEndTime = 2
end

--Score Settlement
local function ShowGBattleUI()
	-- Set the total score
	local stage = CurrStage.stage
	local score = CurrStage.score
	for idx=1, stage-1 do
		score = score + GameSData[idx].score
	end

	local ret, txt = Game:getDefString(3176)
	local txtInfo = string.format('%s:%d', txt,score)

	UI:setGBattleUI('right_little_desc', txtInfo)
	UI:setGBattleUI('battle_btn', false)
	UI:setGBattleUI('result', false)
	UI:setGBattleUI('result_bkg', false)
	UI:setGBattleUI('reopen', true)
end

--Reset new round
local function StartNewRound()
	-- Stop the clock and destroy it
	print('Fz==>>>', CurrStage.clocks)
	for idx = #CurrStage.clocks, 1, -1 do
		local clock = CurrStage.clocks[idx]
		clock.stop = true
		ClockCrtOrDel(clock, true)
		table.remove(CurrStage.clocks, idx)
	end
			
	-- Clear Required part /Delayed call
	print('Fw==>>>', CurrStage.seqids)
	for idx = #CurrStage.seqids, 1, -1 do
		local seqId = CurrStage.seqids[idx]
		threadpool:kick(seqId)--delete Delayed call
		table.remove(CurrStage.seqids, idx)
	end
	
	Game_Start() --Restart the game
end

--Get the point and check if the level is completed
local function TeamAddScore(teamId, addScore)
	local teamId = teamId and teamId or teamIdx
	local ret = Team:addTeamScore(teamId, addScore)
	local ret, score = Team:getTeamScore(teamId)
	if ret == ErrorCode.OK then CurrStage.score = score end

	local ret,num,players = World:getAllPlayers()
	if ret==ErrorCode.OK then
		for idx = 1, #players do --add tips to all players
			local scoreTips = addScore==1 and GameTips.windScore1 or GameTips.windScore2
			--print('Fz==>>>', scoreTips, score==1)
			Player:notifyGameInfo2Self(players[idx], scoreTips)
		end
	end

	local cur_stage = CurrStage.stage
	local stage_score = GameSData[cur_stage].score
	if CurrStage.score >= stage_score then
		local new_stage = cur_stage+1		

		if new_stage > #GameSData then
			IsGameEnded = true --finished all levels
			BattleResult = TEAM_RESULTS.TEAM_RESULTS_WIN
			Game:doGameEnd()
		else --turn to next level
			CurrStage.stage = new_stage
			--Chat:sendSystemMsg(GameTips.NewStage)
			for idx = 1, #players do --Changed to player tips
				Player:notifyGameInfo2Self(players[idx], GameTips.NewStage)
			end
			
			--Reset the new round after 3 seconds
			miniTimer2 = 3
			MiniTimer:pauseTimer(miniTimer1)
			--threadpool:delay(3, StartNewRound)

			if IsLastCount then --Reset timer music
				IsLastCount = false
				for stage = 1, 3 do --All levels
					local musicId = IDs.musicBlkIdx
					local mPos = GameSData[stage].mpos[2]
					Block:setBlockAll(mPos.x, mPos.y, mPos.z, musicId)	
				end
			end
		end
	end
end

local IsLastCount = false
--------Game start--------
Game_Start = function()
	-- ShowItemName()
	print('Fz==>Game_Start')

	customers = 0
	miniTimer2 = -1
	CurrStage.score = 0 --Reset score
	Team:setTeamScore(teamIdx, CurrStage.score)

	-- Set game rules
	if not IsGRuleInit then InitGameRule() end

	local stage = CurrStage.stage
	local ret,num,players = World:getAllPlayers()
	if ret~=ErrorCode.OK or not players then return end

	local items = {241, 12502, 12512, 12516, 12517, 12518, 12519}
	local windTips = string.format(GameTips.windStage, stage)
	for idx = 1, #players do--Traversing the player
		local playerId = players[idx]
		-- Set player team
		Player:setTeam(playerId, teamIdx)
		-- Clear the specified item on the player
		for idx, itemId in ipairs(items) do
			Backpack:removeGridItemByItemID(playerId, itemId)
		end

		-- Set player Spawn Point
		local allPos = GameSData[stage].pos
		local index = (idx-1)%3 + 1
		local curPos = allPos[index] --Three position cycle
		--if not curPos then curPos = allPos[1] end
		Player:setPosition(playerId, curPos.x, curPos.y, curPos.z)

		-- Tip for fist time in the level
		Player:notifyGameInfo2Self(players[idx], windTips)
	end
	
	-- Create a game timer
	if miniTimer1 <= 0 then
		local ret, timerId = MiniTimer:createTimer('Timer1')
		if ret==ErrorCode.OK then miniTimer1 = timerId end
	end
	if miniTimer1 > 0 then --Start level timer
		local stTime = GameSData[stage].dtime
		MiniTimer:startBackwardTimer(miniTimer1, stTime)
		local sTip = string.format(GameTips.CountTip, stage)
		MiniTimer:showTimerTips(players, miniTimer1, sTip, true)
	end

	local score = GameSData[stage].score
	local dtime = math.modf(GameSData[stage].dtime/60)
	local chatTips = string.format(GameTips.chatStage, stage,dtime,score)
	Chat:sendSystemMsg(chatTips)
	if stage == 1 then Chat:sendSystemMsg(GameTips.chatNewIn) end

	--Chat:sendSystemMsg(GameTips.NewTips)
	--add new required after 1 second
	threadpool:delay(1, TargetRefresh)
	
	IsLastCount = false
	local mcPos = GameSData[stage].mpos[2]
	Block:setBlockAll(mcPos.x, mcPos.y, mcPos.z, IDs.musicBlkIdx)
end

--------Update--------
Game_RunTime = function()
	--10 seconds left 10 tick Generate block
	if IsLastCount and tickCount==10 then
		local stage = CurrStage.stage
		local mPos = GameSData[stage].mpos[2]
		Block:setBlockAll(mPos.x, mPos.y, mPos.z, IDs.musicBlkIdx)
	end

	if not IsCanTick() then return end
	if IsGameEnded then return end

	--10 seconds left 20 tick delete block
	local stage = CurrStage.stage
	if IsLastCount then --10 seconds left
		local mPos = GameSData[stage].mpos[2]
		Block:destroyBlock(mPos.x, mPos.y, mPos.z)
	end

	if miniTimer2 >= 0 then
		if miniTimer2 > 0 then
			local timeTip = string.format('#R%d#n',miniTimer2)
			--Chat:sendSystemMsg(timeTip)
			-- Changed to player Tip
			local ret,num,players = World:getAllPlayers()
			if ret==ErrorCode.OK then
				for idx = 1, #players do
					Player:notifyGameInfo2Self(players[idx], timeTip)
				end
			end
		else
			StartNewRound()
		end
		miniTimer2 = miniTimer2-1
	end

	local csize = #CurrStage.clocks
	if csize <= 0 then return end
	for idx = #CurrStage.clocks, 1, -1 do
		local clock = CurrStage.clocks[idx]
		if clock.time < 0 then --destroy
			ClockCrtOrDel(clock, true)
			table.remove(CurrStage.clocks, idx)
			-- Tips of guest left
			local chatTips = string.format(GameTips.windLeave, customers)
			Chat:sendSystemMsg(chatTips)

			local randsec = math.random(1, 2)
			threadpool:delay(randsec, TargetRefresh)
		elseif not clock.stop then --Timing
			ClockCounted(clock, 'count')
			clock.time = clock.time-1
		end
	end

	if miniTimer1 ~= 0 then
		local ret, curTime = MiniTimer:getTimerTime(miniTimer1)
		if ret==ErrorCode.OK then
			if curTime == 30 then -- Last 30 seconds
				Chat:sendSystemMsg(GameTips.chatLast30)

				IsLastCount = true
				local mPos = GameSData[stage].mpos[2]
				Block:destroyBlock(mPos.x, mPos.y, mPos.z)
			elseif curTime == 10 then --Last 10 seconds
				Chat:sendSystemMsg(GameTips.chatLast10)
			elseif curTime <= 0 then --Game over
				IsGameEnded = true --Sorry, game over
				BattleResult = TEAM_RESULTS.TEAM_RESULTS_LOSE
				Game:doGameEnd()
				return
			end
		end
	end
end

--------Game over--------
Game_Over = function()
	local txtIdx = 270 --win
	if BattleResult==TEAM_RESULTS.TEAM_RESULTS_LOSE then
		txtIdx = 271 --lost
	end

	local ret, txtInfox = Game:getDefString(txtIdx)
	print('Fz==>>>', BattleResult, txtIdx, ret, txtInfox)

	Chat:sendSystemMsg(txtInfox)
	Team:setTeamResults(teamIdx, BattleResult)
	Team:setTeamPlayersResults(teamIdx, BattleResult)

	ShowGBattleUI()
end

--------game timeout--------
Game_Tout = function()
	BattleResult = TEAM_RESULTS.TEAM_RESULTS_LOSE
end

-------Player initialization-------
Player_Init = function(trigger_obj)
	if not IsGRuleInit then InitGameRule() end

	local playerId = trigger_obj['eventobjid']
	if not playerId then return end
	Player:setTeam(playerId, teamIdx)

	if miniTimer1 > 0 then --Game start
		local stage = CurrStage.stage
		local allPos = GameSData[stage].pos
		local index = 1
		local ret, num = World:getPlayerTotal()
		if ret==ErrorCode.OK then index = (num-1)%3+1 end

		local curPos = allPos[index] --Three position cycle
		Player:setPosition(playerId, curPos.x, curPos.y, curPos.z)
	end
end

local curr_playerid = nil
--------start to dig the event--------
Block_DigBegin = function(trigger_obj)
	print('Begin===>>', trigger_obj)
	local x, y, z = trigger_obj['x'], trigger_obj['y'], trigger_obj['z']
	local blockId, playerId = trigger_obj['blockid'], trigger_obj['eventobjid']

	if blockId==IDs.cutBoardxId or blockId==IDs.washTableId or blockId==IDs.waterTapxId then
		--Set up like Dig.End evnet can not get ID
		curr_playerid = trigger_obj['eventobjid']
		Block_DigEnded(trigger_obj)
		return
	end

	-- Get the current manual item ID
	local ret, toolIdx = Player:getCurToolID(playerId)
	if ret ~= ErrorCode.OK then return end

	-- 0、store block
	if blockId == IDs.storeBoxIdx then
	end

	-- 1、The current square is a funnel->Click to get points
	local isSpecialDish = toolIdx==IDs.emptyDishId or blockId==IDs.dirtyDishId
	if (blockId==IDs.funnelBlkId or blockId==IDs.arrowheadId) and 
		not isSpecialDish and KeyInTable(toolIdx, DishBlks) then
		local cur_stage = CurrStage.stage
		local fpos = GameSData[cur_stage].fpos
		local isStagePos = false
		for idx = 1, #fpos do --Check the place
			print('Click2===>>>', x,y,z, fpos)
			if x==fpos[idx].x and z==fpos[idx].z and (y==fpos[idx].y or y==fpos[idx].y-1 or y==fpos[idx].y+1) then
				isStagePos = true;
				break
			end
		end

		if not isStagePos then return end
		Player:onCurToolUsed(playerId, 1)

		local seqId = threadpool:delay(5, GensDirtyDish)
		local seqSize = #CurrStage.seqids
		CurrStage.seqids[seqSize+1] = seqId

		-- Bonus points for delivery
		local csize = #CurrStage.clocks
		if csize <= 0 then return end
		for idx = 1, csize do --return after deleted
			local clock = CurrStage.clocks[idx]
			local goalIdx = clock.goal --target ID
			if goalIdx == toolIdx then
				TargetHited(clock)

				clock.stop = true--stop timing
				local delayRemove = function()
					return (function(cclock,cidx)
						ClockCrtOrDel(cclock, true)
						table.remove(CurrStage.clocks,cidx)
					end)(clock,idx)
				end
				local seqId1 = threadpool:delay(2, delayRemove)
				local seqSize = #CurrStage.seqids
				CurrStage.seqids[seqSize+1] = seqId1

				local randsec = math.random(3, 4)
				local seqId2 = threadpool:delay(randsec, TargetRefresh)
				local seqSize = #CurrStage.seqids
				CurrStage.seqids[seqSize+1] = seqId2

				-- more than 10sec get 2 points, within 10sec get 1 point
				local score = clock.time>10 and 2 or 1
				-- put it back to see if pass
				TeamAddScore(teamIdx, score)
				return
			end
		end

		--Error delivery returns with a tip
		local ret,num,players = World:getAllPlayers()
		if ret==ErrorCode.OK then
			for idx = 1, #players do
				local scoreTips = GameTips.windScore0
				Player:notifyGameInfo2Self(players[idx], scoreTips)
			end
		end
		return
	end

	-- 2、scene block->Put the dishes
	local isGameBlock = blockId==IDs.sceneBlk1Id or blockId==IDs.sceneBlk2Id
	if isGameBlock and KeyInTable(toolIdx, DishBlks) then
		Block:placeBlock(toolIdx, x, y+1, z)
		return
	end

	-- 3、dish block->Plate convert/fetch
	if KeyInTable(blockId, DishBlks) then
		-- 3.1、Click the plate empty-handed->get plate
		if toolIdx == 0 then
			local bType = BACKPACK_TYPE.SHORTCUT
			local ret = Player:gainItems(playerId, blockId, 1, bType)
			if ret==ErrorCode.OK then Block:setBlockAll(x, y, z, 0) end
			return
		end

		-- 3.2、Hold the food+click the plate->Corresponding delivery block
		if KeyInTable(toolIdx, FoodIDs) then
			local newBlockId = FinalIDs[toolIdx][blockId]
			if newBlockId ~= nil then --There are output items that can be converted
				local ret = Block:setBlockAll(x, y, z, newBlockId)
				if ret == ErrorCode.OK then--consume hand-held items
					Player:onCurToolUsed(playerId, 1)
				end
			end
			return
		end
	end
end

--------Dig the end of the event--------
Block_DigEnded = function(trigger_obj)
	print('End1=======>>>', trigger_obj)
	local x, y, z = trigger_obj['x'], trigger_obj['y'], trigger_obj['z']
	local blockId, playerId = trigger_obj['blockid'], trigger_obj['eventobjid']

	-- Return directly if neither is obtained
	if not playerId and not curr_playerid then return end

	--DigEnd event did not reture objid
	if playerId == nil then playerId = curr_playerid end
	curr_playerid = nil --replace after used
	
	local cur_stage = CurrStage.stage
	local tools = GameSData[cur_stage].tools
	print('End2=======>>>', tools, cur_stage, playerId)
	-- Step to make items:machining=>New item
	if tools[blockId] ~= nil then --Cut potatoes/rack of lamb..
		local ret, toolId = Player:getCurToolID(playerId)
		if ret == ErrorCode.OK then
			for idx=1, #tools[blockId] do--Traversal search
				local retFood = tools[blockId][idx]
				local outputId = retFood[toolId]
				if outputId ~= nil then --matching outputs and replacing items
					local ret = Player:onCurToolUsed(playerId, 1)
					if ret == ErrorCode.OK then
						local bType = BACKPACK_TYPE.SHORTCUT
						Player:gainItems(playerId, outputId, 1, bType)
					end
				end
			end
		end
	end
end

-- Mobile can not distinguish keys of left and right 
Block_PlaceBy = function(trigger_obj)
	print('Place=======>>>', trigger_obj)
	local x, y, z = trigger_obj['x'], trigger_obj['y'], trigger_obj['z']
	local blockId, playerId = trigger_obj['blockid'], trigger_obj['eventobjid']

	-- 1、The block is a funnel->Click deliver and get the score
	local isSpecialDish = blockId==IDs.emptyDishId or blockId==IDs.dirtyDishId
	if not isSpecialDish and KeyInTable(blockId, DishBlks) then
		local cur_stage = CurrStage.stage
		local fpos = GameSData[cur_stage].fpos
		local isStagePos = false
		for idx = 1, #fpos do --check the place
			if x==fpos[idx].x and z==fpos[idx].z and (y==fpos[idx].y or y==fpos[idx].y-1 or y==fpos[idx].y+1) then
				isStagePos = true;
				break
			end
		end
		print('Place==>>>', isStagePos)
		-- Return if it is a wrong place 
		if not isStagePos then return end
		Block:destroyBlock(x, y, z, false)

		--Generates dirty disks with a delay of 5 seconds and cancels if it goes to the next level
		local seqId = threadpool:delay(5, GensDirtyDish)
		local seqSize = #CurrStage.seqids
		CurrStage.seqids[seqSize+1] = seqId

		-- Bonus points for delivery
		local csize = #CurrStage.clocks
		if csize <= 0 then return end
		for idx = 1, csize do --return after deleted
			local clock = CurrStage.clocks[idx]
			local goalIdx = clock.goal --target ID
			if goalIdx == blockId then
				TargetHited(clock)

				clock.stop = true--Timing stop
				local delayRemove = function()
					return (function(cclock,cidx)
						ClockCrtOrDel(cclock, true)
						table.remove(CurrStage.clocks,cidx)
					end)(clock,idx)
				end
				local seqId1 = threadpool:delay(2, delayRemove)
				local seqSize = #CurrStage.seqids
				CurrStage.seqids[seqSize+1] = seqId1

				local randsec = math.random(3, 4)--Random refresh within 3 seconds
				--Delay refresh request within 3 seconds and cancels if it goes to the next level
				local seqId2 = threadpool:delay(randsec, TargetRefresh)
				local seqSize = #CurrStage.seqids
				CurrStage.seqids[seqSize+1] = seqId2

				-- 10sec more get 2 points, in 10sec get 1 point
				local score = clock.time>10 and 2 or 1
				-- put it back to see if can pass
				TeamAddScore(teamIdx, score)
				return
			end
		end

		--return if error delivery
		local ret,num,players = World:getAllPlayers()
		if ret==ErrorCode.OK then --Get all players correctly
			for idx = 1, #players do --Give tips to all players
				local scoreTips = GameTips.windScore0
				Player:notifyGameInfo2Self(players[idx], scoreTips)
			end
		end
		return
	end
end

--Registered Listening event
function ListenEvents_MiniCook()
	InitGameData()

	--Listening for game events
	ScriptSupportEvent:registerEvent([=[Game.Start]=], Game_Start)
	ScriptSupportEvent:registerEvent([=[Game.Run]=], Game_RunTime)
	ScriptSupportEvent:registerEvent([=[Game.End]=], Game_Over)
	ScriptSupportEvent:registerEvent([=[Game.TimeOver]=], Game_Tout)
	ScriptSupportEvent:registerEvent([=[Player.Init]=], Player_Init)

    --Event trigger condition-Begin to mining block
    local bgConsIds = {IDs.sceneBlk1Id, IDs.sceneBlk2Id, IDs.storeBoxIdx, IDs.funnelBlkId, IDs.arrowheadId}
    for idx=1, #DishBlks do bgConsIds[#bgConsIds+1] = DishBlks[idx] end

    --Event trigger condition-End mining block
    local egConsIds = {IDs.cutBoardxId, IDs.washTableId, IDs.waterTapxId}
    for idx=1, #egConsIds do bgConsIds[#bgConsIds+1] = egConsIds[idx] end

    --Listening for block events
	ScriptSupportEvent:registerEvent_Block([=[Player.ClickBlock]=], Block_DigBegin, bgConsIds)
	ScriptSupportEvent:registerEvent_Block([=[Block.PlaceBy]=], Block_PlaceBy, bgConsIds)
	--ScriptSupportEvent:registerEvent_Block([=[Block.Dig.Begin]=], Block_DigBegin, bgConsIds)
	--ScriptSupportEvent:registerEvent_Block([=[Block.Dig.End]=], Block_DigEnded, egConsIds)
end

-- Listening for events
ListenEvents_MiniCook()
end)()
Last Update: 9/9/2019, 5:57:21 PM