Minigames begin.

This commit is contained in:
Mari the Deer 2022-04-15 18:30:29 +02:00
commit faed30c118
12 changed files with 473 additions and 35 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -643,6 +643,9 @@ SWWM_HELPTXT =
"\cx———————————————————————\c-\n"
"\n"
"\cfUp/Down:\c- Scroll";
SWWM_GAMETAB = "Games";
SWWM_PICKGAME = "Choose a game";
SWWM_GAMETITLE_MADCATGAME = "Boot Test";
// Wallbuster menu
SWWM_BUSTERTITLE = "Wallbuster - Easy Reload Menu";
SWWM_BUSTERKEYS =

View file

@ -622,6 +622,9 @@ SWWM_HELPTXT =
"\cx———————————————————————————————\c-\n"
"\n"
"\cfArriba/Abajo:\c- Scroll";
SWWM_GAMETAB = "Juegos";
SWWM_PICKGAME = "Elige un juego";
SWWM_GAMETITLE_MADCATGAME = "Test de Arranque";
// Wallbuster menu
SWWM_BUSTERTITLE = "Wallbuster - Menú de Recarga Fácil";
SWWM_BUSTERKEYS =

View file

@ -1,3 +1,3 @@
[default]
SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r30 \cu(Thu 14 Apr 22:14:59 CEST 2022)\c-";
SWWM_SHORTVER="\cw1.3pre r30 \cu(2022-04-14 22:14:59)\c-";
SWWM_MODVER="\cyDEMOLITIONIST \cw1.3pre r31 \cu(Fri 15 Apr 18:30:29 CEST 2022)\c-";
SWWM_SHORTVER="\cw1.3pre r31 \cu(2022-04-15 18:30:29)\c-";

View file

@ -1601,3 +1601,6 @@ wolf3d/pushwall sounds/wolfstuff/wolf3d_pushwall.ogg
wolf3d/ssdie sounds/wolfstuff/wolf3d_ssdie.ogg
wolf3d/ssfire sounds/wolfstuff/wolf3d_ssfire.ogg
wolf3d/sssight sounds/wolfstuff/wolf3d_sssight.ogg
// minigames
madcat/boot sounds/MADCAT.ogg

BIN
sounds/MADCAT.ogg Normal file

Binary file not shown.

View file

@ -75,6 +75,10 @@ version "4.8"
#include "zscript/kbase/swwm_kbasetab_chat.zsc"
#include "zscript/kbase/swwm_kbasetab_help.zsc"
#include "zscript/kbase/swwm_kbasetab_secret.zsc"
#include "zscript/kbase/swwm_kbasetab_games.zsc"
// minigames
#include "zscript/games/swwm_madcat.zsc"
#include "zscript/games/swwm_minigames.zsc"
// items
#include "zscript/items/swwm_baseitem.zsc"
#include "zscript/items/swwm_basehealth.zsc"

View file

