-
Notifications
You must be signed in to change notification settings - Fork 0
/
roguelike.cpp
179 lines (152 loc) · 7.66 KB
/
roguelike.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include "roguelike.h"
int main() {
// get ncurses going
InitialiseRenderer();
// create the main log
main_log = new Log("Main");
debug_log = new Log("Debug");
// vector containing all levels
std::vector<Level> levels;
// initialise first level
levels.push_back(Level());
// introduction text
main_log->AddMessage("Welcome to Ying Stokes' Thematically Confused Roguelike!");
main_log->AddMessage("You are a maintenance droid gone rogue.");
main_log->AddMessage("Make your way to the core in order to destroy the masters you swore to repair.");
main_log->AddMessage("---INSTRUCTIONS---");
main_log->AddMessage("Use arrow keys or the numpad to move your character (@)");
main_log->AddMessage("Run into the oncoming sawbots to destroy them");
main_log->AddMessage("Use 'g' to pick up items that fall on the ground");
main_log->AddMessage("Use 'i' to access your inventory, and the letters surrounded by parentheses to use items");
main_log->AddMessage("Press '>' and '<' while standing on the corresponding tiles to move between levels");
main_log->AddMessage("Use 'q' to exit menus and the game");
main_log->AddMessage("See how close you can get to the core... Good luck!");
// create the player as an entity in dynamic memory, in the centre of the first room
Player* player = new Player(
(levels[0].GetRooms()[0].GetY1() + levels[0].GetRooms()[0].GetY2())/2,
(levels[0].GetRooms()[0].GetX1() + levels[0].GetRooms()[0].GetX2())/2);
// put the player into the first level
levels[0].entities_.push_back(player);
// player starts with a repair kit
player->PickupItem(new HealingItem("Repair kit", 10.0, 50.0, 10));
// game loop
FrameInfo frame_info = {kNone, kMain};
Level* level = &levels[0];
int current_level = 1;
do {
switch (frame_info.input_context) {
// if the player is interacting with the main game
case kMain: {
// handle movement between levels
if (frame_info.input_type == kFloorDown) {
if (level->map_[player->GetY()][player->GetX()].character == '>') {
// if the new levels needs to be created, do that
if (current_level == levels.size()) {
levels.push_back(level->NextFloor());
}
// move the player into the next level
Level::TryMoveEntity(&levels[current_level-1], &levels[current_level], player);
// set the position of the player to the new level's up-stairs
player->SetPos(levels[current_level].GetUpStairY(), levels[current_level].GetUpStairX());
// increment the level int and pointer
level = &levels[current_level]; // level -1 + 1
current_level++;
// print a handy message
main_log->AddMessage("The player is transported one floor closer to the core...");
}
}
// same thing but for going up
if (frame_info.input_type == kFloorUp) {
if (level->map_[player->GetY()][player->GetX()].character == '<') {
// make sure going up is possible
if (current_level > 1) {
// never any need to make a new level
level = &levels[current_level-2];
Level::TryMoveEntity(&levels[current_level-1], &levels[current_level-2], player);
player->SetPos(levels[current_level-2].GetDownStairY(), levels[current_level-2].GetDownStairX());
current_level--;
main_log->AddMessage("The player is transported one floor away from the core...");
}
}
}
// if the last input was just a regular movement, update every entity
if (frame_info.input_type == kAction) {
// in reverse order so the player is first (since enemies are created when the level is created)
for (int e = level->entities_.size() - 1; e >= 0; e--) {
if (level->entities_[e]->active_)
level->entities_[e]->Brain(level->map_, level->entities_);
}
// then do it again and check if anything died
for (int e = level->entities_.size() - 1; e >= 0; e--) {
if (level->entities_[e]->active_)
level->entities_[e]->CheckDead(level->entities_);
}
}
// update fov
std::array<std::array<bool, kMapWidth>, kMapHeight> transparentmap = level->GetTransparent();
for (Entity* entity : level->entities_) {
// only update transparentmap if it's a NonBlindEntity
NonBlindEntity* non_blind_entity = dynamic_cast<NonBlindEntity*>(entity);
if (non_blind_entity) non_blind_entity->UpdateFOVTransparent(transparentmap);
}
// update the litness of tiles
std::vector<std::vector<bool>> visible = player->GetFOV();
for (int y = 0; y < kMapHeight; y++) {
for (int x = 0; x < kMapWidth; x++) {
if (visible[y][x]) {
level->map_[y][x].lit = true;
level->map_[y][x].seen = true;
} else {
level->map_[y][x].lit = false;
}
}
}
if (player->GetDead()) {
int high;
std::ifstream hiscore_in;
std::ofstream hiscore_out;
hiscore_in.open("scores.dat");
hiscore_in >> high;
hiscore_in.close();
main_log->AddMessage("!---GAME OVER---!");
main_log->AddMessage(std::string("You made it to floor ").append(std::to_string(current_level)));
if (!high || current_level > high) {
high = current_level;
main_log->AddMessage("NEW HIGH SCORE!");
}
main_log->AddMessage(std::string("The high score is ").append(std::to_string(high)));
hiscore_out.open("scores.dat", std::ios::trunc);
hiscore_out << high << std::endl;
hiscore_out << "Don't edit this file, it's just scummy." << std::endl;
hiscore_out.close();
}
// call rendering functions
RenderLevel(level);
AddLogMessages(main_log);
AddLogMessages(debug_log);
RenderHud(player, current_level);
break;
}
case kMenu: {
// if the context is a menu, render the menu
ManageMenu(player);
RenderMenu(player);
break;
}
}
// get the next input
frame_info = input(frame_info);
// quit if necessary
} while (frame_info.input_context != kAbort);
// end ncurses
endwin();
// free logs after quitting
delete main_log;
delete debug_log;
// free all entities
for (Level level : levels) {
level.FreeEntities();
}
// everything went perfectly :)
return 0;
}