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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
|
#include <stdio.h>
#define TB_IMPL
#include "termbox2.h"
#define MIN_W 40
#define MIN_H 12
#define SIDEBAR_W 40
#define CP_H 0x2500
#define CP_V 0x2502
#define CP_TL 0x250c
#define CP_TR 0x2510
#define CP_BL 0x2514
#define CP_BR 0x2518
static void draw_border(int x, int y, int w, int h, uintattr_t fg) {
int ix;
int iy;
for (ix = 0; ix < w; ix++) {
tb_set_cell(x + ix, y, CP_H, fg, TB_DEFAULT);
tb_set_cell(x + ix, y + h - 1, CP_H, fg, TB_DEFAULT);
}
for (iy = 0; iy < h; iy++) {
tb_set_cell(x, y + iy, CP_V, fg, TB_DEFAULT);
tb_set_cell(x + w - 1, y + iy, CP_V, fg, TB_DEFAULT);
}
tb_set_cell(x, y, CP_TL, fg, TB_DEFAULT);
tb_set_cell(x + w - 1, y, CP_TR, fg, TB_DEFAULT);
tb_set_cell(x, y + h - 1, CP_BL, fg, TB_DEFAULT);
tb_set_cell(x + w - 1, y + h - 1, CP_BR, fg, TB_DEFAULT);
}
static void draw_room(int x, int y, int w, int h, uintattr_t fg) {
draw_border(x, y, w, h, fg);
tb_set_cell(x + w / 2, y, '+', fg, TB_DEFAULT);
}
static void get_layout(int w, int h, int *map_x, int *map_y, int *map_w,
int *map_h, int *side_x, int *side_y, int *side_w, int *side_h,
int *msg1_y, int *msg2_y) {
*map_x = 0;
*map_y = 0;
*map_w = w - SIDEBAR_W;
*map_h = h - 2;
*side_x = w - SIDEBAR_W;
*side_y = 0;
*side_w = SIDEBAR_W;
*side_h = h - 2;
*msg1_y = h - 2;
*msg2_y = h - 1;
}
static void draw_map(int map_x, int map_y, int map_w, int map_h, int px,
int py) {
if (px >= 0 && py >= 0) {
tb_set_cell(map_x + px, map_y + py, '@', TB_WHITE | TB_BOLD, TB_DEFAULT);
}
}
static void draw_progress_bar(int x, int y, int w, int value, int max) {
int filled;
int ix;
int inner_w = w - 2;
if (w < 4) {
return;
}
if (max <= 0) {
max = 1;
}
if (value < 0) {
value = 0;
}
if (value > max) {
value = max;
}
filled = (inner_w * value) / max;
tb_set_cell(x, y, '[', TB_WHITE, TB_DEFAULT);
for (ix = 0; ix < inner_w; ix++) {
uintattr_t fg = ix < filled ? TB_GREEN : TB_WHITE;
uint32_t ch = ix < filled ? '=' : ' ';
tb_set_cell(x + 1 + ix, y, ch, fg, TB_DEFAULT);
}
tb_set_cell(x + w - 1, y, ']', TB_WHITE, TB_DEFAULT);
}
static void draw_stats(int x, int y) {
tb_print(x, y, TB_WHITE | TB_BOLD, TB_DEFAULT, "Stats");
tb_print(x, y + 2, TB_WHITE, TB_DEFAULT, "HP 12/12");
draw_progress_bar(x, y + 3, 18, 12, 12);
tb_print(x, y + 4, TB_WHITE, TB_DEFAULT, "AC: 7");
tb_print(x, y + 5, TB_WHITE, TB_DEFAULT, "Str: 16");
tb_print(x, y + 6, TB_WHITE, TB_DEFAULT, "Gold: 42");
}
static void draw_inventory(int x, int y) {
tb_print(x, y, TB_WHITE | TB_BOLD, TB_DEFAULT, "Inventory");
tb_print(x, y + 2, TB_WHITE, TB_DEFAULT, "a) dagger");
tb_print(x, y + 3, TB_WHITE, TB_DEFAULT, "b) ration");
tb_print(x, y + 4, TB_WHITE, TB_DEFAULT, "c) potion");
tb_print(x, y + 5, TB_WHITE, TB_DEFAULT, "d) scroll");
}
static const char *status_msg = "";
static void update_status(const char *message) {
status_msg = message ? message : "";
}
static void render(int px, int py, int *out_map_w, int *out_map_h) {
int w;
int h;
int map_x;
int map_y;
int map_w;
int map_h;
int side_x;
int side_y;
int side_w;
int side_h;
int stats_x;
int stats_y;
int stats_w;
int stats_h;
int inv_x;
int inv_y;
int inv_w;
int inv_h;
int msg1_y;
int msg2_y;
w = tb_width();
h = tb_height();
get_layout(w, h, &map_x, &map_y, &map_w, &map_h, &side_x, &side_y, &side_w, &side_h, &msg1_y, &msg2_y);
tb_clear();
if (w < MIN_W || h < MIN_H || map_w < 8 || map_h < 3) {
tb_print(1, 1, TB_RED | TB_BOLD, TB_DEFAULT, "Window too small. Resize to at least 40x12.");
tb_present();
*out_map_w = map_w;
*out_map_h = map_h;
return;
}
draw_border(map_x, map_y, map_w, map_h, TB_WHITE);
draw_map(map_x + 1, map_y + 1, map_w - 2, map_h - 2, px, py);
stats_x = side_x;
stats_y = side_y;
stats_w = side_w;
stats_h = 11;
inv_x = side_x;
inv_y = side_y + stats_h;
inv_w = side_w;
inv_h = side_h - stats_h;
if (stats_w >= 12 && stats_h >= 9) {
draw_border(stats_x, stats_y, stats_w, stats_h, TB_WHITE);
draw_stats(stats_x + 2, stats_y + 1);
}
if (inv_w >= 12 && inv_h >= 7) {
draw_border(inv_x, inv_y, inv_w, inv_h, TB_WHITE);
draw_inventory(inv_x + 2, inv_y + 1);
}
tb_print(2, msg1_y, TB_GREEN, TB_DEFAULT, status_msg);
tb_print(2, msg2_y, TB_WHITE, TB_DEFAULT, "Move: arrows Quit: q/ESC");
tb_present();
*out_map_w = map_w - 2;
*out_map_h = map_h - 2;
}
static int clamp(int value, int min, int max) {
if (value < min) {
return min;
}
if (value > max) {
return max;
}
return value;
}
int main(void) {
int px = 6;
int py = 4;
int running = 1;
int map_w = 0;
int map_h = 0;
if (tb_init() != TB_OK) {
fprintf(stderr, "Failed to init termbox.\n");
return 1;
}
tb_set_input_mode(TB_INPUT_ESC);
update_status("You feel like you have a lot of potential.");
while (running) {
struct tb_event ev;
render(px, py, &map_w, &map_h);
tb_poll_event(&ev);
if (ev.type == TB_EVENT_KEY) {
if (ev.key == TB_KEY_ESC || ev.ch == 'q') {
running = 0;
} else if (ev.key == TB_KEY_ARROW_UP) {
py -= 1;
} else if (ev.key == TB_KEY_ARROW_DOWN) {
py += 1;
} else if (ev.key == TB_KEY_ARROW_LEFT) {
px -= 1;
} else if (ev.key == TB_KEY_ARROW_RIGHT) {
px += 1;
}
px = clamp(px, 0, map_w > 1 ? map_w - 1 : 0);
py = clamp(py, 0, map_h > 1 ? map_h - 1 : 0);
} else if (ev.type == TB_EVENT_RESIZE) {
px = clamp(px, 0, map_w > 1 ? map_w - 1 : 0);
py = clamp(py, 0, map_h > 1 ? map_h - 1 : 0);
}
}
tb_shutdown();
return 0;
}
|