Files
Catacomb3D/C3_GAME.C
2026-03-12 19:22:23 +01:00

1200 lines
23 KiB
C

/* Catacomb 3-D Source Code
* Copyright (C) 1993-2014 Flat Rock Software
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
// C3_GAME.C
#include "C3_DEF.H"
#pragma hdrstop
#ifdef PROFILE
#include "TIME.H"
#endif
/*
=============================================================================
LOCAL CONSTANTS
=============================================================================
*/
#define NUMLUMPS 25
#define CONTROLSLUMP 0
#define ORCLUMP 1
#define TROLLLUMP 2
#define WARPLUMP 3
#define BOLTLUMP 4
#define NUKELUMP 5
#define POTIONLUMP 6
#define RKEYLUMP 7
#define YKEYLUMP 8
#define GKEYLUMP 9
#define BKEYLUMP 10
#define SCROLLLUMP 11
#define CHESTLUMP 12
#define PLAYERLUMP 13
#define WALL1LUMP 14
#define WALL2LUMP 15
#define BDOORLUMP 16
#define DEMONLUMP 17
#define MAGELUMP 18
#define BATLUMP 19
#define GRELLUMP 20
#define GOALLUMP 21
int lumpstart[NUMLUMPS] = {
CONTROLS_LUMP_START,
ORC_LUMP_START,
TROLL_LUMP_START,
WARP_LUMP_START,
BOLT_LUMP_START,
NUKE_LUMP_START,
POTION_LUMP_START,
RKEY_LUMP_START,
YKEY_LUMP_START,
GKEY_LUMP_START,
BKEY_LUMP_START,
SCROLL_LUMP_START,
CHEST_LUMP_START,
PLAYER_LUMP_START,
WALL1_LUMP_START,
WALL2_LUMP_START,
BDOOR_LUMP_START,
DEMON_LUMP_START,
MAGE_LUMP_START,
BAT_LUMP_START,
GREL_LUMP_START,
NEMESISPIC
};
int lumpend[NUMLUMPS] = {
CONTROLS_LUMP_END,
ORC_LUMP_END,
TROLL_LUMP_END,
WARP_LUMP_END,
BOLT_LUMP_END,
NUKE_LUMP_END,
POTION_LUMP_END,
RKEY_LUMP_END,
YKEY_LUMP_END,
GKEY_LUMP_END,
BKEY_LUMP_END,
SCROLL_LUMP_END,
CHEST_LUMP_END,
PLAYER_LUMP_END,
WALL1_LUMP_END,
WALL2_LUMP_END,
BDOOR_LUMP_END,
DEMON_LUMP_END,
MAGE_LUMP_END,
BAT_LUMP_END,
GREL_LUMP_END,
NEMESISPIC
};
/*
=============================================================================
GLOBAL VARIABLES
=============================================================================
*/
unsigned latchpics[NUMLATCHPICS];
unsigned tileoffsets[NUMTILE16];
unsigned textstarts[27];
/*
=============================================================================
LOCAL VARIABLES
=============================================================================
*/
boolean lumpneeded[NUMLUMPS];
//===========================================================================
/*
==========================
=
= ScanInfoPlane
=
= Spawn all actors and mark down special places
=
==========================
*/
void ScanInfoPlane (void)
{
unsigned x,y,i,j;
int tile;
unsigned far *start;
InitObjList(); // start spawning things with a clean slate
memset (lumpneeded,0,sizeof(lumpneeded));
start = mapsegs[2];
for (y=0;y<mapheight;y++)
for (x=0;x<mapwidth;x++)
{
tile = *start++;
if (!tile)
continue;
switch (tile)
{
case 1:
case 2:
case 3:
case 4:
lumpneeded[PLAYERLUMP] = true;
SpawnPlayer(x,y,NORTH+tile-1);
break;
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
lumpneeded[tile-5+BOLTLUMP] = true;
SpawnBonus(x,y,tile-5);
break;
case 12:
case 13:
case 14:
case 15:
case 16:
case 17:
case 18:
case 19:
lumpneeded[SCROLLLUMP] = true;
SpawnBonus(x,y,B_SCROLL1+tile-12);
break;
case 20: // goal
lumpneeded[GOALLUMP] = true;
SpawnBonus(x,y,B_GOAL);
break;
case 21: // chest
lumpneeded[CHESTLUMP] = true;
SpawnBonus(x,y,B_CHEST);
break;
case 24:
lumpneeded[WARPLUMP] = true;
SpawnWarp (x,y,0);
break;
//------
case 41:
if (gamestate.difficulty <gd_Hard)
break;
case 36:
if (gamestate.difficulty <gd_Normal)
break;
case 22:
lumpneeded[TROLLLUMP] = true;
SpawnTroll (x,y);
break;
case 42:
if (gamestate.difficulty <gd_Hard)
break;
case 37:
if (gamestate.difficulty <gd_Normal)
break;
case 23:
lumpneeded[ORCLUMP] = true;
SpawnOrc (x,y);
break;
case 43:
if (gamestate.difficulty <gd_Hard)
break;
case 38:
if (gamestate.difficulty <gd_Normal)
break;
case 25:
lumpneeded[BATLUMP] = true;
SpawnBat (x,y);
break;
case 44:
if (gamestate.difficulty <gd_Hard)
break;
case 39:
if (gamestate.difficulty <gd_Normal)
break;
case 26:
lumpneeded[DEMONLUMP] = true;
SpawnDemon (x,y);
break;
case 45:
if (gamestate.difficulty <gd_Hard)
break;
case 40:
if (gamestate.difficulty <gd_Normal)
break;
case 27:
lumpneeded[MAGELUMP] = true;
SpawnMage (x,y);
break;
case 28:
lumpneeded[GRELLUMP] = true;
SpawnNemesis (x,y);
break;
case 29:
SpawnBounce (x,y,0);
break;
case 30:
SpawnBounce (x,y,1);
break;
case 31:
case 32:
case 33:
case 34:
lumpneeded[WARPLUMP] = true;
SpawnWarp (x,y,tile-30);
break;
}
}
}
//==========================================================================
/*
==================
=
= ScanText
=
==================
*/
void ScanText (void)
{
int i;
char far *text;
text = (char _seg *)grsegs[LEVEL1TEXT+mapon];
textstarts[0] = 0;
for (i=1;i<=26;i++)
{
while (*text != '\n')
{
if (*text == '\r')
*text = 0;
text++;
}
text++;
textstarts[i] = FP_OFF(text);
}
}
//==========================================================================
/*
==================
=
= DrawEnterScreen
=
==================
*/
static char *levelnames[] =
{
"The Approach",
"Nemesis's Keep",
"Ground Floor",
"Second Floor",
"Third Floor",
"Tower One",
"Tower Two",
"Secret Halls",
"Access Floor",
"The Dungeon",
"Lower Dungeon",
"Catacomb",
"Lower Reaches",
"The Warrens",
"Hidden Caverns",
"The Fens of Insanity",
"Chaos Corridors",
"The Labyrinth",
"Halls of Blood",
"Nemesis's Lair"
};
void DrawEnterScreen (void)
{
int x,y;
VW_Bar(0,0,VIEWWIDTH,VIEWHEIGHT,9); // Medium blue
x = (VIEWWIDTH - (18 * 8)) / 2 -3;
y = (VIEWHEIGHT - (5 * 8)) / 2;
VW_DrawPic(x / 8,y,ENTERPLAQUEPIC);
WindowX = x;
WindowW = 18 * 8;
PrintY = (VIEWHEIGHT/2) + 3;
US_CPrint (levelnames[gamestate.mapon]);
}
//==========================================================================
boolean tileneeded[NUMFLOORS];
/*
==================
=
= CacheScaleds
=
==================
*/
void CacheScaleds (void)
{
int i,j;
unsigned source,dest;
FreeUpMemory ();
CA_CacheGrChunk(LEVEL1TEXT+mapon);
ScanText ();
//
// make sure we are displaying screenpage 0
//
if (screenpage)
{
source = screenloc[screenpage];
dest = screenloc[0];
VW_ScreenToScreen (source,dest,40,VIEWHEIGHT);
screenpage = 0;
VW_SetScreen (dest,0);
displayofs = dest;
}
//
// cache wall pictures
//
for (i=1;i<NUMFLOORS;i++)
if (tileneeded[i])
{
SetupScaleWall (walllight1[i]);
SetupScaleWall (walllight2[i]);
SetupScaleWall (walldark1[i]);
SetupScaleWall (walldark2[i]);
}
//
// cache the actor pictures
//
for (i=0;i<NUMLUMPS;i++)
if (lumpneeded[i])
for (j=lumpstart[i];j<=lumpend[i];j++)
SetupScalePic(j);
source = screenloc[0];
for (i=1;i<=2;i++)
{
dest = screenloc[i];
VW_ScreenToScreen (source,dest,40,VIEWHEIGHT);
}
screenpage = 1;
}
//==========================================================================
/*
==================
=
= SetupGameLevel
=
==================
*/
void SetupGameLevel (void)
{
int x,y,i;
unsigned far *map,tile,spot;
memset (tileneeded,0,sizeof(tileneeded));
//
// randomize if not a demo
//
if (DemoMode)
{
US_InitRndT(false);
gamestate.difficulty = gd_Normal;
}
else
US_InitRndT(true);
//
// load the level
//
CA_CacheMap (gamestate.mapon);
mapwidth = mapheaderseg[mapon]->width;
mapheight = mapheaderseg[mapon]->height;
//
// make a lookup table for the maps left edge
//
spot = 0;
for (y=0;y<mapheight;y++)
{
farmapylookup[y] = spot;
spot += mapwidth;
}
//
// copy the wall data to a data segment array
//
memset (tilemap,0,sizeof(tilemap));
memset (actorat,0,sizeof(actorat));
map = mapsegs[0];
for (y=0;y<mapheight;y++)
for (x=0;x<mapwidth;x++)
{
tile = *map++;
if (tile<NUMFLOORS)
{
tileneeded[tile] = true;
tilemap[x][y] = tile;
if (tile>=EXPWALLSTART && tile<EXPWALLSTART+NUMEXPWALLS)
{
tileneeded[WALLEXP] = tileneeded[WALLEXP+1]
= tileneeded[WALLEXP+2] = true;
}
if (tile>0)
(unsigned)actorat[x][y] = tile;
}
}
//
// decide which graphics are needed and spawn actors
//
ScanInfoPlane ();
//
// have the caching manager load and purge stuff to make sure all marks
// are in memory
//
CA_LoadAllSounds ();
}
//==========================================================================
/*
=====================
=
= LatchDrawPic
=
=====================
*/
void LatchDrawPic (unsigned x, unsigned y, unsigned picnum)
{
unsigned wide, height, source, dest;
wide = pictable[picnum-STARTPICS].width;
height = pictable[picnum-STARTPICS].height;
dest = bufferofs + ylookup[y]+x;
source = latchpics[picnum-FIRSTLATCHPIC];
EGAWRITEMODE(1);
EGAMAPMASK(15);
asm mov bx,[linewidth]
asm sub bx,[wide]
asm mov ax,[screenseg]
asm mov es,ax
asm mov ds,ax
asm mov si,[source]
asm mov di,[dest]
asm mov dx,[height] // scan lines to draw
asm mov ax,[wide]
lineloop:
asm mov cx,ax
asm rep movsb
asm add di,bx
asm dec dx
asm jnz lineloop
asm mov ax,ss
asm mov ds,ax // restore turbo's data segment
EGAWRITEMODE(0);
}
//==========================================================================
/*
=====================
=
= Victory
=
=====================
*/
void Victory (void)
{
FreeUpMemory ();
NormalScreen ();
CA_CacheGrChunk (FINALEPIC);
VWB_DrawPic (0,0,FINALEPIC);
UNMARKGRCHUNK(FINALEPIC);
VW_UpdateScreen ();
SD_PlaySound (GETBOLTSND);
SD_WaitSoundDone ();
SD_PlaySound (GETNUKESND);
SD_WaitSoundDone ();
SD_PlaySound (GETPOTIONSND);
SD_WaitSoundDone ();
SD_PlaySound (GETKEYSND);
SD_WaitSoundDone ();
SD_PlaySound (GETSCROLLSND);
SD_WaitSoundDone ();
SD_PlaySound (GETPOINTSSND);
SD_WaitSoundDone ();
IN_ClearKeysDown ();
IN_Ack();
}
//==========================================================================
/*
===================
=
= Died
=
===================
*/
void Died (void)
{
unsigned page1,page2;
//
// fizzle fade screen to grey
//
FreeUpMemory ();
SD_PlaySound (GAMEOVERSND);
bufferofs = screenloc[(screenpage+1)%3];
LatchDrawPic(0,0,DEADPIC);
FizzleFade(bufferofs,displayofs,VIEWWIDTH,VIEWHEIGHT,false);
IN_ClearKeysDown();
IN_Ack();
VW_SetScreen (bufferofs,0);
}
//==========================================================================
/*
===================
=
= NormalScreen
=
===================
*/
void NormalScreen (void)
{
VW_SetSplitScreen (200);
bufferofs = displayofs = SCREEN1START;
VW_Bar(0,0,320,200,0);
bufferofs = SCREEN2START;
VW_Bar(0,0,320,200,0);
VW_SetScreen (displayofs,0);
}
//==========================================================================
/*
===================
=
= DrawPlayScreen
=
===================
*/
void DrawPlayScreen (void)
{
int i,j,p,m;
screenpage = 0;
bufferofs = 0;
VW_Bar (0,0,320,STATUSLINES,7);
for (i=0;i<3;i++)
{
bufferofs = screenloc[i];
VW_Bar (0,0,320,VIEWHEIGHT,7);
}
VW_SetSplitScreen(144);
VW_SetScreen(screenloc[0],0);
bufferofs = 0;
CA_CacheGrChunk (STATUSPIC);
CA_CacheGrChunk (SIDEBARSPIC);
VW_DrawPic (0,0,STATUSPIC);
for (i=0;i<3;i++)
{
bufferofs = screenloc[i];
VW_DrawPic (33,0,SIDEBARSPIC);
}
grneeded[STATUSPIC]&= ~ca_levelbit;
grneeded[SIDEBARSPIC]&= ~ca_levelbit;
MM_SetPurge(&grsegs[STATUSPIC],3);
MM_SetPurge(&grsegs[SIDEBARSPIC],3);
RedrawStatusWindow ();
bufferofs = displayofs = screenloc[0];
}
//==========================================================================
/*
===================
=
= LoadLatchMem
=
===================
*/
void LoadLatchMem (void)
{
int i,j,p,m;
byte far *src, far *dest;
unsigned destoff;
EGAWRITEMODE(0);
//
// draw some pics into latch memory
//
//
// tile 8s
//
latchpics[0] = freelatch;
src = (byte _seg *)grsegs[STARTTILE8];
dest = MK_FP(0xa000,freelatch);
for (i=0;i<NUMTILE8;i++)
{
for (p=0;p<4;p++)
{
m = 1<<p;
asm mov dx,SC_INDEX
asm mov al,SC_MAPMASK
asm mov ah,[BYTE PTR m]
asm out dx,ax
for (j=0;j<8;j++)
*(dest+j)=*src++;
}
dest+=8;
}
//
// tile 16s
//
src = (byte _seg *)grsegs[STARTTILE16];
for (i=0;i<NUMTILE16;i++)
{
CA_CacheGrChunk (STARTTILE16+i);
src = (byte _seg *)grsegs[STARTTILE16+i];
if (src)
{
tileoffsets[i] = FP_OFF(dest);
for (p=0;p<4;p++)
{
m = 1<<p;
asm mov dx,SC_INDEX
asm mov al,SC_MAPMASK
asm mov ah,[BYTE PTR m]
asm out dx,ax
for (j=0;j<32;j++)
*(dest+j)=*src++;
}
dest+=32;
MM_FreePtr (&grsegs[STARTTILE16+i]);
UNMARKGRCHUNK(STARTTILE16+i);
}
else
tileoffsets[i] = 0;
}
//
// pics
//
destoff = FP_OFF(dest);
for (i=FIRSTLATCHPIC+1;i<FIRSTSCALEPIC;i++)
{
latchpics[i-FIRSTLATCHPIC] = destoff;
CA_CacheGrChunk (i);
j = pictable[i-STARTPICS].width * pictable[i-STARTPICS].height;
VW_MemToScreen (grsegs[i],destoff,j,1);
destoff+=j;
MM_FreePtr (&grsegs[i]);
UNMARKGRCHUNK(i);
}
EGAMAPMASK(15);
}
//==========================================================================
/*
===================
=
= FizzleFade
=
===================
*/
#define PIXPERFRAME 1600
void FizzleFade (unsigned source, unsigned dest,
unsigned width,unsigned height, boolean abortable)
{
unsigned drawofs,pagedelta;
unsigned char maskb[8] = {1,2,4,8,16,32,64,128};
unsigned x,y,p,frame;
long rndval;
pagedelta = dest-source;
VW_SetScreen (dest,0);
rndval = 1;
y = 0;
asm mov es,[screenseg]
asm mov dx,SC_INDEX
asm mov al,SC_MAPMASK
asm out dx,al
TimeCount=frame=0;
do // while (1)
{
if (abortable)
{
IN_ReadControl(0,&c);
if (c.button0 || c.button1 || Keyboard[sc_Space]
|| Keyboard[sc_Enter])
{
VW_ScreenToScreen (source,dest,width/8,height);
return;
}
}
for (p=0;p<PIXPERFRAME;p++)
{
//
// seperate random value into x/y pair
//
asm mov ax,[WORD PTR rndval]
asm mov dx,[WORD PTR rndval+2]
asm mov bx,ax
asm dec bl
asm mov [BYTE PTR y],bl // low 8 bits - 1 = y xoordinate
asm mov bx,ax
asm mov cx,dx
asm shr cx,1
asm rcr bx,1
asm shr bx,1
asm shr bx,1
asm shr bx,1
asm shr bx,1
asm shr bx,1
asm shr bx,1
asm shr bx,1
asm mov [x],bx // next 9 bits = x xoordinate
//
// advance to next random element
//
asm shr dx,1
asm rcr ax,1
asm jnc noxor
asm xor dx,0x0001
asm xor ax,0x2000
noxor:
asm mov [WORD PTR rndval],ax
asm mov [WORD PTR rndval+2],dx
if (x>width || y>height)
continue;
drawofs = source+ylookup[y];
asm mov cx,[x]
asm mov si,cx
asm and si,7
asm mov dx,GC_INDEX
asm mov al,GC_BITMASK
asm mov ah,BYTE PTR [maskb+si]
asm out dx,ax
asm mov si,[drawofs]
asm shr cx,1
asm shr cx,1
asm shr cx,1
asm add si,cx
asm mov di,si
asm add di,[pagedelta]
asm mov dx,GC_INDEX
asm mov al,GC_READMAP // leave GC_INDEX set to READMAP
asm out dx,al
asm mov dx,SC_INDEX+1
asm mov al,1
asm out dx,al
asm mov dx,GC_INDEX+1
asm mov al,0
asm out dx,al
asm mov bl,[es:si]
asm xchg [es:di],bl
asm mov dx,SC_INDEX+1
asm mov al,2
asm out dx,al
asm mov dx,GC_INDEX+1
asm mov al,1
asm out dx,al
asm mov bl,[es:si]
asm xchg [es:di],bl
asm mov dx,SC_INDEX+1
asm mov al,4
asm out dx,al
asm mov dx,GC_INDEX+1
asm mov al,2
asm out dx,al
asm mov bl,[es:si]
asm xchg [es:di],bl
asm mov dx,SC_INDEX+1
asm mov al,8
asm out dx,al
asm mov dx,GC_INDEX+1
asm mov al,3
asm out dx,al
asm mov bl,[es:si]
asm xchg [es:di],bl
if (rndval == 1) // entire sequence has been completed
{
EGABITMASK(255);
EGAMAPMASK(15);
return;
};
}
frame++;
while (TimeCount<frame) // don't go too fast
;
} while (1);
}
//==========================================================================
/*
===================
=
= FizzleOut
=
===================
*/
void FizzleOut (int showlevel)
{
unsigned page1,page2;
//
// fizzle fade screen to grey
//
bufferofs = screenloc[(screenpage+1)%3];
if (showlevel)
DrawEnterScreen ();
FizzleFade(bufferofs,displayofs,VIEWWIDTH,VIEWHEIGHT,false);
}
//==========================================================================
/*
====================
=
= FreeUpMemory
=
====================
*/
void FreeUpMemory (void)
{
int i;
for (i=0;i<NUMSCALEPICS;i++)
if (shapedirectory[i])
MM_SetPurge (&(memptr)shapedirectory[i],3);
for (i=0;i<NUMSCALEWALLS;i++)
if (walldirectory[i])
MM_SetPurge (&(memptr)walldirectory[i],3);
}
//==========================================================================
/*
==================
=
= DrawHighScores
=
==================
*/
void DrawHighScores(void)
{
char buffer[16],*str;
word i,j,
w,h,
x,y;
HighScore *s;
CA_CacheGrChunk (HIGHSCORESPIC);
VWB_DrawPic (0,0,HIGHSCORESPIC);
MM_SetPurge (&grsegs[HIGHSCORESPIC],3);
UNMARKGRCHUNK(HIGHSCORESPIC);
for (i = 0,s = Scores;i < MaxScores;i++,s++)
{
PrintY = 68 + (16 * i);
//
// name
//
PrintX = 60;
US_Print(s->name);
//
// level
//
ultoa(s->completed,buffer,10);
for (str = buffer;*str;str++)
*str = *str + (129 - '0'); // Used fixed-width numbers (129...)
USL_MeasureString(buffer,&w,&h);
PrintX = (25 * 8) - 8 - w;
US_Print(buffer);
//
// score
//
ultoa(s->score,buffer,10);
for (str = buffer;*str;str++)
*str = *str + (129 - '0'); // Used fixed-width numbers (129...)
USL_MeasureString(buffer,&w,&h);
PrintX = (34 * 8) - 8 - w;
US_Print(buffer);
}
fontcolor = F_BLACK;
}
/*
=======================
=
= CheckHighScore
=
=======================
*/
void CheckHighScore (long score,word other)
{
word i,j;
int n;
HighScore myscore;
strcpy(myscore.name,"");
myscore.score = score;
myscore.completed = other;
for (i = 0,n = -1;i < MaxScores;i++)
{
if
(
(myscore.score > Scores[i].score)
|| (
(myscore.score == Scores[i].score)
&& (myscore.completed > Scores[i].completed)
)
)
{
for (j = MaxScores;--j > i;)
Scores[j] = Scores[j - 1];
Scores[i] = myscore;
n = i;
HighScoresDirty = true;
break;
}
}
if (n != -1)
{
//
// got a high score
//
DrawHighScores ();
PrintY = 68 + (16 * n);
PrintX = 60;
US_LineInput(PrintX,PrintY,Scores[n].name,nil,true,MaxHighName,100);
}
}
//==========================================================================
/*
===================
=
= GameLoop
=
===================
*/
void GameLoop (void)
{
int i,xl,yl,xh,yh;
char num[20];
#ifdef PROFILE
clock_t start,end;
#endif
DrawPlayScreen ();
restart:
if (!loadedgame)
{
gamestate.difficulty = restartgame;
restartgame = gd_Continue;
DrawEnterScreen ();
}
do
{
playstate = gd_Continue;
if (!loadedgame)
SetupGameLevel ();
else
loadedgame = false;
CacheScaleds ();
#ifdef PROFILE
start = clock();
while (start == clock());
start++;
#endif
PlayLoop ();
#ifdef PROFILE
end = clock();
itoa(end-start,str,10);
Quit (str);
#endif
switch (playstate)
{
case ex_died:
Died ();
NormalScreen ();
FreeUpMemory ();
CheckHighScore (gamestate.score,gamestate.mapon+1);
return;
case ex_warped:
FizzleOut (true);
if (gamestate.mapon >= NUMLEVELS)
{
Victory ();
FreeUpMemory ();
CheckHighScore(gamestate.score,gamestate.mapon+1);
return;
}
break;
case ex_abort:
FreeUpMemory ();
return;
case ex_resetgame:
case ex_loadedgame:
goto restart;
case ex_victorious:
Victory ();
FreeUpMemory();
CheckHighScore(gamestate.score,gamestate.mapon+1);
return;
}
} while (1);
}