forked from github/server
1735 lines
49 KiB
C
1735 lines
49 KiB
C
#ifdef _MSC_VER
|
|
#include <platform.h>
|
|
#endif
|
|
|
|
#include <curses.h>
|
|
|
|
#include "gmtool.h"
|
|
#include "direction.h"
|
|
|
|
#include <modules/autoseed.h>
|
|
|
|
#include "kernel/building.h"
|
|
#include "kernel/config.h"
|
|
#include "kernel/faction.h"
|
|
#include "kernel/item.h"
|
|
#include "kernel/plane.h"
|
|
#include "kernel/region.h"
|
|
#include "kernel/resources.h"
|
|
#include "kernel/terrainid.h"
|
|
#include "kernel/unit.h"
|
|
#include "kernel/save.h"
|
|
#include "kernel/ship.h"
|
|
#include "kernel/terrain.h"
|
|
|
|
#include <kernel/attrib.h>
|
|
#include <util/base36.h>
|
|
#include <util/lists.h>
|
|
#include <util/macros.h>
|
|
#include "util/path.h"
|
|
#include "util/rand.h"
|
|
#include "util/rng.h"
|
|
#include "util/unicode.h"
|
|
|
|
#include "gmtool_structs.h"
|
|
#include "console.h"
|
|
#include "listbox.h"
|
|
#include "teleport.h"
|
|
|
|
#include <selist.h>
|
|
|
|
#include <assert.h>
|
|
#include <limits.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
static int g_quit;
|
|
int force_color = 0;
|
|
newfaction * new_players = 0;
|
|
|
|
state *current_state = NULL;
|
|
|
|
#define IFL_SHIPS (1<<0)
|
|
#define IFL_UNITS (1<<1)
|
|
#define IFL_FACTIONS (1<<2)
|
|
#define IFL_BUILDINGS (1<<3)
|
|
|
|
static WINDOW *hstatus;
|
|
|
|
#ifdef STDIO_CP
|
|
int gm_codepage = STDIO_CP;
|
|
#else
|
|
int gm_codepage = -1;
|
|
#endif
|
|
|
|
static void unicode_remove_diacritics(const char *rp, char *wp) {
|
|
while (*rp) {
|
|
if (gm_codepage >= 0 && *rp & 0x80) {
|
|
size_t sz = 0;
|
|
unsigned char ch;
|
|
switch (gm_codepage) {
|
|
case 1252:
|
|
unicode_utf8_to_cp1252(&ch, rp, &sz);
|
|
break;
|
|
case 437:
|
|
unicode_utf8_to_cp437(&ch, rp, &sz);
|
|
break;
|
|
default:
|
|
unicode_utf8_to_ascii(&ch, rp, &sz);
|
|
break;
|
|
}
|
|
rp += sz;
|
|
*wp++ = (char)ch;
|
|
}
|
|
else {
|
|
*wp++ = *rp++;
|
|
}
|
|
}
|
|
*wp = 0;
|
|
}
|
|
|
|
static void simplify(const char *rp, char *wp) {
|
|
unicode_remove_diacritics(rp, wp);
|
|
}
|
|
|
|
int umvwprintw(WINDOW *win, int y, int x, const char *format, ...) {
|
|
char buffer[128];
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
|
memset(buffer, 0, sizeof(buffer));
|
|
vsnprintf(buffer, sizeof(buffer) - 1, format, args);
|
|
va_end(args);
|
|
|
|
simplify(buffer, buffer);
|
|
|
|
return mvwaddstr(win, y, x, buffer);
|
|
}
|
|
|
|
int umvwaddnstr(WINDOW *w, int y, int x, const char * str, int len) {
|
|
char buffer[128];
|
|
simplify(str, buffer);
|
|
return mvwaddnstr(w, y, x, buffer, len);
|
|
}
|
|
|
|
static void init_curses(void)
|
|
{
|
|
initscr();
|
|
|
|
if (has_colors() || force_color) {
|
|
int fg, bg;
|
|
short bcol = COLOR_BLACK;
|
|
short hcol = COLOR_MAGENTA;
|
|
start_color();
|
|
#ifdef __PDCURSES__
|
|
/* looks crap on putty with TERM=linux */
|
|
if (can_change_color()) {
|
|
init_color(COLOR_YELLOW, 1000, 1000, 0);
|
|
init_color(COLOR_CYAN, 0, 1000, 1000);
|
|
}
|
|
#endif
|
|
for (fg = 0; fg != 8; ++fg) {
|
|
for (bg = 0; bg != 2; ++bg) {
|
|
init_pair((short)(fg + 8 * bg), (short)fg, (short)(bg ? hcol : bcol));
|
|
}
|
|
}
|
|
|
|
attrset(COLOR_PAIR(COLOR_BLACK));
|
|
bkgd(' ' | COLOR_PAIR(COLOR_BLACK));
|
|
bkgdset(' ' | COLOR_PAIR(COLOR_BLACK));
|
|
}
|
|
|
|
keypad(stdscr, TRUE); /* enable keyboard mapping */
|
|
meta(stdscr, TRUE);
|
|
nonl(); /* tell curses not to do NL->CR/NL on output */
|
|
cbreak(); /* take input chars one at a time, no wait for \n */
|
|
noecho(); /* don't echo input */
|
|
scrollok(stdscr, FALSE);
|
|
refresh();
|
|
}
|
|
|
|
void cnormalize(const coordinate * c, int *x, int *y)
|
|
{
|
|
*x = c->x;
|
|
*y = c->y;
|
|
pnormalize(x, y, c->pl);
|
|
}
|
|
|
|
map_region *mr_get(const view * vi, int xofs, int yofs)
|
|
{
|
|
return vi->regions + xofs + yofs * vi->size.width;
|
|
}
|
|
|
|
static point *coor2point(const coordinate * c, point * p)
|
|
{
|
|
assert(c && p);
|
|
p->x = c->x * TWIDTH + c->y * TWIDTH / 2; /*-V537 */
|
|
p->y = c->y * THEIGHT;
|
|
return p;
|
|
}
|
|
|
|
static window *wnd_first, *wnd_last;
|
|
|
|
static window *win_create(WINDOW * hwin)
|
|
{
|
|
window *wnd = calloc(1, sizeof(window));
|
|
wnd->handle = hwin;
|
|
if (wnd_first != NULL) {
|
|
wnd->next = wnd_first;
|
|
wnd_first->prev = wnd;
|
|
wnd_first = wnd;
|
|
}
|
|
else {
|
|
wnd_first = wnd;
|
|
wnd_last = wnd;
|
|
}
|
|
return wnd;
|
|
}
|
|
|
|
static void untag_region(selection * s, int nx, int ny)
|
|
{
|
|
unsigned int key = ((nx << 12) ^ ny);
|
|
tag **tp = &s->tags[key & (MAXTHASH - 1)];
|
|
tag *t = NULL;
|
|
while (*tp) {
|
|
t = *tp;
|
|
if (t->coord.x == nx && t->coord.y == ny)
|
|
break;
|
|
tp = &t->nexthash;
|
|
}
|
|
if (!*tp)
|
|
return;
|
|
*tp = t->nexthash;
|
|
free(t);
|
|
return;
|
|
}
|
|
|
|
static void tag_region(selection * s, int nx, int ny)
|
|
{
|
|
unsigned int key = ((nx << 12) ^ ny);
|
|
tag **tp = &s->tags[key & (MAXTHASH - 1)];
|
|
while (*tp) {
|
|
tag *t = *tp;
|
|
if (t->coord.x == nx && t->coord.y == ny)
|
|
return;
|
|
tp = &t->nexthash;
|
|
}
|
|
*tp = calloc(1, sizeof(tag));
|
|
(*tp)->coord.x = nx;
|
|
(*tp)->coord.y = ny;
|
|
(*tp)->coord.pl = findplane(nx, ny);
|
|
return;
|
|
}
|
|
|
|
static int tagged_region(selection * s, int nx, int ny)
|
|
{
|
|
unsigned int key = ((nx << 12) ^ ny);
|
|
tag **tp = &s->tags[key & (MAXTHASH - 1)];
|
|
while (*tp) {
|
|
tag *t = *tp;
|
|
if (t->coord.x == nx && t->coord.y == ny)
|
|
return 1;
|
|
tp = &t->nexthash;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static chtype mr_tile(const map_region * mr, int highlight)
|
|
{
|
|
int hl = 8 * highlight;
|
|
if (mr != NULL && mr->r != NULL) {
|
|
const region *r = mr->r;
|
|
switch (r->terrain->_name[0]) {
|
|
case 'o':
|
|
return '.' | COLOR_PAIR(hl + COLOR_CYAN) | A_BOLD; /*-V525 */
|
|
case 'd':
|
|
return 'D' | COLOR_PAIR(hl + COLOR_YELLOW) | A_BOLD;
|
|
case 't':
|
|
return '%' | COLOR_PAIR(hl + COLOR_YELLOW) | A_BOLD;
|
|
case 'f':
|
|
if (r->terrain->_name[1] == 'o') { /* fog */
|
|
return '.' | COLOR_PAIR(hl + COLOR_YELLOW) | A_NORMAL;
|
|
}
|
|
else if (r->terrain->_name[1] == 'i') { /* firewall */
|
|
return '%' | COLOR_PAIR(hl + COLOR_RED) | A_BOLD;
|
|
}
|
|
break;
|
|
case 'h':
|
|
return 'H' | COLOR_PAIR(hl + COLOR_YELLOW) | A_NORMAL;
|
|
case 'm':
|
|
return '^' | COLOR_PAIR(hl + COLOR_WHITE) | A_NORMAL;
|
|
case 'p':
|
|
if (r->terrain->_name[1] == 'l') { /* plain */
|
|
if (r_isforest(r))
|
|
return '#' | COLOR_PAIR(hl + COLOR_GREEN) | A_NORMAL;
|
|
return '+' | COLOR_PAIR(hl + COLOR_GREEN) | A_BOLD;
|
|
}
|
|
else if (r->terrain->_name[1] == 'a') { /* packice */
|
|
return ':' | COLOR_PAIR(hl + COLOR_WHITE) | A_BOLD;
|
|
}
|
|
break;
|
|
case 'g':
|
|
return '*' | COLOR_PAIR(hl + COLOR_WHITE) | A_BOLD;
|
|
case 's':
|
|
return 'S' | COLOR_PAIR(hl + COLOR_MAGENTA) | A_NORMAL;
|
|
}
|
|
return r->terrain->_name[0] | COLOR_PAIR(hl + COLOR_RED);
|
|
}
|
|
return ' ' | COLOR_PAIR(hl + COLOR_WHITE);
|
|
}
|
|
|
|
static void paint_map(window * wnd, const state * st)
|
|
{
|
|
WINDOW *win = wnd->handle;
|
|
int lines = getmaxy(win);
|
|
int cols = getmaxx(win);
|
|
int vx, vy;
|
|
|
|
assert(st);
|
|
if (!st) return;
|
|
lines = lines / THEIGHT;
|
|
cols = cols / TWIDTH;
|
|
for (vy = 0; vy != lines; ++vy) {
|
|
int yp = (lines - vy - 1) * THEIGHT;
|
|
for (vx = 0; vx != cols; ++vx) {
|
|
map_region *mr = mr_get(&st->display, vx, vy);
|
|
int xp = vx * TWIDTH + (vy & 1) * TWIDTH / 2;
|
|
int nx, ny;
|
|
if (mr) {
|
|
int attr = 0;
|
|
int hl = 0;
|
|
cnormalize(&mr->coord, &nx, &ny);
|
|
if (tagged_region(st->selected, nx, ny)) {
|
|
attr |= A_REVERSE;
|
|
}
|
|
if (mr->r && (mr->r->flags & RF_MAPPER_HIGHLIGHT))
|
|
hl = 1;
|
|
mvwaddch(win, yp, xp, mr_tile(mr, hl) | attr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
map_region *cursor_region(const view * v, const coordinate * c)
|
|
{
|
|
if (c) {
|
|
int cx, cy;
|
|
coordinate relpos;
|
|
|
|
relpos.x = c->x - v->topleft.x;
|
|
relpos.y = c->y - v->topleft.y;
|
|
cy = relpos.y;
|
|
cx = relpos.x + cy / 2;
|
|
return mr_get(v, cx, cy);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
draw_cursor(WINDOW * win, selection * s, const view * v, const coordinate * c,
|
|
int show)
|
|
{
|
|
int lines = getmaxy(win) / THEIGHT;
|
|
int xp, yp, nx, ny;
|
|
int attr = 0;
|
|
map_region *mr = cursor_region(v, c);
|
|
coordinate relpos;
|
|
int cx, cy;
|
|
|
|
if (!mr)
|
|
return;
|
|
|
|
relpos.x = c->x - v->topleft.x;
|
|
relpos.y = c->y - v->topleft.y;
|
|
cy = relpos.y;
|
|
cx = relpos.x + cy / 2;
|
|
|
|
yp = (lines - cy - 1) * THEIGHT;
|
|
xp = cx * TWIDTH + (cy & 1) * TWIDTH / 2;
|
|
cnormalize(&mr->coord, &nx, &ny);
|
|
if (s && tagged_region(s, nx, ny))
|
|
attr = A_REVERSE;
|
|
if (mr->r) {
|
|
int hl = 0;
|
|
if (mr->r->flags & RF_MAPPER_HIGHLIGHT)
|
|
hl = 1;
|
|
mvwaddch(win, yp, xp, mr_tile(mr, hl) | attr);
|
|
}
|
|
else
|
|
mvwaddch(win, yp, xp, ' ' | attr | COLOR_PAIR(COLOR_YELLOW));
|
|
if (show) {
|
|
attr = A_BOLD;
|
|
mvwaddch(win, yp, xp - 1, '<' | attr | COLOR_PAIR(COLOR_YELLOW));
|
|
mvwaddch(win, yp, xp + 1, '>' | attr | COLOR_PAIR(COLOR_YELLOW));
|
|
}
|
|
else {
|
|
attr = A_NORMAL;
|
|
mvwaddch(win, yp, xp - 1, ' ' | attr | COLOR_PAIR(COLOR_WHITE));
|
|
mvwaddch(win, yp, xp + 1, ' ' | attr | COLOR_PAIR(COLOR_WHITE));
|
|
}
|
|
wmove(win, yp, xp);
|
|
wnoutrefresh(win);
|
|
}
|
|
|
|
static void paint_status(window * wnd, const state * st)
|
|
{
|
|
WINDOW *win = wnd->handle;
|
|
const char *name = "";
|
|
int nx, ny, uid = 0;
|
|
const char *terrain = "----";
|
|
map_region *mr = cursor_region(&st->display, &st->cursor);
|
|
if (mr && mr->r) {
|
|
uid = mr->r->uid;
|
|
if (mr->r->land) {
|
|
name = (const char *)mr->r->land->name;
|
|
}
|
|
else {
|
|
name = mr->r->terrain->_name;
|
|
}
|
|
terrain = mr->r->terrain->_name;
|
|
}
|
|
cnormalize(&st->cursor, &nx, &ny);
|
|
umvwprintw(win, 0, 0, "%4d %4d | %.4s | %.20s (%d)", nx, ny, terrain, name,
|
|
uid);
|
|
wclrtoeol(win);
|
|
}
|
|
|
|
static bool handle_info_region(window * wnd, state * st, int c)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int wxborder(WINDOW *win)
|
|
{
|
|
#ifdef __PDCURSES__
|
|
return wborder(win, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
#else
|
|
return wborder(win, '|', '|', '-', '-', '+', '+', '+', '+');
|
|
#endif
|
|
}
|
|
|
|
static void paint_info_region(window * wnd, const state * st)
|
|
{
|
|
WINDOW *win = wnd->handle;
|
|
int size = getmaxx(win) - 2;
|
|
int maxline = getmaxy(win) - 2;
|
|
map_region *mr = cursor_region(&st->display, &st->cursor);
|
|
|
|
UNUSED_ARG(st);
|
|
werase(win);
|
|
wxborder(win);
|
|
if (mr && mr->r) {
|
|
int line = 0;
|
|
const region *r = mr->r;
|
|
if (r->land) {
|
|
umvwaddnstr(win, line++, 1, (char *)r->land->name, size);
|
|
}
|
|
else {
|
|
umvwaddnstr(win, line++, 1, r->terrain->_name, size);
|
|
}
|
|
line++;
|
|
umvwprintw(win, line++, 1, "%s, age %d", r->terrain->_name, r->age);
|
|
if (r->land) {
|
|
int iron = region_getresource_level(r, get_resourcetype(R_IRON));
|
|
int stone = region_getresource_level(r, get_resourcetype(R_STONE));
|
|
mvwprintw(win, line++, 1, "$:%6d P:%5d", rmoney(r), rpeasants(r));
|
|
mvwprintw(win, line++, 1, "S:%6d I:%5d", stone, iron);
|
|
mvwprintw(win, line++, 1, "H:%6d %s:%5d", rhorses(r),
|
|
(r->flags & RF_MALLORN) ? "M" : "T",
|
|
r->land->trees[1] + r->land->trees[2]);
|
|
}
|
|
line++;
|
|
if (r->units && (st->info_flags & IFL_FACTIONS)) {
|
|
unit *u;
|
|
wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW));
|
|
mvwaddnstr(win, line++, 1, "* factions:", size - 5);
|
|
wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW));
|
|
for (u = r->units; u && line < maxline; u = u->next) {
|
|
if (!fval(u->faction, FFL_MARK)) {
|
|
mvwprintw(win, line, 1, "%.4s ", itoa36(u->faction->no));
|
|
umvwaddnstr(win, line++, 6, (char *)u->faction->name, size - 5);
|
|
fset(u->faction, FFL_MARK);
|
|
}
|
|
}
|
|
for (u = r->units; u && line < maxline; u = u->next) {
|
|
freset(u->faction, FFL_MARK);
|
|
}
|
|
}
|
|
if (r->units && (st->info_flags & IFL_UNITS)) {
|
|
unit *u;
|
|
wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW));
|
|
mvwaddnstr(win, line++, 1, "* units:", size - 5);
|
|
wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW));
|
|
for (u = r->units; u && line < maxline; u = u->next) {
|
|
mvwprintw(win, line, 1, "%.4s ", itoa36(u->no));
|
|
umvwaddnstr(win, line++, 6, unit_getname(u), size - 5);
|
|
}
|
|
}
|
|
if (r->ships && (st->info_flags & IFL_SHIPS)) {
|
|
ship *sh;
|
|
wattron(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW));
|
|
mvwaddnstr(win, line++, 1, "* ships:", size - 5);
|
|
wattroff(win, A_BOLD | COLOR_PAIR(COLOR_YELLOW));
|
|
for (sh = r->ships; sh && line < maxline; sh = sh->next) {
|
|
mvwprintw(win, line, 1, "%.4s ", itoa36(sh->no));
|
|
umvwaddnstr(win, line++, 6, (char *)sh->type->_name, size - 5);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void(*paint_info) (struct window * wnd, const struct state * st);
|
|
|
|
static void paint_info_default(window * wnd, const state * st)
|
|
{
|
|
if (paint_info)
|
|
paint_info(wnd, st);
|
|
else
|
|
paint_info_region(wnd, st);
|
|
}
|
|
|
|
void set_info_function(void(*callback) (struct window *, const struct state *))
|
|
{
|
|
paint_info = callback;
|
|
}
|
|
|
|
static char *askstring(WINDOW * win, const char *q, char *buffer, size_t size)
|
|
{
|
|
werase(win);
|
|
mvwaddstr(win, 0, 0, (char *)q);
|
|
wmove(win, 0, (int)(strlen(q) + 1));
|
|
echo();
|
|
wgetnstr(win, buffer, (int)size);
|
|
noecho();
|
|
return buffer;
|
|
}
|
|
|
|
static void statusline(WINDOW * win, const char *str)
|
|
{
|
|
mvwaddstr(win, 0, 0, (char *)str);
|
|
wclrtoeol(win);
|
|
wnoutrefresh(win);
|
|
}
|
|
|
|
static void reset_resources(region *r, const struct terrain_type *terrain)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; terrain->production[i].type; ++i) {
|
|
rawmaterial *rm;
|
|
const terrain_production *production = terrain->production + i;
|
|
const resource_type *rtype = production->type;
|
|
|
|
for (rm = r->resources; rm; rm = rm->next) {
|
|
if (rm->rtype == rtype)
|
|
break;
|
|
}
|
|
if (rm) {
|
|
struct rawmaterial_type *rmt;
|
|
set_resource(rm,
|
|
dice_rand(production->startlevel),
|
|
dice_rand(production->base),
|
|
dice_rand(production->divisor));
|
|
rmt = rmt_get(rtype);
|
|
if (rmt && rmt->terraform) {
|
|
rmt->terraform(rm, r);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void reset_region(region *r) {
|
|
unit **up = &r->units;
|
|
bool players = false;
|
|
|
|
r->flags = 0;
|
|
a_removeall(&r->attribs, NULL);
|
|
while (*up) {
|
|
unit *u = *up;
|
|
if (is_monsters(u->faction)) {
|
|
remove_unit(up, u);
|
|
}
|
|
else {
|
|
players = true;
|
|
up = &u->next;
|
|
}
|
|
}
|
|
if (!players) {
|
|
while (r->ships) {
|
|
remove_ship(&r->ships, r->ships);
|
|
}
|
|
while (r->buildings) {
|
|
remove_building(&r->buildings, r->buildings);
|
|
}
|
|
if (r->land) {
|
|
init_region(r);
|
|
reset_resources(r, r->terrain);
|
|
}
|
|
}
|
|
}
|
|
|
|
static region * state_region(state *st) {
|
|
int nx = st->cursor.x;
|
|
int ny = st->cursor.y;
|
|
pnormalize(&nx, &ny, st->cursor.pl);
|
|
return findregion(nx, ny);
|
|
}
|
|
|
|
static void reset_area_cb(void *arg) {
|
|
region *r = (region *)arg;
|
|
r->age = 0;
|
|
freset(r, RF_MARK);
|
|
}
|
|
|
|
static void reset_area(state *st) {
|
|
region * r = state_region(st);
|
|
if (r != NULL) {
|
|
selist * ql = NULL;
|
|
int qi = 0, qlen = 0;
|
|
fset(r, RF_MARK);
|
|
selist_insert(&ql, qlen++, r);
|
|
while (qi != qlen) {
|
|
int i;
|
|
region *adj[MAXDIRECTIONS];
|
|
r = selist_get(ql, qi++);
|
|
get_neighbours(r, adj);
|
|
for (i = 0; i != MAXDIRECTIONS; ++i) {
|
|
region *rn = adj[i];
|
|
if (rn && !fval(rn, RF_MARK)) {
|
|
if ((rn->terrain->flags & FORBIDDEN_REGION) == 0) {
|
|
fset(rn, RF_MARK);
|
|
selist_insert(&ql, qlen++, rn);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
selist_foreach(ql, reset_area_cb);
|
|
selist_free(ql);
|
|
}
|
|
}
|
|
|
|
static void reset_cursor(state *st) {
|
|
region * r = state_region(st);
|
|
if (r != NULL) {
|
|
reset_region(r);
|
|
}
|
|
}
|
|
|
|
static void reset_rect(state *st) {
|
|
int x, y, bs = 3;
|
|
for (x=0;x!=bs;++x) {
|
|
for (y = 0; y != bs; ++y) {
|
|
region *r;
|
|
int nx = st->cursor.x + x;
|
|
int ny = st->cursor.y + y;
|
|
pnormalize(&nx, &ny, st->cursor.pl);
|
|
if ((r = findregion(nx, ny)) != NULL) {
|
|
reset_region(r);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void terraform_at(coordinate * c, const terrain_type * terrain)
|
|
{
|
|
if (terrain != NULL) {
|
|
region *r;
|
|
int nx = c->x, ny = c->y;
|
|
pnormalize(&nx, &ny, c->pl);
|
|
r = findregion(nx, ny);
|
|
if (r == NULL) {
|
|
r = new_region(nx, ny, c->pl, 0);
|
|
}
|
|
if (!(r->units && fval(r->terrain, LAND_REGION) && !fval(terrain, LAND_REGION))) {
|
|
terraform_region(r, terrain);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void selection_walk(selection * selected, void(*callback)(region *, void *), void *udata) {
|
|
int i;
|
|
|
|
for (i = 0; i != MAXTHASH; ++i) {
|
|
tag **tp = &selected->tags[i];
|
|
while (*tp) {
|
|
region *r;
|
|
tag *t = *tp;
|
|
int nx = t->coord.x, ny = t->coord.y;
|
|
plane *pl = t->coord.pl;
|
|
|
|
pnormalize(&nx, &ny, pl);
|
|
r = findregion(nx, ny);
|
|
if (r != NULL) {
|
|
callback(r, udata);
|
|
}
|
|
tp = &t->nexthash;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void reset_levels_cb(region *r, void *udata) {
|
|
struct rawmaterial *res;
|
|
UNUSED_ARG(udata);
|
|
for (res = r->resources; res; res = res->next) {
|
|
if (res->level > 3) {
|
|
res->level = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* BUG 2506: reset drained mountains to level 1
|
|
*/
|
|
static void
|
|
fix_selection(selection * selected)
|
|
{
|
|
selection_walk(selected, reset_levels_cb, NULL);
|
|
}
|
|
|
|
static void
|
|
reset_selection(selection * selected)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i != MAXTHASH; ++i) {
|
|
tag **tp = &selected->tags[i];
|
|
while (*tp) {
|
|
region *r;
|
|
tag *t = *tp;
|
|
int nx = t->coord.x, ny = t->coord.y;
|
|
plane *pl = t->coord.pl;
|
|
|
|
pnormalize(&nx, &ny, pl);
|
|
r = findregion(nx, ny);
|
|
if (r != NULL) {
|
|
reset_region(r);
|
|
}
|
|
tp = &t->nexthash;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
terraform_selection(selection * selected, const terrain_type * terrain)
|
|
{
|
|
int i;
|
|
|
|
if (terrain == NULL)
|
|
return;
|
|
for (i = 0; i != MAXTHASH; ++i) {
|
|
tag **tp = &selected->tags[i];
|
|
while (*tp) {
|
|
region *r;
|
|
tag *t = *tp;
|
|
int nx = t->coord.x, ny = t->coord.y;
|
|
plane *pl = t->coord.pl;
|
|
|
|
pnormalize(&nx, &ny, pl);
|
|
r = findregion(nx, ny);
|
|
if (r == NULL) {
|
|
r = new_region(nx, ny, pl, 0);
|
|
}
|
|
if (!(r->units && fval(r->terrain, LAND_REGION) && !fval(terrain, LAND_REGION))) {
|
|
terraform_region(r, terrain);
|
|
}
|
|
tp = &t->nexthash;
|
|
}
|
|
}
|
|
}
|
|
|
|
static faction *select_faction(state * st)
|
|
{
|
|
list_selection *ilist = NULL, **iinsert;
|
|
list_selection *selected = NULL;
|
|
faction *f = factions;
|
|
|
|
if (!f)
|
|
return NULL;
|
|
iinsert = &ilist;
|
|
|
|
while (f) {
|
|
char buffer[32];
|
|
sprintf(buffer, "%.4s %.26s", itoa36(f->no), f->name);
|
|
insert_selection(iinsert, NULL, buffer, (void *)f);
|
|
f = f->next;
|
|
}
|
|
selected = do_selection(ilist, "Select Faction", NULL, NULL);
|
|
st->wnd_info->update |= 1;
|
|
st->wnd_map->update |= 1;
|
|
st->wnd_status->update |= 1;
|
|
|
|
if (selected == NULL)
|
|
return NULL;
|
|
return (faction *)selected->data;
|
|
}
|
|
|
|
static const terrain_type *select_terrain(state * st,
|
|
const terrain_type * default_terrain)
|
|
{
|
|
list_selection *ilist = NULL, **iinsert;
|
|
list_selection *selected = NULL;
|
|
const terrain_type *terrain = terrains();
|
|
|
|
if (!terrain)
|
|
return NULL;
|
|
iinsert = &ilist;
|
|
|
|
while (terrain) {
|
|
insert_selection(iinsert, NULL, terrain->_name, (void *)terrain);
|
|
terrain = terrain->next;
|
|
}
|
|
selected = do_selection(ilist, "Terrain", NULL, NULL);
|
|
st->wnd_info->update |= 1;
|
|
st->wnd_map->update |= 1;
|
|
st->wnd_status->update |= 1;
|
|
|
|
if (selected == NULL)
|
|
return NULL;
|
|
return (const terrain_type *)selected->data;
|
|
}
|
|
|
|
static coordinate *region2coord(const region * r, coordinate * c)
|
|
{
|
|
c->x = r->x;
|
|
c->y = r->y;
|
|
c->pl = rplane(r);
|
|
return c;
|
|
}
|
|
|
|
#ifdef __PDCURSES__
|
|
#define FAST_UP CTL_UP
|
|
#define FAST_DOWN CTL_DOWN
|
|
#define FAST_LEFT CTL_LEFT
|
|
#define FAST_RIGHT CTL_RIGHT
|
|
#else
|
|
#define FAST_UP KEY_PPAGE
|
|
#define FAST_DOWN KEY_NPAGE
|
|
#define FAST_LEFT KEY_SLEFT
|
|
#define FAST_RIGHT KEY_SRIGHT
|
|
#endif
|
|
|
|
void highlight_region(region * r, int toggle)
|
|
{
|
|
if (r != NULL) {
|
|
if (toggle)
|
|
r->flags |= RF_MAPPER_HIGHLIGHT;
|
|
else
|
|
r->flags &= ~RF_MAPPER_HIGHLIGHT;
|
|
}
|
|
}
|
|
|
|
void select_coordinate(struct selection *selected, int nx, int ny, bool toggle)
|
|
{
|
|
if (toggle)
|
|
tag_region(selected, nx, ny);
|
|
else
|
|
untag_region(selected, nx, ny);
|
|
}
|
|
|
|
enum select_t { MODE_MARK, MODE_SELECT, MODE_UNMARK, MODE_UNSELECT };
|
|
|
|
static void select_island(state *st, int selectmode)
|
|
{
|
|
region *r;
|
|
int nx = st->cursor.x;
|
|
int ny = st->cursor.y;
|
|
|
|
pnormalize(&nx, &ny, st->cursor.pl);
|
|
r = findregion(nx, ny);
|
|
if (r && r->land) {
|
|
selist *ql, *stack = NULL;
|
|
int qi = 0;
|
|
|
|
selist_push(&stack, r);
|
|
for (ql = stack, qi = 0; ql; selist_advance(&ql, &qi, 1)) {
|
|
region *r = (region *)selist_get(ql, qi);
|
|
region *rnext[MAXDIRECTIONS];
|
|
int i;
|
|
|
|
fset(r, RF_MARK);
|
|
if (selectmode & MODE_SELECT) {
|
|
select_coordinate(st->selected, r->x, r->y,
|
|
selectmode == MODE_SELECT);
|
|
}
|
|
else {
|
|
highlight_region(r, selectmode == MODE_MARK);
|
|
}
|
|
get_neighbours(r, rnext);
|
|
for (i = 0; i != MAXDIRECTIONS; ++i) {
|
|
region *rn = rnext[i];
|
|
if (rn && rn->land && !fval(rn, RF_MARK)) {
|
|
selist_push(&stack, rn);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (ql = stack, qi = 0; ql; selist_advance(&ql, &qi, 1)) {
|
|
region *r = (region *)selist_get(ql, qi);
|
|
freset(r, RF_MARK);
|
|
}
|
|
selist_free(stack);
|
|
}
|
|
}
|
|
|
|
static void select_regions(state * st, int selectmode)
|
|
{
|
|
char sbuffer[80];
|
|
int findmode;
|
|
const char *statustext[] = {
|
|
"mark-", "select-", "unmark-", "deselect-"
|
|
};
|
|
const char *status = statustext[selectmode];
|
|
statusline(st->wnd_status->handle, status);
|
|
doupdate();
|
|
findmode = getch();
|
|
if (findmode == 'n') { /* none */
|
|
sprintf(sbuffer, "%snone", status);
|
|
statusline(st->wnd_status->handle, sbuffer);
|
|
if (selectmode & MODE_SELECT) {
|
|
int i;
|
|
for (i = 0; i != MAXTHASH; ++i) {
|
|
tag **tp = &st->selected->tags[i];
|
|
while (*tp) {
|
|
tag *t = *tp;
|
|
*tp = t->nexthash;
|
|
free(t);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
region *r;
|
|
for (r = regions; r; r = r->next) {
|
|
r->flags &= ~RF_MAPPER_HIGHLIGHT;
|
|
}
|
|
}
|
|
}
|
|
else if (findmode == 'c') {
|
|
region *r;
|
|
sprintf(sbuffer, "%schaos", status);
|
|
statusline(st->wnd_status->handle, sbuffer);
|
|
for (r = regions; r; r = r->next) {
|
|
if (fval(r, RF_CHAOTIC)) {
|
|
if (selectmode & MODE_SELECT) {
|
|
select_coordinate(st->selected, r->x, r->y,
|
|
selectmode == MODE_SELECT);
|
|
}
|
|
else {
|
|
highlight_region(r, selectmode == MODE_MARK);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (findmode == 'm') {
|
|
region *r;
|
|
sprintf(sbuffer, "%smonsters", status);
|
|
statusline(st->wnd_status->handle, sbuffer);
|
|
for (r = regions; r; r = r->next) {
|
|
unit *u = r->units;
|
|
for (; u; u = u->next) {
|
|
if (fval(u->faction, FFL_NPC) != 0)
|
|
break;
|
|
}
|
|
if (u) {
|
|
if (selectmode & MODE_SELECT) {
|
|
select_coordinate(st->selected, r->x, r->y,
|
|
selectmode == MODE_SELECT);
|
|
}
|
|
else {
|
|
highlight_region(r, selectmode == MODE_MARK);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (findmode == 'p') {
|
|
region *r;
|
|
sprintf(sbuffer, "%splayers", status);
|
|
statusline(st->wnd_status->handle, sbuffer);
|
|
for (r = regions; r; r = r->next) {
|
|
unit *u = r->units;
|
|
for (; u; u = u->next) {
|
|
if (fval(u->faction, FFL_NPC) == 0)
|
|
break;
|
|
}
|
|
if (u) {
|
|
if (selectmode & MODE_SELECT) {
|
|
select_coordinate(st->selected, r->x, r->y,
|
|
selectmode == MODE_SELECT);
|
|
}
|
|
else {
|
|
highlight_region(r, selectmode == MODE_MARK);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (findmode == 'u') {
|
|
region *r;
|
|
sprintf(sbuffer, "%sunits", status);
|
|
statusline(st->wnd_status->handle, sbuffer);
|
|
for (r = regions; r; r = r->next) {
|
|
if (r->units) {
|
|
if (selectmode & MODE_SELECT) {
|
|
select_coordinate(st->selected, r->x, r->y,
|
|
selectmode == MODE_SELECT);
|
|
}
|
|
else {
|
|
highlight_region(r, selectmode == MODE_MARK);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (findmode == 's') {
|
|
region *r;
|
|
sprintf(sbuffer, "%sships", status);
|
|
statusline(st->wnd_status->handle, sbuffer);
|
|
for (r = regions; r; r = r->next) {
|
|
if (r->ships) {
|
|
if (selectmode & MODE_SELECT) {
|
|
select_coordinate(st->selected, r->x, r->y,
|
|
selectmode == MODE_SELECT);
|
|
}
|
|
else {
|
|
highlight_region(r, selectmode == MODE_MARK);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (findmode == 'f') {
|
|
char fbuffer[12];
|
|
sprintf(sbuffer, "%sfaction:", status);
|
|
askstring(st->wnd_status->handle, sbuffer, fbuffer, 12);
|
|
if (fbuffer[0]) {
|
|
faction *f = findfaction(atoi36(fbuffer));
|
|
|
|
if (f != NULL) {
|
|
unit *u;
|
|
|
|
sprintf(sbuffer, "%sfaction: %s", status, itoa36(f->no));
|
|
statusline(st->wnd_status->handle, sbuffer);
|
|
for (u = f->units; u; u = u->nextF) {
|
|
region *r = u->region;
|
|
if (selectmode & MODE_SELECT) {
|
|
select_coordinate(st->selected, r->x, r->y,
|
|
selectmode == MODE_SELECT);
|
|
}
|
|
else {
|
|
highlight_region(r, selectmode == MODE_MARK);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
statusline(st->wnd_status->handle, "faction not found.");
|
|
beep();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else if (findmode == 'i') {
|
|
sprintf(sbuffer, "%swand: ", status);
|
|
statusline(st->wnd_status->handle, sbuffer);
|
|
select_island(st, selectmode);
|
|
}
|
|
else if (findmode == 't') {
|
|
const struct terrain_type *terrain;
|
|
sprintf(sbuffer, "%sterrain: ", status);
|
|
statusline(st->wnd_status->handle, sbuffer);
|
|
terrain = select_terrain(st, NULL);
|
|
if (terrain != NULL) {
|
|
region *r;
|
|
sprintf(sbuffer, "%sterrain: %s", status, terrain->_name);
|
|
statusline(st->wnd_status->handle, sbuffer);
|
|
for (r = regions; r; r = r->next) {
|
|
if (r->terrain == terrain) {
|
|
if (selectmode & MODE_SELECT) {
|
|
select_coordinate(st->selected, r->x, r->y,
|
|
selectmode == MODE_SELECT);
|
|
}
|
|
else {
|
|
highlight_region(r, selectmode == MODE_MARK);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
statusline(st->wnd_status->handle, "unknown command.");
|
|
beep();
|
|
return;
|
|
}
|
|
st->wnd_info->update |= 3;
|
|
st->wnd_status->update |= 3;
|
|
st->wnd_map->update |= 3;
|
|
}
|
|
|
|
static void loaddata(state *st) {
|
|
char datafile[PATH_MAX];
|
|
|
|
askstring(st->wnd_status->handle, "load from:", datafile, sizeof(datafile));
|
|
if (strlen(datafile) > 0) {
|
|
readgame(datafile);
|
|
st->modified = 0;
|
|
}
|
|
}
|
|
|
|
static void savedata(state *st) {
|
|
char datafile[PATH_MAX];
|
|
|
|
askstring(st->wnd_status->handle, "save as:", datafile, sizeof(datafile));
|
|
if (strlen(datafile) > 0) {
|
|
remove_empty_units();
|
|
writegame(datafile);
|
|
st->modified = 0;
|
|
}
|
|
}
|
|
|
|
static void seed_player(state *st, const newfaction *player) {
|
|
if (player) {
|
|
region *r;
|
|
int nx = st->cursor.x;
|
|
int ny = st->cursor.y;
|
|
|
|
pnormalize(&nx, &ny, st->cursor.pl);
|
|
r = findregion(nx, ny);
|
|
if (r) {
|
|
faction *f = addfaction(player->email, player->password,
|
|
player->race, player->lang);
|
|
addplayer(r, f);
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool confirm(WINDOW * win, const char *q) {
|
|
int ch;
|
|
werase(win);
|
|
mvwaddstr(win, 0, 0, (char *)q);
|
|
wmove(win, 0, (int)(strlen(q) + 1));
|
|
ch = wgetch(win);
|
|
return (ch == 'y') || (ch == 'Y');
|
|
}
|
|
|
|
|
|
static void handlekey(state * st, int c)
|
|
{
|
|
window *wnd;
|
|
coordinate *cursor = &st->cursor;
|
|
static char locate[80];
|
|
static int findmode = 0;
|
|
region *r;
|
|
char sbuffer[80];
|
|
const char *loc = locate;
|
|
int n, nx, ny, minpop, maxpop;
|
|
|
|
switch (c) {
|
|
case FAST_RIGHT:
|
|
cursor->x += 10;
|
|
st->wnd_info->update |= 1;
|
|
st->wnd_status->update |= 1;
|
|
break;
|
|
case FAST_LEFT:
|
|
cursor->x -= 10;
|
|
st->wnd_info->update |= 1;
|
|
st->wnd_status->update |= 1;
|
|
break;
|
|
case FAST_UP:
|
|
cursor->y += 10;
|
|
st->wnd_info->update |= 1;
|
|
st->wnd_status->update |= 1;
|
|
break;
|
|
case FAST_DOWN:
|
|
cursor->y -= 10;
|
|
st->wnd_info->update |= 1;
|
|
st->wnd_status->update |= 1;
|
|
break;
|
|
case KEY_UP:
|
|
cursor->y++;
|
|
st->wnd_info->update |= 1;
|
|
st->wnd_status->update |= 1;
|
|
break;
|
|
case KEY_DOWN:
|
|
cursor->y--;
|
|
st->wnd_info->update |= 1;
|
|
st->wnd_status->update |= 1;
|
|
break;
|
|
case KEY_RIGHT:
|
|
cursor->x++;
|
|
st->wnd_info->update |= 1;
|
|
st->wnd_status->update |= 1;
|
|
break;
|
|
case KEY_LEFT:
|
|
cursor->x--;
|
|
st->wnd_info->update |= 1;
|
|
st->wnd_status->update |= 1;
|
|
break;
|
|
case 'S':
|
|
case KEY_SAVE:
|
|
case KEY_F(2):
|
|
savedata(st);
|
|
break;
|
|
case KEY_F(3):
|
|
case KEY_OPEN:
|
|
loaddata(st);
|
|
break;
|
|
case 'B':
|
|
cnormalize(&st->cursor, &nx, &ny);
|
|
minpop = config_get_int("editor.island.min", 8);
|
|
maxpop = config_get_int("editor.island.max", minpop);
|
|
if (maxpop > minpop) {
|
|
n = rng_int() % (maxpop - minpop) + minpop;
|
|
}
|
|
else {
|
|
n = minpop;
|
|
}
|
|
build_island(nx, ny, n, NULL, 0);
|
|
st->modified = 1;
|
|
st->wnd_info->update |= 1;
|
|
st->wnd_status->update |= 1;
|
|
st->wnd_map->update |= 1;
|
|
break;
|
|
case 0x02: /* CTRL+b */
|
|
cnormalize(&st->cursor, &nx, &ny);
|
|
make_block(nx, ny, 6, newterrain(T_OCEAN));
|
|
st->modified = 1;
|
|
st->wnd_info->update |= 1;
|
|
st->wnd_status->update |= 1;
|
|
st->wnd_map->update |= 1;
|
|
break;
|
|
case 'A': /* clear/reset area */
|
|
if (confirm(st->wnd_status->handle, "Are you sure you want to reset this entire area?")) {
|
|
reset_area(st);
|
|
st->modified = 1;
|
|
st->wnd_map->update |= 1;
|
|
}
|
|
break;
|
|
case 'c': /* clear/reset */
|
|
reset_cursor(st);
|
|
st->modified = 1;
|
|
st->wnd_map->update |= 1;
|
|
break;
|
|
case 'C': /* clear/reset */
|
|
reset_rect(st);
|
|
st->modified = 1;
|
|
st->wnd_map->update |= 1;
|
|
break;
|
|
case 0x09: /* tab = next selected */
|
|
if (regions != NULL) {
|
|
map_region *mr = cursor_region(&st->display, cursor);
|
|
if (mr) {
|
|
region *first = mr->r;
|
|
region *cur = (first && first->next) ? first->next : regions;
|
|
|
|
while (cur != first) {
|
|
coordinate coord;
|
|
region2coord(cur, &coord);
|
|
cnormalize(&coord, &nx, &ny);
|
|
if (tagged_region(st->selected, nx, ny)) {
|
|
st->cursor = coord;
|
|
st->wnd_info->update |= 1;
|
|
st->wnd_status->update |= 1;
|
|
break;
|
|
}
|
|
cur = cur->next;
|
|
if (!cur && first)
|
|
cur = regions;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'p':
|
|
if (planes) {
|
|
plane *pl = planes;
|
|
if (cursor->pl) {
|
|
while (pl && pl != cursor->pl) {
|
|
pl = pl->next;
|
|
}
|
|
if (pl && pl->next) {
|
|
cursor->pl = pl->next;
|
|
}
|
|
else {
|
|
cursor->pl = get_homeplane();
|
|
}
|
|
}
|
|
else {
|
|
cursor->pl = planes;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 'a':
|
|
if (regions != NULL) {
|
|
map_region *mr = cursor_region(&st->display, cursor);
|
|
if (mr && mr->r) {
|
|
region *cur = mr->r;
|
|
plane *pl = rplane(cur);
|
|
if (pl == NULL) {
|
|
cur = r_standard_to_astral(cur);
|
|
}
|
|
else if (is_astral(cur)) {
|
|
cur = r_astral_to_standard(cur);
|
|
}
|
|
else {
|
|
cur = NULL;
|
|
}
|
|
if (cur != NULL) {
|
|
region2coord(cur, &st->cursor);
|
|
}
|
|
else {
|
|
beep();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 'g':
|
|
askstring(st->wnd_status->handle, "goto-x:", sbuffer, 12);
|
|
if (sbuffer[0]) {
|
|
askstring(st->wnd_status->handle, "goto-y:", sbuffer + 16, 12);
|
|
if (sbuffer[16]) {
|
|
st->cursor.x = atoi(sbuffer);
|
|
st->cursor.y = atoi(sbuffer + 16);
|
|
st->wnd_info->update |= 1;
|
|
st->wnd_status->update |= 1;
|
|
}
|
|
}
|
|
break;
|
|
case 'f':
|
|
case 0x14: /* C-t */
|
|
terraform_at(&st->cursor, select_terrain(st, NULL));
|
|
st->modified = 1;
|
|
st->wnd_info->update |= 1;
|
|
st->wnd_status->update |= 1;
|
|
st->wnd_map->update |= 1;
|
|
break;
|
|
case 'I':
|
|
statusline(st->wnd_status->handle, "info-");
|
|
doupdate();
|
|
do {
|
|
c = getch();
|
|
switch (c) {
|
|
case 's':
|
|
st->info_flags ^= IFL_SHIPS;
|
|
if (st->info_flags & IFL_SHIPS)
|
|
statusline(st->wnd_status->handle, "info-ships true");
|
|
else
|
|
statusline(st->wnd_status->handle, "info-ships false");
|
|
break;
|
|
case 'b':
|
|
st->info_flags ^= IFL_BUILDINGS;
|
|
if (st->info_flags & IFL_BUILDINGS)
|
|
statusline(st->wnd_status->handle, "info-buildings true");
|
|
else
|
|
statusline(st->wnd_status->handle, "info-buildings false");
|
|
break;
|
|
case 'f':
|
|
st->info_flags ^= IFL_FACTIONS;
|
|
if (st->info_flags & IFL_FACTIONS)
|
|
statusline(st->wnd_status->handle, "info-factions true");
|
|
else
|
|
statusline(st->wnd_status->handle, "info-factions false");
|
|
break;
|
|
case 'u':
|
|
st->info_flags ^= IFL_UNITS;
|
|
if (st->info_flags & IFL_UNITS)
|
|
statusline(st->wnd_status->handle, "info-units true");
|
|
else
|
|
statusline(st->wnd_status->handle, "info-units false");
|
|
break;
|
|
case 27: /* esc */
|
|
break;
|
|
default:
|
|
beep();
|
|
c = 0;
|
|
}
|
|
} while (c == 0);
|
|
break;
|
|
case 'L':
|
|
if (global.vm_state) {
|
|
move(0, 0);
|
|
refresh();
|
|
lua_do((struct lua_State *)global.vm_state);
|
|
/* todo: do this from inside the script */
|
|
clear();
|
|
st->wnd_info->update |= 1;
|
|
st->wnd_status->update |= 1;
|
|
st->wnd_map->update |= 1;
|
|
}
|
|
break;
|
|
case 12: /* Ctrl-L */
|
|
clear();
|
|
st->wnd_info->update |= 1;
|
|
st->wnd_status->update |= 1;
|
|
st->wnd_map->update |= 1;
|
|
break;
|
|
case 'h':
|
|
select_regions(st, MODE_MARK);
|
|
break;
|
|
case 'H':
|
|
select_regions(st, MODE_UNMARK);
|
|
break;
|
|
case 't':
|
|
select_regions(st, MODE_SELECT);
|
|
break;
|
|
case 'T':
|
|
select_regions(st, MODE_UNSELECT);
|
|
break;
|
|
case ';':
|
|
statusline(st->wnd_status->handle, "tag-");
|
|
doupdate();
|
|
switch (getch()) {
|
|
case 'r':
|
|
reset_selection(st->selected);
|
|
break;
|
|
case 'f':
|
|
fix_selection(st->selected);
|
|
break;
|
|
case 't':
|
|
terraform_selection(st->selected, select_terrain(st, NULL));
|
|
st->modified = 1;
|
|
st->wnd_info->update |= 1;
|
|
st->wnd_status->update |= 1;
|
|
st->wnd_map->update |= 1;
|
|
break;
|
|
case 'm':
|
|
break;
|
|
default:
|
|
statusline(st->wnd_status->handle, "unknown command.");
|
|
beep();
|
|
}
|
|
break;
|
|
case ' ':
|
|
cnormalize(cursor, &nx, &ny);
|
|
if (tagged_region(st->selected, nx, ny))
|
|
untag_region(st->selected, nx, ny);
|
|
else
|
|
tag_region(st->selected, nx, ny);
|
|
break;
|
|
case 's': /* seed */
|
|
if (new_players) {
|
|
newfaction * next = new_players->next;
|
|
seed_player(st, new_players);
|
|
free(new_players->email);
|
|
free(new_players->password);
|
|
free(new_players);
|
|
new_players = next;
|
|
}
|
|
break;
|
|
case '/':
|
|
statusline(st->wnd_status->handle, "find-");
|
|
doupdate();
|
|
findmode = getch();
|
|
if (findmode == 'r') {
|
|
askstring(st->wnd_status->handle, "find-region:", locate,
|
|
sizeof(locate));
|
|
}
|
|
else if (findmode == 'u') {
|
|
askstring(st->wnd_status->handle, "find-unit:", locate, sizeof(locate));
|
|
}
|
|
else if (findmode == 'f') {
|
|
askstring(st->wnd_status->handle, "find-faction:", locate,
|
|
sizeof(locate));
|
|
}
|
|
else if (findmode == 'F') {
|
|
faction *f = select_faction(st);
|
|
if (f != NULL) {
|
|
loc = itoa36_r(f->no, locate, sizeof(locate));
|
|
findmode = 'f';
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
statusline(st->wnd_status->handle, "unknown command.");
|
|
beep();
|
|
break;
|
|
}
|
|
/* achtung: fall-through ist absicht: */
|
|
if (!strlen(loc)) {
|
|
break;
|
|
}
|
|
case 'n':
|
|
if (findmode == 'u') {
|
|
unit *u = findunit(atoi36(locate));
|
|
r = u ? u->region : NULL;
|
|
}
|
|
else if (findmode && regions != NULL) {
|
|
struct faction *f = NULL;
|
|
map_region *mr = cursor_region(&st->display, cursor);
|
|
region *first = (mr && mr->r && mr->r->next) ? mr->r->next : regions;
|
|
|
|
if (findmode == 'f') {
|
|
snprintf(sbuffer, sizeof(sbuffer), "find-faction: %s", loc);
|
|
statusline(st->wnd_status->handle, sbuffer);
|
|
f = findfaction(atoi36(loc));
|
|
if (f == NULL) {
|
|
statusline(st->wnd_status->handle, "faction not found.");
|
|
beep();
|
|
break;
|
|
}
|
|
}
|
|
for (r = first;;) {
|
|
if (findmode == 'r' && r->land && r->land->name
|
|
&& strstr((const char *)r->land->name, locate)) {
|
|
break;
|
|
}
|
|
else if (findmode == 'f') {
|
|
unit *u;
|
|
for (u = r->units; u; u = u->next) {
|
|
if (u->faction == f) {
|
|
break;
|
|
}
|
|
}
|
|
if (u)
|
|
break;
|
|
}
|
|
r = r->next;
|
|
if (r == NULL)
|
|
r = regions;
|
|
if (r == first) {
|
|
r = NULL;
|
|
statusline(st->wnd_status->handle, "not found.");
|
|
beep();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
r = NULL;
|
|
}
|
|
if (r != NULL) {
|
|
region2coord(r, &st->cursor);
|
|
st->wnd_info->update |= 1;
|
|
st->wnd_status->update |= 1;
|
|
}
|
|
break;
|
|
case 'Q':
|
|
g_quit = 1;
|
|
break;
|
|
default:
|
|
for (wnd = wnd_first; wnd != NULL; wnd = wnd->next) {
|
|
if (wnd->handlekey) {
|
|
if (wnd->handlekey(wnd, st, c))
|
|
break;
|
|
}
|
|
}
|
|
if (wnd == NULL) {
|
|
static char kbuffer[80];
|
|
if (kbuffer[0] == 0) {
|
|
strcpy(kbuffer, "getch:");
|
|
}
|
|
sprintf(sbuffer, " 0x%x", c);
|
|
strncat(kbuffer, sbuffer, sizeof(kbuffer) - 1);
|
|
statusline(st->wnd_status->handle, kbuffer);
|
|
if (strlen(kbuffer) > 70)
|
|
kbuffer[0] = 0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void init_view(view * display, WINDOW * win)
|
|
{
|
|
display->topleft.x = 1;
|
|
display->topleft.y = 1;
|
|
display->topleft.pl = get_homeplane();
|
|
display->pl = get_homeplane();
|
|
display->size.width = getmaxx(win) / TWIDTH;
|
|
display->size.height = getmaxy(win) / THEIGHT;
|
|
display->regions =
|
|
calloc(display->size.height * display->size.width, sizeof(map_region));
|
|
}
|
|
|
|
static void update_view(view * vi)
|
|
{
|
|
int i, j;
|
|
for (i = 0; i != vi->size.width; ++i) {
|
|
for (j = 0; j != vi->size.height; ++j) {
|
|
map_region *mr = mr_get(vi, i, j);
|
|
mr->coord.x = vi->topleft.x + i - j / 2;
|
|
mr->coord.y = vi->topleft.y + j;
|
|
mr->coord.pl = vi->pl;
|
|
pnormalize(&mr->coord.x, &mr->coord.y, mr->coord.pl);
|
|
mr->r = findregion(mr->coord.x, mr->coord.y);
|
|
}
|
|
}
|
|
}
|
|
|
|
state *state_open(void)
|
|
{
|
|
state *st = (state *)calloc(1, sizeof(state));
|
|
st->display.pl = get_homeplane();
|
|
st->cursor.pl = get_homeplane();
|
|
st->cursor.x = 0;
|
|
st->cursor.y = 0;
|
|
st->selected = calloc(1, sizeof(struct selection));
|
|
st->modified = 0;
|
|
st->info_flags = 0xFFFFFFFF;
|
|
st->prev = current_state;
|
|
current_state = st;
|
|
return st;
|
|
}
|
|
|
|
void state_close(state * st)
|
|
{
|
|
assert(st == current_state);
|
|
current_state = st->prev;
|
|
free(st);
|
|
}
|
|
|
|
void run_mapper(void)
|
|
{
|
|
WINDOW *hwinstatus;
|
|
WINDOW *hwininfo;
|
|
WINDOW *hwinmap;
|
|
int width, height, x, y;
|
|
int split = 20;
|
|
state *st;
|
|
point tl;
|
|
|
|
if (!new_players) {
|
|
char sbuffer[512];
|
|
path_join(basepath(), "newfactions", sbuffer, sizeof(sbuffer));
|
|
new_players = read_newfactions(sbuffer);
|
|
}
|
|
|
|
init_curses();
|
|
curs_set(1);
|
|
set_readline(curses_readline);
|
|
assert(stdscr);
|
|
getbegyx(stdscr, x, y);
|
|
width = getmaxx(stdscr);
|
|
height = getmaxy(stdscr);
|
|
|
|
hwinmap = subwin(stdscr, getmaxy(stdscr) - 1, getmaxx(stdscr) - split, y, x);
|
|
hwininfo =
|
|
subwin(stdscr, getmaxy(stdscr) - 1, split, y, x + getmaxx(stdscr) - split);
|
|
hwinstatus = subwin(stdscr, 1, width, height - 1, x);
|
|
|
|
st = state_open();
|
|
st->wnd_map = win_create(hwinmap);
|
|
st->wnd_map->paint = &paint_map;
|
|
st->wnd_map->update = 1;
|
|
st->wnd_info = win_create(hwininfo);
|
|
st->wnd_info->paint = &paint_info_default;
|
|
st->wnd_info->handlekey = &handle_info_region;
|
|
st->wnd_info->update = 1;
|
|
st->wnd_status = win_create(hwinstatus);
|
|
st->wnd_status->paint = &paint_status;
|
|
st->wnd_status->update = 1;
|
|
|
|
init_view(&st->display, hwinmap);
|
|
coor2point(&st->display.topleft, &tl);
|
|
|
|
hstatus = st->wnd_status->handle; /* the lua console needs this */
|
|
|
|
while (!g_quit) {
|
|
int c;
|
|
point p;
|
|
window *wnd;
|
|
view *vi = &st->display;
|
|
|
|
getbegyx(hwinmap, x, y);
|
|
coor2point(&st->cursor, &p);
|
|
|
|
if (st->cursor.pl != vi->pl) {
|
|
vi->pl = st->cursor.pl;
|
|
st->wnd_map->update |= 1;
|
|
}
|
|
if (p.y < tl.y) {
|
|
vi->topleft.y = st->cursor.y - vi->size.height / 2;
|
|
st->wnd_map->update |= 1;
|
|
}
|
|
else if (p.y >= tl.y + vi->size.height * THEIGHT) {
|
|
vi->topleft.y = st->cursor.y - vi->size.height / 2;
|
|
st->wnd_map->update |= 1;
|
|
}
|
|
if (p.x <= tl.x) {
|
|
vi->topleft.x =
|
|
st->cursor.x + (st->cursor.y - vi->topleft.y) / 2 - vi->size.width / 2;
|
|
st->wnd_map->update |= 1;
|
|
}
|
|
else if (p.x >= tl.x + vi->size.width * TWIDTH - 1) {
|
|
vi->topleft.x =
|
|
st->cursor.x + (st->cursor.y - vi->topleft.y) / 2 - vi->size.width / 2;
|
|
st->wnd_map->update |= 1;
|
|
}
|
|
|
|
if (st->wnd_map->update) {
|
|
update_view(vi);
|
|
coor2point(&vi->topleft, &tl);
|
|
}
|
|
for (wnd = wnd_last; wnd != NULL; wnd = wnd->prev) {
|
|
if (wnd->update && wnd->paint) {
|
|
if (wnd->update & 1) {
|
|
wnd->paint(wnd, st);
|
|
wnoutrefresh(wnd->handle);
|
|
}
|
|
if (wnd->update & 2) {
|
|
touchwin(wnd->handle);
|
|
}
|
|
wnd->update = 0;
|
|
}
|
|
}
|
|
draw_cursor(st->wnd_map->handle, st->selected, vi, &st->cursor, 1);
|
|
doupdate();
|
|
c = getch();
|
|
draw_cursor(st->wnd_map->handle, st->selected, vi, &st->cursor, 0);
|
|
handlekey(st, c);
|
|
}
|
|
g_quit = 0;
|
|
set_readline(NULL);
|
|
curs_set(1);
|
|
endwin();
|
|
/* FIXME: reset logging
|
|
log_flags = old_flags;
|
|
*/
|
|
state_close(st);
|
|
}
|
|
|
|
int
|
|
curses_readline(struct lua_State *L, char *buffer, size_t size,
|
|
const char *prompt)
|
|
{
|
|
UNUSED_ARG(L);
|
|
askstring(hstatus, prompt, buffer, size);
|
|
return buffer[0] != 0;
|
|
}
|
|
|
|
void seed_players(newfaction **players, bool new_island)
|
|
{
|
|
if (players) {
|
|
while (*players) {
|
|
int n = listlen(*players);
|
|
int k = (n + ISLANDSIZE - 1) / ISLANDSIZE;
|
|
k = n / k;
|
|
n = autoseed(players, k, new_island ? 0 : TURNS_PER_ISLAND);
|
|
if (n == 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void make_block(int x, int y, int radius, const struct terrain_type *terrain)
|
|
{
|
|
int cx, cy;
|
|
region *r;
|
|
plane *pl = findplane(x, y);
|
|
|
|
if (terrain == NULL)
|
|
return;
|
|
|
|
for (cx = x - radius; cx != x + radius; ++cx) {
|
|
for (cy = y - radius; cy != y + radius; ++cy) {
|
|
int nx = cx, ny = cy;
|
|
pnormalize(&nx, &ny, pl);
|
|
if (koor_distance(nx, ny, x, y) < radius) {
|
|
if (!findregion(nx, ny)) {
|
|
r = new_region(nx, ny, pl, 0);
|
|
terraform_region(r, terrain);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|