I've just released a homebrew for PSP: wololo.net/downloads/index.php/download/8183
The goal is to destroy a lemon pie by playing tennis against it. The lemon pie sends at times mini-games.
I've tried it under PPSSPP and two mini-games behave badly.
One of them is to smash the right TVs.
The VRAM emulation seems to be confused by what I want to write in it.
Code:
short shoot_teevees(int diff, int *health, int round)
{
short reussi=1, enemyx=random(2), enemyy=random(3), fired=13, hasdied=0;
int i, j, u, frame=0, skipframe=0, hgx=208;
int teevees[3][4]; //angle-ecran-y-fallspeed
OSL_SOUND *passs = oslLoadSoundFile("./sfx/sfx-0053.wav", OSL_FMT_NONE);
OSL_SOUND *dead = oslLoadSoundFile("./sfx/sfx-0025.wav", OSL_FMT_NONE);
OSL_SOUND *pew = oslLoadSoundFile("./sfx/sfx-0100.wav", OSL_FMT_NONE);
OSL_SOUND *oof = oslLoadSoundFile("./sfx/sfx-0101.wav", OSL_FMT_NONE);
OSL_SOUND *ambient = oslLoadSoundFile("./sfx/sfx-0017.wav", OSL_FMT_NONE);
OSL_IMAGE *pass = oslLoadImageFilePNG("./gfx/gfx-0718.png",OSL_IN_RAM, OSL_PF_5551);
OSL_IMAGE *bg = oslLoadImageFilePNG("./gfx/gfx-0776.png",OSL_IN_RAM, OSL_PF_5551);
OSL_IMAGE *teevee = oslLoadImageFilePNG("./gfx/teevee.png",OSL_IN_RAM, OSL_PF_5551);
OSL_IMAGE *teevee_targets = oslLoadImageFilePNG("./gfx/teevee_targets.png",OSL_IN_RAM, OSL_PF_5551);
OSL_IMAGE *numberz = oslLoadImageFilePNG("./gfx/numberz.png",OSL_IN_RAM, OSL_PF_5551);
OSL_IMAGE *handgun = oslLoadImageFilePNG("./gfx/handgun.png",OSL_IN_RAM, OSL_PF_5551);
OSL_IMAGE *explode = oslLoadImageFilePNG("./gfx/explode.png",OSL_IN_RAM, OSL_PF_5551);
OSL_IMAGE *temp = oslCreateImage(128, 96, OSL_IN_VRAM, OSL_PF_5551);
oslSetImageRotCenter(pass);
oslSetImageRotCenter(temp);
oslSetSoundLoop(ambient, 1);
oslClearImage(temp, RGB(0, 0, 0));
for (i=0; i<3; i++)
{
teevees[i][0]=random(180)-90;
teevees[i][1]=random(2);
teevees[i][2]=-1*random(128)-128;
teevees[i][3]=diff+1+random(3);
}
oslSetImageTileSize(handgun, 0, 0, 64, 64);
oslPlaySound(ambient, 1);
while (frame < 900*diff)
{
if (!skipframe)
{
oslStartDrawing();
oslDrawFillRect(0,0,480,272, RGB(0,0,0));
spr_draw(bg, 0, 0);
oslSetTransparentColor(RGB(255,0,255));
oslSetBkColor(RGB(255,0,255));
oslSetTextColor(RGB(255, 255, 255));
oslDrawString(160, 2, "Shoot the TVs with that screen:");
oslSetImageTileSize(teevee_targets, 99*enemyx, 71*enemyy, 99, 71);
oslSetBilinearFilter(1);
teevee_targets -> stretchX = 50;
teevee_targets -> stretchY = 35;
spr_draw(teevee_targets, 215, 14);
oslSetBilinearFilter(0);
teevee_targets -> stretchX = 99;
teevee_targets -> stretchY = 71;
explode -> stretchX = 128;
explode -> stretchY = 96;
oslSetImageTileSize(numberz,160,0,16,16);
spr_draw(numberz, 2, 2);
for (i=0; i<3; i++)
{
oslSetDrawBuffer(temp);
oslSetImageTileSize(teevee_targets, teevees[i][1]*99, 71*enemyy, 99, 71);
spr_draw(teevee, 0, 0);
spr_draw(teevee_targets, 14, 10);
oslSetDrawBuffer(OSL_DEFAULT_BUFFER);
temp -> angle = teevees[i][0];
spr_draw(temp, 160*i+80, teevees[i][2]);
teevees[i][2] += teevees[i][3];
if (teevees[i][2] > (336+((int)128*(sin(teevee -> stretchX)*3.14/180))))
{
if (teevees[i][1]==enemyx)
{
*health -= 12*diff;
if ((*health <= 0) && (!hasdied))
{
oslPlaySound(dead, 2);
hasdied=1;
frame=900*diff-131;
}
}
teevees[i][0]=random(180)-90;
teevees[i][1]=random(2);
teevees[i][2]=-1*random(128)-128;
teevees[i][3]=diff+1+random(3);
}
}
if (*health > 0) spr_draw(handgun, hgx, 211+((int)3*sin(0.0625*frame))); else spr_draw(handgun, hgx, 211+((int)3*sin(frame)));
oslReadKeys();
if (((osl_keys -> held.left) || (osl_pad.analogX<-16)) && (hgx > 8) && (*health > 0)) hgx-=8;
if (((osl_keys -> held.right) || (osl_pad.analogX>16)) && (hgx < 408) && (*health > 0)) hgx+=8;
if (fired < 13)
{
fired--;
if ((teevees[hgx/160][1]==enemyx) && (teevees[hgx/160][2] > 140))
{
spr_draw(explode, 160*i+80, teevees[hgx/160][2]);
}
if (fired > 9)
{
oslSetImageTileSize(handgun, 64, 0, 64, 64);
spr_draw(handgun, hgx, 211+((int)3*sin(0.0625*frame)));
}
else
{
oslSetImageTileSize(handgun, 0, 0, 64, 64);
if (fired==8)
{
if ((teevees[hgx/160][1]==enemyx) && (teevees[hgx/160][2] > 140))
{
teevees[hgx/160][0]=random(180)-90;
teevees[hgx/160][1]=random(2);
teevees[hgx/160][2]=-1*random(128)-128;
teevees[hgx/160][3]=diff+1+random(3);
*health += 2*(4-diff);
if (*health >= 100) *health=100;
}
}
}
}
if (!fired)
{
fired=13;
oslSetImageTileSize(handgun, 0, 0, 64, 64);
}
if (((osl_keys -> pressed.circle) || (osl_keys -> pressed.cross) || (osl_keys -> pressed.triangle) || (osl_keys -> pressed.square)) && (fired==13) && (*health > 0))
{
fired--;
oslPlaySound(pew, 3);
if ((teevees[hgx/160][1]!=enemyx) && (teevees[hgx/160][2] > 140))
{
*health -= 6*diff;
oslPlaySound(oof, 4);
}
}
i=random(15);
u=18;
if (*health <= 0)
{
*health=0;
}
if (*health < 25) j=16; else j=0;
if (*health / 100)
{
oslSetImageTileSize(numberz,((round==2)?((i<12)?16:random(144)):16),0,16,16);
spr_draw(numberz, u + ((round==2)?random(3):0), ((round==2)?1+random(3):2));
u += 16;
}
if (*health > 9)
{
if (round==2)
{
if (i<12)
{
oslSetImageTileSize(numberz,((*health%100)/10)*16,j,16,16);
}
else
{
oslSetImageTileSize(numberz,random(128),j,16,16);
}
}
else oslSetImageTileSize(numberz,((*health%100)/10)*16,j,16,16);
spr_draw(numberz, u + ((round==2)?random(3):0), ((round==2)?1+random(3):2));
u += 16;
}
if (round==2)
{
if (i<12)
{
oslSetImageTileSize(numberz,(*health%10)*16,j,16,16);
}
else
{
oslSetImageTileSize(numberz,random(128),j,16,16);
}
}
else oslSetImageTileSize(numberz,(*health%10)*16,j,16,16);
spr_draw(numberz, u + ((round==2)?random(3):0), ((round==2)?1+random(3):2));
frame++;
oslEndDrawing();
oslEndFrame();
}
skipframe=oslSyncFrame();
}
oslClearImage(OSL_SECONDARY_BUFFER, RGB(0,0,0));
if (*health > 0)
{
oslStopSound(ambient);
for (i=0; i<10; i++) oslClearImage(OSL_SECONDARY_BUFFER, RGB(255, 255, 255));
oslPlaySound(passs, 2);
for (i=135; i<=272; i+=24)
{
oslStartDrawing();
oslDrawFillRect(0,0,480,272, RGB(0,0,0));
spr_draw(pass,240,136);
pass -> stretchX = pass -> stretchY = i;
oslEndDrawing();
oslSwapBuffers();
oslWaitVSync();
}
}
else reussi=0;
oslDeleteImage(bg);
oslDeleteImage(pass);
oslDeleteImage(teevee);
oslDeleteImage(teevee_targets);
oslDeleteImage(handgun);
oslDeleteImage(temp);
oslDeleteImage(numberz);
oslDeleteImage(explode);
oslDeleteSound(passs);
oslDeleteSound(dead);
oslDeleteSound(pew);
oslDeleteSound(ambient);
oslDeleteSound(oof);
return reussi;
}
As a result, specific code for PPSSPP had to be written so these mini-games won't trigger. Also, a specific punishment is reserved to all those who have played this game on PPSSPP.