237 lines
9.1 KiB
JavaScript
237 lines
9.1 KiB
JavaScript
import { method, RUN_LENGTH, GOLD_PER_WIN, CARD_PRICE, REST_HEAL, RELIC_PRICE, ACT_COUNT, ACT_MAPS, LOBBY_MAP, LOBBY_SPAWN } from '../lib/codeblock.mjs';
|
|
import { CARDS, ENEMIES, CLASSES, JOBS, SOUL_UNLOCKS, CARDFRAMES, RARITIES, MAP_ROWS, MAP_COLS, CHEST_CLOSED_RUID, CHEST_OPEN_RUID, NODEICONS, CHARS, CAM, RELICS, POTIONS, luaSoulShopTable, frameRuid, luaFramesTable, luaNodeIconsTable, luaCharsTable, luaRelicsTable, luaPotionsTable, luaIntentsArray, luaEnemiesTable, luaStr, luaJobsTable, luaCardsTable, luaDeckTable } from '../lib/data.mjs';
|
|
import { UI_FILE, COMMON_FILE, UI_ROOT, GENERATED_UI_SECTIONS, UI_APPEND_ORDER, DISABLED_STOCK_CONTROLS, TRANSPARENT, DARK, GOLD, ATTACK, DEFEND, SKILL, DAMAGE_DIGIT_RUIDS, DAMAGE_POP_MAX_DIGITS, DAMAGE_POP_DIGIT_W, DAMAGE_POP_DIGIT_H, DAMAGE_POP_DIGIT_SPACING, MAX_MONSTERS, HEAD_OFFSET_Y, HP_BAR_W, WHITE, CARD_NAME_TEXT, CARD_DESC_TEXT, cardFaceLayout, CARD_W, CARD_H, CARD_SPACING, CARD_XS, ALIGN_CENTER, ALIGN_BOTTOM_CENTER, guid, transform, sprite, button, text, scrollLayoutGroup, popupLayerFor, uiOrderFor, displayOrderFor, applySortingOverride, entity, uiPath, sectionRoot, isGeneratedUiEntity, appendUiSection } from '../lib/ui-helpers.mjs';
|
|
|
|
export const runMethods = [
|
|
method('StartRun', `if self.SelectedClass == "magician" then
|
|
self.PlayerMaxHp = ${CLASSES.magician.maxHp}
|
|
self.RunDeck = { ${CARDS.starterDecks.magician.map(luaStr).join(', ')} }
|
|
elseif self.SelectedClass == "bandit" then
|
|
self.PlayerMaxHp = ${CLASSES.bandit.maxHp}
|
|
self.RunDeck = { ${CARDS.starterDecks.bandit.map(luaStr).join(', ')} }
|
|
else
|
|
self.PlayerMaxHp = ${CLASSES.warrior.maxHp}
|
|
self.RunDeck = { ${CARDS.starterDecks.warrior.map(luaStr).join(', ')} }
|
|
end
|
|
self.PlayerMaxHp = self.PlayerMaxHp - self:AscStartHpPenalty()
|
|
self.PlayerHp = self.PlayerMaxHp
|
|
self.Gold = 0
|
|
self.Floor = 1
|
|
self.RunLength = ${ACT_COUNT}
|
|
self.RunActive = true
|
|
self.RunRelics = {}
|
|
self.RunPotions = {}
|
|
self.PotionSlots = ${POTIONS.baseSlots}
|
|
${luaPotionsTable(POTIONS.potions)}
|
|
${luaRelicsTable(RELICS.relics)}
|
|
self.RelicPool = { ${RELICS.relicPool.map(luaStr).join(', ')} }
|
|
${luaEnemiesTable(ENEMIES.enemies)}
|
|
self.CurrentNodeId = ""
|
|
self.CurrentEnemyId = ""
|
|
self.PlayerJob = ""
|
|
${luaJobsTable(JOBS)}
|
|
${luaFramesTable()}
|
|
${luaNodeIconsTable()}
|
|
${luaCharsTable()}
|
|
self:GenerateMap()
|
|
self:BindButtons()
|
|
self:AddRelic("${RELICS.startingRelic}")
|
|
self:ApplySoulUnlocks()
|
|
self:RenderPotions()
|
|
self:TeleportToActMap()
|
|
self:ShowMap()`),
|
|
method('KickCombatCamera', `local cam = nil
|
|
local lp = _UserService.LocalPlayer
|
|
if lp ~= nil then cam = lp.CameraComponent end
|
|
if cam == nil then cam = _CameraService:GetCurrentCameraComponent() end
|
|
if cam ~= nil then cam.ConfineCameraArea = false end
|
|
_TimerService:SetTimerOnce(function()
|
|
local cc = nil
|
|
local lp2 = _UserService.LocalPlayer
|
|
if lp2 ~= nil then cc = lp2.CameraComponent end
|
|
if cc == nil then cc = _CameraService:GetCurrentCameraComponent() end
|
|
if cc ~= nil then
|
|
cc.ZoomRatio = ${CAM.zoomRatio}
|
|
cc.CameraOffset = Vector2(${CAM.cameraOffsetX}, ${CAM.cameraOffsetY})
|
|
cc.ScreenOffset = Vector2(${CAM.screenOffsetX}, ${CAM.screenOffsetY})
|
|
cc.ConfineCameraArea = true
|
|
end
|
|
end, 0.2)`),
|
|
method('StartCombat', `self:ShowState("combat")
|
|
self:KickCombatCamera()
|
|
self:SetEntityEnabled("/ui/RunUIGroup/CombatHud/Result", false)
|
|
self:SetEntityEnabled("/ui/RunUIGroup/CombatHud/PotionMenu", false)
|
|
self:SetEntityEnabled("/ui/RunUIGroup/CombatHud/TooltipBox", false)
|
|
self:SetEntityEnabled("/ui/RunUIGroup/CombatHud/DiscardPrompt", false)
|
|
self:SetText("/ui/RunUIGroup/CombatHud/PlayerPanel/Name", self:JobLabel())
|
|
self.MaxEnergy = 3
|
|
self.Turn = 0
|
|
self.PlayerBlock = 0
|
|
self.BlockGainMultiplier = 1
|
|
self.NextSkillCostZero = false
|
|
self.SkillCostReductionThisTurn = 0
|
|
self.PlayerStr = 0
|
|
self.PlayerDex = 0
|
|
self.PlayerThorns = 0
|
|
self.PlayerWeak = 0
|
|
self.PlayerVuln = 0
|
|
self.PlayerPowers = {}
|
|
self.FightAttackCount = 0
|
|
self.TurnAttackCardsPlayed = 0
|
|
self.TurnDiscardedCards = 0
|
|
self.DmgPopSeq = 0
|
|
self.FirstHpLossDone = false
|
|
self.ClayBlockNext = 0
|
|
self.DiscardSelectRemaining = 0
|
|
self.DiscardSelectTotal = 0
|
|
self.DiscardPostShiv = 0
|
|
self.DiscardShivPerPick = 0
|
|
self.RetainSelectActive = false
|
|
self.ReserveSelectActive = false
|
|
self.NextTurnBlock = 0
|
|
self.NextTurnDraw = 0
|
|
self.NextTurnKeepBlock = false
|
|
self.NextTurnAttackMultiplier = 1
|
|
self.TurnAttackMultiplier = 1
|
|
self.NextTurnSelectPrompt = ""
|
|
self.NextTurnSelectCopies = 0
|
|
self.NextTurnAddCards = {}
|
|
self.CombatOver = false
|
|
self.DiscardPile = {}
|
|
self.ExhaustPile = {}
|
|
self.Hand = {}
|
|
${luaCardsTable(CARDS.cards)}
|
|
self.DrawPile = {}
|
|
for i = 1, #self.RunDeck do
|
|
self.DrawPile[i] = self.RunDeck[i]
|
|
end
|
|
self:Shuffle(self.DrawPile)
|
|
self:PrepareCombatDrawPile()
|
|
self:BuildMonsters()
|
|
self:RenderCombat()
|
|
self:StartPlayerTurn()
|
|
self:ApplyRelics("combatStart")
|
|
self:RenderCombat()
|
|
local slotTid = 0
|
|
slotTid = _TimerService:SetTimerRepeat(function()
|
|
if self.CombatOver == true or self.Monsters == nil or #self.Monsters == 0 then
|
|
_TimerService:ClearTimer(slotTid)
|
|
return
|
|
end
|
|
for i = 1, #self.Monsters do
|
|
if self.Monsters[i] ~= nil and self.Monsters[i].alive == true then
|
|
self:PositionMonsterSlot(i)
|
|
end
|
|
end
|
|
end, 0.15)`),
|
|
method('RegisterMonster', `if self.Registered == nil then
|
|
self.Registered = {}
|
|
end
|
|
local g = group
|
|
if g == nil or g == "" then g = "combat" end
|
|
local mp = mapName
|
|
if mp == nil then mp = "" end
|
|
table.insert(self.Registered, { entity = monster, enemyId = enemyId, group = g, map = mp })`, [
|
|
{ Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'monster' },
|
|
{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'enemyId' },
|
|
{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'group' },
|
|
{ Type: 'string', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'mapName' },
|
|
]),
|
|
method('BuildMonsters', `self.Monsters = {}
|
|
local g = "combat"
|
|
local node = self.MapNodes[self.CurrentNodeId]
|
|
if node ~= nil and node.type ~= nil then g = node.type end
|
|
local pmap = ""
|
|
local lp = _UserService.LocalPlayer
|
|
if lp ~= nil and lp.CurrentMapName ~= nil then pmap = lp.CurrentMapName end
|
|
local reg = self.Registered or {}
|
|
for i = 1, #reg do
|
|
if reg[i].entity ~= nil and isvalid(reg[i].entity) then
|
|
reg[i].entity:SetVisible(false)
|
|
end
|
|
end
|
|
local byGroup = {}
|
|
for i = 1, #reg do
|
|
local r = reg[i]
|
|
if r.entity ~= nil and isvalid(r.entity) and (r.map == nil or r.map == "" or pmap == "" or r.map == pmap) then
|
|
local gg = r.group
|
|
if gg == nil or gg == "" then gg = "combat" end
|
|
if byGroup[gg] == nil then byGroup[gg] = {} end
|
|
local x = 0
|
|
if r.entity.TransformComponent ~= nil then
|
|
x = r.entity.TransformComponent.WorldPosition.x
|
|
end
|
|
table.insert(byGroup[gg], { entity = r.entity, enemyId = r.enemyId, x = x })
|
|
end
|
|
end
|
|
-- 노드 타입별 랜덤 구성: 일반 1~3 / 엘리트 1+일반0~2 / 보스 1
|
|
local chosen = {}
|
|
local function takeFrom(key, k)
|
|
local src = byGroup[key] or {}
|
|
local pool = {}
|
|
for i = 1, #src do pool[i] = src[i] end
|
|
self:Shuffle(pool)
|
|
local taken = 0
|
|
for i = 1, #pool do
|
|
if taken >= k then break end
|
|
table.insert(chosen, pool[i])
|
|
taken = taken + 1
|
|
end
|
|
end
|
|
if g == "boss" then
|
|
takeFrom("boss", 1)
|
|
elseif g == "elite" then
|
|
takeFrom("elite", 1)
|
|
takeFrom("combat", math.random(0, 2))
|
|
else
|
|
takeFrom("combat", math.random(1, 3))
|
|
end
|
|
if #chosen == 0 then takeFrom(g, 1) end
|
|
if #chosen == 0 then takeFrom("combat", 1) end
|
|
table.sort(chosen, function(a, b) return a.x < b.x end)
|
|
local mult = 1 + (self.Floor - 1) * 0.45
|
|
if g == "elite" or g == "boss" then
|
|
mult = mult + self:AscEliteBonus()
|
|
end
|
|
local n = #chosen
|
|
if n > ${MAX_MONSTERS} then n = ${MAX_MONSTERS} end
|
|
for i = 1, n do
|
|
local item = chosen[i]
|
|
local e = self.Enemies[item.enemyId]
|
|
if e == nil then e = { name = item.enemyId, maxHp = 10, intents = { { kind = "Attack", value = 5 } } } end
|
|
local intents = {}
|
|
for k = 1, #e.intents do
|
|
local v = e.intents[k].value or 0
|
|
if e.intents[k].kind == "Attack" then
|
|
v = math.floor(v * mult * self:AscAtkMult())
|
|
elseif e.intents[k].kind ~= "Debuff" then
|
|
v = math.floor(v * mult)
|
|
end
|
|
intents[k] = { kind = e.intents[k].kind, value = v, effect = e.intents[k].effect, card = e.intents[k].card, count = e.intents[k].count }
|
|
end
|
|
local maxHp = math.floor(e.maxHp * mult * self:AscHpMult())
|
|
local hitClip = nil
|
|
local standClip = nil
|
|
if item.entity.StateAnimationComponent ~= nil then
|
|
pcall(function()
|
|
hitClip = item.entity.StateAnimationComponent.ActionSheet["hit"]
|
|
standClip = item.entity.StateAnimationComponent.ActionSheet["stand"]
|
|
end)
|
|
end
|
|
local startIdx = 1
|
|
if #intents > 0 then startIdx = math.random(1, #intents) end
|
|
self.Monsters[i] = { entity = item.entity, enemyId = item.enemyId, name = e.name,
|
|
hp = maxHp, maxHp = maxHp, block = 0, str = 0, weak = 0, vuln = 0, poison = 0,
|
|
hitClip = hitClip, standClip = standClip, motionBusy = false,
|
|
intents = intents, intentIdx = startIdx, alive = true, slot = i }
|
|
self:ReviveMonsterEntity(item.entity)
|
|
self:PositionMonsterSlot(i)
|
|
end
|
|
self.TargetIndex = 1`),
|
|
method('ReviveMonsterEntity', `if monster == nil or not isvalid(monster) then
|
|
return
|
|
end
|
|
monster:SetEnable(true)
|
|
monster:SetVisible(true)`, [{ Type: 'any', DefaultValue: null, SyncDirection: 0, Attributes: [], Name: 'monster' }]),
|
|
];
|