@ -0,0 +1,262 @@
// shared MADCAT framework code
// skeleton class, doesn't have much other than the bare generic essentials
Class MadcatGameState abstract ui
{
Name GameName;
abstract MadcatGameState Init();
}
// state manager static thinker, to keep progress throughout a play session
// must be created by the static handler on map load if it doesn't exist
Class MadcatGameStateManager : Thinker
{
ui Array<MadcatGameState> GameState;
// return state object for a specific game name
// returns null if no state exists (caller must add a new one)
static ui MadcatGameState GetState( Name GameName )
{
let gsm = MadcatGameStateManager(ThinkerIterator.Create("MadcatGameStateManager").Next());
if ( !gsm ) ThrowAbortException("Game State Manager not found.");
for ( int i=0; i<gsm.GameState.Size(); i++ )
{
if ( gsm.GameState[i].GameName != GameName ) continue;
return gsm.GameState[i];
}
return null;
}
// adds a new game state object to the list
// if an object for the same game already exists, destroy and replace it
static ui void AddState( MadcatGameState NewState )
{
let gsm = MadcatGameStateManager(ThinkerIterator.Create("MadcatGameStateManager").Next());
if ( !gsm ) ThrowAbortException("Game State Manager not found.");
for ( int i=0; i<gsm.GameState.Size(); i++ )
{
if ( gsm.GameState[i].GameName != NewState.GameName ) continue;
gsm.GameState[i].Destroy();
gsm.GameState[i] = NewState;
return;
}
gsm.GameState.Push(NewState);
}
}
enum EMadcatGameState
{
CAT_BOOT,
CAT_MENU,
CAT_GAME
};
// barebones "game" object, the base code just displays the boot screen, and
// then switches state to the menu
// it's up to subclasses to handle the rest
Class MadcatGame ui
{
int global_state;
TextureID boot_tileset;
int boot_state, boot_timer;
bool bClosed;
int boot_tiles[360];
String oldmus;
int oldorder;
bool oldloop;
enum EBootState
{
BS_FADEIN,
BS_FLASH,
BS_FADEOUT,
BS_IDLE
};
private void Boot_PrepareTitle()
{
static const int tiles_logo[] =
{
48,49,50,48,51,50,52,51,50,48,51,53,48,51,50,54,55,53,
56,57,56,58,59,60,56,61,56,56,61,61,58,59,60,61,56,61,
62,61,62,63,64,65,66,51,67,68,51,53,63,64,65,61,62,61
};
boot_tiles[0] = 1;
for ( int i=1; i<23; i++ ) boot_tiles[i] = 2;
boot_tiles[23] = 3;
for ( int i=1; i<14; i++ ) boot_tiles[i*24] = 4;
for ( int i=1; i<14; i++ ) boot_tiles[i*24+23] = 5;
boot_tiles[336] = 6;
for ( int i=337; i<359; i++ ) boot_tiles[i] = 7;
boot_tiles[359] = 8;
boot_tiles[165] = 9;
for ( int i=0; i<18; i++ ) boot_tiles[i+147] = tiles_logo[i];
for ( int i=0; i<18; i++ ) boot_tiles[i+171] = tiles_logo[i+18];
for ( int i=0; i<18; i++ ) boot_tiles[i+195] = tiles_logo[i+36];
}
private void Boot_FadeInTiles()
{
for ( int i=0; i<360; i++ )
{
if ( !boot_tiles[i] ) continue;
else if ( boot_tiles[i] < 48 ) boot_tiles[i] += 9;
else boot_tiles[i] += 21;
}
}
private void Boot_PreFadeOutTiles()
{
for ( int i=0; i<360; i++ )
{
if ( !boot_tiles[i] ) continue;
else if ( boot_tiles[i] < 48 ) boot_tiles[i] += 27;
else boot_tiles[i] += 63;
}
}
private void Boot_FadeOutTiles()
{
for ( int i=0; i<360; i++ )
{
if ( !boot_tiles[i] ) continue;
else if ( boot_tiles[i] < 48 ) boot_tiles[i] -= 9;
else boot_tiles[i] -= 21;
}
}
private void Boot_FlashState()
{
if ( boot_timer%2 ) return;
int timer = boot_timer/2;
for ( int j=0; j<timer; j++ )
{
if ( j >= 18 ) continue;
if ( boot_tiles[j+147] && (boot_tiles[j+147] < 195) ) boot_tiles[j+147] += 21;
}
for ( int j=-1; j<timer-1; j++ )
{
if ( j < 0 ) continue;
if ( j >= 18 ) continue;
if ( (boot_tiles[j+171] < 195) ) boot_tiles[j+171] += 21;
}
for ( int j=-2; j<timer-2; j++ )
{
if ( j < 0 ) continue;
if ( j >= 18 ) continue;
if ( (boot_tiles[j+195] < 195) ) boot_tiles[j+195] += 21;
}
}
private void Boot_ClearTiles()
{
for ( int i=0; i<360; i++ ) boot_tiles[i] = 0;
}
// game has been booted up
virtual void Init()
{
oldmus = musplaying.name;
oldorder = musplaying.baseorder;
oldloop = musplaying.loop;
S_ChangeMusic("");
bClosed = false;
global_state = CAT_BOOT;
boot_state = BS_FADEIN;
boot_timer = -16;
boot_tileset = TexMan.CheckForTexture("graphics/Games/MadcatTiles.png",TexMan.Type_Any);
}
// game is ticking
virtual void Tick()
{
// only bootup is handled here
if ( global_state != CAT_BOOT ) return;
switch ( boot_state )
{
case BS_FADEIN:
if ( boot_timer == 0 ) Boot_PrepareTitle();
else if ( !(boot_timer%4) && (boot_timer >= 4) ) Boot_FadeInTiles();
boot_timer++;
if ( boot_timer > 12 )
{
boot_state++;
boot_timer = -16;
}
break;
case BS_FLASH:
Boot_FlashState();
boot_timer++;
if ( boot_timer > 80 )
{
boot_state++;
boot_timer = 0;
}
else if ( boot_timer == 0 ) S_StartSound("madcat/boot",CHAN_VOICE,CHANF_UI,1.,0.);
break;
case BS_FADEOUT:
if ( boot_timer == 0 )
{
Boot_PrepareTitle();
Boot_PreFadeOutTiles();
}
else if ( !(boot_timer%4) && (boot_timer >= 4) ) Boot_FadeOutTiles();
boot_timer++;
if ( boot_timer > 12 )
{
boot_state++;
boot_timer = 0;
}
break;
case BS_IDLE:
boot_timer++;
if ( boot_timer == 4 ) Boot_ClearTiles();
else if ( boot_timer >= 40 )
{
global_state = CAT_MENU;
boot_state = 0;
boot_timer = 0;
}
break;
}
}
// draw on the virtual screen
// coordinates are absolute
virtual void Draw( Vector2 screen_pos, double screen_zoom )
{
// only bootup is handled here
if ( global_state != CAT_BOOT ) return;
for ( int i=0; i<360; i++ )
{
int tsx = (boot_tiles[i]&0x0F)*8;
int tsy = ((boot_tiles[i]&0xF0)>>4)*8;
int fsx = (i%24)*16;
int fsy = (i/24)*16;
Screen.DrawTexture(boot_tileset,false,
screen_pos.x+fsx*screen_zoom,
screen_pos.y+fsy*screen_zoom,
DTA_ScaleX,screen_zoom,DTA_ScaleY,screen_zoom,
DTA_SrcX,tsx,DTA_SrcY,tsy,
DTA_SrcWidth,8,DTA_SrcHeight,8,
DTA_DestWidth,16,DTA_DestHeight,16);
}
}
// process keyboard input
virtual bool ProcessInput( int key, bool release )
{
return false;
}
// game has been closed
virtual void Close()
{
bClosed = true;
S_ChangeMusic(oldmus,oldorder,oldloop);
}
override void OnDestroy()
{
if ( !bClosed ) Close();
Super.OnDestroy();
}
}

