mirror of
https://github.com/DramaticShape/DramaticShapeVoxelMod.git
synced 2026-08-12 09:10:49 +02:00
update all battle locations
This commit is contained in:
+72
-8
@@ -109,6 +109,57 @@ BattleArena.SHAPES = {
|
||||
{ id = "narrow", w = 1, h = 4, enemy = { 0, 0 }, player = { 0, 3 } },
|
||||
}
|
||||
|
||||
-- ------- which way round the fight stands
|
||||
--
|
||||
-- Both shapes above are drawn north-south, with the foe at the top and the
|
||||
-- player below it, and the camera is solved for that: it sits off the
|
||||
-- player's shoulder, low and back down the arena's own axis. `turn` swings
|
||||
-- the WHOLE staging a quarter at a time -- the footprint, the two cells, and
|
||||
-- the camera with them -- so the composition on screen is identical and only
|
||||
-- the ground under it is different.
|
||||
--
|
||||
-- It buys two things.
|
||||
--
|
||||
-- A footprint that FITS. The wide shape is three cells by six; an east-west
|
||||
-- corridor two cells deep has no room for it standing up and all the room in
|
||||
-- the world for it lying down. Half the maps in Kanto run the other way from
|
||||
-- the one shape this mode was drawn in.
|
||||
--
|
||||
-- And a BACKDROP. A quarter turn moves the camera to a different side of the
|
||||
-- same patch of ground, so the wall behind the pair becomes the window
|
||||
-- behind them, or the cliff becomes the valley. Nothing about the shot's
|
||||
-- geometry changes -- the mons land on the same two screen anchors at the
|
||||
-- same size -- so this is purely a choice about what is behind them, made
|
||||
-- per map by somebody looking at it.
|
||||
--
|
||||
-- Written in DEGREES in data/battle_arenas.lua (`turn = 90`) because that is
|
||||
-- what it is; handled as quarter turns everywhere below.
|
||||
local function quarters(turn)
|
||||
local q = math.floor(((tonumber(turn) or 0) / 90) + 0.5)
|
||||
return ((q % 4) + 4) % 4
|
||||
end
|
||||
|
||||
BattleArena.quarters = quarters
|
||||
|
||||
-- The footprint a shape covers once turned: a quarter or three of a turn
|
||||
-- swaps how far it reaches in each direction, which is the whole reason a
|
||||
-- corridor takes one and not the other.
|
||||
function BattleArena.extent(shape, turn)
|
||||
if quarters(turn) % 2 == 1 then return shape.h, shape.w end
|
||||
return shape.w, shape.h
|
||||
end
|
||||
|
||||
-- Where a cell offset inside the shape ends up under the same turn, measured
|
||||
-- from the turned footprint's own north-west corner -- so the corner an entry
|
||||
-- names stays the corner, whichever way the fight faces from it.
|
||||
local function spin(shape, turn, ox, oy)
|
||||
local q = quarters(turn)
|
||||
if q == 1 then return shape.h - 1 - oy, ox end
|
||||
if q == 2 then return shape.w - 1 - ox, shape.h - 1 - oy end
|
||||
if q == 3 then return oy, shape.w - 1 - ox end
|
||||
return ox, oy
|
||||
end
|
||||
|
||||
-- Whether a cell is open ground for the purpose above.
|
||||
--
|
||||
-- "Open" is the walk test the player themselves answer to, so an arena can
|
||||
@@ -174,12 +225,19 @@ end
|
||||
|
||||
-- Build the record the renderer reads: the two mons' cells and, in world
|
||||
-- pixels, the centre of each and of the pair.
|
||||
local function place(shape, x, y)
|
||||
local ex, ey = x + shape.enemy[1], y + shape.enemy[2]
|
||||
local px, py = x + shape.player[1], y + shape.player[2]
|
||||
local function place(shape, x, y, turn)
|
||||
local eox, eoy = spin(shape, turn, shape.enemy[1], shape.enemy[2])
|
||||
local pox, poy = spin(shape, turn, shape.player[1], shape.player[2])
|
||||
local ex, ey = x + eox, y + eoy
|
||||
local px, py = x + pox, y + poy
|
||||
local w, h = BattleArena.extent(shape, turn)
|
||||
local arena = {
|
||||
shape = shape.id,
|
||||
x = x, y = y, w = shape.w, h = shape.h,
|
||||
-- carried in degrees, so everything downstream that reasons about the
|
||||
-- shot -- the camera's base yaw above all -- reads the same number the
|
||||
-- data file was written with
|
||||
turn = quarters(turn) * 90,
|
||||
x = x, y = y, w = w, h = h,
|
||||
enemyCell = { ex, ey },
|
||||
playerCell = { px, py },
|
||||
-- world-pixel centres of the two cells a mon stands on
|
||||
@@ -302,8 +360,12 @@ function BattleArena.find(map, fromX, fromY, surfing)
|
||||
-- ocean rather than on a scrap of beach at the edge of the map. Land
|
||||
-- entries are unaffected: land passes the test either way.
|
||||
local grid, gw = openGrid(host, true)
|
||||
if fits(grid, gw, pick.x, pick.y, shape.w, shape.h) then
|
||||
local arena = place(shape, pick.x, pick.y)
|
||||
-- measured against the TURNED footprint: an entry that lies the arena
|
||||
-- down an east-west corridor covers different ground from the one that
|
||||
-- stands it up, and the fit test is the thing that has to know
|
||||
local fw, fh = BattleArena.extent(shape, pick.turn)
|
||||
if fits(grid, gw, pick.x, pick.y, fw, fh) then
|
||||
local arena = place(shape, pick.x, pick.y, pick.turn)
|
||||
arena.map = host
|
||||
-- which camera rig this spot is framed for; nil is the default long
|
||||
-- lens, "close" the short one small rooms need (see BattleCam)
|
||||
@@ -321,9 +383,11 @@ end
|
||||
-- The arena at a given north-west corner, whatever the map says about it.
|
||||
-- The authoring tool's manual override: a spot chosen by eye rather than by
|
||||
-- the search, so it can be photographed and judged before it is written down.
|
||||
function BattleArena.at(x, y, shapeId)
|
||||
function BattleArena.at(x, y, shapeId, turn)
|
||||
for _, shape in ipairs(BattleArena.SHAPES) do
|
||||
if shape.id == (shapeId or "wide") then return place(shape, x, y) end
|
||||
if shape.id == (shapeId or "wide") then
|
||||
return place(shape, x, y, turn)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
+21
-2
@@ -431,7 +431,22 @@ function BattleCam.rig(arena, groundY, canonical)
|
||||
-- arena's own axis, and the room the player has is all on the far side of
|
||||
-- that -- out toward square-on. (orbitRange measures exactly that room.)
|
||||
local steer = steered and -BattleCam.orbit * BattleCam.orbitRange(arena) or 0
|
||||
local yaw = steer + (fixed and 0
|
||||
-- ------- and the quarter turn the arena itself is standing at
|
||||
--
|
||||
-- An arena may be laid down any of the four ways (BattleArena's `turn`),
|
||||
-- and the rig is solved for ONE of them: eye off the player's shoulder,
|
||||
-- back down an axis that runs north-south. So the whole offset is turned
|
||||
-- with the ground under it, which leaves the camera in exactly the same
|
||||
-- place RELATIVE to the two mons -- same distance, same height, same
|
||||
-- angle -- and therefore lands them on the same two screen anchors at the
|
||||
-- same size. A turn is a fact about the map, never about the shot.
|
||||
--
|
||||
-- It goes in with the drift and the steer rather than beside them because
|
||||
-- it is the same rotation about the same point; the player's own orbit is
|
||||
-- then measured from wherever the arena starts, so both stops travel with
|
||||
-- it and side-on stays side-on.
|
||||
local base = math.rad(arena.turn or 0)
|
||||
local yaw = base + steer + (fixed and 0
|
||||
or BattleCam.PAN_YAW * phase(BattleCam.t, BattleCam.PAN_PERIOD))
|
||||
local c, s = math.cos(yaw), math.sin(yaw)
|
||||
-- the breath scales the whole offset, height included, so the eye moves
|
||||
@@ -443,7 +458,11 @@ function BattleCam.rig(arena, groundY, canonical)
|
||||
local dz = (R.side * s + R.back * c) * k
|
||||
|
||||
local eye = { mx + dx, groundY + R.height * k, mz + dz }
|
||||
local focus = { mx + R.lookX, groundY + R.lookY, mz }
|
||||
-- the aim's own offset turns with the arena too, and with the BASE alone --
|
||||
-- the drift and the steer swing the eye about the focus, so a focus that
|
||||
-- followed them would take the thing being orbited around with it
|
||||
local bc, bs = math.cos(base), math.sin(base)
|
||||
local focus = { mx + R.lookX * bc, groundY + R.lookY, mz + R.lookX * bs }
|
||||
|
||||
-- and the climb: the eye swung UP about the focus, at a constant radius.
|
||||
-- About the focus so the aim stays nailed to the two mons and only the
|
||||
|
||||
@@ -303,7 +303,11 @@ end
|
||||
-- first drawn in.
|
||||
local function shadowSignature(state, arena, terrain, nbMesh, token)
|
||||
local host = arena.map or state.map
|
||||
-- `turn` is in the signature with the corner and the shape: the same corner
|
||||
-- turned a quarter is a different footprint standing on different ground,
|
||||
-- and a cast kept from the other one freezes the shadows across it
|
||||
local parts = { "battle", host.id, arena.x, arena.y, arena.shape,
|
||||
tostring(arena.turn or 0),
|
||||
tostring(terrain), tostring(token or 0),
|
||||
-- the cycle keeps running through a fight, and an arena lit
|
||||
-- from somewhere new must be re-cast from there
|
||||
|
||||
Reference in New Issue
Block a user