Scripting: Add EVENT_DAMAGEHPLANE and document it in Lunatic doc Appendix B.

Also add test/damagehplane.lua with these demonstrations:
 - custom breakable ceilings
 - breakable TROR glass

git-svn-id: https://svn.eduke32.com/eduke32@4206 1a8010ca-5511-0410-912e-c29ae57300e0
This commit is contained in:
helixhorned 2013-12-20 18:31:33 +00:00
parent f10e1b1a16
commit 0c69779b98
9 changed files with 187 additions and 9 deletions

View file

@ -695,6 +695,7 @@ const char *EventNames[MAXEVENTS] =
"EVENT_SAVEGAME",
"EVENT_PREGAME",
"EVENT_CHANGEMENU",
"EVENT_DAMAGEHPLANE",
#ifdef LUNATIC
"EVENT_ANIMATEALLSPRITES",
#endif

View file

@ -125,8 +125,9 @@ enum GameEvent_t {
EVENT_SAVEGAME,
EVENT_PREGAME,
EVENT_CHANGEMENU,
EVENT_DAMAGEHPLANE, // 95
#ifdef LUNATIC
EVENT_ANIMATEALLSPRITES, // 95
EVENT_ANIMATEALLSPRITES,
#endif
MAXEVENTS
};

View file

@ -17,7 +17,7 @@ MAXGAMETYPES = 16
MAXSKILLS = 7
MAXEVENTS = 95 -- KEEPINSYNC with EVENT_* list
MAXEVENTS = 96 -- KEEPINSYNC with EVENT_* list
MAXSOUNDS = 4096
MAXSESSIONVARS = 8 -- KEEPINSYNC lunatic_game.c
@ -170,7 +170,8 @@ EVENT = {
EVENT_SAVEGAME = 92,
EVENT_PREGAME = 93,
EVENT_CHANGEMENU = 94,
-- EVENT_ANIMATEALLSPRITES = 95, -- internal
EVENT_DAMAGEHPLANE = 95,
-- EVENT_ANIMATEALLSPRITES = 96, -- internal
}
-- NOTE: negated values are not exported to the ffi.C namespace or CON.

View file

@ -272,6 +272,8 @@ end
function insertsprite(tab_or_tilenum, ...)
local tilenum, pos, sectnum -- mandatory
-- optional with defaults:
-- TODO: swap order of owner and statnum?
-- XXX: owner -1 valid???
local owner, statnum
local shade, xrepeat, yrepeat, ang, xvel, zvel = 0, 48, 48, 0, 0, 0

View file

@ -2091,7 +2091,7 @@ local function our_gameactor(args)
-- Register our EVENT_ANIMATEALLSPRITES only now so that it is not
-- called if there are no 'animate' definitions.
gameevent_internal(95, animate_all_sprites) -- EVENT_ANIMATEALLSPRITES
gameevent_internal(96, animate_all_sprites) -- EVENT_ANIMATEALLSPRITES
end
-- All good, set the tile bits in initial run and register the actor!

View file

@ -884,7 +884,7 @@ static_members.sector.STAT = conststruct
TRANS2 = 128,
TRANS1 = 256,
BLOCK = 512,
HITSCAN = 1024,
HITSCAN = 2048,
FLIP_BITMASK = 16+32,
ORIENT_BITMASK = 4+16+32,
@ -936,6 +936,8 @@ static_members.sprite.CSTAT = conststruct
ALIGN_BITMASK = 16+32,
TRANS_BITMASK = 2+512,
INVISIBLE = 32768,
}
local bitar = require("bitar")
@ -944,6 +946,19 @@ local bitar = require("bitar")
-- machines. This sucks.
static_members.sector.showbitmap = bitar.new(ffiC.MAXSECTORS-1, ffi.cast("int32_t *", ffiC.show2dsector))
static_members.sector.DAMAGEHPLANE = conststruct
{
SUPPRESS = -1,
DEFAULT = 0,
GLASSBREAK = 2^20,
}
function static_members.sector.damagehplane_whatsect(RETURN)
local what = (band(RETURN, 65536)~=0) and "ceiling" or "floor"
local sectnum = band(RETURN, ffiC.MAXSECTORS-1)
return what, sectnum
end
local function iter_allsprites(_, curi)
for i=curi+1,ffiC.MAXSPRITES-1 do
if (ffiC.sprite[i].statnum ~= ffiC.MAXSTATUS) then

