ref: 423e5319e3d3501637fffb11bb5c0acd48c2f424
parent: 2d2fda85ac4907d53a26b9afebdfadf9364a6436
author: rodri <rgl@antares-labs.eu>
date: Fri Nov 15 11:38:47 EST 2024
bts: add vfx. use stringn instead of string.
binary files /dev/null b/assets/vfx/hit.png differ
binary files /dev/null b/assets/vfx/miss.png differ
--- a/bts.c
+++ b/bts.c
@@ -135,6 +135,8 @@
Font *titlefont;
char winspec[32];
char uid[8+1], oid[8+1];
+Sprite *spritetab[NVFX];
+Vfx vfxqueue;
Channel *drawchan;
Channel *reconnc;
Channel *ingress, *egress;
@@ -277,12 +279,8 @@
Point
vstring(Image *dst, Point p, Image *src, Point sp, Font *f, char *s)
{
- char buf[2];
-
- buf[1] = 0;
while(*s){
- buf[0] = *s++;
- string(dst, p, src, sp, f, buf);
+ stringn(dst, p, src, sp, f, s++, 1);
p.y += font->height;
}
return p;
@@ -408,6 +406,9 @@
snprint(aux, sizeof aux, "%s (%d)", shipname(curship-armada), curship->ncells);
p = Pt(SCRW/2 - stringwidth(font, aux)/2, SCRH-Boardmargin);
string(dst, p, pal[PCYellow], ZP, font, aux);
+ s = "MMB to rotate the ship";
+ p = Pt(SCRW/2 - stringwidth(font, s)/2, SCRH-Boardmargin+font->height);
+ string(dst, p, pal[PCYellow], ZP, font, s);
}else{
s = "done with the layout?";
p = Pt(SCRW/2 - stringwidth(font, s)/2, SCRH-Boardmargin);
@@ -452,6 +453,8 @@
void
redraw(void)
{
+ Vfx *vfx;
+
lockdisplay(display);
draw(screenb, screenb->r, pal[PCBlack], nil, ZP);
@@ -468,6 +471,8 @@
drawinfo(screenb);
break;
}
+ for(vfx = vfxqueue.next; vfx != &vfxqueue; vfx = vfx->next)
+ vfx->draw(vfx, screenb);
drawconclusion(screenb);
draw(screen, screen->r, screenb, nil, ZP);
@@ -603,6 +608,18 @@
}
void
+initvfx(void)
+{
+ char aux[64];
+
+ snprint(aux, sizeof aux, "%s/%s", assetdir, "vfx/hit.png");
+ spritetab[VFXHit] = readpngsprite(aux, ZP, Rect(0, 0, 32, 32), 12, 100);
+ snprint(aux, sizeof aux, "%s/%s", assetdir, "vfx/miss.png");
+ spritetab[VFXMiss] = readpngsprite(aux, ZP, Rect(0, 0, 32, 32), 7, 150);
+ initvfxq(&vfxqueue);
+}
+
+void
initsfx(void)
{
struct {
@@ -763,11 +780,11 @@
if(!rectinrect(curship->bbox, localboard.bbox)){
switch(curship->orient){
case OH:
- curship->bbox.min.x -= curship->bbox.max.x-localboard.bbox.max.x;
+ curship->bbox.min.x -= curship->bbox.max.x - localboard.bbox.max.x;
curship->bbox.max.x = localboard.bbox.max.x;
break;
case OV:
- curship->bbox.min.y -= curship->bbox.max.y-localboard.bbox.max.y;
+ curship->bbox.min.y -= curship->bbox.max.y - localboard.bbox.max.y;
curship->bbox.max.y = localboard.bbox.max.y;
break;
}
@@ -878,7 +895,7 @@
void
keelhaul(void)
{
- static char s[] = "…YOU LOST";
+ static char s[] = "...YOU LOST";
conclusion.c = pal[PCRed];
conclusion.s = s;
@@ -1009,11 +1026,17 @@
idx = strtoul(cb->f[1], nil, 10);
cell = coords2cell(cb->f[2]);
settile(match.bl[idx^1], cell, Thit);
+ addvfx(&vfxqueue,
+ newvfx(spritetab[VFXHit]->clone(spritetab[VFXHit]),
+ addpt(fromboard(match.bl[idx^1], cell), Pt(TW/2, TH/2)), 1));
break;
case CMplayermiss:
idx = strtoul(cb->f[1], nil, 10);
cell = coords2cell(cb->f[2]);
settile(match.bl[idx^1], cell, Tmiss);
+ addvfx(&vfxqueue,
+ newvfx(spritetab[VFXMiss]->clone(spritetab[VFXMiss]),
+ addpt(fromboard(match.bl[idx^1], cell), Pt(TW/2, TH/2)), 1));
break;
case CMplayerplays:
idx = strtoul(cb->f[1], nil, 10);
@@ -1045,6 +1068,9 @@
break;
case CMwehit:
settile(&alienboard, lastshot, Thit);
+ addvfx(&vfxqueue,
+ newvfx(spritetab[VFXHit]->clone(spritetab[VFXHit]),
+ addpt(fromboard(&alienboard, lastshot), Pt(TW/2, TH/2)), 1));
break;
case CMwemiss:
if(!silent)
@@ -1051,6 +1077,9 @@
playaudio(playlist[SWATER]);
settile(&alienboard, lastshot, Tmiss);
+ addvfx(&vfxqueue,
+ newvfx(spritetab[VFXMiss]->clone(spritetab[VFXMiss]),
+ addpt(fromboard(&alienboard, lastshot), Pt(TW/2, TH/2)), 1));
break;
}
break;
@@ -1064,6 +1093,9 @@
cell = coords2cell(cb->f[1]);
for(i = 0; i < nelem(armada); i++)
if(ptinrect(fromboard(&localboard, cell), armada[i].bbox)){
+ addvfx(&vfxqueue,
+ newvfx(spritetab[VFXHit]->clone(spritetab[VFXHit]),
+ addpt(fromboard(&localboard, cell), Pt(TW/2, TH/2)), 1));
cell = subpt2(cell, armada[i].p);
armada[i].hit[(int)vec2len(cell)] = 1;
break;
@@ -1072,6 +1104,9 @@
case CMtheymiss:
cell = coords2cell(cb->f[1]);
settile(&localboard, cell, Tmiss);
+ addvfx(&vfxqueue,
+ newvfx(spritetab[VFXMiss]->clone(spritetab[VFXMiss]),
+ addpt(fromboard(&localboard, cell), Pt(TW/2, TH/2)), 1));
break;
}
break;
@@ -1101,7 +1136,9 @@
void
timerproc(void *)
{
- uvlong t0, Δt, acc;
+ Vfx *vfx;
+ uvlong t0, Δt, φt, acc;
+ int refresh;
threadsetname("timer");
@@ -1109,8 +1146,17 @@
acc = 0;
for(;;){
Δt = nsec() - t0;
+ φt = Δt/1000000ULL;
acc += Δt;
+ refresh = 0;
+ for(vfx = vfxqueue.next; vfx != &vfxqueue; vfx = vfx->next){
+ vfx->step(vfx, φt);
+ refresh = 1;
+ }
+ if(refresh)
+ nbsend(drawchan, nil);
+
if(gamestate == Waiting0 && acc >= 5*SEC){
chanprint(egress, "watch\n");
acc = 0;
@@ -1117,7 +1163,7 @@
}
t0 += Δt;
- sleep(HZ2MS(10));
+ sleep(HZ2MS(20));
}
}
@@ -1232,6 +1278,7 @@
initmainbtns();
initboards();
initarmada();
+ initvfx();
matches = newmenulist(14*font->height, "ongoing matches");
gamestate = Waiting0;
--- a/dat.h
+++ b/dat.h
@@ -7,7 +7,7 @@
Tmiss,
NTILES,
- TBITS = 2, /* ceil(log(NTILES)/log(2)) */
+ TBITS = 2, /* ceil(log(NTILES)/log(2)) */
TMASK = (1<<TBITS) - 1,
Scarrier = 0,
@@ -17,9 +17,13 @@
Sdestroyer,
NSHIPS,
- OH, /* horizontal */
- OV, /* vertical */
+ VFXHit = 0,
+ VFXMiss,
+ NVFX,
+ OH = 0, /* horizontal */
+ OV, /* vertical */
+
GMPvP = 0,
GMPvAI,
@@ -178,6 +182,35 @@
Rectangle r;
int status;
void (*handler)(Button*);
+};
+
+typedef struct Sprite Sprite;
+typedef struct Vfx Vfx;
+
+struct Sprite
+{
+ Image *sheet;
+ Point sp;
+ Rectangle r;
+ int nframes;
+ int curframe;
+ ulong period;
+ ulong elapsed;
+
+ void (*step)(Sprite*, ulong);
+ void (*draw)(Sprite*, Image*, Point);
+ Sprite *(*clone)(Sprite*);
+};
+
+struct Vfx
+{
+ Sprite *a; /* animation */
+ Point p;
+ int times; /* to repeat. -1 loops forever */
+ Vfx *prev, *next;
+
+ void (*step)(Vfx*, ulong);
+ void (*draw)(Vfx*, Image*);
};
typedef struct Mentry Mentry;
--- a/fns.h
+++ b/fns.h
@@ -36,6 +36,22 @@
void delmenulist(Menulist*);
/*
+ * sprite
+ */
+Sprite *newsprite(Image*, Point, Rectangle, int, ulong);
+Sprite *readsprite(char*, Point, Rectangle, int, ulong);
+Sprite *readpngsprite(char*, Point, Rectangle, int, ulong);
+void delsprite(Sprite*);
+
+/*
+ * vfx
+ */
+Vfx *newvfx(Sprite*, Point, int);
+void delvfx(Vfx*);
+void addvfx(Vfx*, Vfx*);
+void initvfxq(Vfx*);
+
+/*
* parse
*/
Cmdbuf *parsecmd(char*, int);
--- a/mkfile
+++ b/mkfile
@@ -13,6 +13,8 @@
andy.$O\
menulist.$O\
mixer.$O\
+ sprite.$O\
+ vfx.$O\
HFILES=\
dat.h\