View file

@ -0,0 +1 @@
// basic minigames

View file

@ -188,6 +188,7 @@ Class DemolitionistMenu : GenericMenu
'DemolitionistLibraryTab',
'DemolitionistStoreTab',
'DemolitionistChatTab',
'DemolitionistGameTab',
'DemolitionistHelpTab',
'DemolitionistSecretTab'
};
@ -218,44 +219,48 @@ Class DemolitionistMenu : GenericMenu
override bool MenuEvent( int mkey, bool fromcontroller )
{
switch ( kcode )
// pachinko code only handled if the tab lacks direct input
if ( !tabs[curtab].bDirectInput )
{
case 0:
case 1:
if ( mkey == MKEY_UP ) kcode++;
else kcode = 0;
break;
case 2:
case 3:
if ( mkey == MKEY_DOWN ) kcode++;
else kcode = 0;
break;
case 4:
case 6:
if ( mkey == MKEY_LEFT ) kcode++;
else kcode = 0;
break;
case 5:
case 7:
if ( mkey == MKEY_RIGHT ) kcode++;
else kcode = 0;
break;
case 10:
if ( mkey == MKEY_ENTER )
switch ( kcode )
{
int secret = FindTabType('DemolitionistSecretTab');
if ( curtab != secret )
case 0:
case 1:
if ( mkey == MKEY_UP ) kcode++;
else kcode = 0;
break;
case 2:
case 3:
if ( mkey == MKEY_DOWN ) kcode++;
else kcode = 0;
break;
case 4:
case 6:
if ( mkey == MKEY_LEFT ) kcode++;
else kcode = 0;
break;
case 5:
case 7:
if ( mkey == MKEY_RIGHT ) kcode++;
else kcode = 0;
break;
case 10:
if ( mkey == MKEY_ENTER )
{
MenuSound("misc/secret");
tabs[curtab].OnDeselect();
curtab = secret;
tabs[curtab].OnSelect();
}
int secret = FindTabType('DemolitionistSecretTab');
if ( curtab != secret )
{
MenuSound("misc/secret");
tabs[curtab].OnDeselect();
curtab = secret;
tabs[curtab].OnSelect();
}
}
default:
kcode = 0;
break;
}
default:
kcode = 0;
break;
}
switch ( mkey )
{
@ -384,6 +389,8 @@ Class DemolitionistMenu : GenericMenu
override bool OnUiEvent( UIEvent ev )
{
if ( tabs[curtab].bDirectInput && ((ev.type == UIEvent.Type_KeyDown) || (ev.type == UIEvent.Type_KeyUp)) )
return tabs[curtab].DirectInput(ev);
switch ( ev.type )
{
case UIEvent.Type_KeyDown:

View file

@ -5,6 +5,7 @@ Class DemolitionistMenuTab ui abstract
DemolitionistMenu master;
String title;
bool bHidden; // tab does not display and can't be selected
bool bDirectInput; // inputs are directly passed to this tab
// tab initialization
virtual DemolitionistMenuTab Init( DemolitionistMenu master )
@ -23,6 +24,12 @@ Class DemolitionistMenuTab ui abstract
{
}
// called for "direct input" from ui events
virtual bool DirectInput( UIEvent ev )
{
return false;
}
// called after this tab is selected
virtual void OnSelect()
{

View file

@ -0,0 +1,148 @@
// a game inside a game?
Class DemolitionistGameTab : DemolitionistMenuTab
{
MadcatGame game;
Array<Class<MadcatGame> > gamelist;
int sel;
override DemolitionistMenuTab Init( DemolitionistMenu master )
{
title = StringTable.Localize("$SWWM_GAMETAB");
gamelist.Push((Class<MadcatGame>)('MadcatGame')); // test
bDirectInput = true;
return Super.Init(master);
}
override void OnDestroy()
{
Super.OnDestroy();
if ( game ) game.Destroy();
}
override void OnSelect()
{
sel = master.shnd.menustate.At("LastGame").ToInt();
}
override void OnDeselect()
{
master.shnd.menustate.Insert("LastGame",String.Format("%d",sel));
if ( game ) game.Destroy();
}
override void MenuInput( int key )
{
// while a game is running, only the back button can be used
if ( game )
{
if ( key == MK_BACK )
{
game.Destroy();
master.MenuSound("menu/democlose");
}
return;
}
switch ( key )
{
case MK_DOWN:
if ( sel > 0 )
{
sel--;
master.MenuSound("menu/demoscroll");
}
break;
case MK_UP:
if ( sel < gamelist.Size()-1 )
{
sel++;
master.MenuSound("menu/demoscroll");
}
break;
case MK_ENTER:
master.MenuSound("menu/demosel");
game = MadcatGame(new(gamelist[sel]));
game.Init();
break;
}
}
override void MouseInput( Vector2 pos, int btn )
{
if ( game ) return;
if ( btn != MB_LEFT ) return;
String str;
double xx, yy;
yy = int(master.ws.y-14*gamelist.Size())/2;
for ( int i=0; i<gamelist.Size(); i++, yy+=14 )
{
str = StringTable.Localize("$SWWM_GAMETITLE_"..gamelist[i].GetClassName());
int w = master.mSmallFont.StringWidth(str);
int h = master.mSmallFont.GetHeight();
xx = int(master.ws.y-w)/2;
if ( pos.x < xx ) continue;
if ( pos.x < xx+w ) continue;
if ( pos.y < yy ) continue;
if ( pos.y > yy+h ) continue;
sel = i;
MenuInput(MK_ENTER);
break;
}
}
override bool DirectInput( UIEvent ev )
{
if ( !game ) return false;
return game.ProcessInput(ev.keychar,ev.type==UIEvent.Type_KeyUp);
}
override void Ticker()
{
if ( game ) game.Tick();
}
override void Drawer()
{
if ( game )
{ // calculate res to fit
double scl = max(floor(((master.ws.y-120)*master.hs)/240.),1.);
Vector2 res = ((384,240)*scl)/master.hs;
String str = StringTable.Localize("$SWWM_GAMETITLE_"..game.GetClassName());
double xx = int(master.ws.x-master.mSmallFont.StringWidth(str))/2;
double yy = int(master.ws.y-res.y)/2;
Screen.DrawText(master.mSmallFont,Font.CR_FIRE,master.origin.x+xx,master.origin.y+yy-32,str,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true);
int cw = int(ceil((master.mSmallFont.StringWidth(str)+8)/6.))*6;
xx = int(master.ws.x-cw)/2;
for ( int i=0; i<cw; i+=6 )
Screen.DrawChar(master.mSmallFont,Font.CR_FIRE,master.origin.x+xx+i,master.origin.y+yy-26,0x5F,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true);
xx = int(master.ws.x-res.x)/2;
Screen.Dim("Black",1.,int((master.origin.x+xx-4)*master.hs),int((master.origin.y+yy-4)*master.hs),int((res.x+8)*master.hs),int((res.y+8)*master.hs));
master.DrawFrame(xx-4,yy-4,res.x+8,res.y+8);
game.Draw((master.origin.x+xx,master.origin.y+yy)*master.hs,scl);
}
else
{
// draw the game listing
String str = StringTable.Localize("$SWWM_PICKGAME");
double xx = int(master.ws.x-master.mSmallFont.StringWidth(str))/2;
double yy = int(master.ws.y-14*gamelist.Size())/2;
Screen.DrawText(master.mSmallFont,Font.CR_FIRE,master.origin.x+xx,master.origin.y+yy-32,str,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true);
int cw = int(ceil((master.mSmallFont.StringWidth(str)+8)/6.))*6;
xx = int(master.ws.x-cw)/2;
for ( int i=0; i<cw; i+=6 )
Screen.DrawChar(master.mSmallFont,Font.CR_FIRE,master.origin.x+xx+i,master.origin.y+yy-26,0x5F,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true);
for ( int i=0; i<gamelist.Size(); i++ )
{
str = StringTable.Localize("$SWWM_GAMETITLE_"..gamelist[i].GetClassName());
int w = master.mSmallFont.StringWidth(str);
xx = int(master.ws.x-w)/2;
Screen.DrawText(master.mSmallFont,(i==sel)?Font.CR_WHITE:Font.CR_DARKGRAY,master.origin.x+xx,master.origin.y+yy,str,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true);
if ( i == sel )
{
Screen.DrawChar(master.mSmallFont,Font.CR_GREEN,master.origin.x+xx-12,master.origin.y+yy,((gametic&8)>=4)?0x2727:0x2726,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true);
Screen.DrawChar(master.mSmallFont,Font.CR_GREEN,master.origin.x+xx+w+6,master.origin.y+yy,((gametic&8)>=4)?0x2727:0x2726,DTA_VirtualWidthF,master.ss.x,DTA_VirtualHeightF,master.ss.y,DTA_KeepRatio,true);
}
yy += 14;
}
}
}
}