CONCEPT:
Castlevania SotN/Zelda II demake. The main focus of the game is the Zelda II-style combat; but also with palace-building scripts that... well... at this point, basically generates pathways to two keys (or enemies that drop them), an item room (that requires one of the keys), a boss room (that requires the other), and an in-palace shop. There's seven "palace chunks" in total, and later I'll be scripting closeoffs for passageways that aren't used.
DESIRED OUTCOME:
A seven-palace romp with progressive/changing enemies, decent assortment of weapons and passive items, enemy drop RNG that on occasion includes some of these weapons and items, to give it more of that SotN replay/uncertainty, a couple of secret areas of some sort?
SPRITING SUNDAY
TL;DR: Okay, I've done a fair portion of the core spriting, and incidentally, worked ahead a little in Music/Mapping Monday.
First row of spriting is the tileset. The "yellow block" includes some probability of generating a locked door (and a key with it, upstream somewhere); the "green blocks" basically take you from one chunk of the area to another.
The rest of the first page is the beginning of a three-layer spriting setup; upper body, lower body, and head (heads will go on page 2). Even though the standing sprites look "full," they're really designed to combine upper and lower body poses for various effects. The lower body relates to movement, while the upper relates to weapon management... so this way, you can still move side to side while executing standing attacks.
Crouching frames, however, are committed to crouch states/attacks. The crouching attack actually gets an ADDITIONAL tile of stretch/range, giving it a little bit of an advantage over standing attacks. This is compensated by making them more vulnerable (partly due to the body stretch) to airborne attacks or downward thrusts. There's also an "up strike" (and upward thrust) in the design to counter air attacks, and a plan of cancelability between them to allow for some comboability. So in a way, it's combining fighting game design with the core gameplay, too.
I also managed to make the subscreen, the top of which (hearts/coins/keys) will likely remain persistent throughout the game... I'm hoping I can make the pause function freeze the "action pane," then scroll it down (revealing the entire subscreen)... and the unpause function scroll it back up and resume. (pointers?)
Heads will be rolling soon (either while wrestling with other parts like the music tracker tomorrow, or next week if this becomes a two-week project). I'm planning on simply changing the colors and assigned heads (and weapons/HP) in a cross-reference kind of table so that a single function can generate an assortment of enemies and attack/defense patterns; like so:
FUNCTION MAKEENEMY(head,color)
head will assign attack/defense priorities (primary and secondary - primary is reactive to a specific player state, secondary is what it does if the player does not enter that state).
color will assign HP and weapon (which will factor up with progression).
The idea is that 12 variants of each will generate 144 creatures, which spread across 7 levels? Each level will have about 20 enemies to pool from, and each playthrough will assign maybe 4 or 5 of them.
I'm also planning on putting a few basic creatures in play as well... some "chunks" are designed for this fighting system (which will focus more on the core enemies), while a few are more focused on the lateral platforming that rounds out the action, which is what the "smaller" creatures are for. But I don't plan on making them so small that you have to crouch-stab everything (or the standing attack's range?).
The thing with the little creatures though, is that since the game is very map intensive, the shared data is going to be map-prioritized... so I've gotta dig through the infamous favorites of the titles and find which ones are most relevant to the game and just make a few of them... but again, after the heads and combat variants are in place. Those are the more important ones.
Well, that's all for today. Tomorrow: Music/Mapping Monday!
It's really just my second time wrestling with the SFX/Music tracker; I'm hoping to compose two alternating palace themes, a boss battle theme, and a "final boss" theme.
There seems to be a "CARTRIDGE FORMAT ERROR 1"... which is a shame, because what you're describing sounds like fun!
It has no code yet, right now it's just sprites and maps. And thank you! I'm using the site as a recursive backup until it's in a playable state (which will be announced).
That said... got invited to a July 4th thing, had to work late and go in early tonight... so this may take more days than I was allowing myself. Tomorrow is "Writing Wednesday" (this is where I start the code part; but I still have to mash some heads in to get the basic FSM in place)... and I'll have to come back to Music Monday/Title Screen Tuesday next week.
I'm okay with this being a two-weeker. Even a three-weeker if that's what it takes. Hopefully my CHIP will ship soon! Then I can dev to and from work, and on at least one of my breaks, too. That'll help things a LOT. (And is the other reason I'm keeping recursive backups here!)
"So where was I again?"
Okay... I'm working on an FSM for the player and humanoid enemies now. I do see how in some projects, a player-based FSM works (mostly through "update()")... but how would I modify this to be on a per-entity basis?
Don't get me wrong, the game's going to have a few basic creature-like things that'll be way simpler, but since the main focus of this is on the dueling, I want to have some universal state control that applies equally between the player and enemies.
Also, going through a checklist of typical states for this sort of thing...
STAND
-idle
-damaged
-attack
-attackup
-block
-walk
-walkattack
CROUCH
-idle
-damaged
-attack
-block
-stun
-dead
JUMP
-upward
-arch
-downward
-damaged (normal)
-popup (hit with up-attack/thrust)
-upthrust
-downthrust
-wing1...wing9 (this is for some special items used to modify jumping)
Finally, a branching pathway generator, to define the parameters of scene usage.
Start...
>Key branch, Item branch (requires key)
>Key branch, Treasure branch (requires key)
>Key branch, Miniboss branch (requires key, awards heart container)
>Key branch, Boss branch (requires key), exit
>Shop branch
>?? Casino branch (a wheel that can modify stats or consumables)
>?? Horde branch
>?? 3-wave Trap branch
Any other room/branch ideas to consider?
Okay. So 2017 was a DISASTER at my job. Tons of relocations, retirements, and a deliberate effort to minimize restaffing - so bad that my job in that year had more work-related injuries than my ENTIRE JOB HISTORY COMBINED. Which of course, only made that problem WORSE.
Long story short, I've been working on my projects again this week after 5 months of not even touching them. Hence, my lack of forum activity as well.
So I'm in the midst of creating (and animating) my FSM for the game... and I'm kind of hitting a syntax hiccup that I'm not understanding right now. In the attack animations, I want to add windup, so when I enter the state, the attack comes out in 5 frames/steps instead of immediately. Now, I can initiate animations right away, but making it trigger the attack on the correct frame is being dicey.
I guess, more specifically, on frame 5 of attack animations, I want to add a "maketarget()" that is the active weapon. I may go back and make different framerates for different kinds of weapons (for tactical reasons), but for now I'm sticking with simplicity.
Anybody know of some trickery that'll do that?
--concert of the damned _init() --globals maxhp=6 maxwp=6 maxrun=0.4 maxjump=28 shotdmg=5 weapdmg=15 accframes=20 --to max, -2 to decel jmpframes=40 --up dshframes=50 --duration chgframes=50 --buster fricrate=0.95 maxdrop=8 gravity=1 facing=1 -- -1=l 0=u 1=r p.st=0 airjump=0 stall=0 screen=0 --title function shuf(t) local r=rnd assert (t,"shuf() expects table, got nil") local iterations=#t local j for i=iterations,2,-1 do j=rnd(i) t(i),t(j)=t(j),t(i) end end function name(n) local nlist={"ace","ard","ang","ent","erg","esk","ilk","ixe","ins","oot","ong","oss","unn","urt","uan","yrt"} n1=n/25 if n1=1 then n1="ch" if n1=2 then n1="b" if n1=3 then n1="c" if n1=4 then n1="d" if n1=5 then n1="sh" if n1=6 then n1="f" if n1=7 then n1="g" if n1=8 then n1="h" if n1=9 then n1="th" if n1=10 then n1="j" if n1=11 then n1="k" if n1=12 then n1="l" if n1=13 then n1="m" if n1=14 then n1="n" if n1=15 then n1="fl" if n1=16 then n1="p" if n1=17 then n1="qu" if n1=18 then n1="r" if n1=19 then n1="s" if n1=20 then n1="t" if n1=21 then n1="ph" if n1=22 then n1="v" if n1=23 then n1="w" if n1=24 then n1="x" if n1=25 then n1="y" n2=nlist#n\16 return (n1,n2) end function p_run() local aframes=accframes local xmove=maxrun if (btnp(0)) facing=-1 if (btnp(1)) facing=1 if (btn(0)=1 and btn(1)=1) then (btn(0),btn(1))=(0,0) else if btn(0)=1 or btn(1) aframes-=1 else if btn(0)=0 and btn(1)=0 foreach aframes<accframes aframes+=2 end for a=1,aframes xmove*=fricrate end if (xmove>maxrun) xmove=maxrun player.x+=xmove*facing end function p_jump(jh or 0, jf or 0) if (jh=0) jh=jumpheight if (jf=0) jf=jumpframes local px=jh/(jf!) for j=-jf,999 ymove=px*j if(ymove>maxdrop)ymove=maxdrop j+=1 if(j>999)j=999 end function hitwall(_x,_y) if (checkspot(p.x,p.y,0)or checkspot(p.x,p.y+7,0) return true if (checkspot(p.x+7,p.y,0)or checkspot(p.x+7,p.y+7,0) return true return false end function hitfloor(_x,_y) if (checkspot(p.x,p.y,0)or checkspot(p.x+7,p.y,0)) return true if (checkspot(p.x,p.y+7,0)or checkspot(p.x+7,p.y+7,0)) return true return false end function checkspot(_x,_y,_flag) local tilex=flr(_x/8) local tiley=flr(_y/8) local tile=mget(tilex+levelx,tiley+levely) return fget(tile,_flag) end function bounce(obj,m,xdir or -1,ydir or -1) obj.xmove=m*xdir*2 obj.ymove=m*ydir if hitwall(obj.x,obj.y)=true then xdir*=-1 obj.xmove=m*xdir*2 obj.ymove=m*ydir else if hitfloor(obj.x,obj.y)=true then ydir*=-1 obj.xmove=m*xdir obj.ymove=m*ydir*2 end function movep() local oldx=p.x local oldy=p.y (p.x,p.y)+=(xmove,ymove) if (hitwall(p.x,p.y)=true) p.x=oldx if (hitfloor(p.x,p.y)=true) p.y=oldy end function maketarget(obj,scr,x,y,xrange or 0,yrange or 0,speed or 0,loop or 0) --x/y position relative to map obj.x=((scr\5)*16+x) obj.y=((scr/5)*16+y) --set sine motions to control local movex=2*sqrt(xrange)*speed local movey=2*sqrt(yrange)*speed --reverse direction! if (movex=xrange or movex=-xrange or xrange<0) movex*=-1 if (movey=yrange or movey=-yrange or yrange<0) movey*=-1 --diagonals or curves if loop=1 then movex=xrange elseif loop=-1 then movex-=xrange end function collide(p,other) if other.p.x+other.hitbox.x+other.hitbox.w > obj.p.x+obj.hitbox.x and other.p.y+other.hitbox.y+other.hitbox.h > obj.p.y+obj.hitbox.y and other.p.x+other.hitbox.x < obj.p.x+obj.hitbox.x+obj.hitbox.w and other.p.y+other.hitbox.y < obj.p.y+obj.hitbox.y+obj.hitbox.h then return true end end function topanim(act,f1,f2 or 0,f3 or 0,f4 or 0, f5 or 0, f6 or 0, f7 or 0) f=f1 spr(f,act.x-8,act.y-16,[16,8],f,0) if f2=0 then f=f1 else f=f2 if f3=0 then f=f1 else f=f3 if f4=0 then f=f1 else f=f4 if f5=0 then f=f1 else f=f5 if f6=0 then f=f1 else f=f6 if f7=0 then f=f1 else f=f7 if f8=0 then f=f1 else f=f8 f=f1 end function botanim(act,f1,f2 or 0,f3 or 0,f4 or 0, f5 or 0, f6 or 0, f7 or 0) frame=1 f=f1 spr(f,act.x-8,act.y-8,[16,8],f,0) if frame=1 then f=f1 elseif frame=2 then if f2=0 then f=f1 and frame=1 else f=f2 elseif frame=3 then if f3=0 then f=f1 and frame=1 else f=f3 elseif frame=4 then if f4=0 then f=f1 and frame=1 else f=f4 elseif frame=5 then if f5=0 then f=f1 and frame=1 else f=f5 elseif frame=6 then if f6=0 then f=f1 and frame=1 else f=f6 elseif frame=7 then if f7=0 then f=f1 and frame=1 else f=f7 elseif frame=8 then if f8=0 then f=f1 and frame=1 else f=f8 frame+=1 if frame>8 then frame=1 end function head() //standing/aerial sprites only spr(act.head,act.x-4,act.y-24,[8,8],f,0) end function state(act,st) if facing=-1 then f=1 else f=0 if act.st=0 then elseif act.st=1 then //display cursor elseif act.st=2 then //stand topanim(act,16) botanim(act,32) head() elseif act.st=3 then //move l/r on ground topanim(act,16) botanim(act,34,34,36,36,38,38) head() p_run() elseif act.st=4 then //jump up~air topanim(act,20) botanim(act,42) head() if airjump>0 or checkspot(x,y+1,solid)=true then p_jump() and p_run() else p_run() elseif act.st=5 then //jump down~air topanim(act,20) botanim(act,44) head() elseif act.st=6 then //block~high topanim(act,16) botanim(act,32) head() elseif act.st=7 then //block~low botanim(act,48) spr(head,act.x-4,act.y-16,[8,8],f,0) elseif act.st=8 then //elevator up elseif act.st=9 then //elevator down elseif act.st=10 then //ai lateral elseif act.st=11 then //recover to neutral botanim(act,56,56) spr(head,act.x-4,act.y-16,[8,8],f,0) elseif act.st=12 then //stand attack topanim(act,20,20,20,22,22,22) botanim(act,32) head() elseif act.st=13 then //uppercut topanim(act,16,16,16,16,26,26,26) botanim(act,32) head() elseif act.st=14 then //air attack topanim(act,20,20,20,22,22,22) botanim(act,36,36,36,42,42,42) elseif act.st=15 then //crouch attack botanim(act,48,48,48,50,50,50) spr(head,act.x-4,act.y-16,[8,8],f,0) if f=1 then spr(52,act.x-8.act.y-8,[8,8],1,0) else spr(52,act.x+16,act.y-8,[8,8],0,1) elseif act.st=16 then //up thrust topanim(act,16,26,26,26,26,28,28,28) botanim(act,38,42,42,42,42,44,44,44) head() elseif act.st=17 then //down thrust botanim(act,56) spr(head,act.x-4,act.y-16,[8,8],f,0) elseif act.st=18 then //bow charge elseif act.st=19 then //bow release elseif act.st=20 then //downed~to recover botamin(act,54,54,54) //add head/spr 53 elseif act.st=21 then //stand-hit react topanim(act,24,24,24,24) botanim(act,40,40,40,40) head() stall=4 elseif act.st=22 then //uppercut react topanim(act,24,24,24,24) botanim(act,40,40,40,40) head() stall=7 elseif act.st=23 then //air-hit react topanim(act,24,24,24,24) botanim(act,40,40,40,40) head() stall=4 elseif act.st=24 then //crouch hit react botanim(act,56,56,56,56) spr(head,act.x-4,act.y-16,[8,8],f,0) stall=4 elseif act.st=25 then //recovery~left elseif act.st=26 then //recovery~right elseif act.st=27 then //bow~up elseif act.st=28 then //bow~down elseif act.st=29 then //reserved elseif act.st=30 then //ai tactic a elseif act.st=31 then //ai tactic b elseif act.st=32 then //ai tactic c elseif act.st=33 then //ai tactic d elseif act.st=34 then //ai tactic e elseif act.st=35 then //ai tactic f elseif act.st=36 then //ai tactic g elseif act.st=37 then //ai tactic h elseif act.st=38 then //ai tactic i elseif act.st=39 then //ai tactic j end end --of _init() _update() end --of _update() _draw() end --of _draw() |
[Please log in to post a comment]