11 Commits

Author SHA1 Message Date
ead2a7d874 fix remaining vulcan-family bug 2024-09-02 14:45:56 -07:00
571412b15e fix chasey xl offsets 2024-09-02 14:15:56 -07:00
907bd8318c several more fixes, now runs to the end but shot offset is wrong 2024-09-02 14:12:35 -07:00
7170552448 first three waves of bug fixes 2024-09-02 13:41:42 -07:00
01ab6d3969 maybe the rest of the refactor? 2024-09-02 12:59:49 -07:00
7869192dee partial refactor continued 2024-08-20 01:21:13 -07:00
a4658e3ef4 halfway through bullet refactor 2024-08-19 16:00:16 -07:00
60b685d94b save a copy of vacuum_gambit.p8 as last_tyrianlike
next step is to pick a real direction -- MMBN-like (+STS-like) or
Survivors-like -- and adapt to match. I am likely to completely remove
the energy system and use permanent autofire, freeing both fire buttons
for more interesting tasks. It loses the opportunity to create a dynamic
around baiting an enemy to keep shooting so its shields don't recover,
but I don't think it loses a lot else.

Either energy management needs to become really important and the game
becomes strategic and tactical, or it needs to be a non-issue and it is
an arcade game. Tyrian itself did not make the energy system interesting
and it was just a tax, so making it interesting would be doing something
new. But I think it's a kind of "interesting" that almost nobody would
adopt unless I go _very hard_ into creating a tactical/strategic shmup.
A shmup that is actually a strange kind of RTS sounds... really cool,
actually, but I'm not at all confident I could design it.

Removing energy entirely gives us a button _and_ a meter back, which
can be used for XP (Survivors-like) or rearm time (MMBN-like).
2024-08-18 15:04:17 -07:00
cc1e7ea5b7 surive at 0hp and adjust hp values to match
Instead of doing a special case for 1HP, 0HP is survivable, ships die
at negative HP instead. all ship health is adjusted to match, assuming
the weakest shot is 0.5hp, which is currently true. the "real" game will
totally rebalance all ships and weapons anyway.

we're getting close to when I have to stop dawdling and implement the
real game, the engine is _there._
2024-08-18 14:57:29 -07:00
6b8efe3438 fix HP-only mode
it was showing the bar intended as the warning that there's no HP
under the shield. but I tried it and that bar just makes it look like
there *is* a sliver of health, which there isn't. so it's better off
without that in either mode.
2024-08-18 14:49:44 -07:00
c2668cefea handle 0 shield and 1 max HP cases 2024-08-18 14:40:11 -07:00
2 changed files with 2336 additions and 148 deletions