View file

@ -942,7 +942,7 @@ sprite by `zofs` units''.
Provides a mapping of symbolic names to values applicable to
<<sprite_cstat,`sprite[i].cstat`>>. These name single bits:
`BLOCK`, `TRANS1`, `XFLIP`, `YFLIP`, `ALIGNWALL`, `ALIGNFLOOR`, `ONESIDE`,
`CENTER`, `HITSCAN`, `TRANS2`,
`CENTER`, `HITSCAN`, `TRANS2`, `INVISIBLE`,
while the following denote _bit masks_: `ALIGN_BITMASK`, `TRANS_BITMASK`.
===== `spriteext`
@ -2232,6 +2232,45 @@ cheat give a different ``full'' amount. A negative value is ignored.
`CHEATGETSTEROIDS`, `CHEATGETHEAT`, `CHEATGETBOOT`, `CHEATGETSHIELD`,
`CHEATGETSCUBA`, `CHEATGETHOLODUKE`, `CHEATGETJETPACK`, `CHEATGETFIRSTAID`.
[float]
`EVENT_DAMAGEHPLANE`
~~~~~~~~~~~~~~~~~~~~
Triggered when a ceiling or a floor (collectively called ``hplane'') is
determined as being damaged. The event receives `RETURN` as a value that can be
decoded into two parts by passing it to `sector.damagehplane_whatsect`:
[source]
----------
local what, sectnum = sector.damagehplane_whatsect(gv.RETURN)
----------
Then,
* `what` is one of the strings `'ceiling'` or `'floor'` and
* `sectnum` is the sector whose hplane is considered to be damaged.
When `EVENT_DAMAGEHPLANE` is left, `RETURN` is examined to determine the
further action. It may be one of three values given by `sector.DAMAGEHPLANE`
(abbreviated `DHP` in the following):
* `DHP.SUPPRESS`: the hard-wired code that would subsequently be run is
suppressed entirely
* `DHP.DEFAULT`: The default code for hplane damaging is run. For floors, it
does nothing. For ceilings, it checks whether it has a tile number in a
hard-coded set of values depicting a breakable light. In that case, the tile
number is changed to the ``broken'' version and a ``glass breaking'' effect
consisting of playing a sound and spawning glass sprites is started. Also,
certain code related to SE3 and SE12 effects is run.
* `DHP.GLASSBREAK`: The light-breaking effect described above is run
unconditionally, but *without* changing the hplane's tile number, which is
assumed to have been done by the event.
If value last assigned to `RETURN` is not one in the above-mentioned set when
`EVENT_DAMAGEHPLANE` is left, the behavior is undefined.
[float]
TODO
~~~~

View file

