Rogue游戏中需要有怪物和战斗,我们采取简单的战斗系统,即战斗双方各有攻击力和防御力,回合制攻击直至一方死亡。战争迷雾的设计可以使得游戏者有探索地图的乐趣。
Makefile同上一篇文章
main.cpp
#include <curses.h>
#define EMPTY 0
#define ME 1
#define ME_ATK 10
#define ME_DEF 15
#define ME_HP 100
#define WALL 2
#define IN 4
#define OUT 5
#define MONSTER_A 3
#define A_ATK 20
#define A_DEF 2
#define A_HP 20
#define A_EXP 20
#define INSTRUCTION mvprintw(0, 0, "My Rogue\na/left w/up s/down d/right q/exit r/restart");
#include <stdlib.h>
static char symbol[] = {'.', '@', '#', 'A', '(', ')'};
static const int m_w = 90;
static const int m_h = 22;
static const int offset_x = 5;
static const int offset_y = 2;
static int **map;
void MakeMap(int _w, int _h, int **_map);
void drawMap()
{
for (int i = 0;i < m_w;++i)
for (int j = 0;j < m_h;++j)
mvaddch(j + offset_y, i + offset_x, symbol[map[j][i]]);
}
class spirit
{
protected:
int x;
int y;
int kind;
int hp;
int atk;
int def;
public:
spirit(){}
spirit(int _x, int _y, int _kind)
{
x = _x;
y = _y;
kind = _kind;
switch(kind)
{
case MONSTER_A:
atk = A_ATK;
def = A_DEF;
hp = A_HP;
break;
}
}
virtual void ShowStatus(){}
bool isDead()
{
if (hp <= 0)
return true;
return false;
}
void attack(spirit *aim)
{
aim->defend(this, atk);
}
void defend(spirit *aim, int _atk)
{
if (def >= _atk)
return;
hp -= (_atk - def);
if (!isDead())
attack(aim);
}
void FightToDeath(spirit *aim)
{
while(1)
{
attack(aim);
if (aim->isDead() || isDead())
break;
}
}
};
class human:public spirit
{
int level;
int exp;
public:
human(int _kind);
void Move(int _dir);
void ShowMove(int fx, int fy, int tx, int ty);
virtual void ShowStatus();
void ShowView();
void GainExp(int _kind);
void LevelUp();
}*me;
human::human(int _kind)
{
kind = _kind;
level = 1;
exp = 0;
do
{
x = rand() % m_w;
y = rand() % m_h;
}while(map[y][x] != 0);
atk = ME_ATK;
def = ME_DEF;
hp = ME_HP;
mvaddch(y + offset_y, x + offset_x, symbol[kind]);
refresh();
}
void human::Move(int _dir)
{
if (isDead())
return;
int dir_x[4] = {-1, 0, 1, 0};
int dir_y[4] = {0, 1, 0, -1};
int old_x = x;
int old_y = y;
x += dir_x[_dir];
y += dir_y[_dir];
if (map[y][x] == WALL)
{
x = old_x;
y = old_y;
return;
}
if (map[y][x] == MONSTER_A)//fight with monster(A kind)
{
spirit temp_m(x, y, map[y][x]);
FightToDeath(&temp_m);
if (isDead())
{
clear();
INSTRUCTION
mvprintw(offset_y+m_h/2, offset_x+m_w/2, "You are dead!");
refresh();
return;
}
map[y][x] = EMPTY;
GainExp(MONSTER_A);
}
ShowMove(old_x, old_y, x, y);
ShowStatus();
ShowView();
refresh();
}
void human::ShowMove(int fx, int fy, int tx, int ty)
{
mvaddch(fy + offset_y, fx + offset_x, symbol[EMPTY]); //EMPTY
mvaddch(ty + offset_y, tx + offset_x, symbol[this->kind]);
}
void human::ShowStatus()
{
mvprintw(offset_y, offset_x + m_w +1, "status of %c ", symbol[kind]);
mvprintw(offset_y+2, offset_x + m_w +1, "HP:%d ", hp);
mvprintw(offset_y+3, offset_x + m_w +1, "ATK:%d ", atk);
mvprintw(offset_y+4, offset_x + m_w +1, "DEF:%d ", def);
mvprintw(offset_y+5, offset_x + m_w +1, "LEV:%d ", level);
mvprintw(offset_y+6, offset_x + m_w +1, "EXP:%d ", exp);
}
void human::ShowView()
{
int dx[8] = {0, 0, 1, 1, 1, -1, -1, -1};
int dy[8] = {1, -1, 1, 0, -1, 1, 0, -1};
for (int i = 0;i < 8;++i)
mvaddch(offset_y+y+dy[i], offset_x+x+dx[i], symbol[map[y+dy[i]][x+dx[i]]]);
}
void human::GainExp(int _kind)
{
switch(_kind)
{
case MONSTER_A: exp += A_EXP;break;
}
}
void InitGame()
{
clear();
if (me != NULL)
delete me;
MakeMap(m_w, m_h, map);
me = new human(ME);
me->ShowStatus();
me->ShowView();
INSTRUCTION
refresh();
}
int main()
{
initscr();
noecho();
curs_set(0);
map = new int*[m_h];
for (int i = 0;i < m_h;++i)
map[i] = new int[m_w];
InitGame();
while(1)
{
char order = getch();
if (order == 'q') break;
switch(order)
{
case 'a': me->Move(0);break;
case 's': me->Move(1);break;
case 'd': me->Move(2);break;
case 'w': me->Move(3);break;
case 'r': InitGame();break;
}
}
for (int i = 0;i < m_h;++i)
delete []map[i];
delete []map;
delete me;
endwin();
return 0;
}
makemap.cpp
#include <stdlib.h>
#include <time.h>
#define ROOM_MIN_W 5
#define ROOM_MIN_H 4
#define ROOM_MAX_W 10
#define ROOM_MAX_H 7
#define ROOM_NUM 10
#define MONSTER_NUM 10
#define MAX_TRY 300
#define EMPTY 0
#define WALL 2
#define ME 1
#define IN 4
#define OUT 5
#define MONSTER_A 3
class room
{
public:
int x;
int y;
int w;
int h;
bool TryCreateRoom(int _w, int _h, int **map)
{
do
w = rand() % (ROOM_MAX_W + 1);
while(w < ROOM_MIN_W);
do
h = rand() % (ROOM_MAX_H + 1);
while(h < ROOM_MIN_H);
x = rand() % (_w + 1);
y = rand() % (_h + 1);
if (x + w > _w || y + h > _h)
return false;
for (int i = x;i < x + w;++i)
for (int j = y;j < y + h;++j)
{
if (map[j][i] != WALL || i == 0 || i == _w-1 || j == 0 || j == _h-1)
return false;
}
return true;
}
bool CreateRoom(int _w, int _h, int **map)
{
for (int i = 0;i < MAX_TRY;++i)
if (TryCreateRoom(_w, _h, map))
{
for (int ii = x;ii < x + w;++ii)
for (int jj = y;jj < y + h;++jj)
map[jj][ii] = 0;
return true;
}
return false;
}
};
void MakePassageWay(int fx, int fy, int tx, int ty, int **map)
{
for (int i = 0;i <= tx || i <= fx;++i)
if (map[fy][i] == WALL
&& ((i <= tx && i >= fx)||(i >= tx && i <= fx)))
map[fy][i] = EMPTY;
for (int i = 0;i <= ty || i <= fy;++i)
if (map[i][tx] == WALL
&& ((i <= ty && i >= fy)||(i >= ty && i <= fy)))
map[i][tx] = EMPTY;
}
void LinkRoom(room *_r1, room *_r2, int **map)
{
MakePassageWay(_r1->x+_r1->w/2, _r1->y+_r1->h/2, _r2->x+_r2->w/2, _r2->y+_r2->h/2, map);
}
void MakeMap(int _w, int _h, int **map)
{
srand((unsigned)time(NULL));
for (int i = 0;i < _w;++i)
for (int j = 0;j < _h;++j)
map[j][i] = WALL;
room r[ROOM_NUM];
r[0].CreateRoom(_w, _h, map);//generate room
for (int i = 1;i < ROOM_NUM;++i)
if (r[i].CreateRoom(_w, _h, map))
LinkRoom(&r[i-1], &r[i], map);
for (int i = 0;i < MONSTER_NUM;++i)//generate monster A
{
int x, y;
for (int ii = 0;ii < MAX_TRY;++ii)
{
x = rand() % _w;
y = rand() % _h;
if (map[y][x] == EMPTY)
{
map[y][x] = MONSTER_A;
break;
}
}
}
while(1)
{
int x = rand() % _w;
int y = rand() % _h;
if (map[y][x] == EMPTY)
{
map[y][x] = IN;
break;
}
}
while(1)
{
int x = rand() % _w;
int y = rand() % _h;
if (map[y][x] == EMPTY)
{
map[y][x] = OUT;
break;
}
}
return;
}
效果如下图:
全部探索完地图: