# Color Fight

local Chat = class.Chat.new();
local World = class.World.new();
local Player = class.Player.new();
local Block = class.Block.new();
local Team = class.Team.new();
local MiniTimer = class.MiniTimer.new();
local Area = class.Area.new();
local Item = class.Item.new();
local Backpack = class.Backpack.new();
local Actor = class.Actor.new();
local Creature = class.Creature.new();


local TimeId = 0;
local CurTime = 0;
local AreaID = 0;
local TimingBomb = 4114;
local Bomb = 1014;
local WhiteBlockid = 667;
local NeglectBombBlockid = {0,991,992,993,994,995,996,997,TimingBomb,Bomb};
local NeglectDyeingBlockid = {0,997,991,992,993,994,995,996,1113,801,TimingBomb,Bomb };

local propGroupConfig = {
    initPropGroup = {
        num = 15,
        {itemid = 4097,num = 1,},
    },
    addPropGroup = {
        num = 3,
        {itemid = 1014,num = 1,},
    }
}


function is_intable(value, tab)
    if tab == nil then
        return false;
    end
    for k,v in pairs(tab) do
        if v == value then
            return true
        end
    end
    return false
end


function blastDyeing(param)
    local x,y,z = param.x,param.y,param.z;
    local tempx,tempy,tempz = 0,0,0;
    local positionBlockid = 0;
    if param.blockid == TimingBomb then
        for i = 1, 5 do
            for j = 1, 5 do
                for k = 1, 3 do
                    tempx = (x-1)+i-1;
                    tempy = (y-1)+j-1;
                    tempz = (z-1)+k-1;
                    _,positionBlockid = Block:getBlockID(tempx,tempy,tempz);
                    if not is_intable(positionBlockid,NeglectBombBlockid)  then
                        if positionBlockid == 1113 or positionBlockid == 801 then
                            Block:setBlockAll(tempx,tempy,tempz,positionBlockid);
                        else
                            Block:setBlockAll(tempx,tempy,tempz,WhiteBlockid);
                        end
                    end
                end
            end
        end
    elseif param.blockid == Bomb then
        for i = 1, 3 do
            for j = 1, 3 do
                for k = 1, 3 do
                    tempx = (x-1)+i-1;
                    tempy = (y-1)+j-1;
                    tempz = (z-1)+k-1;
                    _,positionBlockid = Block:getBlockID(tempx,tempy,tempz);
                    if not is_intable(positionBlockid,NeglectBombBlockid)  then
                        if positionBlockid == 1113 or positionBlockid == 801 then
                            Block:setBlockAll(tempx,tempy,tempz,positionBlockid);
                        else
                            Block:setBlockAll(tempx,tempy,tempz,WhiteBlockid);
                        end
                    end
                end
            end
        end
    end
end

