Bean's Dynamite Derby and What I Made for It
Once again Out of Character
, as it will be hard for me to properly explain things in character.
Also this post is STILL incomplete! There may be more things added in the future.
What the FUCK is a Dynamite Derby?
Well...
Bean's Dynamite Derby is a gamemode mod for Dr. Robotnik's Ring Racers, with it being a remake of the Elimination mod from SRB2Kart, featuring not just a fresh coat of paint, but also new features for better gameplay.
This is not the first project I've worked on for Ring Racers, see Party Phase for one of them, nor this is the first gamemode modification I've made (Combinator is the first for Ring Racers in that regard).
This is however, besides Party Phase, one of the biggest projects I've worked on, and now that it's released, I can show you what I've contributed to the mod, and some scrapped stuff in between.
How I got in the dev team in the first place
One of the first few things noted in the mod during testing about a few months ago was crucial and needed to be fixed- rampant desyncs.
A desync is a term referring to the client not keeping up with what the server sees, and the server sees that, so it resends the server's information about that to the client. This is a bad thing, as it'll stutter the server for a bit, and may get longer the more info the server needs to send. It was even worse back in SRB2Kart, where everyone basically stalls as the server attempts to sync back a client, with a high chance of it just straight up not working and kicking the desynching player anyway.
I was called into the dev team by Mr. Logan (the artist) for this purpose- attempt to figure out the reason for the desyncs. And in a bit me and Aqua figured out why.
The bdd
table, at the time, was sending the entire table every time it needs to send the info (e.g. on player join)
addHook("NetVars", function(net) bdd = net($) end)
lua/derbyInit.lua
The bdd
table contains specific information that can't be archived to be sent, like cvar pointers. These are userdata that can't be sent specifically.
After fixing that, we concluded that the resyncs were mostly gone.
Programming splitscreen
The horror.
Splitscreen- A Ring Racers feature, and the hardest to develop for, atleast in terms of making HUD code for it.
It also doesn't help that a dedicated video flag to help with said splitscreen jimbo jumbo does not work in Lua due to the differences of how Lua hud hooks render.
-- This don't work !!! -- Always defaults to the last screen v.draw(0, 0, v.cachePatch("MISSING"), V_SPLITSCREEN)
fuck.lua
So for this, I made an entire dedicated function to fucking do the splitscreen snapping myself.
Feel free to take this, or anything in derbyUtils.lua
for that matter.
local function DBU_SnapSplitscreen(v, c, x, y, scr, spl) scr = $ or 0 spl = $ or DBU_FSplitscreen -- heeere it is local screenwidth = (v.width()/v.dupx())<<FRACBITS local screenheight = (v.height()/v.dupy())<<FRACBITS local basewidth = 320<<FRACBITS local baseheight = 200<<FRACBITS local splitnum = c.pnum - 1 -- can you believe it guys??? an undocumented feature !!!! -- If splitscreen is not available, then simply default to 0 -- TODO: Use a displayplayers hack to do normal splitscreen on 2.3 local splitscr = spl -- Handle halving depending on splitscreen shit if splitscr > 0 then screenheight = $ / 2 baseheight = $ / 2 if splitscr > 1 then screenwidth = $ / 2 basewidth = $ / 2 end end -- Splitscreen non 16:10 resolution never works. Lets try anyway. if v.width() ~= 320*v.dupx() then if (scr & V_SNAPTORIGHT) then x = $ + (screenwidth - basewidth) elseif ((scr & V_SNAPTOLEFT) ~= V_SNAPTOLEFT) then x = $ + ((screenwidth - basewidth) / 2) end end if v.height() ~= 200*v.dupy() then if (scr & V_SNAPTOBOTTOM) then y = $ + (screenheight - baseheight) elseif ((scr & V_SNAPTOTOP) ~= V_SNAPTOTOP) then y = $ + ((screenheight - baseheight) / 2) end end -- The part thats actually important if splitscr == 1 and splitnum == 1 then y = $ + screenheight elseif splitscr > 1 then if (splitnum == 1 or splitnum == 3) then x = $ + screenwidth end if (splitnum >= 2) then y = $ + screenheight end end return x, y end
lua/derbyUtils.lua
Now all you needed to do is define splitscreen positions for a single screen of that splitscreen type, add V_SNAPTOLEFT|V_SNAPTOTOP
to the draw flags (as the function automatically handles that) and voila.
local OUT_X = 320/2 local OUT_Y = 200/2 -- Handle splitscreen positioning if splitscr then -- splitscreen OUT_Y = 200/4 if splitscr > 1 then -- 3/4p OUT_X = 320/4 end end -- Killing everyone OUT_X, OUT_Y = BDD_SplitscreenFUCK(v, c, OUT_X<<FRACBITS, OUT_Y<<FRACBITS) -- Alias, and its original name before it was moved -- 3/4p, stationary (2.3) if splitscr > 1 then -- oh hey we can ignore scrolling for now v.drawScaled(OUT_X - ((patch.width/2)<<FRACBITS), OUT_Y - ((patch.height/2)<<FRACBITS), FRACUNIT, patch, splitflags) return end
lua/derbyHudNeoNeo.lua
I wish to no longer work on splitscreen again. Atleast without this function.
Tally
Ah... the tally.... The custom end of level tally I worked probably too hard on.
As you can see, the rings counter and input display are still on screen. I cannot hide them. Teehee!
This arguably took me less time to make than splitscreen logic, though it was hard to actually get the tally to function normally.
You cannot hide the vanilla tally. Best you can do is to not trigger the tally at all.
But what about triggering stuff on p.exiting
you say?????
Just don't. Lmao
-- ThinkFrame runs after player thinkers, which is why this works addHook("ThinkFrame", function() for p in players.iterate do if p.spectator then continue end -- Pretend there's more here... p.exiting = 1 end end) -- At the start of the next tic, set it back to zero. This is called as the "exiting hack". addHook("PreThinkFrame", function() for p in players.iterate do if p.spectator then continue end -- Pretend there's more here too... p.exiting = 0 end end)
example.lua
As to why we didn't use P_DoPlayerExit
, well... it bugged out the point distribution. That's a story for another day.
The tally itself is set up in a way similar to the vanilla tally, though it's global, but sets specific stuff for the player in HUD code. Nothing too special.
Bean's Woods
Not yet. Not yet....
Conclusion
Bean's Woods is not done, therefore no conclusion. I did say this is still incomplete after all.....
:)
- ← Previous
the rss feed works now - Next →
thy birthday is now