--FUNCTIONS------------------------------------------------------------ local GemCoroutine function AddGemCoroutine(...) scene:AddCoroutineWithParams(GemCoroutine, ...) end GemCoroutine = function(actor) while (true) do actor:WaitRightClick() if (not switching and not falling and actor.col<=COLUMNS) then --Actor currently selected, de-select him --Broadcast("Clicking row "..actor.row..", col "..actor.col) if (actor.isSelected==true) then actor.isSelected = false selected = nil actor:ClearSpellVisual( actor.myVisual) actor:PlaySpellCastVisual(CLICK_CAST_B) else if (selected ~= nil) then local selectDeltaRow = math.abs(selected.row-actor.row) local selectDeltaCol = math.abs(selected.col-actor.col) selected.isSelected = false selected:ClearSpellVisual( selected.myVisual) if (selectDeltaRow+selectDeltaCol==1 and selected.dying==false) then actor:PlaySpellCastVisual(CLICK_CAST_B) Switch(actor, selected, false) else actor.isSelected = true actor.myVisual = actor:PlaySpellStateVisual(SELECTED_STATE) selected = actor actor:PlaySpellCastVisual(CLICK_CAST_A) end else actor.isSelected = true actor.myVisual = actor:PlaySpellStateVisual(SELECTED_STATE) selected = actor actor:PlaySpellCastVisual(CLICK_CAST_A) end end end end end function Switch(actorA, actorB, switchBack) --Broadcast("SWITCHING with column "..actorB.row..", column "..actorB.col) switching = true local posA = actorA:GetPosition() local posB = actorB:GetPosition() local distance = Vector.Magnitude(posA-posB) if distance<2*GEM_SPACING then local rowA,colA = actorA.row, actorA.col local rowB,colB = actorB.row, actorB.col local typeA,typeB = actorA.type, actorB.type local flyerDropA, flyerDropB = 0, 0 flyerDropA = DROPS[typeA] flyerDropB = DROPS[typeB] --actorA:MoveToAbs(posB, MOVE_TIME) --actorB:MoveToAbs(posA, MOVE_TIME) local gemOffsetA = Vector:New(0, colA*GEM_SPACING, (-rowA)*GEM_SPACING-flyerDropB) local gemOffsetB = Vector:New(0, colB*GEM_SPACING, (-rowB)*GEM_SPACING-flyerDropA) RideVehicleActor(actorA, playerDisplay, MOVE_TIME, AttachmentPoint.Head, sceneOffset+gemOffsetB, Vector:New(playerDisplay:GetTransform().yaw+180, 0, 0)) RideVehicleActor(actorB, playerDisplay, MOVE_TIME, AttachmentPoint.Head, sceneOffset+gemOffsetA, Vector:New(playerDisplay:GetTransform().yaw+180, 0, 0)) if switchBack then actorA:PlaySpellCastVisual(SLIDE_CAST_B) else actorA:PlaySpellCastVisual(SLIDE_CAST_A) end lastSwitchedA = actorA lastSwitchedB = actorB Wait(MOVE_TIME) gems[colA][rowA] = actorB gems[colB][rowB] = actorA actorA.row = rowB actorA.col = colB actorB.row = rowA actorB.col = colA --actorA:SetFacing(sceneFacing) --actorB:SetFacing(sceneFacing) falling = true switching = false if switchBack==false then selected = nil CheckForMatches(true) end end end function CheckForMatches(firstMove) local matchFound = false local maxGaps = 0 local gaps = {} for i=1, COLUMNS do table.insert(gaps, 0) end --Broadcast("=========================================================") local matchTable = {} local currentType = 0 local matchCount = 0 --Check vertical matches for i=1, COLUMNS do for j=1, ROWS do if gems[i][j]~= nil then local thisType = gems[i][j].type if thisType==currentType then matchCount = matchCount+1 --Broadcast("match") else --Broadcast("no match, current/this: "..currentType.."/"..thisType) currentType=thisType matchCount=0 end if matchCount==2 then --Broadcast("adding to delete table") GemDelete(gems[i][j-2]) function GemDelete(gem) local row = gem.row local col = gem.col if gem.deleted==false then gem.deleted=true for j=1,row-1 do if gems[col][j]~= nil then --Broadcast("Incrementing rows to fall") gems[col][j].rowsToFall = gems[col][j].rowsToFall + 1 end end end end function CreateGem(column, row, height) --Broadcast("Creating gem at col "..column..", row "..row..", height "..height) local type = math.random(#DISPLAY) gemCreateData.creatureDisplayID = DISPLAY[type] flyerDrop = DROPS[type] local gemOffset = Vector:New(0, column*GEM_SPACING, (height-row)*GEM_SPACING - flyerDrop) gemCreateData.transform = Transform:New(sceneOffset+gemOffset, playerDisplay:GetTransform().yaw+180, 0, 0) gems[column][row] = scene:SpawnActor(gemCreateData) gems[column][row]:SetInteractCursor("interact", CursorRange.RangeFromPlayer, 20, nil) gems[column][row].col = column gems[column][row].row = row gems[column][row].selected = false gems[column][row].myVisual = nil gems[column][row].type = type gems[column][row].deleted = false gems[column][row].rowsToFall = 0 gems[column][row].height = height gems[column][row].dying = false --gems[column][row]:SetFacingToTarget(playerDisplay, Vector:New()) RideVehicleActor(gems[column][row], playerDisplay, 0, AttachmentPoint.Head, sceneOffset+gemOffset, Vector:New(playerDisplay:GetTransform().yaw+180, 0, 0)) AddGemCoroutine(gems[column][row]) return gems[column][row] end function FaceForward() for i=1, COLUMNS do for j=1, ROWS do if gems[i][j]~= nil then --gems[i][j]:SetFacingToTarget(playerDisplay, Vector:New()) gems[i][j]:StopAnimKit(FALL_ANIM_KIT) gems[i][j].isSelected = false end end end end local DeathCoroutine function AddDeathCoroutine(...) scene:AddCoroutineWithParams(DeathCoroutine, ...) end DeathCoroutine = function(actor) actor.dying = true actor.row = 1000000 actor.col = 1000000 --actor:SetFacingToTarget(playerDisplay, Vector:New()) --actor:PlayLoopingAnimKit(4170) actor:PlaySpellCastVisual(EXPLOSION_CAST) local newPos = actor:GetPosition() + deathVector actor:MoveToAbs(newPos, DEATH_TIME) FadeOut(actor, DEATH_TIME) Wait(DEATH_TIME) actor:Despawn() end function PrettyNumberString( number ) local string = tostring(number) local millions = string.sub(string, 1, string.len(string)-6) local thousands = string.sub(string, -6, -4) local singles = string.sub(string, -3) if number<1000 then string = singles elseif number<1000000 then string = thousands..","..singles else string = millions..","..thousands..","..singles end return string end function ShowScore(actor, amount) score = score + amount local type = WorldText.Critical actor:AddCustomWorldText( type, true, Color:New(250,100,250), "?" ) --Win check if score >= ACHIEVEMENT_SCORE_THRESHOLD then scene:TriggerServerEvent("win") end end