📄 isohex19_2.cpp
字号:
/*****************************************************************************
IsoHex19_2.cpp
Ernest S. Pazera
04OCT2000
Start a WIN32 Application Workspace, add in this file
Requires the following libs:
ddraw.lib, dxguid.lib
Requires the following files:
DDFuncs.h.cpp, GDICanvas.h/cpp, IsoMouseMap.h/cpp,
IsoScroller.h/cpp, IsoTilePlotter.h/cpp, IsoTileWalker.h/cpp
TileSet.h/cpp. IsoHexCore.h, IsoHexDefs.h
IsoRenderer.h/cpp
*****************************************************************************/
//////////////////////////////////////////////////////////////////////////////
//INCLUDES
//////////////////////////////////////////////////////////////////////////////
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "DDFuncs.h"
#include "TileSet.h"
#include "IsoHexCore.h"
#include "IsoRenderer.h"
#include <list>
//////////////////////////////////////////////////////////////////////////////
//DEFINES
//////////////////////////////////////////////////////////////////////////////
//name for our window class
#define WINDOWCLASS "ISOHEX19"
//title of the application
#define WINDOWTITLE "IsoHex 19-2"
const int MAPWIDTH=40;
const int MAPHEIGHT=40;
//gamestates
const int GS_IDLE=0;//waits for a keypress
const int GS_STARTTURN=1;//starts a players turn
const int GS_ENDTURN=2;//ends a players turn
const int GS_NEXTUNIT=3;//finds the next unit to move
const int GS_STARTMOVE=4;//starts moving the unit
const int GS_DOMOVE=5;//moves the unit
const int GS_ENDMOVE=6;//ends a unit move
const int GS_NULLMOVE=7;//tells a unit to not move
const int GS_SKIPMOVE=8;//temporarily skip the move
const int GS_HOLDPOSITION=9;//fortify
const int GS_CLICKSELECT=10;//when a click occurs, this gamestate is selected
const int GS_CLICKCENTER=11;//click on a map location with none of the players units
const int GS_CLICKSTACK=12;//click on a map location with at least two of the players units
const int GS_PICKUNIT=13;//pick unit from the selection window
//////////////////////////////////////////////////////////////////////////////
//TYPEDEFS/STRUCTS
//////////////////////////////////////////////////////////////////////////////
struct UnitInfo//unit information structure
{
int iType;//type of unit
int iTeam;//team to which the unit belongs
POINT ptPosition;//map location of the unit
int iMovePoints;//number of movepoints left this turn
bool bHolding;//true if holding position
};
typedef UnitInfo *PUNITINFO;//pointer type alias for unitinfo
typedef std::list<PUNITINFO> UNITLIST;//list of units
typedef std::list<PUNITINFO>::iterator UNITLISTITER;//iterator for unit list
//////////////////////////////////////////////////////////////////////////////
//PROTOTYPES
//////////////////////////////////////////////////////////////////////////////
bool Prog_Init();//game data initalizer
void Prog_Loop();//main game loop
void Prog_Done();//game clean up
//minimap functions
void SetupMiniMap();//does initial setup of the minimap
void UpdateMiniMap();//updates the minimap to reflect current game status
void RedrawMiniMap();//redraws the minimap to reflect current gamestate
void ShowMiniMap();//shows the minimap on-screen
void DestroyMiniMap();//cleans up the minimap
//////////////////////////////////////////////////////////////////////////////
//GLOBALS
//////////////////////////////////////////////////////////////////////////////
HINSTANCE hInstMain=NULL;//main application handle
HWND hWndMain=NULL;//handle to our main window
//game state
int iGameState=GS_IDLE;
int iCurrentTeam=0;//the team whose turn it currently is
//directdraw
LPDIRECTDRAW7 lpdd=NULL;
LPDIRECTDRAWSURFACE7 lpddsMain=NULL;
LPDIRECTDRAWSURFACE7 lpddsBack=NULL;
LPDIRECTDRAWSURFACE7 lpddsFrame=NULL;
LPDIRECTDRAWSURFACE7 lpddsMiniMap=NULL;//minimap surface
//tilesets
CTileSet tsBack;//background
CTileSet tsUnit;//unit
CTileSet tsShield;//shields
CTileSet tsPressEnter;//press enter text
CTileSet tsMiniMap;//minimap tileset
//offsets for the shields
POINT ptShieldOffset[2];//one for each unit
//isohexcore components
CTilePlotter TilePlotter;//plotter
CTileWalker TileWalker;//walker
CScroller Scroller;//scroller
CMouseMap MouseMap;//mousemap
CRenderer Renderer;//renderer
//minimap components
CTilePlotter MiniTilePlotter;
CScroller MiniScroller;
POINT ptScroll;//keep track of how quickly we scroll
POINT ptClick;//keep track of the clicked position
//map location structure
struct MapLocation
{
UNITLIST ulUnitList;//list of units on this map location
};
MapLocation mlMap[MAPWIDTH][MAPHEIGHT];//map array
UNITLIST MainUnitList;//unit list for all units
UNITLIST TeamUnitList;//unit list for teams(Current Players Turn)
PUNITINFO pCurrentUnit;//current unit being moved
bool bFlash;//controls the flashing of the current unit
ISODIRECTION idMoveUnit;//direction in which the unit will be moved
bool bMovedUnit;//indicates whether or not a unit has been moved by the current player this turn
//unit selection variables(for selecting stacks of units)
RECT rcSelectWindow;//the selection window
POINT ptCellSize;//size of selection cell
PUNITINFO SelectUnitList[20];//unit selection list (max of 20 units)
POINT ptUnitOffset;//offset for placing units in the selection window
DWORD dwSelectWindowColor;//color for the selection window
//minimap array
int* MiniMap;//current minimap array
//rendering functionprototype
void RenderFunc(LPDIRECTDRAWSURFACE7 lpddsDst,RECT* rcClip,int xDst,int yDst,int xMap,int yMap);
//////////////////////////////////////////////////////////////////////////////
//WINDOWPROC
//////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK TheWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
//which message did we get?
switch(uMsg)
{
case WM_LBUTTONDOWN://beginning of click-select
{
//process differently, depending on gamestate
switch(iGameState)
{
case GS_IDLE:
{
//grab the mouse position
POINT ptCursor;
ptCursor.x=LOWORD(lParam);
ptCursor.y=HIWORD(lParam);
//use the mousemap to get click position
ptClick=MouseMap.MapMouse(ptCursor);
}break;
}
return(0);//handled
}break;
case WM_LBUTTONUP://end of click-select
{
//process differently, depending on gamestate
switch(iGameState)
{
case GS_IDLE:
{
//grab the mouse position
POINT ptCursor;
ptCursor.x=LOWORD(lParam);
ptCursor.y=HIWORD(lParam);
//use the mousemap to get click position
POINT ptMap=MouseMap.MapMouse(ptCursor);
//check map position against ptClick
if(ptMap.x==ptClick.x && ptMap.y==ptClick.y)
{
//set gamestate to GS_CLICKSELECT
iGameState=GS_CLICKSELECT;
}
}break;
case GS_PICKUNIT:
{
//grab the mouse position
POINT ptMouse;
ptMouse.x=LOWORD(lParam);
ptMouse.y=HIWORD(lParam);
//check to see if the click was within the select window
if(PtInRect(&rcSelectWindow,ptMouse))
{
//within the select window
//determine which cell was clicked
ptMouse.x-=rcSelectWindow.left;//subtract top left of the window
ptMouse.y-=rcSelectWindow.top;
ptMouse.x/=ptCellSize.x;//divide by cellsize
ptMouse.y/=ptCellSize.y;
int cellnum=ptMouse.x+5*ptMouse.y;//calc cell number
//check for a NULL
if(SelectUnitList[cellnum]==NULL)
{
//empty cell
//do nothing
return(0);
}
else
{
//non-empty cell
//check if the unit has any movement points left
if(SelectUnitList[cellnum]->iMovePoints==0)
{
//no movement points
//do nothing
return(0);
}
else
{
//check for holding position
if(SelectUnitList[cellnum]->bHolding)
{
//set holding to false
SelectUnitList[cellnum]->bHolding=false;
}
//remove this unit from the team list
TeamUnitList.remove(SelectUnitList[cellnum]);
//re-add this unit to the team list at the beginning
TeamUnitList.push_front(SelectUnitList[cellnum]);
//select next unit
iGameState=GS_NEXTUNIT;
//add entire screen to update rect
Renderer.AddRect(Scroller.GetScreenSpace());
}
}
}
else
{
//outside of select window
iGameState=GS_NEXTUNIT;
}
}break;
}
return(0);//handled
}break;
case WM_KEYDOWN:
{
switch(wParam)
{
case VK_ESCAPE:
{
DestroyWindow(hWndMain);
return(0);
}break;
case VK_RETURN://at end of turn, if no unit has been moved
{
if(iGameState==GS_IDLE && pCurrentUnit==NULL) iGameState=GS_ENDTURN;
return(0);
}break;
case VK_SPACE://do not move unit
{
if(iGameState==GS_IDLE && pCurrentUnit!=NULL) iGameState=GS_NULLMOVE;//only respond when gamestate is GS_IDLE;
return(0);
}break;
case 'W'://wait to move this unit later
{
if(iGameState==GS_IDLE && pCurrentUnit!=NULL) iGameState=GS_SKIPMOVE;//skip this unit for now
}break;
case 'H'://tell unit to hold position
{
if(iGameState==GS_IDLE && pCurrentUnit!=NULL) iGameState=GS_HOLDPOSITION;//tell the unit to hold position
}break;
case 'C'://center on the current unit
{
if(iGameState==GS_IDLE && pCurrentUnit!=NULL)
{
//plot the current unit's world position
POINT ptPlot=TilePlotter.PlotTile(pCurrentUnit->ptPosition);
//adjust by half width and height of the screen
ptPlot.x-=(Scroller.GetScreenSpaceWidth()/2);
ptPlot.y-=(Scroller.GetScreenSpaceHeight()/2);
//set the anchor
Scroller.SetAnchor(&ptPlot);
//add update rect to renderer
Renderer.AddRect(Scroller.GetScreenSpace());
}
}break;
case VK_NUMPAD8:
case VK_UP:
{
if(iGameState==GS_IDLE && pCurrentUnit!=NULL)//gamestate must be GS_IDLE
{
idMoveUnit=ISO_NORTH;//move to the north
POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
{
if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
{
iGameState=GS_STARTMOVE;//set the unit in motion
}
else
{
UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
PUNITINFO pUnitInfo=*iter;//get the unit from the list
if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
{
iGameState=GS_STARTMOVE;
}
}
}
}
}break;
case VK_NUMPAD9:
case VK_PRIOR:
{
if(iGameState==GS_IDLE && pCurrentUnit!=NULL)//gamestate must be GS_IDLE
{
idMoveUnit=ISO_NORTHEAST;//move to the north
POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
{
if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
{
iGameState=GS_STARTMOVE;//set the unit in motion
}
else
{
UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
PUNITINFO pUnitInfo=*iter;//get the unit from the list
if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
{
iGameState=GS_STARTMOVE;
}
}
}
}
}break;
case VK_NUMPAD6:
case VK_RIGHT:
{
if(iGameState==GS_IDLE && pCurrentUnit!=NULL)//gamestate must be GS_IDLE
{
idMoveUnit=ISO_EAST;//move to the north
POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
{
if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
{
iGameState=GS_STARTMOVE;//set the unit in motion
}
else
{
UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
PUNITINFO pUnitInfo=*iter;//get the unit from the list
if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
{
iGameState=GS_STARTMOVE;
}
}
}
}
}break;
case VK_NUMPAD3:
case VK_NEXT:
{
if(iGameState==GS_IDLE && pCurrentUnit!=NULL)//gamestate must be GS_IDLE
{
idMoveUnit=ISO_SOUTHEAST;//move to the north
POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
{
if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
{
iGameState=GS_STARTMOVE;//set the unit in motion
}
else
{
UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
PUNITINFO pUnitInfo=*iter;//get the unit from the list
if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
{
iGameState=GS_STARTMOVE;
}
}
}
}
}break;
case VK_NUMPAD2:
case VK_DOWN:
{
if(iGameState==GS_IDLE && pCurrentUnit!=NULL)//gamestate must be GS_IDLE
{
idMoveUnit=ISO_SOUTH;//move to the north
POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
{
if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
{
iGameState=GS_STARTMOVE;//set the unit in motion
}
else
{
UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
PUNITINFO pUnitInfo=*iter;//get the unit from the list
if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
{
iGameState=GS_STARTMOVE;
}
}
}
}
}break;
case VK_NUMPAD1:
case VK_END:
{
if(iGameState==GS_IDLE && pCurrentUnit!=NULL)//gamestate must be GS_IDLE
{
idMoveUnit=ISO_SOUTHWEST;//move to the north
POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
{
if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
{
iGameState=GS_STARTMOVE;//set the unit in motion
}
else
{
UNITLISTITER iter=mlMap[ptNext.x][ptNext.y].ulUnitList.begin();//get the first entry in the list
PUNITINFO pUnitInfo=*iter;//get the unit from the list
if(pUnitInfo->iTeam==pCurrentUnit->iTeam)//must be the same team
{
iGameState=GS_STARTMOVE;
}
}
}
}
}break;
case VK_NUMPAD4:
case VK_LEFT:
{
if(iGameState==GS_IDLE && pCurrentUnit!=NULL)//gamestate must be GS_IDLE
{
idMoveUnit=ISO_WEST;//move to the north
POINT ptNext=TileWalker.TileWalk(pCurrentUnit->ptPosition,idMoveUnit);//check the next position
if(ptNext.x>=0 && ptNext.y>=0 && ptNext.x<MAPWIDTH && ptNext.y<MAPWIDTH)//bounds checking
{
if(mlMap[ptNext.x][ptNext.y].ulUnitList.empty())//if the map location is empty
{
iGameState=GS_STARTMOVE;//set the unit in motion
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -