mirror of
https://github.com/jmarshall23/Hellfire.git
synced 2026-08-12 16:00:51 +02:00
761 lines
23 KiB
C++
761 lines
23 KiB
C++
/****************************************************************************
|
|
*
|
|
* RPG.CPP
|
|
*
|
|
* This is a simple game which demonstrates the use of synchonous networking.
|
|
* It is basically an Ultima IV style tiled graphics engine, with Warcraft
|
|
* style mouse controls.
|
|
*
|
|
* At the beginning of the game, each player sends out two null orders.
|
|
* During the game, players send out orders as they are received from the
|
|
* user (a sample order would be "move to this location"), and fabricate
|
|
* null orders as necessary to make sure there are always at least two in
|
|
* transit.
|
|
*
|
|
* Each turn, each player waits until he has received the next set of orders
|
|
* from all players, and then executes all orders, starting at the lowest
|
|
* player number. Since orders are processed at the same time and in the
|
|
* same order on every computer in the network, the game stays in sync.
|
|
*
|
|
***/
|
|
|
|
#include <windows.h>
|
|
#include <storm.h>
|
|
#include "bnetart.h"
|
|
|
|
#define PROGRAMID 'RPG1'
|
|
#define VERSIONID 1
|
|
#define MAXPLAYERS 8
|
|
#define TITLE "RPG Example"
|
|
#define ARTDIR "art\\"
|
|
#define NETARTDIR "netart\\"
|
|
|
|
#define ORDER_NULL 0
|
|
#define ORDER_START 1
|
|
#define ORDER_MOVE 2
|
|
#define ORDER_QUIT 3
|
|
|
|
#define TILE_DEEPSEA 0
|
|
#define TILE_SEA 1
|
|
#define TILE_SHALLOWSEA 2
|
|
#define TILE_SWAMP 3
|
|
#define TILE_GRASS 4
|
|
#define TILE_BRUSH 5
|
|
#define TILE_FOREST 6
|
|
#define TILE_HILLS 7
|
|
#define TILE_MOUNTAINS 8
|
|
#define TILE_DUNGEON 9
|
|
#define TILE_TOWN 10
|
|
#define TILE_CASTLE 11
|
|
#define TILE_VILLAGE 12
|
|
|
|
#define SCREENCX 640
|
|
#define SCREENCY 480
|
|
#define SCREENTILESX 20
|
|
#define SCREENTILESY 15
|
|
#define SCROLLCX 672
|
|
#define SCROLLCY 512
|
|
#define SCROLLTILESX 21
|
|
#define SCROLLTILESY 16
|
|
#define TILES 16
|
|
#define TILECX 32
|
|
#define TILECY 32
|
|
#define WORLDMAPCX 256
|
|
#define WORLDMAPCY 256
|
|
|
|
LPBYTE cursor = NULL;
|
|
POINT cursorpos = {0,0};
|
|
DWORD localplayer = 0;
|
|
POINT orderpos[MAXPLAYERS];
|
|
PALETTEENTRY pe[256];
|
|
LPBYTE player = NULL;
|
|
POINT playerpos[MAXPLAYERS];
|
|
DWORD players = 0;
|
|
LPBYTE scrollbuffer = NULL;
|
|
POINT scrollpos;
|
|
POINT scrollvel = {0,0};
|
|
BOOL started = 0;
|
|
LPBYTE tileset = NULL;
|
|
LPBYTE worldmap = NULL;
|
|
|
|
BOOL CALLBACK CreateCallback (SNETCREATEDATAPTR createdata,
|
|
SNETPROGRAMDATAPTR programdata,
|
|
SNETPLAYERDATAPTR playerdata,
|
|
SNETUIDATAPTR interfacedata,
|
|
SNETVERSIONDATAPTR versiondata,
|
|
DWORD *playerid);
|
|
BOOL LoadGraphicsData ();
|
|
void MovePlayer (DWORD player);
|
|
void CALLBACK OnButtonDown (LPPARAMS params);
|
|
void CALLBACK OnClose (LPPARAMS params);
|
|
void CALLBACK OnEraseBkgnd (LPPARAMS params);
|
|
void CALLBACK OnPaint (LPPARAMS params);
|
|
void CALLBACK OnVkEscape (LPPARAMS params);
|
|
void CALLBACK OnVkSpace (LPPARAMS params);
|
|
BOOL ProcessOrders ();
|
|
BOOL UpdateScrollVelocity ();
|
|
|
|
//===========================================================================
|
|
BOOL CALLBACK ArtCallback (DWORD providerid,
|
|
DWORD artid,
|
|
LPPALETTEENTRY pe,
|
|
LPBYTE buffer,
|
|
DWORD buffersize,
|
|
int *width,
|
|
int *height,
|
|
int *bitdepth) {
|
|
|
|
char filename[MAX_PATH] = "";
|
|
|
|
if (providerid == 'BNET') {
|
|
// Check for battlenet specific art
|
|
switch (artid) {
|
|
|
|
case SNET_ART_BACKGROUND: strcpy(filename,NETARTDIR "chat_bkg.pcx"); break;
|
|
case SNET_ART_BATTLE_LISTBOX: strcpy(filename, NETARTDIR "bnlist.pcx"); break;
|
|
|
|
case SNET_ART_BATTLE_BTNS: strcpy(filename, NETARTDIR "bnbuttns.pcx"); break;
|
|
|
|
case SNET_ART_BATTLE_HELP_BKG: strcpy(filename, NETARTDIR "lpopup.pcx"); break;
|
|
case SNET_ART_JOINBACKGROUND: strcpy(filename, NETARTDIR "bnjoinbg.pcx"); break;
|
|
|
|
case SNET_ART_BATTLE_REDLAG: strcpy(filename, NETARTDIR "redlag.pcx"); break;
|
|
case SNET_ART_BATTLE_YELLOWLAG: strcpy(filename, NETARTDIR "yellolag.pcx"); break;
|
|
case SNET_ART_BATTLE_GREENLAG: strcpy(filename, NETARTDIR "greenlag.pcx"); break;
|
|
}
|
|
|
|
}
|
|
else if ((providerid == 'IPXN') || (providerid == 'TEST')) {
|
|
switch (artid) {
|
|
case SNET_ART_BACKGROUND: strcpy(filename, NETARTDIR "ipx_bkg.pcx"); break;
|
|
}
|
|
}
|
|
else if (providerid == 0) {
|
|
switch (artid) {
|
|
case SNET_ART_BACKGROUND: strcpy(filename, NETARTDIR "connect.pcx"); break;
|
|
}
|
|
}
|
|
|
|
if (!filename[0]) {
|
|
// Check for generic artwork
|
|
switch (artid) {
|
|
case SNET_ART_JOINBACKGROUND: // fall through
|
|
case SNET_ART_BACKGROUND: strcpy(filename,NETARTDIR "menu.pcx"); break;
|
|
case SNET_ART_BUTTONTEXTURE: strcpy(filename,NETARTDIR "but_lrg.pcx"); break;
|
|
case SNET_ART_POPUPBACKGROUND: strcpy(filename,NETARTDIR "lpopup.pcx"); break;
|
|
case SNET_ART_HELPBACKGROUND: strcpy(filename,NETARTDIR "lpopup.pcx"); break;
|
|
|
|
case SNET_ART_BUTTON_XSML: strcpy(filename,NETARTDIR "but_xsm.pcx"); break;
|
|
case SNET_ART_BUTTON_SML: strcpy(filename,NETARTDIR "but_sml.pcx"); break;
|
|
case SNET_ART_BUTTON_MED: strcpy(filename,NETARTDIR "but_med.pcx"); break;
|
|
case SNET_ART_BUTTON_LRG: strcpy(filename,NETARTDIR "but_lrg.pcx"); break;
|
|
}
|
|
}
|
|
|
|
if (filename[0])
|
|
return SBmpLoadImage(filename,pe,buffer,buffersize,width,height,bitdepth);
|
|
else
|
|
return 0;
|
|
|
|
}
|
|
|
|
//===========================================================================
|
|
void ChooseStartingLocations () {
|
|
for (DWORD loop = 0; loop < MAXPLAYERS; ++loop) {
|
|
BOOL found = 0;
|
|
while (!found) {
|
|
int x = rand() % WORLDMAPCX;
|
|
int y = rand() % WORLDMAPCY;
|
|
if (*(worldmap+y*WORLDMAPCX+x) == TILE_GRASS) {
|
|
found = 1;
|
|
for (DWORD loop2 = 1; loop2 < loop; ++loop2)
|
|
if ((playerpos[loop2].x == x) && (playerpos[loop2].y == y))
|
|
found = 0;
|
|
if (found) {
|
|
orderpos[loop].x = x;
|
|
orderpos[loop].y = y;
|
|
playerpos[loop].x = x;
|
|
playerpos[loop].y = y;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
BOOL Connect () {
|
|
|
|
// BUILD A PROGRAM DATA RECORD
|
|
SNETPROGRAMDATA programdata;
|
|
ZeroMemory(&programdata,sizeof(SNETPROGRAMDATA));
|
|
programdata.size = sizeof(SNETPROGRAMDATA);
|
|
programdata.programname = TITLE;
|
|
programdata.programid = PROGRAMID;
|
|
programdata.versionid = VERSIONID;
|
|
programdata.maxplayers = MAXPLAYERS;
|
|
|
|
// GENERATE A PLAYER NAME
|
|
char computername[MAX_COMPUTERNAME_LENGTH+1] = "";
|
|
DWORD size = MAX_COMPUTERNAME_LENGTH+1;
|
|
GetComputerName(computername,&size);
|
|
|
|
// BUILD A PLAYER DATA RECORD
|
|
SNETPLAYERDATA playerdata;
|
|
ZeroMemory(&playerdata,sizeof(SNETPLAYERDATA));
|
|
playerdata.size = sizeof(SNETPLAYERDATA);
|
|
playerdata.playername = computername;
|
|
|
|
// BUILD AN INTERFACE DATA RECORD
|
|
SNETUIDATA interfacedata;
|
|
ZeroMemory(&interfacedata,sizeof(SNETUIDATA));
|
|
interfacedata.size = sizeof(SNETUIDATA);
|
|
interfacedata.parentwindow = SDrawGetFrameWindow();
|
|
interfacedata.artcallback = ArtCallback;
|
|
interfacedata.createcallback = CreateCallback;
|
|
|
|
// SELECT A NETWORK PROVIDER
|
|
while (SNetSelectProvider(NULL,
|
|
&programdata,
|
|
&playerdata,
|
|
&interfacedata,
|
|
NULL,
|
|
NULL)) {
|
|
|
|
// SELECT A GAME
|
|
if (SNetSelectGame(0,
|
|
&programdata,
|
|
&playerdata,
|
|
&interfacedata,
|
|
NULL,
|
|
&localplayer))
|
|
return 1;
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//===========================================================================
|
|
BOOL CALLBACK ConnectIdleProc (DWORD) {
|
|
DWORD currtime = GetTickCount();
|
|
|
|
// TWICE A SECOND, UPDATE THE LIST OF PLAYERS
|
|
{
|
|
static DWORD lasttime = 0;
|
|
if (currtime-lasttime > 1000)
|
|
lasttime = currtime-500;
|
|
while (currtime-lasttime >= 500) {
|
|
|
|
// DRAW THE LIST
|
|
LPBYTE videobuffer;
|
|
int videopitch;
|
|
if (SDrawLockSurface(SDRAW_SURFACE_FRONT,NULL,&videobuffer,&videopitch)) {
|
|
SGdiSetPitch(videopitch);
|
|
SNetGetNumPlayers(NULL,&players,NULL);
|
|
++players;
|
|
for (DWORD loop = 0; loop < players; ++loop) {
|
|
char buffer[SNET_MAXNAMELENGTH+2] = "0 ";
|
|
buffer[0] += (char)loop;
|
|
if (SNetGetPlayerName(loop,buffer+2,SNET_MAXNAMELENGTH))
|
|
SGdiTextOut(videobuffer,4,loop*20,PALETTEINDEX(255-loop),buffer);
|
|
}
|
|
SGdiTextOut(videobuffer,440,20,PALETTEINDEX(255),"PRESS SPACE TO START");
|
|
SDrawUnlockSurface(SDRAW_SURFACE_FRONT,videobuffer);
|
|
}
|
|
|
|
lasttime += 500;
|
|
}
|
|
}
|
|
|
|
// FOUR TIMES A SECOND, PROCESS ORDERS
|
|
{
|
|
static DWORD lasttime = 0;
|
|
if (currtime-lasttime > 1000)
|
|
lasttime = currtime-250;
|
|
while (currtime-lasttime >= 250) {
|
|
if (ProcessOrders())
|
|
lasttime += 250;
|
|
else
|
|
lasttime = GetTickCount();
|
|
currtime = GetTickCount();
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
//===========================================================================
|
|
BOOL CALLBACK CreateCallback (SNETCREATEDATAPTR createdata,
|
|
SNETPROGRAMDATAPTR programdata,
|
|
SNETPLAYERDATAPTR playerdata,
|
|
SNETUIDATAPTR interfacedata,
|
|
SNETVERSIONDATAPTR versiondata,
|
|
DWORD *playerid) {
|
|
return SNetCreateGame(playerdata->playername,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
createdata->maxplayers,
|
|
playerdata->playername,
|
|
NULL,
|
|
playerid);
|
|
}
|
|
|
|
//===========================================================================
|
|
BOOL CreateScrollBuffer () {
|
|
scrollbuffer = (LPBYTE)ALLOC(SCROLLTILESX*TILECX*SCROLLTILESY*TILECY);
|
|
return (scrollbuffer != NULL);
|
|
}
|
|
|
|
//===========================================================================
|
|
void Destroy () {
|
|
if (cursor) {
|
|
FREE(cursor);
|
|
cursor = NULL;
|
|
}
|
|
if (player) {
|
|
FREE(player);
|
|
player = NULL;
|
|
}
|
|
if (scrollbuffer) {
|
|
FREE(scrollbuffer);
|
|
scrollbuffer = NULL;
|
|
}
|
|
if (tileset) {
|
|
FREE(tileset);
|
|
tileset = NULL;
|
|
}
|
|
if (worldmap) {
|
|
FREE(worldmap);
|
|
worldmap = NULL;
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
void DrawScreen () {
|
|
LPBYTE videobuffer;
|
|
int pitch;
|
|
if (SDrawLockSurface(SDRAW_SURFACE_BACK,NULL,&videobuffer,&pitch)) {
|
|
int startx = scrollpos.x % SCROLLCX;
|
|
int starty = scrollpos.y % SCROLLCY;
|
|
|
|
// BLT FROM THE SCROLL BUFFER ONTO THE BACK SURFACE
|
|
SBltROP3(videobuffer,
|
|
scrollbuffer+starty*SCROLLCX+startx,
|
|
min(SCREENCX,SCROLLCX-startx),
|
|
min(SCREENCY,SCROLLCY-starty),
|
|
pitch,
|
|
SCROLLCX,
|
|
0,
|
|
SRCCOPY);
|
|
if (SCROLLCX-startx < SCREENCX)
|
|
SBltROP3(videobuffer+SCROLLCX-startx,
|
|
scrollbuffer+starty*SCROLLCX,
|
|
SCREENCX+startx-SCROLLCX,
|
|
min(SCREENCY,SCROLLCY-starty),
|
|
pitch,
|
|
SCROLLCX,
|
|
0,
|
|
SRCCOPY);
|
|
if (SCROLLCY-starty < SCREENCY)
|
|
SBltROP3(videobuffer+(SCROLLCY-starty)*pitch,
|
|
scrollbuffer+startx,
|
|
min(SCREENCX,SCROLLCX-startx),
|
|
SCREENCY+starty-SCROLLCY,
|
|
pitch,
|
|
SCROLLCX,
|
|
0,
|
|
SRCCOPY);
|
|
if ((SCROLLCX-startx < SCREENCX) &&
|
|
(SCROLLCY-starty < SCREENCY))
|
|
SBltROP3(videobuffer+(SCROLLCY-starty)*pitch+SCROLLCX-startx,
|
|
scrollbuffer,
|
|
SCREENCX+startx-SCROLLCX,
|
|
SCREENCY+starty-SCROLLCY,
|
|
pitch,
|
|
SCROLLCX,
|
|
0,
|
|
SRCCOPY);
|
|
|
|
// DRAW THE MOUSE CURSOR ONTO THE BACK SURFACE
|
|
if (started) {
|
|
GetCursorPos(&cursorpos);
|
|
SBltROP3(videobuffer+cursorpos.y*pitch+cursorpos.x,
|
|
cursor,
|
|
min(32,SCREENCX-cursorpos.x),
|
|
min(32,SCREENCY-cursorpos.y),
|
|
pitch,
|
|
32,
|
|
0,
|
|
SRCPAINT);
|
|
}
|
|
|
|
SDrawUnlockSurface(SDRAW_SURFACE_BACK,videobuffer);
|
|
SDrawFlipPage();
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
void FillScrollBuffer (LPRECT rect) {
|
|
int startxtile = scrollpos.x/TILECX;
|
|
int startytile = scrollpos.y/TILECY;
|
|
int startxpos = (scrollpos.x % SCROLLCX)/TILECX;
|
|
int startypos = (scrollpos.y % SCROLLCY)/TILECY;
|
|
for (int y = rect->top; y <= rect->bottom; ++y) {
|
|
int mapy = startytile+y+((y >= startypos) ? 0 : SCROLLTILESY)-startypos;
|
|
for (int x = rect->left; x <= rect->right; ++x) {
|
|
int mapx = startxtile+x+((x >= startxpos) ? 0 : SCROLLTILESX)-startxpos;
|
|
int tile = min(TILES-1,*(worldmap+mapy*WORLDMAPCX+mapx));
|
|
SBltROP3(scrollbuffer+y*TILECY*SCROLLCX+x*TILECX,
|
|
tileset+tile*TILECX,
|
|
TILECX,
|
|
TILECY,
|
|
SCROLLCX,
|
|
TILES*TILECX,
|
|
0,
|
|
SRCCOPY);
|
|
}
|
|
}
|
|
for (DWORD loop = 0; loop < players; ++loop) {
|
|
if ((playerpos[loop].x >= startxtile) &&
|
|
(playerpos[loop].y >= startytile) &&
|
|
(playerpos[loop].x < startxtile+SCROLLTILESX) &&
|
|
(playerpos[loop].y < startytile+SCROLLTILESY)) {
|
|
int posx = (startxpos+(playerpos[loop].x-startxtile)) % SCROLLTILESX;
|
|
int posy = (startypos+(playerpos[loop].y-startytile)) % SCROLLTILESY;
|
|
if ((posx >= rect->left) && (posx <= rect->right) &&
|
|
(posy >= rect->top) && (posy <= rect->bottom)) {
|
|
DWORD pattern = ((255-loop) << 24) | ((255-loop) << 16) | ((255-loop) << 8) | (255-loop);
|
|
// pattern 11110000
|
|
// source 11001100
|
|
// dest 10101010
|
|
// --------
|
|
// rop 11100010 = 0xE2
|
|
SBltROP3(scrollbuffer+posy*TILECY*SCROLLCX+posx*TILECX,
|
|
player,
|
|
TILECX,
|
|
TILECY,
|
|
SCROLLCX,
|
|
TILECX,
|
|
pattern,
|
|
0xE20746);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
BOOL CALLBACK GameIdleProc (DWORD) {
|
|
DWORD currtime = GetTickCount();
|
|
|
|
// FOUR TIMES A SECOND, MOVE THE PLAYERS
|
|
{
|
|
static DWORD lasttime = GetTickCount();
|
|
if (currtime-lasttime > 1000)
|
|
lasttime = currtime-250;
|
|
while (currtime-lasttime >= 250) {
|
|
for (DWORD loop = 0; loop < players; ++loop)
|
|
MovePlayer(loop);
|
|
RECT rect = {0,0,SCROLLTILESX-1,SCROLLTILESY-1};
|
|
FillScrollBuffer(&rect);
|
|
lasttime += 250;
|
|
}
|
|
}
|
|
|
|
// TWICE A SECOND, PROCESS ORDERS
|
|
{
|
|
static DWORD lasttime = GetTickCount();
|
|
if (currtime-lasttime > 2000)
|
|
lasttime = currtime-500;
|
|
while (currtime-lasttime >= 500) {
|
|
if (ProcessOrders())
|
|
lasttime += 500;
|
|
else
|
|
lasttime = GetTickCount();
|
|
currtime = GetTickCount();
|
|
}
|
|
}
|
|
|
|
// PROCESS SCROLLING
|
|
if (UpdateScrollVelocity()) {
|
|
|
|
// UPDATE THE SCROLL POSITION
|
|
POINT oldscrollpos = scrollpos;
|
|
scrollpos.x = max(0,min(WORLDMAPCX*TILECX-SCROLLCX,scrollpos.x+scrollvel.x));
|
|
scrollpos.y = max(0,min(WORLDMAPCY*TILECY-SCROLLCY,scrollpos.y+scrollvel.y));
|
|
|
|
// UPDATE THE SCROLL BUFFER
|
|
if (scrollpos.x/TILECX != oldscrollpos.x/TILECX) {
|
|
int updatex = (scrollvel.x > 0) ? (oldscrollpos.x % SCROLLCX)/TILECX
|
|
: (scrollpos.x % SCROLLCX)/TILECX;
|
|
RECT rect = {updatex,0,updatex,SCROLLTILESY-1};
|
|
FillScrollBuffer(&rect);
|
|
}
|
|
if (scrollpos.y/TILECY != oldscrollpos.y/TILECY) {
|
|
int updatey = (scrollvel.y > 0) ? (oldscrollpos.y % SCROLLCY)/TILECY
|
|
: (scrollpos.y % SCROLLCY)/TILECY;
|
|
RECT rect = {0,updatey,SCROLLTILESX-1,updatey};
|
|
FillScrollBuffer(&rect);
|
|
}
|
|
|
|
}
|
|
|
|
// DRAW THE SCREEN
|
|
DrawScreen();
|
|
|
|
return 1;
|
|
}
|
|
|
|
//===========================================================================
|
|
BOOL CALLBACK IdleProc (DWORD count) {
|
|
if (started)
|
|
return GameIdleProc(count);
|
|
else
|
|
return ConnectIdleProc(count);
|
|
}
|
|
|
|
//===========================================================================
|
|
void IssueOrder (LPDWORD paramarray, DWORD paramcount) {
|
|
SNetSendTurn(paramarray,
|
|
paramcount*sizeof(DWORD));
|
|
}
|
|
|
|
//===========================================================================
|
|
BOOL Initialize (HINSTANCE instance) {
|
|
if (!SDrawAutoInitialize(instance,
|
|
TITLE "_CLASS",
|
|
TITLE,
|
|
NULL,
|
|
SDRAW_SERVICE_PAGEFLIP)) {
|
|
SDrawMessageBox("Unable to initialize DirectDraw.",TITLE,0);
|
|
return 0;
|
|
}
|
|
if (!LoadGraphicsData()) {
|
|
SDrawMessageBox("Unable to load graphics data.",TITLE,0);
|
|
return 0;
|
|
}
|
|
if (!CreateScrollBuffer()) {
|
|
SDrawMessageBox("Out of memory.",TITLE,0);
|
|
return 0;
|
|
}
|
|
SMsgRegisterMessage(NULL,WM_ERASEBKGND,OnEraseBkgnd);
|
|
if (!Connect())
|
|
return 0;
|
|
ChooseStartingLocations();
|
|
scrollpos.x = max(0,min(WORLDMAPCX*TILECX-SCROLLCX,playerpos[localplayer].x*TILECX-SCROLLCX/2));
|
|
scrollpos.y = max(0,min(WORLDMAPCY*TILECY-SCROLLCY,playerpos[localplayer].y*TILECY-SCROLLCY/2));
|
|
SDrawUpdatePalette(0,256,&pe[0]);
|
|
SMsgRegisterMessage(NULL,WM_CLOSE ,OnClose);
|
|
SMsgRegisterMessage(NULL,WM_LBUTTONDOWN,OnButtonDown);
|
|
SMsgRegisterMessage(NULL,WM_PAINT ,OnPaint);
|
|
SMsgRegisterMessage(NULL,WM_RBUTTONDOWN,OnButtonDown);
|
|
SMsgRegisterKeyDown(NULL,VK_ESCAPE ,OnVkEscape);
|
|
SMsgRegisterKeyDown(NULL,VK_SPACE ,OnVkSpace);
|
|
return 1;
|
|
}
|
|
|
|
//===========================================================================
|
|
BOOL LoadGraphicsData () {
|
|
|
|
// LOAD IN THE CURSOR
|
|
cursor = (LPBYTE)ALLOC(32*32);
|
|
if (!cursor)
|
|
return 0;
|
|
if (!SBmpLoadImage(ARTDIR "cursor.pcx",NULL,cursor,32*32))
|
|
return 0;
|
|
|
|
// LOAD IN THE PLAYER IMAGE
|
|
player = (LPBYTE)ALLOC(32*32);
|
|
if (!player)
|
|
return 0;
|
|
if (!SBmpLoadImage(ARTDIR "player.pcx",NULL,player,32*32))
|
|
return 0;
|
|
|
|
// LOAD IN THE WORLD MAP
|
|
worldmap = (LPBYTE)ALLOC(WORLDMAPCX*WORLDMAPCY);
|
|
if (!worldmap)
|
|
return 0;
|
|
if (!SBmpLoadImage(ARTDIR "map.pcx",NULL,worldmap,WORLDMAPCX*WORLDMAPCY))
|
|
return 0;
|
|
|
|
// LOAD IN THE GRAPHICS TILESET
|
|
tileset = (LPBYTE)ALLOC(TILES*TILECX*TILECY);
|
|
if (!tileset)
|
|
return 0;
|
|
if (!SBmpLoadImage(ARTDIR "tileset.pcx",&pe[0],tileset,TILES*TILECX*TILECY))
|
|
return 0;
|
|
|
|
// CREATE A FONT
|
|
HSGDIFONT font;
|
|
{
|
|
HFONT winfont = CreateFont(-17,0,0,0,FW_BOLD,0,0,0,ANSI_CHARSET,
|
|
OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
|
|
VARIABLE_PITCH | FF_ROMAN,TEXT("Times New Roman"));
|
|
if (!SGdiImportFont(winfont,&font))
|
|
return 0;
|
|
DeleteObject(winfont);
|
|
}
|
|
if (!SGdiSelectObject(font))
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
//===========================================================================
|
|
void MovePlayer (DWORD player) {
|
|
int xdir = orderpos[player].x-playerpos[player].x;
|
|
xdir = (xdir > 0) ? 1 : xdir ? -1 : 0;
|
|
int ydir = orderpos[player].y-playerpos[player].y;
|
|
ydir = (ydir > 0) ? 1 : ydir ? -1 : 0;
|
|
if (xdir) {
|
|
BYTE tile = *(worldmap+playerpos[player].y*WORLDMAPCX+playerpos[player].x+xdir);
|
|
if ((tile >= TILE_GRASS) && (tile != TILE_MOUNTAINS))
|
|
playerpos[player].x += xdir;
|
|
}
|
|
if (ydir) {
|
|
BYTE tile = *(worldmap+(playerpos[player].y+ydir)*WORLDMAPCX+playerpos[player].x);
|
|
if ((tile >= TILE_GRASS) && (tile != TILE_MOUNTAINS))
|
|
playerpos[player].y += ydir;
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
void CALLBACK OnButtonDown (LPPARAMS params) {
|
|
if (started) {
|
|
DWORD order[3] = {ORDER_MOVE,
|
|
(scrollpos.x+LOWORD(params->lparam))/TILECX,
|
|
(scrollpos.y+HIWORD(params->lparam))/TILECY};
|
|
IssueOrder(&order[0],3);
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
void CALLBACK OnClose (LPPARAMS) {
|
|
Destroy();
|
|
}
|
|
|
|
//===========================================================================
|
|
void CALLBACK OnEraseBkgnd (LPPARAMS params) {
|
|
params->useresult = 1;
|
|
params->result = 1;
|
|
}
|
|
|
|
//===========================================================================
|
|
void CALLBACK OnPaint (LPPARAMS params) {
|
|
if (scrollbuffer && tileset) {
|
|
RECT rect = {0,0,SCROLLTILESX-1,SCROLLTILESY-1};
|
|
FillScrollBuffer(&rect);
|
|
DrawScreen();
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
void CALLBACK OnVkEscape (LPPARAMS) {
|
|
DWORD order = ORDER_QUIT;
|
|
IssueOrder(&order,1);
|
|
}
|
|
|
|
//===========================================================================
|
|
void CALLBACK OnVkSpace (LPPARAMS) {
|
|
if (!started) {
|
|
DWORD order = ORDER_START;
|
|
IssueOrder(&order,1);
|
|
}
|
|
}
|
|
|
|
//===========================================================================
|
|
BOOL ProcessOrders () {
|
|
|
|
// MAKE SURE THERE ARE ALWAYS AT LEAST TWO ORDERS IN TRANSIT
|
|
{
|
|
DWORD turns;
|
|
if (SNetGetTurnsInTransit(&turns)) {
|
|
while (turns < 2) {
|
|
DWORD order = ORDER_NULL;
|
|
IssueOrder(&order,1);
|
|
++turns;
|
|
}
|
|
}
|
|
}
|
|
|
|
// GATHER ORDERS FROM ALL PLAYERS
|
|
LPDWORD data[MAXPLAYERS];
|
|
DWORD databytes[MAXPLAYERS];
|
|
DWORD playerstatus[MAXPLAYERS];
|
|
BOOL insync = 1;
|
|
{
|
|
int timeout = 20;
|
|
while ((!SNetReceiveTurns(0,players,(LPVOID *)&data[0],&databytes[0],&playerstatus[0])) &&
|
|
--timeout) {
|
|
insync = 0;
|
|
Sleep(50);
|
|
}
|
|
if (!timeout) {
|
|
SDrawMessageBox("network error",TITLE,0);
|
|
SDrawPostClose();
|
|
}
|
|
}
|
|
|
|
// PROCESS EACH PLAYER'S ORDERS
|
|
for (DWORD player = 0; player < players; ++player)
|
|
if (data[player] && databytes[player])
|
|
switch (*data[player]) {
|
|
|
|
case ORDER_START:
|
|
started = 1;
|
|
break;
|
|
|
|
case ORDER_MOVE:
|
|
orderpos[player].x = *(data[player]+1);
|
|
orderpos[player].y = *(data[player]+2);
|
|
break;
|
|
|
|
case ORDER_QUIT:
|
|
SDrawPostClose();
|
|
break;
|
|
|
|
}
|
|
|
|
return insync;
|
|
}
|
|
|
|
//===========================================================================
|
|
BOOL UpdateScrollVelocity () {
|
|
|
|
// DETERMINE THE SCROLL DIRECTION
|
|
POINT pos;
|
|
GetCursorPos(&pos);
|
|
int x = (pos.x == 639) ? 1 : pos.x ? 0 : -1;
|
|
int y = (pos.y == 479) ? 1 : pos.y ? 0 : -1;
|
|
int velx = (scrollvel.x > 0) ? 1 : scrollvel.x ? -1 : 0;
|
|
int vely = (scrollvel.y > 0) ? 1 : scrollvel.y ? -1 : 0;
|
|
|
|
// UPDATE THE X VELOCITY
|
|
if (x) {
|
|
if ((velx != x) || (abs(scrollvel.x) < 24))
|
|
scrollvel.x += (abs(scrollvel.x) > 12) ? 2*x : x;
|
|
}
|
|
else if (velx)
|
|
scrollvel.x -= velx;
|
|
|
|
// UPDATE THE Y VELOCITY
|
|
if (y) {
|
|
if ((vely != y) || (abs(scrollvel.y) < 16))
|
|
scrollvel.y += (abs(scrollvel.y) > 8) ? 2*y : y;
|
|
}
|
|
else if (vely)
|
|
scrollvel.y -= vely;
|
|
|
|
return (scrollvel.x || scrollvel.y);
|
|
}
|
|
|
|
//===========================================================================
|
|
int APIENTRY WinMain (HINSTANCE instance, HINSTANCE, LPSTR, int) {
|
|
if (!Initialize(instance)) {
|
|
Destroy();
|
|
return 1;
|
|
}
|
|
return SMsgDoMessageLoop(IdleProc);
|
|
}
|