2164
last_tyrianlike.p8 Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
pico-8 cartridge // http://www.pico-8.com
version 41
version 42
__lua__
-- vacuum gambit
-- by kistaro windrider
@ -18,6 +18,11 @@ function csv(s)
end
return ret
end
function const_fxn(x)
return function()
return x
end
end
-- generate standard "overlay"
-- constructor for type tt.
@ -118,7 +123,7 @@ end
function _init()
init_blip_pals()
wipe_level()
primary_ship.main_gun = zap_gun.new()
primary_ship.main_gun = zap_gun_p.new() -- redundant?
load_level(example_level_csv)
state = game
pal(2,129)
@ -320,6 +325,7 @@ function drawgame()
end
powcols=split"170,154,153,148,68"
shlcols = split"204,220,221"
function drawhud()
-- 112-and-right is hud zone
rectfill(112, 0, 127, 127,0x56)
@ -337,12 +343,16 @@ function drawhud()
inset(120,66,125,125)
-- 57 px vertically
local mxs, mxh = primary_ship.maxshield, primary_ship.maxhp
if mxs + mxh > 1 then
local split = 57 * (mxs / (mxs + mxh-1)) \ 1 + 66
local mxs, cs, mxh, ch = primary_ship.maxshield, primary_ship.shield, primary_ship.maxhp, primary_ship.hp
if (mxs > 0) and (mxh > 0) then
local split = 57 * (mxs / (mxs + mxh)) \ 1 + 66
line(121, split, 124, split, 0xba)
vertmeter(121,67,124,split-1,primary_ship.shield, mxs,{204,220,221})
vertmeter(121,split+1,124,124,primary_ship.hp-1, mxh-1, hpcols)
vertmeter(121,67,124,split-1,cs, mxs,shlcols)
vertmeter(121,split+1,124,124,ch, mxh, hpcols)
elseif mxs > 0 then
vertmeter(121,67,124,124,cs,mxs,shlcols)
elseif mxh > 0 then
vertmeter(121,67,124,124,ch,mxh,hpcols)
else
print("!", 122, 94, 9)
print("!", 121, 93, 8)
@ -436,7 +446,7 @@ mknew(ship_m)
function ship_m:die()
self.dead = true
if (self.hp <= 0) boom(self.x+self.size*4, self.y+self.size*4,12*self.size, self.boss)
if (self.hp < 0) boom(self.x+self.size*4, self.y+self.size*4,12*self.size, self.boss)
end
function ship_m:calc_velocity(v0, t)
@ -546,7 +556,7 @@ function ship_m:hitsomething(dmg)
dmg -= self.shield
self.shield = 0
self.hp -= dmg
if self.hp <= 0 then
if self.hp < 0 then
self:die()
return true
end
@ -575,9 +585,15 @@ end
-->8
-- bullet and gun behaviors
bullet_base = {
enemyspd = 0.5
}
function player_blt_cat()
return pbullets
end
function enemy_blt_cat()
return ebullets
end
bullet_base = { }
mknew(bullet_base)
gun_base = {
@ -596,18 +612,10 @@ end
function bullet_base:move()
self.x += self.dx
if self.enemy then
self.y += self.dy
if self.y > 128 then
self:die()
return true
end
else
self.y -= self.dy
if self.y < -8*self.height then
self:die()
return true
end
self.y += self.dy
if (self.y > 128) or (self.y < -8 * self.height) then
self:die()
return true
end
return false
end
@ -616,19 +624,20 @@ function bullet_base:draw()
spr(self.sprite, self.x, self.y, self.width, self.height)
end
function bullet_base:spawn_at(x, y)
self.x = x - self.center_x_off
if self.enemy then
self.dx *= self.enemyspd
self.dy *= self.enemyspd
self.y = y + self.top_y_off
ebullets:push_back(self)
else
self.y = y - (8 * self.height) + self.bottom_y_off
pbullets:push_back(self)
-- An `actually_shoot` factory
-- for trivial guns
function spawn_one(t)
return function(gun, x, y)
t.new{}:spawn_at(x, y)
end
end
function bullet_base:spawn_at(x, y)
self.x = x - self.x_off
self.y = y - self.y_off
self.category():push_back(self)
end
function gun_base:shoot(x, y)
if (lframe < self.shoot_ready) return false
if self.ammo then
@ -640,23 +649,12 @@ function gun_base:shoot(x, y)
return true
end
function gun_base:actually_shoot(x, y)
local typ = self.t
local b = typ.new{
enemy = self.enemy,
sprite = self.enemy and typ.esprite or typ.psprite,
}
b:spawn_at(x, y)
return true
end
-->8
-- bullets and guns
zap = bullet_base.new{
zap_e = bullet_base.new{
--shape
psprite = 8, --index of player ammo sprite
esprite = 9, -- index of enemy ammo sprite
sprite = 9, --index of enemy ammo sprite
width = 1, --in 8x8 blocks
height = 1,
hurt = { -- hurtbox - where this ship can be hit
@ -665,33 +663,43 @@ zap = bullet_base.new{
width = 2,
height = 8
},
center_x_off = 1, -- how to position by ship
bottom_y_off = 0,
top_y_off = 0,
x_off = 1, -- how to position by ship
y_off = 8,
damage = 1,
dx = 0, -- px/frame
dy = 8,
dy = 4,
hitship = function(_, _)
return true
end
hitship = const_fxn(true),
category = enemy_blt_cat,
}
mknew(zap)
mknew(zap_e)
zap_gun = gun_base.new{
enemy = false,
zap_p = zap_e.new{
sprite = 8,
dy = -8,
y_off = 0,
category = player_blt_cat,
}
mknew(zap_p)
zap_gun_e = gun_base.new{
power = 20, -- power consumed per shot
cooldown = 0x0.000a, -- frames between shots
ammo = nil, -- unlimited ammo - main gun
t = zap -- metatable of bullet to fire
actually_shoot = spawn_one(zap_e),
}
mknew(zap_gun)
mknew(zap_gun_e)
zap_gun_p = zap_gun_e.new{
actually_shoot = spawn_one(zap_p),
}
mknew(zap_gun_p)
blast = bullet_base.new{
--shape
psprite = 12, --index of player ammo sprite
esprite = 3, -- index of enemy ammo sprite
sprite = 12, --index of player ammo sprite
width = 1, --in 8x8 blocks
height = 1,
hurt = { -- hurtbox - where this ship can be hit
@ -700,13 +708,12 @@ blast = bullet_base.new{
width = 6,
height = 6
},
center_x_off = 4, -- how to position by ship
bottom_y_off = 0,
top_y_off = 0,
x_off = 4, -- how to position by ship
y_off = 0,
damage = 4,
dx = 0, -- px/frame
dy = 2,
dy = -2,
awaitcancel = false,
-- disable damage for 2 frames
@ -731,25 +738,24 @@ blast = bullet_base.new{
self.awaitcancel = false
end)
end
end
end,
category=player_blt_cat
}
mknew(blast)
blast_gun = gun_base.new{
icon = 13,
enemy = false,
power = 0, -- ammo, not power
power = 0, -- only cost is ammo
cooldown = 0x0.0020, -- frames between shots
ammo = 5,
maxammo = 5,
t = blast -- type of bullet to fire
actually_shoot = spawn_one(blast),
}
mknew(blast_gun)
protron = bullet_base.new{
protron_e = bullet_base.new{
--shape
psprite = 23, --index of player ammo sprite
esprite = 24, -- index of enemy ammo sprite
sprite = 24,
width = 1, --in 8x8 blocks
height = 1,
hurt = { -- hurtbox - where this ship can be hit
@ -758,56 +764,63 @@ protron = bullet_base.new{
width = 2,
height = 2
},
center_x_off = 1, -- how to position by ship
bottom_y_off = 4,
top_y_off = 0,
x_off = 1, -- how to position by ship
y_off = 4,
damage = 1,
dx = 0, -- px/frame
dy = 3,
dym = 0.5, -- gun sets dy;
-- this is mult
category = enemy_blt_cat,
}
mknew(protron)
mknew(protron_e)
protron_gun = gun_base.new{
protron_p = protron_e.new{
sprite=23,
dym = -1,
y_off = 0,
category=player_blt_cat,
}
mknew(protron_p)
protron_gun_e = gun_base.new{
icon = 25,
enemy = false,
power = 60,
cooldown = 0x0.000f, -- frames between shots
ammo = nil,
maxammo = nil,
actually_shoot = function(self, x, y)
local sprite = protron.psprite
if (self.enemy) sprite=protron.esprite
for i=1,3 do
local b = protron.new{
enemy=self.enemy,
sprite=sprite,
dx = i,
dy = 4-i
}
b:spawn_at(x,y)
local b2 = protron.new{
enemy=self.enemy,
sprite=sprite,
dx = -i,
dy = 4-i
}
b2:spawn_at(x,y)
end
local bup = protron.new{
enemy=self.enemy,
sprite=sprite,
dy=4
}
bup:spawn_at(x,y)
end
munition = protron_e
}
mknew(protron_gun)
mknew(protron_gun_e)
vulcan = bullet_base.new{
function protron_gun_e:actually_shoot(x, y)
local m = self.munition.dym
for i=1,3 do
local b = self.munition.new{
dx = i*m,
dy = (4-i)*m,
}
b:spawn_at(x,y)
local b2 = self.munition.new{
dx = -i*m,
dy = (4-i)*m,
}
b2:spawn_at(x,y)
end
local bup = self.munition.new{
dx=0,
dy=4*m,
}
bup:spawn_at(x,y)
end
protron_gun_p = protron_gun_e.new{
munition = protron_p,
}
mknew(protron_gun_p)
vulcan_e = bullet_base.new{
--shape
psprite = 22, --index of player ammo sprite
esprite = 21, -- index of enemy ammo sprite
sprite = 21,
width = 1, --in 8x8 blocks
height = 1,
hurt = { -- hurtbox - where this ship can be hit
@ -816,31 +829,37 @@ vulcan = bullet_base.new{
width = 1,
height = 4
},
center_x_off = 0.5, -- how to position by ship
bottom_y_off = 4,
top_y_off = 0,
x_off = 0.5, -- how to position by ship
y_off = 0,
damage = 0.5,
dx = 0, -- px/frame
dy = 4,
-- dx from gun
dy = 2,
category=enemy_blt_cat
}
mknew(vulcan)
mknew(vulcan_e)
vulcan_gun = gun_base.new{
vulcan_p = vulcan_e.new{
sprite=22,
y_off = 4,
dy = -4,
category=player_blt_cat
}
mknew(vulcan_p)
vulcan_gun_e = gun_base.new{
icon = 37,
enemy = false,
power = 8,
cooldown = 0x0.0002, -- frames between shots
ammo = nil,
maxammo = nil,
munition=vulcan_e,
dxs = {0.35, -0.35, -0.7, 0.7, 0.35, -0.35},
xoffs = {1, 0, -1, 1, 0, -1},
dxidx = 1,
actually_shoot = function(self, x, y)
local sprite = self.enemy and vulcan.esprite or vulcan.psprite
local b = vulcan.new{
enemy=self.enemy,
sprite=sprite,
local b = self.munition.new{
dx = self.dxs[self.dxidx],
}
b:spawn_at(self.xoffs[self.dxidx]+x,y)
@ -848,7 +867,12 @@ vulcan_gun = gun_base.new{
if (self.dxidx > #self.dxs) self.dxidx = 1
end
}
mknew(vulcan_gun)
mknew(vulcan_gun_e)
vulcan_gun_p = vulcan_gun_e.new{
munition=vulcan_p,
}
mknew(vulcan_gun_p)
-->8
--ships, including player
@ -910,12 +934,11 @@ player = ship_m.new{
}
mknew(player,
function(p)
p.main_gun = zap_gun.new()
-- ONE HIT MODE: max hp is
-- minimum nonzero value.
p.main_gun = zap_gun_p.new()
-- ONE HIT MODE
--
-- p.hp = 0x0.0001
-- p.maxhp = 0x0.0001
-- p.hp = 0
-- p.maxhp = 0
-- p.shield = 0
-- p.maxshield = 0
end
@ -935,7 +958,7 @@ frownie = ship_m.new{
sparkodds = 8,
-- health and power
hp = 1, -- enemy ships need no max hp
hp = 0.5, -- enemy ships need no max hp
-- position
x=60, -- x and y are for upper left corner
@ -957,7 +980,7 @@ mknew(frownie)
blocky = frownie.new{
sprite = 10,
hp = 2,
hp = 1.5,
hurt = {
x_off = 0,
y_off = 0,
@ -966,7 +989,7 @@ blocky = frownie.new{
},
ow = function(self)
if self.hp <= 1 then
if self.hp < 1 then
self.sprite = 11
else
self.sprite = 10
@ -985,7 +1008,7 @@ spewy = frownie.new{
width=8,
height=5
},
hp=1,
hp=0.5,
maxpower=70,
generator=0.5,
fire_off_x=4,
@ -996,7 +1019,7 @@ spewy = frownie.new{
end
}
mknew(spewy, function(ship)
ship.main_gun=ship.main_gun or protron_gun.new{enemy=true}
ship.main_gun=ship.main_gun or protron_gun_e.new{enemy=true}
end)
chasey = ship_m.new{
@ -1010,7 +1033,7 @@ chasey = ship_m.new{
},
sparks = smokespark,
sparkodds = 8,
hp = 2,
hp = 1.5,
shield = 1,
maxshield = 1,
shieldcost = 180,
@ -1024,7 +1047,7 @@ chasey = ship_m.new{
slip = true,
}
mknew(chasey, function(ship)
ship.main_gun=ship.main_gun or zap_gun.new{enemy=true}
ship.main_gun=ship.main_gun or zap_gun_e.new{}
end)
function chasey:act()
@ -1042,7 +1065,9 @@ xl_chasey=chasey.new{
width = 12,
height = 10
},
hp = 20,
fire_off_x = 8,
fire_off_y = 15,
hp = 19.5,
shield = 5,
boss = true,
slip = false,
@ -1058,7 +1083,7 @@ xl_chasey=chasey.new{
end,
}
mknew(xl_chasey, function(ship)
ship.main_gun=ship.main_gun or zap_gun.new{enemy=true}
ship.main_gun=ship.main_gun or zap_gun_e.new{}
end)
-->8
-- collisions
@ -1267,9 +1292,9 @@ end
function spawn_bonus_vulcan_chasey()
local c = spawn_chasey()
c.main_gun=vulcan_gun.new{enemy=true}
c.main_gun=vulcan_gun_e.new{enemy=true}
c.die = function(self)
spawn_main_gun_at(self.x-1, self.y-1, vulcan_gun)
spawn_main_gun_at(self.x-1, self.y-1, vulcan_gun_p)
chasey.die(self)
end
c.sprite=4
@ -1372,7 +1397,7 @@ example_level_csv=[[1,spawn_frownie
310,spawn_blocking_blocky
310,spawn_blocking_blocky
311,spawn_frownie
350,spawn_main_gun_at,70,-11,protron_gun
350,spawn_main_gun_at,70,-11,protron_gun_p
401,spawn_frownie
420,spawn_blocking_frownie
430,spawn_bonus_vulcan_chasey
@ -1482,8 +1507,9 @@ bullets
shots much easier to dodge
* damage - damage per hit;
used by ships
* psprite, esprite - index of
player or enemy sprite.
* sprite - sprite index.
* x_off, y_off - renamed for
the next two vars. may revert
* center_off_x - the horizontal
centerpoint of the bullet,
for positioning when firing.
@ -1872,7 +1898,7 @@ powerup = bullet_base.new{
-- easy to pick up
dx = 0,
dy = 1.5, -- 0.75 after enemyspd
enemy = true, -- collides with player ship
category = enemy_blt_cat, -- collides with player ship
damage = 0,
anim_speed = 2,
@ -1905,9 +1931,8 @@ repair = powerup.new{
width = 12,
height = 12
},
center_x_off = 4,
top_y_off = 0,
bottom_y_off = 0,
x_off = 4,
y_off = 0,
sprites = sheen8x8,
hitship = function(self, ship)
if (ship ~= primary_ship) return false
@ -1933,9 +1958,8 @@ gun_swap = powerup.new{
height = 16
},
-- gun = gun_type.new{}
center_x_off = 6,
top_y_off = 0,
bottom_y_off = 4,
x_off = 6,
y_off = 0,
width = 2,
height = 2,
sprites = {64, 66, 68, 70, 72, 74, 76, 78},