28 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
eebd84544b one hit comment now shows correct value to use
some guns do less than one damage per shot (vulcan gun does 0.5), so
Instant Death Mode needs to max at 0x0.0001, the smallest nonzero value
in Pico-8's fixed-point numeric type.

One Hit Mode is just a comment for now, but I've been uncommenting it
to test it. Note that replacing the health meter with a "!" is triggered
by max HP + max shield <= 1 because 1 hp shows an empty bar.

this needs some more special cases for low-HP ships with active shields.
2024-08-18 01:57:53 -07:00
965fc0d688 major rebalances
10s generator is too slow -- 10 seconds ago is an eternity in a shmup
and a player who has stopped firing should recover much faster. The
generator's max capacity is much lower and shield cost has been
rebalanced to match.

The Protron is much more expensive to fire, it was previously just
easy mode.

Shields now recover faster _once they start recovering_ (every second
if energy is available) but getting hit causes a "penalty cooldown"
that is much longer than the standard recovery interval. This behavior
is taken from Halo and basically every modern FPS that came after it;
it's unlike Tyrian, which had consistent shield recovery behavior.
But I think Halo's rule plays much better.
2024-08-18 01:46:39 -07:00
cc3ed20f76 fix overshield 2024-08-18 01:29:27 -07:00
fa0cff1ffc one hit mode, fix vertmeter
full height meters overflowed p8num range
2024-08-18 01:28:12 -07:00
4f8b861cdb okay I special cased it 2024-08-18 01:14:05 -07:00
5dc259c094 the Secret Hit Point: you have 1hp when the meter is empty
this won't work if your maxhp is 1, will need to special case that
2024-08-18 01:13:25 -07:00
51629376f2 adjust HUD
Health and shields now share one bar. one hit point is (about) the same
size in each. There is an indicator splitting the two categories of HP.
2024-08-18 01:10:20 -07:00
c5e49740c4 reorganize UI 2024-08-17 23:22:42 -07:00
59738d0376 use constraints to make chasey chase; now it is not wiggly 2024-08-16 19:48:44 -07:00
f736f50870 port improvements to autobrake_test too, excluding the weird calc_targets thing 2024-08-16 19:37:43 -07:00
ccb897af24 fix calculation 2024-08-16 19:37:05 -07:00
c130f4cf52 actually invoke calc_targets 2024-08-16 19:25:10 -07:00
cf48497432 ymin and ymax for player 2024-08-16 19:23:20 -07:00
9dc36a95ee port ship constraints logic 2024-08-16 19:20:30 -07:00
d33d7ad6d1 xmax constraint -- imperfect but good enough 2024-07-27 18:49:48 -07:00
00678f97fd Fix brake location calculation; was applying it to the wrong spot. 2024-07-27 17:47:29 -07:00
8fa98e3132 handle undershot and ok cases 2024-01-28 01:33:25 -08:00
3 changed files with 2459 additions and 201 deletions

View File

@ -81,9 +81,10 @@ function _draw()
print("dx: ".. the_ship.dx, 20, 86, 7) print("dx: ".. the_ship.dx, 20, 86, 7)
meter(80, 86, 128, 90, the_ship.dx/the_ship.maxspd/2) meter(80, 86, 128, 90, the_ship.dx/the_ship.maxspd/2)
print("x: "..the_ship.x, 24, 92, 7) print("x: "..the_ship.x, 24, 92, 7)
print("bx: "..gbx, 20, 98, 7)
print("xmin:"..tostr(constraints.xmin), 12, 102, 7) print("xmin:"..tostr(constraints.xmin), 12, 108, 7)
print("xmax:"..tostr(constraints.xmax), 12, 108, 7) print("xmax:"..tostr(constraints.xmax), 12, 114, 7)
end end
function meter(x0, y0, x1, y1, frac) function meter(x0, y0, x1, y1, frac)
@ -127,26 +128,24 @@ function ship:draw()
spr(1,self.x,self.y) spr(1,self.x,self.y)
end end
if (self.dx == 0) return --if (self.dx == 0) return
local bd, f = brake_dist(self.dx, self.thrust + self.drag) local bd, f = brake_dist(self.dx, self.thrust + self.drag)
local bdx = self.x+bd-2 gbx = self.x+bd
spr(3, bdx,self.y-2) spr(3, gbx-2,self.y-2)
print(tostr(f), bdx, self.y - 8, 14) print(tostr(f), gbx-2, self.y - 8, 14)
end end
function calc_velocity(v0, t, vmax, drag) function calc_velocity(v0, t, vmax, drag)
local v1 = v0 + t v0 = mid(v0 + t, vmax, -vmax)
local sg = sgn(v1) return v0 - mid(drag, -drag, v0)
v1 -= sg*drag
if (sgn(v1) != sg) return 0
if (abs(v1) > vmax) return sg*vmax
return v1
end end
function ship:update() function ship:update()
local t = btn(0) and -1 or btn(1) and 1 or 0 local t = btn(0) and -1 or btn(1) and 1 or 0
t *= self.thrust t *= self.thrust
t = constraints:constrain(self, t) t = constraints:constrain(self, t)
-- t = constraints:constrain(self, t)
-- t = constraints:constrain(self, t)
local s = calc_velocity(self.dx, t, self.maxspd, self.drag) local s = calc_velocity(self.dx, t, self.maxspd, self.drag)
self.x += s self.x += s
@ -165,10 +164,31 @@ constraints = {
function constraints:constrain(s, want) function constraints:constrain(s, want)
self.color=10 self.color=10
if (not self.xmin) return want
local v1 = calc_velocity(s.dx, want, s.maxspd, s.drag) -- bmx: brake max
local bd, bf = brake_dist(v1, s.thrust + s.drag) local v1, bmx = calc_velocity(s.dx, want, s.maxspd, s.drag), s.thrust + s.drag
local bd, bf = brake_dist(v1, bmx)
local bx, txm = s.x + bd + v1, self.xmax
if bx < self.xmin then
-- predicted brake point left
-- of xmin; apply max reverse
-- thrust, treat xmin as our
-- max target, and handle
-- overbraking by coalescing
-- with past +xmax case
self.color = 9
want = s.thrust
txm = self.xmin
v1 = calc_velocity(s.dx, want, s.maxspd, s.drag)
bd, bf = brake_dist(v1, bmx)
bx = bd + s.x + v1
end
if (bx <= txm) return want
self.color = 8
local overage = bx - txm
want -= overage/max(bf,1)
if (want < -s.thrust) want = -s.thrust
return want return want
end end

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 pico-8 cartridge // http://www.pico-8.com
version 41 version 42
__lua__ __lua__
-- vacuum gambit -- vacuum gambit
-- by kistaro windrider -- by kistaro windrider
@ -18,6 +18,11 @@ function csv(s)
end end
return ret return ret
end end
function const_fxn(x)
return function()
return x
end
end
-- generate standard "overlay" -- generate standard "overlay"
-- constructor for type tt. -- constructor for type tt.
@ -118,7 +123,7 @@ end
function _init() function _init()
init_blip_pals() init_blip_pals()
wipe_level() wipe_level()
primary_ship.main_gun = zap_gun.new() primary_ship.main_gun = zap_gun_p.new() -- redundant?
load_level(example_level_csv) load_level(example_level_csv)
state = game state = game
pal(2,129) pal(2,129)
@ -320,6 +325,7 @@ function drawgame()
end end
powcols=split"170,154,153,148,68" powcols=split"170,154,153,148,68"
shlcols = split"204,220,221"
function drawhud() function drawhud()
-- 112-and-right is hud zone -- 112-and-right is hud zone
rectfill(112, 0, 127, 127,0x56) rectfill(112, 0, 127, 127,0x56)
@ -328,20 +334,29 @@ function drawhud()
line(113,127) line(113,127)
draw_gun_info("❎",1,116,3,primary_ship.main_gun) draw_gun_info("❎",1,116,3,primary_ship.main_gun)
draw_gun_info("🅾️",2,116,31,primary_ship.special_gun) draw_gun_info("🅾️",1,116,31,primary_ship.special_gun)
dropshadow("pwr",114,59,1) dropshadow("p h",114,59,1)
inset(114,66,125,92) inset(114,66,119,125)
fillp(0x5a5a) fillp(0x5a5a)
vertmeter(115,67,124,91,primary_ship.power, primary_ship.max_power, powcols) vertmeter(115,67,118,124,primary_ship.power, primary_ship.max_power, powcols)
inset(120,66,125,125)
dropshadow("h s",114,97,1) -- 57 px vertically
inset(114,104,125,125) local mxs, cs, mxh, ch = primary_ship.maxshield, primary_ship.shield, primary_ship.maxhp, primary_ship.hp
line(119,105,119,124,119) if (mxs > 0) and (mxh > 0) then
line(120,105,120,125,85) local split = 57 * (mxs / (mxs + mxh)) \ 1 + 66
vertmeter(115,105,118,124,primary_ship.hp, primary_ship.maxhp, hpcols) line(121, split, 124, split, 0xba)
vertmeter(121,105,124,124,primary_ship.shield, primary_ship.maxshield,{204,220,221}) 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)
end
fillp(0) fillp(0)
end end
@ -368,9 +383,9 @@ function draw_gun_info(lbl,fgc,x,y,gun)
end end
function vertmeter(x0,y0,x1,y1,val,maxval,cols) function vertmeter(x0,y0,x1,y1,val,maxval,cols)
if (val <= 0) return if ((val <= 0) or (maxval <= 0)) return
local h = y1-y0 local h = y1-y0
local px = -flr(-(h*val)\maxval) local px = val/maxval * h \ 1
local ncols = #cols local ncols = #cols
local firstcol = ((h-px)*ncols\h)+1 local firstcol = ((h-px)*ncols\h)+1
local lastbottom = y0+(h*firstcol\ncols) local lastbottom = y0+(h*firstcol\ncols)
@ -408,51 +423,86 @@ ship_m = {
shield = 0, shield = 0,
maxshield = 0, maxshield = 0,
shieldcost = 32767.9, shieldcost = 32767.9,
shieldcooldown = 0x0.00a0, shieldcooldown = 0x0.003c,--1s
shieldpenalty = 0x0.012c, --5s
-- default generator behavior: max_power = 120,
-- 10 seconds for a full charge power = 120,
max_power = 600, generator = 2, -- power gen per frame
power = 600,
generator = 1, -- power gen per frame
slip = true, -- most enemies slide slip = true, -- most enemies slide
xmomentum = 0, xmomentum = 0,
ymomentum = 0, ymomentum = 0,
-- xmin, xmax, ymin, ymax:
-- movement constraints
-- enforced by `constrain`.
xmin = 0, xmax = 104,
-- ymin, ymax default to nil
-- pship needs more constraint
} }
mknew(ship_m) mknew(ship_m)
function ship_m:die() function ship_m:die()
self.dead = true 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)
v0 = mid(v0 + t, self.maxspd, -self.maxspd)
return v0 - mid(self.drag, -self.drag, v0)
end
function ship_m:brake_dist(v0)
local brake_max = self.thrust + self.drag
local tri_frames = abs(v0\brake_max)
local chunks = tri_frames * (tri_frames - 1) >> 1
local chunk_zone = chunks * brake_max
local overage = abs(v0) - tri_frames * brake_max
return (chunk_zone + overage * (tri_frames + 1)) * sgn(v0), (overage > 0) and tri_frames + 1 or tri_frames
end
function ship_m:constrain(p, dp, pmin, pmax, want)
if (not pmin) return want
local v1, bd, bf, bp
function calc_targets()
-- velocity after move
v1 = self:calc_velocity(dp, want)
-- brake distance and frames
bd, bf = self:brake_dist(v1)
-- brake point
bp = p + bd + v1
end
calc_targets()
if bp < pmin then
-- undershoot. max thrust,
-- then treat as overshoot
-- targeting minimum bound
want, pmax = self.thrust, pmin
calc_targets()
end
if (bp <= pmax) return want
-- spread overshoot across frames
want -= (bp - pmax)/max(bf,1)
return max(want, -self.thrust)
end end
function ship_m:move() function ship_m:move()
self:refresh_shield() self:refresh_shield()
self.power = min(self.max_power, self.power + self.generator) self.power = min(self.max_power, self.power + self.generator)
local dx, dy, shoot_spec, shoot_main = self:act() local dx, dy, shoot_spec, shoot_main = self:act()
dx = self:constrain(self.x, self.xmomentum, self.xmin, self.xmax, dx)
dy = self:constrain(self.y, self.ymomentum, self.ymin, self.ymax, dy)
if (shoot_main) self:maybe_shoot(self.main_gun) if (shoot_main) self:maybe_shoot(self.main_gun)
if (shoot_spec) self:maybe_shoot(self.special_gun) if (shoot_spec) self:maybe_shoot(self.special_gun)
if (dx ~= 0 or dy ~= 0) spark(self.sparks, self.x + 4*self.size, self.y + 4*self.size, dx*2.5, dy*2.5, self.sparkodds) if (dx ~= 0 or dy ~= 0) spark(self.sparks, self.x + 4*self.size, self.y + 4*self.size, dx*2.5, dy*2.5, self.sparkodds)
self.xmomentum += dx self.xmomentum = self:calc_velocity(self.xmomentum, dx)
self.ymomentum += dy self.ymomentum = self:calc_velocity(self.ymomentum, dy)
self.xmomentum = mid(-self.maxspd, self.maxspd, self.xmomentum)
self.ymomentum = mid(-self.maxspd, self.maxspd, self.ymomentum)
self.x += self.xmomentum self.x += self.xmomentum
self.y += self.ymomentum self.y += self.ymomentum
if self == primary_ship then
self.x = mid(0, 112 - 8 * self.size, self.x)
self.y = mid(0, 128 - 8 * self.size, self.y)
end
--friction
local d = self.drag
self.xmomentum -= mid(d, -d, self.xmomentum)
self.ymomentum -= mid(d, -d, self.ymomentum)
-- "scrolling" behavior -- "scrolling" behavior
if self.slip then if self.slip then
self.y += scrollrate self.y += scrollrate
@ -497,7 +547,7 @@ end
function ship_m:hitsomething(dmg) function ship_m:hitsomething(dmg)
if (dmg <= 0) return false if (dmg <= 0) return false
self.shield_refresh_ready = lframe + self.shieldcooldown self.shield_refresh_ready = lframe + self.shieldpenalty
if self.shield >= dmg then if self.shield >= dmg then
self.shield -= dmg self.shield -= dmg
self:ow(true) self:ow(true)
@ -506,7 +556,7 @@ function ship_m:hitsomething(dmg)
dmg -= self.shield dmg -= self.shield
self.shield = 0 self.shield = 0
self.hp -= dmg self.hp -= dmg
if self.hp <= 0 then if self.hp < 0 then
self:die() self:die()
return true return true
end end
@ -527,6 +577,7 @@ function ship_m:refresh_shield()
if (lframe < self.shield_refresh_ready) return if (lframe < self.shield_refresh_ready) return
if (self.power < self.shieldcost) return if (self.power < self.shieldcost) return
self.shield += 1 self.shield += 1
self.shield = min(self.shield, self.maxshield)
self.power -= self.shieldcost self.power -= self.shieldcost
self.shield_refresh_ready = lframe + self.shieldcooldown self.shield_refresh_ready = lframe + self.shieldcooldown
end end
@ -534,9 +585,15 @@ end
-->8 -->8
-- bullet and gun behaviors -- bullet and gun behaviors
bullet_base = { function player_blt_cat()
enemyspd = 0.5 return pbullets
} end
function enemy_blt_cat()
return ebullets
end
bullet_base = { }
mknew(bullet_base) mknew(bullet_base)
gun_base = { gun_base = {
@ -555,19 +612,11 @@ end
function bullet_base:move() function bullet_base:move()
self.x += self.dx self.x += self.dx
if self.enemy then
self.y += self.dy self.y += self.dy
if self.y > 128 then if (self.y > 128) or (self.y < -8 * self.height) then
self:die() self:die()
return true return true
end end
else
self.y -= self.dy
if self.y < -8*self.height then
self:die()
return true
end
end
return false return false
end end
@ -575,19 +624,20 @@ function bullet_base:draw()
spr(self.sprite, self.x, self.y, self.width, self.height) spr(self.sprite, self.x, self.y, self.width, self.height)
end end
function bullet_base:spawn_at(x, y) -- An `actually_shoot` factory
self.x = x - self.center_x_off -- for trivial guns
if self.enemy then function spawn_one(t)
self.dx *= self.enemyspd return function(gun, x, y)
self.dy *= self.enemyspd t.new{}:spawn_at(x, y)
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)
end end
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) function gun_base:shoot(x, y)
if (lframe < self.shoot_ready) return false if (lframe < self.shoot_ready) return false
if self.ammo then if self.ammo then
@ -599,23 +649,12 @@ function gun_base:shoot(x, y)
return true return true
end 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 -->8
-- bullets and guns -- bullets and guns
zap = bullet_base.new{ zap_e = bullet_base.new{
--shape --shape
psprite = 8, --index of player ammo sprite sprite = 9, --index of enemy ammo sprite
esprite = 9, -- index of enemy ammo sprite
width = 1, --in 8x8 blocks width = 1, --in 8x8 blocks
height = 1, height = 1,
hurt = { -- hurtbox - where this ship can be hit hurt = { -- hurtbox - where this ship can be hit
@ -624,33 +663,43 @@ zap = bullet_base.new{
width = 2, width = 2,
height = 8 height = 8
}, },
center_x_off = 1, -- how to position by ship x_off = 1, -- how to position by ship
bottom_y_off = 0, y_off = 8,
top_y_off = 0,
damage = 1, damage = 1,
dx = 0, -- px/frame dx = 0, -- px/frame
dy = 8, dy = 4,
hitship = function(_, _) hitship = const_fxn(true),
return true
end category = enemy_blt_cat,
} }
mknew(zap) mknew(zap_e)
zap_gun = gun_base.new{ zap_p = zap_e.new{
enemy = false, 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 power = 20, -- power consumed per shot
cooldown = 0x0.000a, -- frames between shots cooldown = 0x0.000a, -- frames between shots
ammo = nil, -- unlimited ammo - main gun 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{ blast = bullet_base.new{
--shape --shape
psprite = 12, --index of player ammo sprite sprite = 12, --index of player ammo sprite
esprite = 3, -- index of enemy ammo sprite
width = 1, --in 8x8 blocks width = 1, --in 8x8 blocks
height = 1, height = 1,
hurt = { -- hurtbox - where this ship can be hit hurt = { -- hurtbox - where this ship can be hit
@ -659,13 +708,12 @@ blast = bullet_base.new{
width = 6, width = 6,
height = 6 height = 6
}, },
center_x_off = 4, -- how to position by ship x_off = 4, -- how to position by ship
bottom_y_off = 0, y_off = 0,
top_y_off = 0,
damage = 4, damage = 4,
dx = 0, -- px/frame dx = 0, -- px/frame
dy = 2, dy = -2,
awaitcancel = false, awaitcancel = false,
-- disable damage for 2 frames -- disable damage for 2 frames
@ -690,25 +738,24 @@ blast = bullet_base.new{
self.awaitcancel = false self.awaitcancel = false
end) end)
end end
end end,
category=player_blt_cat
} }
mknew(blast) mknew(blast)
blast_gun = gun_base.new{ blast_gun = gun_base.new{
icon = 13, icon = 13,
enemy = false, power = 0, -- only cost is ammo
power = 0, -- ammo, not power
cooldown = 0x0.0020, -- frames between shots cooldown = 0x0.0020, -- frames between shots
ammo = 5, ammo = 5,
maxammo = 5, maxammo = 5,
t = blast -- type of bullet to fire actually_shoot = spawn_one(blast),
} }
mknew(blast_gun) mknew(blast_gun)
protron = bullet_base.new{ protron_e = bullet_base.new{
--shape --shape
psprite = 23, --index of player ammo sprite sprite = 24,
esprite = 24, -- index of enemy ammo sprite
width = 1, --in 8x8 blocks width = 1, --in 8x8 blocks
height = 1, height = 1,
hurt = { -- hurtbox - where this ship can be hit hurt = { -- hurtbox - where this ship can be hit
@ -717,56 +764,63 @@ protron = bullet_base.new{
width = 2, width = 2,
height = 2 height = 2
}, },
center_x_off = 1, -- how to position by ship x_off = 1, -- how to position by ship
bottom_y_off = 4, y_off = 4,
top_y_off = 0,
damage = 1, damage = 1,
dx = 0, -- px/frame dym = 0.5, -- gun sets dy;
dy = 3, -- 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, icon = 25,
enemy = false, power = 60,
power = 35,
cooldown = 0x0.000f, -- frames between shots cooldown = 0x0.000f, -- frames between shots
ammo = nil, ammo = nil,
maxammo = nil, maxammo = nil,
actually_shoot = function(self, x, y) munition = protron_e
local sprite = protron.psprite }
if (self.enemy) sprite=protron.esprite mknew(protron_gun_e)
function protron_gun_e:actually_shoot(x, y)
local m = self.munition.dym
for i=1,3 do for i=1,3 do
local b = protron.new{ local b = self.munition.new{
enemy=self.enemy, dx = i*m,
sprite=sprite, dy = (4-i)*m,
dx = i,
dy = 4-i
} }
b:spawn_at(x,y) b:spawn_at(x,y)
local b2 = protron.new{ local b2 = self.munition.new{
enemy=self.enemy, dx = -i*m,
sprite=sprite, dy = (4-i)*m,
dx = -i,
dy = 4-i
} }
b2:spawn_at(x,y) b2:spawn_at(x,y)
end end
local bup = protron.new{ local bup = self.munition.new{
enemy=self.enemy, dx=0,
sprite=sprite, dy=4*m,
dy=4
} }
bup:spawn_at(x,y) bup:spawn_at(x,y)
end end
}
mknew(protron_gun)
vulcan = bullet_base.new{ protron_gun_p = protron_gun_e.new{
munition = protron_p,
}
mknew(protron_gun_p)
vulcan_e = bullet_base.new{
--shape --shape
psprite = 22, --index of player ammo sprite sprite = 21,
esprite = 21, -- index of enemy ammo sprite
width = 1, --in 8x8 blocks width = 1, --in 8x8 blocks
height = 1, height = 1,
hurt = { -- hurtbox - where this ship can be hit hurt = { -- hurtbox - where this ship can be hit
@ -775,31 +829,37 @@ vulcan = bullet_base.new{
width = 1, width = 1,
height = 4 height = 4
}, },
center_x_off = 0.5, -- how to position by ship x_off = 0.5, -- how to position by ship
bottom_y_off = 4, y_off = 0,
top_y_off = 0,
damage = 0.5, damage = 0.5,
dx = 0, -- px/frame -- dx from gun
dy = 4, 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, icon = 37,
enemy = false, enemy = false,
power = 8, power = 8,
cooldown = 0x0.0002, -- frames between shots cooldown = 0x0.0002, -- frames between shots
ammo = nil, ammo = nil,
maxammo = nil, maxammo = nil,
munition=vulcan_e,
dxs = {0.35, -0.35, -0.7, 0.7, 0.35, -0.35}, dxs = {0.35, -0.35, -0.7, 0.7, 0.35, -0.35},
xoffs = {1, 0, -1, 1, 0, -1}, xoffs = {1, 0, -1, 1, 0, -1},
dxidx = 1, dxidx = 1,
actually_shoot = function(self, x, y) actually_shoot = function(self, x, y)
local sprite = self.enemy and vulcan.esprite or vulcan.psprite local b = self.munition.new{
local b = vulcan.new{
enemy=self.enemy,
sprite=sprite,
dx = self.dxs[self.dxidx], dx = self.dxs[self.dxidx],
} }
b:spawn_at(self.xoffs[self.dxidx]+x,y) b:spawn_at(self.xoffs[self.dxidx]+x,y)
@ -807,7 +867,12 @@ vulcan_gun = gun_base.new{
if (self.dxidx > #self.dxs) self.dxidx = 1 if (self.dxidx > #self.dxs) self.dxidx = 1
end end
} }
mknew(vulcan_gun) mknew(vulcan_gun_e)
vulcan_gun_p = vulcan_gun_e.new{
munition=vulcan_p,
}
mknew(vulcan_gun_p)
-->8 -->8
--ships, including player --ships, including player
@ -834,8 +899,8 @@ player = ship_m.new{
maxhp = 3, -- player only; other ships never heal maxhp = 3, -- player only; other ships never heal
shield = 2, -- regenerates, using power shield = 2, -- regenerates, using power
maxshield = 2, maxshield = 2,
shieldcost = 300, -- power cost to refill shield shieldcost = 60, -- power cost to refill shield
generator = 1.5, -- 1 feels too slow generator = 2,
-- gun -- gun
main_gun = nil, -- assign at spawn time main_gun = nil, -- assign at spawn time
@ -850,6 +915,7 @@ player = ship_m.new{
ymomentum = 0, ymomentum = 0,
maxspd = 2.5, -- momentum cap maxspd = 2.5, -- momentum cap
thrust = 0.25, -- momentum added from button thrust = 0.25, -- momentum added from button
ymin = 0, ymax = 120, -- stay on screen
drag = 0.125, -- momentum lost per frame drag = 0.125, -- momentum lost per frame
slip = false, -- does not slide down screen slip = false, -- does not slide down screen
act = function(self) -- fetch buttons act = function(self) -- fetch buttons
@ -868,7 +934,13 @@ player = ship_m.new{
} }
mknew(player, mknew(player,
function(p) function(p)
p.main_gun = zap_gun.new() p.main_gun = zap_gun_p.new()
-- ONE HIT MODE
--
-- p.hp = 0
-- p.maxhp = 0
-- p.shield = 0
-- p.maxshield = 0
end end
) )
@ -886,7 +958,7 @@ frownie = ship_m.new{
sparkodds = 8, sparkodds = 8,
-- health and power -- health and power
hp = 1, -- enemy ships need no max hp hp = 0.5, -- enemy ships need no max hp
-- position -- position
x=60, -- x and y are for upper left corner x=60, -- x and y are for upper left corner
@ -908,7 +980,7 @@ mknew(frownie)
blocky = frownie.new{ blocky = frownie.new{
sprite = 10, sprite = 10,
hp = 2, hp = 1.5,
hurt = { hurt = {
x_off = 0, x_off = 0,
y_off = 0, y_off = 0,
@ -917,7 +989,7 @@ blocky = frownie.new{
}, },
ow = function(self) ow = function(self)
if self.hp <= 1 then if self.hp < 1 then
self.sprite = 11 self.sprite = 11
else else
self.sprite = 10 self.sprite = 10
@ -936,7 +1008,7 @@ spewy = frownie.new{
width=8, width=8,
height=5 height=5
}, },
hp=1, hp=0.5,
maxpower=70, maxpower=70,
generator=0.5, generator=0.5,
fire_off_x=4, fire_off_x=4,
@ -947,7 +1019,7 @@ spewy = frownie.new{
end end
} }
mknew(spewy, function(ship) 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) end)
chasey = ship_m.new{ chasey = ship_m.new{
@ -961,7 +1033,7 @@ chasey = ship_m.new{
}, },
sparks = smokespark, sparks = smokespark,
sparkodds = 8, sparkodds = 8,
hp = 2, hp = 1.5,
shield = 1, shield = 1,
maxshield = 1, maxshield = 1,
shieldcost = 180, shieldcost = 180,
@ -975,14 +1047,13 @@ chasey = ship_m.new{
slip = true, slip = true,
} }
mknew(chasey, function(ship) 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) end)
function chasey:act() function chasey:act()
local dx = 0 self.xmin = max(primary_ship.x-8, 0)
if (self.x < primary_ship.x) dx=self.thrust self.xmax = min(primary_ship.x + 8, 112 - 8*self.size)
if (self.x > primary_ship.x) dx=-self.thrust return 0, 0, false, self.x - 16 < primary_ship.x and self.x + 16 > primary_ship.x
return dx, 0, false, self.x - 16 < primary_ship.x and self.x + 16 > primary_ship.x
end end
xl_chasey=chasey.new{ xl_chasey=chasey.new{
@ -994,7 +1065,9 @@ xl_chasey=chasey.new{
width = 12, width = 12,
height = 10 height = 10
}, },
hp = 20, fire_off_x = 8,
fire_off_y = 15,
hp = 19.5,
shield = 5, shield = 5,
boss = true, boss = true,
slip = false, slip = false,
@ -1010,7 +1083,7 @@ xl_chasey=chasey.new{
end, end,
} }
mknew(xl_chasey, function(ship) 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) end)
-->8 -->8
-- collisions -- collisions
@ -1219,9 +1292,9 @@ end
function spawn_bonus_vulcan_chasey() function spawn_bonus_vulcan_chasey()
local c = spawn_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) 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) chasey.die(self)
end end
c.sprite=4 c.sprite=4
@ -1324,7 +1397,7 @@ example_level_csv=[[1,spawn_frownie
310,spawn_blocking_blocky 310,spawn_blocking_blocky
310,spawn_blocking_blocky 310,spawn_blocking_blocky
311,spawn_frownie 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 401,spawn_frownie
420,spawn_blocking_frownie 420,spawn_blocking_frownie
430,spawn_bonus_vulcan_chasey 430,spawn_bonus_vulcan_chasey
@ -1434,8 +1507,9 @@ bullets
shots much easier to dodge shots much easier to dodge
* damage - damage per hit; * damage - damage per hit;
used by ships used by ships
* psprite, esprite - index of * sprite - sprite index.
player or enemy sprite. * x_off, y_off - renamed for
the next two vars. may revert
* center_off_x - the horizontal * center_off_x - the horizontal
centerpoint of the bullet, centerpoint of the bullet,
for positioning when firing. for positioning when firing.
@ -1522,10 +1596,12 @@ shields - ship.shieldcost per
point of shields. shieldcooldown point of shields. shieldcooldown
is the interval between is the interval between
restoring shield points, which restoring shield points, which
is reset when a ship takes is reset to shieldpenalty when a
damage (regardless of whether ship takes damage (regardless of
that damage is stopped by the whether that damage is stopped
shield or not). by the shield or not).
shieldpenalty is much worse than
shieldcooldown (hALO shield).
therefore: therefore:
* damaged ships spend power * damaged ships spend power
@ -1822,7 +1898,7 @@ powerup = bullet_base.new{
-- easy to pick up -- easy to pick up
dx = 0, dx = 0,
dy = 1.5, -- 0.75 after enemyspd dy = 1.5, -- 0.75 after enemyspd
enemy = true, -- collides with player ship category = enemy_blt_cat, -- collides with player ship
damage = 0, damage = 0,
anim_speed = 2, anim_speed = 2,
@ -1855,9 +1931,8 @@ repair = powerup.new{
width = 12, width = 12,
height = 12 height = 12
}, },
center_x_off = 4, x_off = 4,
top_y_off = 0, y_off = 0,
bottom_y_off = 0,
sprites = sheen8x8, sprites = sheen8x8,
hitship = function(self, ship) hitship = function(self, ship)
if (ship ~= primary_ship) return false if (ship ~= primary_ship) return false
@ -1883,9 +1958,8 @@ gun_swap = powerup.new{
height = 16 height = 16
}, },
-- gun = gun_type.new{} -- gun = gun_type.new{}
center_x_off = 6, x_off = 6,
top_y_off = 0, y_off = 0,
bottom_y_off = 4,
width = 2, width = 2,
height = 2, height = 2,
sprites = {64, 66, 68, 70, 72, 74, 76, 78}, sprites = {64, 66, 68, 70, 72, 74, 76, 78},