@ -0,0 +1,105 @@
local bit = require("bit")
local band = bit.band
local tostring = tostring
local gv = gv
local actor = actor
local sector, wall, sprite = sector, wall, sprite
local printf = printf
local sectorsofbunch = sectorsofbunch
local con = require("con")
local D = require("CON.DEFS")
----------
local TROR_GLASSBREAKER = 2959 -- red 'T'
-- Actor controlling the timing of a TROR hplane breaking.
gameactor
{
TROR_GLASSBREAKER,
function(aci, pli, dist)
local spr = sprite[aci]
if (not (spr.lotag == 712 and spr.hitag == 119)) then -- check BREAKER_MAGIC
sprite.changestat(aci, actor.STAT.DEFAULT)
return
end
local cnt = actor[aci]:get_count()
local finish = (cnt >= 6)
if (cnt == 0) then
-- NOTE: INTERNAL interface, DON'T USE!
con._sound(aci, D.GLASS_BREAKING)
end
local bunchnum = spr.extra
for sectnum, what in sectorsofbunch(bunchnum, gv.BOTH_CF) do
local cf = sector[sectnum][what]
-- TODO: provide cf:set_picnum()
if (what=="ceiling") then
sector[sectnum]:set_ceilingpicnum(D.GLASS2 + cnt)
else
sector[sectnum]:set_floorpicnum(D.GLASS2 + cnt)
end
cf.statbits:clear(sector.STAT.BLOCK + sector.STAT.HITSCAN)
if (finish) then
cf.statbits:clear(sector.STAT.TRANS_BITMASK)
end
end
if (finish) then
con.killit()
end
end
}
local DHP = sector.DAMAGEHPLANE
gameevent
{
gv.EVENT_DAMAGEHPLANE,
function(aci, pli, dist)
local what, sectnum = sector.damagehplane_whatsect(gv.RETURN)
local sec = sector[sectnum]
-- Part I: make various screens breakable when it's a ceiling picnum.
if (what == "ceiling") then
-- hit ceiling
if (sec.ceilingpicnum >= 263 and sec.ceilingpicnum <= 275) then
sec:set_ceilingpicnum(D.W_SCREENBREAK + gv.krand()%3)
gv.RETURN = DHP.GLASSBREAK
return
end
end
-- Part II: breakable TROR hplanes
local cf = sec[what]
-- printf("damage %s of sector %d (pic %d, bunch %d, hittable: %s)", what, sectnum,
-- cf.picnum, cf.bunch, tostring(cf.statbits:test(sector.STAT.HITSCAN)))
if (cf.bunch >= 0 and (cf.picnum==198 or cf.picnum==D.GLASS2) and
cf.statbits:test(sector.STAT.HITSCAN)) then
local bi = con.insertsprite(TROR_GLASSBREAKER, wall[sec.wallptr], sectnum, aci, actor.STAT.ACTOR)
local breaker = sprite[bi]
breaker.cstat = sprite.CSTAT.INVISIBLE
breaker.lotag, breaker.hitag = 712, 119 -- BREAKER_MAGIC
breaker.extra = cf.bunch
gv.RETURN = DHP.SUPPRESS
return
end
gv.RETURN = DHP.DEFAULT
end
}

View file

@ -1874,13 +1874,27 @@ void A_DamageWall(int32_t spr,int32_t dawallnum,const vec3_t *pos,int32_t atwith
}
}
// NOTE: return value never examined in any of the callers.
int32_t Sect_DamageCeilingOrFloor(int32_t floorp, int32_t sn)
{
int32_t i, j;
const int32_t RETURN_in = floorp ? 131072+sn : 65536+sn;
int32_t ret = VM_OnEvent(EVENT_DAMAGEHPLANE, g_player[screenpeek].ps->i, screenpeek, -1, RETURN_in);
if (ret < 0)
return 0;
if (floorp)
return 0;
if (ret == (1<<20))
{
// Execute the hard-coded stuff without changing picnum (expected to
// have been done by the event).
goto GLASSBREAK_CODE;
}
switch (DYNAMICTILEMAP(sector[sn].ceilingpicnum))
{
case WALLLIGHT1__STATIC:
@ -1890,9 +1904,6 @@ int32_t Sect_DamageCeilingOrFloor(int32_t floorp, int32_t sn)
case TECHLIGHT2__STATIC:
case TECHLIGHT4__STATIC:
A_SpawnCeilingGlass(g_player[myconnectindex].ps->i,sn,10);
A_PlaySound(GLASS_BREAKING,g_player[screenpeek].ps->i);
if (sector[sn].ceilingpicnum == WALLLIGHT1)
sector[sn].ceilingpicnum = WALLLIGHTBUST1;
@ -1911,6 +1922,9 @@ int32_t Sect_DamageCeilingOrFloor(int32_t floorp, int32_t sn)
if (sector[sn].ceilingpicnum == TECHLIGHT4)
sector[sn].ceilingpicnum = TECHLIGHTBUST4;
GLASSBREAK_CODE:
A_SpawnCeilingGlass(g_player[myconnectindex].ps->i,sn,10);
A_PlaySound(GLASS_BREAKING,g_player[screenpeek].ps->i);
if (sector[sn].hitag == 0)
{