# Tank Battle

return (function()

local X, Y, Z = 0, 0, 0 
local Map_Wid, Map_Len = -1,-1 

local Players = {} 
local PlayerPos = {} 
local TmCityPos = {} 
local TmCityIdx = -1 

local tickCount = 0   
local newTicker = 20  
local isGameEnded = false 
local isGameStart = false 
local isGRuleInit = false 

local bulletIdx = 15003
local LoserIdx = -1 
local itemcTime = 0 

local wpBlocks = {[408]={idx=15000, num=1}, [409]={idx=15005, num=1},
				  [450]={idx=15003, num=64}, [410]={idx=15004, num=1}}
local bufItems = {11023, 11024, 11025, 11015} 
local itemObjIds = {} 
local wpBlockPos = {} 

local Teamx = {red=1, blue=2} 
local Gamex = {win=1, lose=2} 
local CellType = {def=1, river=2, wall=3, point=4, city=5}   
local TmEffects = {[Teamx.red]={glEffectId=-1, lastTime = 0},
				   [Teamx.blue]={glEffectId=-1, lastTime = 0}}

-----------------地图相关-----------------
local datax_map = [[19,23,,,,,,,,,,,,
*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*
*,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,*
*,c,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,c,*
*,c,q,0,0,0,0,y,m,x,0,0,0,0,0,0,q,c,*
*,c,q,0,0,0,r,x,x,x,r,0,0,0,0,0,q,c,*
*,c,q,0,0,0,0,0,0,0,0,0,0,0,0,0,q,c,*
*,c,q,0,0,0,0,0,0,0,u,u,u,u,u,u,q,c,*
*,c,q,x,y,y,x,x,q,v,v,v,v,v,v,v,q,c,*
*,c,q,0,0,0,0,w,w,w,w,w,w,w,w,w,q,c,*
*,c,q,0,0,0,0,y,0,0,u,y,u,u,u,0,q,c,*
*,c,q,0,y,0,y,0,0,y,0,0,y,0,0,0,q,c,*
*,c,q,0,0,0,q,y,0,0,0,y,q,0,0,0,q,c,*
*,c,q,0,0,0,y,0,0,y,0,0,y,0,y,0,q,c,*
*,c,q,0,u,u,u,y,u,0,0,y,0,0,0,0,q,c,*
*,c,q,w,w,w,w,w,w,w,w,w,0,0,0,0,q,c,*
*,c,q,v,v,v,v,v,v,v,q,x,x,y,y,x,q,c,*
*,c,q,u,u,u,u,u,u,0,0,0,0,0,0,0,q,c,*
*,c,q,0,0,0,0,0,0,0,0,0,0,0,0,0,q,c,*
*,c,q,0,0,0,0,0,b,x,x,x,b,0,0,0,q,c,*
*,c,q,0,0,0,0,0,0,x,m,y,0,0,0,0,q,c,*
*,c,q,q,q,q,q,q,q,q,q,q,q,q,q,q,q,c,*
*,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,c,*
*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*]]

function GetCellIdx(ccType)
	local cellIdx = -1 

	if ccType == "q" then cellIdx = 1   	
	elseif ccType == "c" then cellIdx = 8   
	elseif ccType == "*" then cellIdx = 678 
	elseif ccType == "r" then cellIdx = 991 
	elseif ccType == "b" then cellIdx = 992 
	elseif ccType == "u" then cellIdx = 218 
	elseif ccType == "v" then cellIdx = 221 
	elseif ccType == "x" then cellIdx = 502 
	elseif ccType == "y" then cellIdx = 101 
	elseif ccType == "m" then cellIdx = 254 
	elseif ccType == "w" then cellIdx = 3 end

	return cellIdx
end
TmCityIdx = GetCellIdx('m')

function InitMapData()
	local MapData = {} 

	MapData['offset_x'] = 100
	MapData['offset_z'] = 100

	local datax = {}
	local listm = string.split(datax_map, "\n")
	for idx, line in pairs(listm) do
		if idx == 1 then 
			local iter = string.gmatch(line, "(%d+),")
			MapData['width'] = iter()
			MapData['height'] = iter()
		else 
			datax[idx-1] = string.split(line, ",")
		end
	end
	MapData['data'] = datax

	return MapData
end
-----------------工具类函数-----------------
function string.split(str, mark)
 	if string.len(str)==0 then return nil end

	local sIdx, tsub = 1, {}
	while true do 
		local pos = string.find(str, mark, sIdx, true)
	   	if not pos then break end

	    table.insert(tsub, string.sub(str, sIdx, pos-1))
	    sIdx = pos + string.len(mark)
	end
  	table.insert (tsub, string.sub(str, sIdx))

	return tsub
end
function table.keys(tab)
    local keys = {}
    for key, val in pairs(tab) do
        keys[#keys+1] = key
    end
    return keys
end

-----------------自定义函数-----------------
function InitCenterPoint()
	local ret = -1
	ret, X, Y, Z = Spawnport:getSpawnPoint()

	if Y==0 then Y = 6 end
end

function InitColorBlock()

	local blockIdx = 737
	Block:setBlockAll(0, Y+1, 0, blockIdx)
	--408, 409, 450--
	local blocks = table.keys(wpBlocks)
	Block:setBlockAll(-1, Y+1, -1, blocks[1])
	Block:setBlockAll(-1, Y+1, -2, blocks[2])

	Block:setBlockAll(-3, Y+1, -3, blocks[3])

	Block:setBlockAll(-5, Y+1, -5, 1037)
	Block:setBlockAll(-5, Y+1, -6, 1038)
	if true then return end

	local xPos = 1
	for idx = 667, 682 do
		xPos = xPos + 1
		local zPos = 1
		for data = 0, 15 do
			zPos = zPos + 1
			Block:setBlockAll(xPos, Y+1, zPos, idx, data)
		end
	end
end

function InitGameMaps(...)
	local data_map = InitMapData()
	if not data_map['data'] then return end

	local step = 1
	local floorIds = {421, 425}
	local ccdata = data_map['data']
	Map_Wid = tonumber(data_map['width'])
	Map_Len = tonumber(data_map['height'])
	for idx = 1, Map_Len do
		local xPos = X+(idx-1)*2+1
		step = step + 2
		for jdx = 1, Map_Wid do
			local zPos = Z+(jdx-1)*2+1

			step = step + 1 
			mod = math.mod(step, 2)
			local floorId = floorIds[mod+1]

			local ccType = ccdata[idx][jdx]
			local cellIdx = GetCellIdx(ccType)

			local cellType = CellType.def
			if ccType=='w' then cellType = CellType.river end 
			if ccType=='*' then cellType = CellType.wall end 
			if ccType=='r' or ccType=='b' then cellType = CellType.point end 
			if ccType=='m' then cellType = CellType.city end 

			if cellType~=CellType.city then
				InitMapCell(cellIdx, xPos, zPos, floorId, cellType)
			else 
				drawBigTree(cellIdx, 255, xPos, 0, zPos)
				TmCityPos[#TmCityPos+1] = {xPos=xPos, zPos=zPos}
				if not TmEffects[Teamx.red].xPos then
					TmEffects[Teamx.red].xPos = xPos
					TmEffects[Teamx.red].zPos = zPos
				else
					TmEffects[Teamx.blue].xPos = xPos
					TmEffects[Teamx.blue].zPos = zPos
				end
			end

		end
	end
end

function InitMapCell(cellId, cxPos, czPos, floorId, cellType)
	for xPos = cxPos-1, cxPos do
		for zPos = czPos-1, czPos do
			Block:setBlockAll(xPos, Y, zPos, floorId)
		end
	end
	if cellId <= 0 then return end

	if cellType==CellType.point then
		if czPos < Map_Wid then czPos = czPos+1 end
		local playPos = {x=cxPos-1, y=Y+1, z=czPos-1}
		Block:setBlockAll(playPos.x, playPos.y, playPos.z, cellId)
		PlayerPos[#PlayerPos+1] = playPos
		return
	end

	local cyPos = cellType==CellType.river and Y-1 or Y+1
	for yPos = cyPos, cyPos+1 do
		for xPos = cxPos-1, cxPos do
			for zPos = czPos-1, czPos do
				Block:setBlockAll(xPos, yPos, zPos, cellId)
			end
		end
	end

	if cellType==CellType.river or cellType==CellType.wall then
		local cyPos = cellType==2 and Y+1 or Y+3
		local blkIdx = cellType==2 and 1018 or 1001
		for yPos = cyPos, cyPos+1 do 
			for xPos = cxPos-1, cxPos do
				for zPos = czPos-1, czPos do
					Block:setBlockAll(xPos, yPos, zPos, blkIdx)
				end
			end
		end
	end
end

function drawBigTree(trunkId, leafId, cx, cy, cz)

	local direct = 4
	local tyPos = 0 
	local txP1, txP2 = X+cx-1, X+cx
	local tzP1, tzP2 = Z+cz-1, Z+cz

	for idx = 1, 10 do
		tyPos = Y + cy + idx
		for xPos = txP1, txP2 do
			for zPos = tzP1, tzP2 do
				Block:placeBlock(trunkId, xPos, tyPos, zPos, direct)
			end
		end
	end

	for level = 3, -3, -1 do
		direct = 0 
		local yPos = tyPos+1-level
		for idx = 1, level do 
			for xPos = txP1-idx, txP2+idx do
				for zPos = tzP1-idx, tzP2+idx do
					local isXInTrunk = xPos>txP1 and xPos<txP2
					local isYInTrunk = zPos>tzP1 and zPos<tzP2
					if not (isXInTrunk and isXInTrunk) then
						Block:placeBlock(leafId, xPos, yPos, zPos, direct)
					end
				end
				direct = direct + 2
				if direct>6 then direct = 0 end
			end
		end

		if level <= 0 then 
			for xPos = txP1-level, txP2+level do
				for zPos = tzP1-level, tzP2+level do
					Block:placeBlock(leafId, xPos, yPos, zPos, direct)
				end
				direct = direct + 2
				if direct>6 then direct = 0 end
			end
		end
	end
end

function InitPlayerData(playerId)
	if not isGameStart then return end

	local itemId, itemCnt = 15004, 1 
	Player:gainItems(playerId, itemId, itemCnt, 1)
	local itemId, itemCnt = 15002, 1 
	Player:gainItems(playerId, itemId, itemCnt, 1)
	local itemId, itemCnt = 15003, 64*3
	Player:gainItems(playerId, itemId, itemCnt, 1)

	-- local itemId, itemCnt = 15002, 1
	-- Player:gainItems(playerId, itemId, itemCnt, 1)
	-- local itemId, itemCnt = 15004, 1
	-- Player:gainItems(playerId, itemId, itemCnt, 1)
	-- local itemId, itemCnt = 15005, 1
	-- Player:gainItems(playerId, itemId, itemCnt, 1)
end

function InitGameRule()
	isGRuleInit = true
	GameRule.EndTime = 6  		 
	GameRule.TeamNum = 2         
	GameRule.TimeLocked = 1  	 
	GameRule.MaxPlayers = 4      
	GameRule.CameraDir = 1       
	GameRule.StartMode = 0       
	GameRule.StartPlayers = 1    
	GameRule.PlayerDieDrops = 1  
	GameRule.DisplayScore = 1    
	GameRule.AllowMidwayJoin = 1 
	GameRule.ScoreKillPlayer = 1 
	GameRule.BlockDestroy = 1    
	GameRule.WinLoseEndTime = 1  
end

function IsCanTick()
	tickCount = tickCount+1

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

	return false
end

function GetPositionX(x1,x2,z1,z2)
	x1 = x1 or 3*2+1
	z1 = z1 or 3*2+1
	x2 = x2 or (Map_Len-3)*2
	z2 = z2 or (Map_Wid-3)*2

	local count = 1
	local ret, blkId = 0, 0
	local xPos, zPos = 0, 0
	while true do
		count = count + 1

		xPos = math.random(x1, x2)
		zPos = math.random(z1, z2)

		ret, blkId = Block:getBlockID(xPos, Y+1, zPos)
		if ret==ErrorCode.OK and blkId==0 then break end

		if count>99 then 
			print("Get Pos Error===>>>")
			return nil
		end
	end
	return xPos, zPos
end

function SetPositionPx(playerId)
	if not isGameStart then return end
	if not playerId or playerId<=0 then return end

	local ret, teamId = Player:getTeam(playerId)
	if ret ~= ErrorCode.OK then return end

	local index = 1
	for idx, val in pairs(Players) do
		if val==playerId then index=idx end
	end
	local teamTdx = teamId==Teamx.red and 0 or 1
	local playIdx = index + teamTdx
	playIdx = math.mod(playIdx-1, 4)+1 

	local playPos = PlayerPos[playIdx]
	if not playPos then playPos = PlayerPos[1] end
	Actor:setPosition(playerId, playPos.x+0.5, playPos.y, playPos.z+0.5);
end

function clearItems()
	for idx = 1, #wpBlockPos do
		local wpPos = wpBlockPos[idx]
		local ret, blockId = Block:getBlockID(wpPos.x, wpPos.y, wpPos.z)
		local ret = Block:destroyBlock(wpPos.x, wpPos.y, wpPos.z)
	end

	for idx = 1, #itemObjIds do
		local objId = itemObjIds[idx]
		local ret = World:despawnItemByObjid(objId)
	end

	wpBlockPos = {}
	itemObjIds = {}
end

function rgensItems(gType)
	if gType == 'T' then
		local ccIdx = math.random(1, #bufItems)
		local xPos, zPos = GetPositionX()
		local ret, objIds = World:spawnItem(xPos, Y+1, zPos, bufItems[ccIdx], 1)
		if ret==ErrorCode.OK then itemObjIds[#itemObjIds+1] = objIds end
		return
	end

	local blocks = table.keys(wpBlocks)
	if gType=='S' then 
		local xPos, zPos = GetPositionX()
		local ret = Block:setBlockAll(xPos, Y+1, zPos, blocks[#blocks])
		if ret == ErrorCode.OK then
			wpBlockPos[#wpBlockPos+1] = {x=xPos, y=Y+1, z=zPos}
		end
		return
	end

	local wpsz = #blocks-1
	local idx1 = math.random(1, wpsz)
	local idx2 = math.random(1, wpsz)

	while idx1==idx2 do
		idx2 = math.random(1, wpsz)
	end

	for idx = idx1, idx2, idx2-idx1 do
		local xPos, zPos = GetPositionX()
		local ret = Block:setBlockAll(xPos, Y+1, zPos, blocks[idx])
		if ret == ErrorCode.OK then
			wpBlockPos[#wpBlockPos+1] = {x=xPos, y=Y+1, z=zPos}
		end
	end
end

-----------------开发者事件-----------------
Game_Started = function()
	tickCount = 0
	itemcTime = 0
	isGameStart = true
	if not isGRuleInit then InitGameRule() end

	InitCenterPoint()
	InitGameMaps()

	local ret, playerId = Player:getMainPlayerUin()
	if ret~=ErrorCode.OK or playerId<=0 then return end

	Backpack:clearAllPack(playerId)
	Player:setTeam(playerId, Teamx.red)

	InitPlayerData(playerId)
	SetPositionPx(playerId) 

	local buffId = math.floor(999002/1000)
	Player:addBuff(playerId, buffId, 2, 10000)

	local buffId1 = math.floor(27003/1000)
	Player:addBuff(playerId, buffId1, 2, 500000)
end

Game_RunX = function()
	if isGameEnded then return end
	if not IsCanTick() then return end
	itemcTime = itemcTime + 1

	for idx = 1, #TmEffects do 
		local lastTime = TmEffects[idx].lastTime-1
		local glEffectId = TmEffects[idx].glEffectId
		if lastTime<=0 and glEffectId~=-1 then
			local ret = Game:removeRenderGlobalEffect(glEffectId)
		 	if ret == ErrorCode.OK then glEffectId = -1 end

		 	TmEffects[idx].glEffectId = glEffectId
		end
		TmEffects[idx].lastTime = lastTime
	end

	if math.mod(itemcTime, 50)==0 then rgensItems('S')
	elseif math.mod(itemcTime, 30)==0 then rgensItems('N')
	elseif math.mod(itemcTime, 15)==0 then clearItems() end

	local randVal = math.random(1, 100) 
	if math.mod(randVal, 16)==0 then rgensItems('T') end
end

Game_Ended = function()
	if LoserIdx > 0 then 
		local ret, playerId = Player:getMainPlayerUin()
		if ret~=ErrorCode.OK or playerId<=0 then return end
		local ret, teamId = Player:getTeam(playerId)
		if ret~=ErrorCode.OK or teamId<=0 then return end

		if LoserIdx==Teamx.blue then
			Battle_Ended(Teamx.red, Gamex.win)

			local strIdx = teamId==Teamx.red and 270 or 271
			local ret, txtInfox = Game:getDefString(strIdx)
			Chat:sendChat(txtInfox,  chatType)
		else
			Battle_Ended(Teamx.blue, Gamex.win)
			local strIdx = teamId==Teamx.blue and 270 or 271
			local ret, txtInfox = Game:getDefString(strIdx)
			Chat:sendChat(txtInfox,  chatType)
		end
	end
end

Game_TimeOver = function()

end

Player_Inited = function(args)
	if not isGRuleInit then InitGameRule() end

	local playerId = args['eventobjid']
	Players[#Players+1] = playerId

	local playerCount = #Players
	if math.mod(playerCount, 2)==1 then
		Player:setTeam(playerId, Teamx.red)
	else 
		Player:setTeam(playerId, Teamx.blue)
	end

	--[[	local ret1, rtNum = Team:getTeamPlayers(Teamx.red, -1)
	local ret2, btNum = Team:getTeamPlayers(Teamx.blue, -1)
	if ret1 ~= ErrorCode.OK or ret1 ~= ErrorCode.OK then return end

	if rtNum <= btNum then
		local ret = Player:setTeam(playerId, Teamx.red)
		if ret==ErrorCode.OK then PlayerTdx = rtNum+1 end
	else
		local ret = Player:setTeam(playerId, Teamx.blue)
		if ret==ErrorCode.OK then PlayerTdx = rtNum+1 end
	end
	--]]end

Player_JoinTeam = function(trigger_obj)
	local playerId = trigger_obj['eventobjid']

	if isGameStart then
		InitPlayerData(playerId)

		local ret, teamId = Player:getTeam(playerId)
		if teamId and teamId>0 then SetPositionPx(playerId) end
	end
end

Player_Dead = function(trigger_obj)
	local killById = trigger_obj['toobjid']
	local playerId = trigger_obj['eventobjid']

end

Player_Revive = function(trigger_obj)
	local playerId = trigger_obj['eventobjid']

	local buffId = math.floor(999002/1000)
	Player:addBuff(playerId, buffId, 2, 20*500)

	SetPositionPx(playerId)
	InitPlayerData(playerId)
end

BackPack_AddItem = function(trigger_obj)
	local itemId = trigger_obj['itemid']
	local itemNum = trigger_obj['itemnum']
	local playerId = trigger_obj['eventobjid']

	local lastTime = 0
	if itemId==bufItems[1] then lastTime=5
	elseif itemId==bufItems[2] then lastTime=10
	elseif itemId==bufItems[3] then lastTime=15
	elseif itemId==bufItems[4] then end

	if lastTime ~= 0 then
		local ret, teamId = Player:getTeam(playerId)
		local effectEntity = TmEffects[teamId]
		if effectEntity ~= nil then
			local oldTime = effectEntity.lastTime
			effectEntity.lastTime = oldTime+lastTime
			if effectEntity.glEffectId == -1 then
				local ret, glEffectId = Game:addRenderGlobalEffect("particles/Fog.ent")
				if ret==ErrorCode.OK and glEffectId >= 0 then
					Game:setRenderGlobalEffectPos(glEffectId, effectEntity.xPos, Y, effectEntity.zPos)
					Game:setRenderGlobalEffectScale(glEffectId, 1.25, 0.045, 1.25)
				end
			end
		end
	end
end

Block_Destroyed = function(trigger_obj)
	local blockId = trigger_obj.blockid
	local x, y, z = trigger_obj.x, trigger_obj.y, trigger_obj.z

	local item = wpBlocks[blockId]
	if item ~= nil then 
		local ret, objIds = World:spawnItem(x, y, z, item.idx, item.num)
		if ret==ErrorCode.OK then itemObjIds[#itemObjIds+1] = objIds end

	end

	if blockId==TmCityIdx then 
		for idx = 1, #TmCityPos do
			local cityIsDestry = true
			local cxPos = TmCityPos[idx].xPos
			local czPos = TmCityPos[idx].zPos
			for yPos=Y+1, Y+2 do
				for xPos=cxPos-1, cxPos do
					for zPos=czPos-1, czPos do
						local ret, blkId= Block:getBlockID(xPos, yPos, zPos)
						if blkId == TmCityIdx then
							cityIsDestry = false
							break
						end
					end
				end
			end

			if cityIsDestry then
				LoserIdx = idx
				Game:doGameEnd()
				isGameEnded = true
				return
			end
		end
	end
end

function Battle_Ended(teamId, retType)
	if teamId == Teamx.red then
		Team:setTeamResults(Teamx.red, retType)
		Team:setTeamPlayersResults(Teamx.red, retType)
		local blueRet = (retType==Gamex.win and Gamex.lose) or Gamex.win
		Team:setTeamResults(Teamx.blue, blueRet)
		Team:setTeamPlayersResults(Teamx.blue, blueRet)
	elseif teamId == Teamx.blue then
		Team:setTeamResults(Teamx.blue, retType)
		Team:setTeamPlayersResults(Teamx.blue, retType)
		local redRet = (retType==Gamex.win and Gamex.lose) or Gamex.win
		Team:setTeamResults(Teamx.red, redRet)
		Team:setTeamPlayersResults(Teamx.red, redRet)
	end

	ShowGBattleUI() 
end

function ShowGBattleUI()
	local ret, rank = Player:getGameRanking()
	if not rank or rank==0 then rank = 1 end
    local ret, score = Player:getGameScore()

    local ret1, teamNum = Team:getNumTeam()
    local ret2, redNum = Team:getTeamPlayers(Teamx.red)
    local ret3, blueNum = Team:getTeamPlayers(Teamx.blue)
  	local totalPlayers = 1
  	if ret2==ErrorCode.OK and ret3==ErrorCode.OK then
  		totalPlayers = redNum+blueNum
  	end

  	local ret, txtTitle = Game:getDefString(rank==1 and 8028 or 8029)
  	local ret, txtTRank = Game:getDefString(8032)
  	local ret, txtRanker = Game:getDefString(8030)
  	local ret, txtDefeat = Game:getDefString(3176)
	UI:setGBattleUI('left_title', txtTRank..tostring(rank))
	UI:setGBattleUI('right_title', "/"..totalPlayers)
	UI:setGBattleUI('left_desc', txtTitle)
	UI:setGBattleUI('left_little_desc', txtRanker..tostring(rank))
	UI:setGBattleUI('right_little_desc', txtDefeat..tostring(score))
	UI:setGBattleUI('battle_btn', false)
	UI:setGBattleUI('result', false)
	UI:setGBattleUI('result_bkg', false)
	UI:setGBattleUI('reopen', true)
end

--添加监听事件--
ScriptSupportEvent:registerEvent([=[Game.Start]=], Game_Started)
ScriptSupportEvent:registerEvent([=[Game.Run]=], Game_RunX)
ScriptSupportEvent:registerEvent([=[Game.End]=], Game_Ended)
ScriptSupportEvent:registerEvent([=[Game.TimeOver]=], Game_TimeOver)

ScriptSupportEvent:registerEvent([=[Player.Init]=], Player_Inited)
ScriptSupportEvent:registerEvent([=[Player.Die]=], Player_Dead)
ScriptSupportEvent:registerEvent([=[Player.Revive]=], Player_Revive)
ScriptSupportEvent:registerEvent([=[Player.JoinTeam]=], Player_JoinTeam)
ScriptSupportEvent:registerEvent([=[Player.AddItem]=], BackPack_AddItem)

ScriptSupportEvent:registerEvent([=[Actor.Die]=], Monster_Dead)
ScriptSupportEvent:registerEvent([=[Block.DestroyBy]=], Block_Destroyed)

end)()

Last Update: 9/9/2019, 5:57:21 PM