local monsterMgr = {
    spiderinfo = {},
    monsterGroup = {actorid = 3107, num = 5},
    spiderMaxNum = 20,
    spiderRefreshPoint = {
        {x=10,y=8,z=1},
        {x=8,y=2,z=8},
        {x=6,y=11,z=21},
        {x=-5,y=8,z=7},
        {x=-2,y=5,z=-1},
		{x=-16,y=6,z=5},
		{x=-13,y=8,z=23},
		{x=-16,y=12,z=16},
    },
    hunterId =3;
    hunterAreaID =0,
    hunterAreapos = {x=8,y=13,z=8},

    init = function(self)
        _,self.hunterAreaID = Area:createAreaRect(self.hunterAreapos,{x=3,y=3,z=3});
    end,

    createAGroupMonster = function(self)
        local RefreshPointnum = #(self.spiderRefreshPoint);
        local num = math.modf(RefreshPointnum/self.monsterGroup.num);
        Chat:sendSystemMsg("Dango are destroying the graffiti, rush them away! ");
        for k, v in pairs(self.spiderRefreshPoint) do
            if (#self.spiderinfo) < self.spiderMaxNum then
                World:spawnCreature(v.x, v.y, v.z, self.monsterGroup.actorid, num);
            end
        end
    end,

    addSpider = function(self,objid)
        self.spiderinfo[objid] = {};
    end,

    removeSpider = function(self,objid)
        self.spiderinfo[objid] = nil;
    end,

    update = function(self)
        local ret,creaturesGroup = Area:getAreaCreatures(self.hunterAreaID);
        local isexistence = true;
        if ret == ErrorCode.OK then
            for k, v in pairs(creaturesGroup) do
                local _,name = Creature:getActorName(v);
                if name == "color hunter"  then
                    isexistence = false;
                end
            end
        end
        if isexistence then
            World:spawnCreature(self.hunterAreapos.x, self.hunterAreapos.y, self.hunterAreapos.z,self.hunterId,1);
            Chat:sendSystemMsg("Beat the monsters destroying the graffiti! ");
        end

        local info = self.spiderinfo;
        for k, v in pairs(info) do
            local ret,x,y,z = Actor:getPosition(k);
            if ret == ErrorCode.OK then
                local _,positionblockid = Block:getBlockID(x-x%1,(y-y%1)-1,z-z%1);
                if not is_intable(positionblockid,NeglectDyeingBlockid) then
                    Block:setBlockAll(x-x%1,(y-y%1)-1,z-z%1,WhiteBlockid);
                end
            end
        end
    end,
}

local playerMgr = {
    allPlayers = {},
    playerTeam = {},
    blockid = {
        681,
        678,
        680,
        671,
        668,
        677,
    },
    itemid = {
        [1] = {slingshotid = 4098,zulletid = 4099},
        [2] = {slingshotid = 4106,zulletid = 4102},
        [3] = {slingshotid = 4107,zulletid = 4103},
        [4] = {slingshotid = 4100,zulletid = 4101},
        [5] = {slingshotid = 4108,zulletid = 4104},
        [6] = {slingshotid = 4109,zulletid = 4105},
    },
    propGroupConfig = {},
    isinit = false;
    init = function(self)
        self.isinit = true;
        _,_,self.allPlayers = World:getAllPlayers(-1);
        self.propGroupConfig = propGroupConfig;
        for i = 1, #self.allPlayers do
            local _,teamId = Player:getTeam(self.allPlayers[i]);
            local playerId = self.allPlayers[i];
            if self.playerTeam[teamId] == nil then
                self.playerTeam[teamId] = {};
                self.playerTeam[teamId].num = 0;
            end
            if self.playerTeam[teamId].blockid == nil then
                self.playerTeam[teamId].blockid = self.blockid[teamId];
            end
            if self.playerTeam[teamId].itemid == nil then
                self.playerTeam[teamId].itemid = self.itemid[teamId].zulletid;
            end
            self.playerTeam[teamId][playerId] = {};

            self:distributionOfProps(playerId,{{itemid = self.itemid[teamId].slingshotid,num = 1}});
            self:distributionOfProps(playerId,self.propGroupConfig.initPropGroup);
        end
    end,


    addPlayer = function(self,uin)
        local _,teamId = Player:getTeam(uin);
        if self.playerTeam[teamId] == nil then
            self.playerTeam[teamId] = {};
            self.playerTeam[teamId].num = 0;
        end
        if self.playerTeam[teamId].blockid == nil then
            self.playerTeam[teamId].blockid = self.blockid[teamId];
        end
        if self.playerTeam[teamId].itemid == nil then
            self.playerTeam[teamId].itemid = self.itemid[teamId].zulletid;
        end

        if self.isinit and self.playerTeam[teamId][uin] == nil then
            self.playerTeam[teamId][uin] = {}

            self:distributionOfProps(uin,{{itemid = self.itemid[teamId].slingshotid,num = 1}});
            self:distributionOfProps(uin,self.propGroupConfig.initPropGroup);
        end
    end,

    removePlayer = function(self,uin)
        if self.isinit then
            for k, v in pairs(self.playerTeam) do
                if v[uin] ~= nil then
                    self.playerTeam[k][uin] = nil;
                end
            end
        end
    end,


    distributionOfProps = function(self,playerid,itemtab)
        local _,teamid = Player:getTeam(playerid);
        if itemtab.num then
            Player:gainItems(playerid,self:getTeamItemid(teamid),itemtab.num,1)
        end
        for k, v in pairs(itemtab) do
            if k ~= "num" then
                Player:gainItems(playerid,v.itemid,v.num,1)
            end
        end
    end,

    addFraction = function(self,blockid)
        for k, v in pairs(self.playerTeam) do
            if v.blockid and v.blockid == blockid then
                v.num = v.num+1;
                Team:setTeamScore(k,v.num);
                local groupNum = v.num/50;
                if not (math.floor(groupNum)<groupNum) then
                    for i = 1, groupNum do
                        monsterMgr:createAGroupMonster();
                    end
                end
            end
        end
    end,

    reduceFraction = function(self,blockid)
        for k, v in pairs(self.playerTeam) do
            if v.blockid and v.blockid == blockid then
                v.num = v.num-1;
                Team:setTeamScore(k,v.num);
            end
        end
    end,

    moveDyeing = function(self,param)
        local _,x,y,z = Player:getPosition(param.eventobjid);
        local _,playerteamid = Player:getTeam(param.eventobjid)
        local teamblockid = self:getTeamBlockid(playerteamid);
        local _,positionblockid = Block:getBlockID(x-x%1,(y-y%1)-1,z-z%1);
        if not is_intable(positionblockid,NeglectDyeingBlockid) then
            Block:setBlockAll(x-x%1,(y-y%1)-1,z-z%1,teamblockid);
        end
    end,

    getTeamBlockid = function(self,teamid)
        return self.playerTeam[teamid].blockid;
    end,

    getTeamItemid = function(self,teamid)
        return self.playerTeam[teamid].itemid;
    end,

    getAllPlayers = function(self)
        _,_,self.allPlayers = World:getAllPlayers(-1);
        return self.allPlayers;
    end,
}
local startMgr = {
    startinfo = {},

    addStartInfo = function(self,param)
        param.time = CurTime;
        table.insert(self.startinfo,param);
    end,


    supplyingPropsOfStars = function(self)
        local allPlayers = playerMgr:getAllPlayers();
        local playerScore = 0;
        local teamid = 0;
        local teamScore = 0;
        for k, v in pairs(allPlayers) do
            _,playerScore = Player:getGameScore(v);
            _,teamid = Player:getTeam(v);
            _,teamScore = Team:getTeamScore(teamid);
            if playerScore >= 1 then
                Player:setGameScore(v,0);
                Team:setTeamScore(teamid,teamScore - playerScore)
                playerMgr:distributionOfProps(v,propGroupConfig.addPropGroup);
            end
        end
    end,

    update = function(self)
        for k, v in pairs(self.startinfo) do
            if CurTime - v.time >= 20 then
                Block:setBlockAll(v.x,v.y,v.z,v.blockid);
                table.remove(self.startinfo,k);
            end
        end
    end,
}
local timingBombMgr = {
    bombData = {},
    countDownTime = 30;
    bombRefreshTime = 90;
    bombinfo = {itemid = TimingBomb,timerid = 0, time = 0};

    addBombto = function(self,uin,info)
        Player:notifyGameInfo2Self(uin,"Threw the time bomb to other players! ");
        Player:gainItems(uin,info.itemid, 1,1)
        _,info.timerid = MiniTimer:createTimer(uin)
        MiniTimer:startBackwardTimer(info.timerid,info.time,false);
        local _,_,allPlayers = World:getAllPlayers(-1);
        MiniTimer:showTimerTips(allPlayers,info.timerid,"Time bomb timer: ",true);

        local _,playerName = Player:getNickname(uin);
        Chat:sendSystemMsg("Player ".. "[ " .. playerName .. "] ".."Got the time bomb timer. Run now! ");
        self.bombData[uin] = info;
        Actor:addBuff(uin,4,4);
        return true;
    end,

    removeBombto = function(self,uin)
        if self.bombData and self.bombData[uin] then
            local _,_,allPlayers = World:getAllPlayers(-1);
            MiniTimer:showTimerTips(allPlayers,self.bombData[uin].timerid,"Timer time ",false);
            MiniTimer:deleteTimer(self.bombData[uin].timerid);
            self.bombData[uin] = nil;
            Actor:removeBuff(uin,4);
        end
    end,

    transferBombto = function(self,curuin,otheruin)
        local tempinfo = self.bombinfo;
        local ret = Backpack:hasItemByBackpackBar(curuin,BACKPACK_TYPE.SHORTCUT,tempinfo.itemid);
        local ret1 = Backpack:hasItemByBackpackBar(curuin,BACKPACK_TYPE.INVENTORY,tempinfo.itemid);
        if not (ret == ErrorCode.OK or ret1 == ErrorCode.OK) then
            return false;
        end
        if otheruin and self.bombData[curuin] then
            tempinfo = self.bombData[curuin];
            Backpack:removeGridItemByItemID(curuin,tempinfo.itemid)
            self:removeBombto(curuin);
            Player:notifyGameInfo2Self(curuin,"Successfully throw the bomb to others! ");
            self:addBombto(otheruin,tempinfo);
            return true;
        else
            tempinfo.time = self.countDownTime;
            return self:addBombto(curuin,tempinfo);
        end
    end,

    randomOneAddBombto = function(self)
        local tempinfo = self.bombinfo;
        tempinfo.time = self.countDownTime;
        local _,uin = World:randomOnePlayer(-1);
        if self.bombData[uin]== nil then
            self:addBombto(uin,tempinfo);
        else
            local  _,_,allPlayers = World:getAllPlayers(-1);
            for k, v in pairs(allPlayers) do
                if self.bombData[v]== nil then
                    self:addBombto(tempinfo);
                    break;
                end
            end
        end
    end,


    chenkBomb = function(self)
        for k, v in pairs(self.bombData) do
            local ret = Backpack:hasItemByBackpackBar(k,BACKPACK_TYPE.SHORTCUT,v.itemid);
            local ret1 = Backpack:hasItemByBackpackBar(k,BACKPACK_TYPE.INVENTORY,v.itemid);
            if not (ret == ErrorCode.OK or ret1 == ErrorCode.OK) then
                Player:gainItems(k,v.itemid,1,1);
            end
            if Actor:hasBuff(k,4004) ~= ErrorCode.OK then
                Actor:addBuff(k,4,4);
            end
        end
    end,

    getBombRefreshTime = function(self)
        return self.bombRefreshTime;
    end,

    update = function(self)
        for k, v in pairs(self.bombData) do
            _,self.bombData[k].time = MiniTimer:getTimerTime(self.bombData[k].timerid);
            if self.bombData[k].time == 10 then
                Chat:sendSystemMsg("10 seconds from the time bomb explosion. Everybody runs now!离定时炸弹爆炸还有10秒,大家快跑! ")
            end
            if self.bombData[k].time <= 0 then
                local _,x,y,z = Actor:getPosition(k);
                World:spawnProjectile(k,self.bombData[k].itemid,x,y,z,x,y,z,5);
                blastDyeing({blockid = self.bombData[k].itemid, x = (x-x%1),y = (y-y%1)-1,z = z-z%1});
                Backpack:removeGridItemByItemID(k,self.bombData[k].itemid)
                self:removeBombto(k);
            end
        end
        self:chenkBomb();
    end,
}




function listenevents_crazyGraffiti()

    ScriptSupportEvent:registerEvent([=[Game.Start]=],crazyGraffiti_gamestart);
    ScriptSupportEvent:registerEvent([=[Game.Run]=],crazyGraffiti_gamerun);
    ScriptSupportEvent:registerEvent([=[Block.Remove]=],crazyGraffiti_blockRemove);
    ScriptSupportEvent:registerEvent([=[Block.Add]=],crazyGraffiti_blockAdd);
    ScriptSupportEvent:registerEvent([=[Block.DestroyBy]=],crazyGraffiti_blockDestroyBy);
    ScriptSupportEvent:registerEvent([=[Player.MoveOneBlockSize]=],crazyGraffiti_PlayerMove);
    ScriptSupportEvent:registerEvent([=[DropItem.AreaIn]=],crazyGraffiti_DropItemAreaIn);
    ScriptSupportEvent:registerEvent([=[Player.ClickActor]=],crazyGraffiti_PlayerClickActor);
    ScriptSupportEvent:registerEvent([=[Game.AnyPlayer.EnterGame]=],crazyGraffiti_AnyPlayerEnterGame);
    ScriptSupportEvent:registerEvent([=[Game.AnyPlayer.LeaveGame]=],crazyGraffiti_AnyPlayerLeaveGame);
    ScriptSupportEvent:registerEvent([=[Actor.Create]=],crazyGraffiti_ActorCreate);
    ScriptSupportEvent:registerEvent([=[Actor.Die]=],crazyGraffiti_ActorDie);

end

function crazyGraffiti_gamerun()
    local _,time = MiniTimer:getTimerTime(TimeId);
    if CurTime ~= time then
        _,CurTime = MiniTimer:getTimerTime(TimeId);
        startMgr:update();
        timingBombMgr:update();
        monsterMgr:update();

        local timers = timingBombMgr:getBombRefreshTime();
        local intervalTime = CurTime % timers;
        if (timers - intervalTime) == 30 then
            Chat:sendSystemMsg("The time bomb is coming. Please pay attention ")
        end
        if intervalTime == 0 then
            timingBombMgr:randomOneAddBombto();
        end

    end

end

function crazyGraffiti_gamestart()
    Chat:sendSystemMsg("Games start! Get more colors for your team, rush! ");
    _,AreaID = Area:createAreaRect({x=-7, y=0, z=-2},{x=26,y=20,z=30})
    _,TimeId = MiniTimer:createTimer("Crazy graffiti ")
    TimeId = 1;
    MiniTimer:startForwardTimer(TimeId)

    playerMgr:init();
    monsterMgr:init();
end

function crazyGraffiti_blockAdd(param)
    playerMgr:addFraction(param.blockid);

end

function crazyGraffiti_blockRemove(param)
    playerMgr:reduceFraction(param.blockid);
    if param.blockid == 997 then
        startMgr:addStartInfo(param);
        startMgr:supplyingPropsOfStars();
    end
end

function crazyGraffiti_blockDestroyBy(param)

    if param.blockid == TimingBomb or param.blockid == Bomb then
        blastDyeing(param);
    else
        if not is_intable(param.blockid,NeglectBombBlockid) then
            if param.blockid == 1113 or param.blockid == 801 then
                Block:setBlockAll(param.x, param.y, param.z,param.blockid);
            else
                Block:setBlockAll(param.x, param.y, param.z,WhiteBlockid);
            end
        end
    end
end

function crazyGraffiti_PlayerMove(param)

    playerMgr:moveDyeing(param);
end

function crazyGraffiti_DropItemAreaIn(param)

    local _,itemid = Item:getItemId(param.eventobjid);
    if itemid == TimingBomb then
        World:despawnItemByObjid(param.eventobjid);
        timingBombMgr:chenkBomb();
    end

end

function crazyGraffiti_PlayerClickActor(param)

    if Actor:isPlayer(param.toobjid) == ErrorCode.OK then
        timingBombMgr:transferBombto(param.eventobjid,param.toobjid);
    end
end

function crazyGraffiti_AnyPlayerEnterGame(param)

    playerMgr:addPlayer(param.eventobjid);
end

function crazyGraffiti_AnyPlayerLeaveGame(param)

    playerMgr:removePlayer(param.eventobjid);
    timingBombMgr:removeBombto(param.eventobjid);
end

function crazyGraffiti_ActorCreate(param)

    local _,name = Creature:getActorName(param.eventobjid);
    if name == "Spiderling" then
        monsterMgr:addSpider(param.eventobjid);
    end
end

function crazyGraffiti_ActorDie(param)
    local _,name = Creature:getActorName(param.eventobjid);
    if name == "Spiderling" then
        monsterMgr:removeSpider(param.eventobjid);
    end

end

istenevents_crazyGraffiti()
Last Update: 9/9/2019, 5:57:21 PM