/* This file was generated by scramble.py. */
#line 1 "src/dungeon.py"
#include "dungeon.h"
#line 74
    /* x=   0 1 2 3 4
     * y=   _   _   _
     * 0 /a\_/a\_/a\
     * \_/a\_/a\_/
     * 1 / \_/ \_/ \
     * \_/.\_/ \_/
     * 2 / \_/.\_/ \
     * \_/ \_/ \_/
     * 3 / \_/ \_/ \
     * \_/ \_/.\_/
     * 4 / \_/ \_/.\
     * \_/ \_/ \_/
     * \_/ \_/
     * 0
     * ____
     * 1 /\  /\ 5
     * /__\/__\
     * \  /\  /
     * 2 \/__\/ 4
     * 3
     */
#line 98
static int hdx [6] = {0, - 1, - 1, 0, 1, 1};
#line 100
static int hdy [2] [6] = {{- 1, - 1, 0, 1, 0, - 1}, {- 1, 0, 1, 1, 1, 0}};
static bool _cb_ctype(Creature * c, int ctype);
static bool _cb_injured(Creature * c, int ctype);
static void _hit(Creature * self, int hitmin, int hitmax);
static bool _attack(Creature * self);
static bool _heal(Creature * self);
static void _creature_clone_from_to(Creature * self, Creature * copy);
static int _cmp_cb(void * data1, void * data2);
#line 102
Dungeon* dungeon_new(void) {
    Dungeon * self;
#line 103
    land_alloc(self);
    self->creatures = land_array_new();
    land_array_add(self->creatures, NULL) /* reserve spot 0 */;
    return self;
}
void dungeon_destroy(Dungeon * self) {
    land_array_destroy_with_free(self->creatures);
    land_free(self);
}
void dungeon_move(int * xp, int * yp, int d) {
    * yp += hdy [(* xp) & 1] [d];
    * xp += hdx [d];
}
int dungeon_distance(int x1, int y1, int x2, int y2) {
    /* /a\_/c\_/e\
     * \_/b\_/d\_/
     * /f\_/h\_/j\
     * \_/g\_/i\_/
     * /k\_/m\_/o\
     * \_/l\_/n\_/
     * \_/ \_/
     * a  0/0 -> 0/0
     * b  1/0 -> 1/0
     * c  2/0 -> 1/-1
     * d  3/0 -> 2/-1
     * e  4/0 -> 2/-2
     * f  0/1 -> 1/1
     * g  1/1 -> 2/1
     * h  2/1 -> 2/0
     * i  3/1 -> 3/0
     * j  4/1 -> 3/-1
     * k  0/2 -> 2/2
     * l  1/2 -> 3/2
     * m  2/2 -> 3/1
     * n  3/2 -> 4/1
     * o  4/2 -> 4/0
     */
    // first step: convert to diamond coordinates
#line 145
    int ax = y1 + ((x1 + 1) >> 1);
    int ay = y1 - (x1 >> 1);
    int bx = y2 + ((x2 + 1) >> 1);
    int by = y2 - (x2 >> 1);
    // second step: hex distance
#line 151
    int dx = bx - ax;
    int dy = by - ay;
    if (dx >= 0) {
        if (dy >= 0) {
            if (dx > dy) {
#line 155
                return dx;
            }
#line 156
            return dy;
        }
#line 157
        return dx - dy;
    }
#line 158
    if (dy <= 0) {
        if (- dx > - dy) {
#line 159
            return - dx;
        }
#line 160
        return - dy;
    }
#line 161
    return - dx + dy;
}
int dungeon_dir(int x1, int y1, int x2, int y2) {
    int dy = y2 - y1;
    int dx = x2 - x1;
    if (dx == 0) {
        if (dy < 0) {
            return 0;
        }
#line 168
        else {
#line 170
            return 3;
        }
    }
#line 171
    else if (dx > 0) {
        if (dy == 0) {
            return x1 & 1 ? 5 : 4;
        }
#line 174
        else if (dy > 0) {
            return 4;
        }
#line 175
        else {
#line 177
            return 5;
        }
    }
#line 177
    else {
#line 179
        if (dy == 0) {
            return x1 & 1 ? 1 : 2;
        }
#line 181
        else if (dy > 0) {
            return 2;
        }
#line 182
        else {
#line 184
            return 1;
        }
    }
}
#line 186
Tile* dungeon_tile(Dungeon * self, int x, int y) {
    return & self->board [y * board_w + x];
}
Tile* dungeon_tile_dir(Dungeon * self, int x, int y, int d) {
    dungeon_move(& x, & y, d);
    return & self->board [y * board_w + x];
}
Creature* dungeon_creature(Dungeon * self, int cid) {
    return land_array_get(self->creatures, cid);
}
int dungeon_kind(Dungeon * self, int x, int y) {
    return self->board [y * board_w + x].kind;
}
void dungeon_clear(Dungeon * self) {
    for (int y = 0; y < board_h; y += 1) {
        for (int x = 0; x < board_w; x += 1) {
            bool border = x <= 1 || y <= 2 || x >= board_w - 2 || y == board_h - 1;
            Tile * tile = dungeon_tile(self, x, y);
            tile->kind = border ? 0 : 2;
            tile->light = 0;
            tile->creature = 0;
            tile->far = 0;
            tile->path_step = 0;
        }
    }
}
#line 210
float dungeon_get_closest_light(Dungeon * self, int xp, int yp) {
    float closest = board_w * board_h;
    for (int y = 0; y < board_h; y += 1) {
        for (int x = 0; x < board_w; x += 1) {
            Tile * tile = dungeon_tile(self, x, y);
            if (tile->kind == 2 && tile->kid == game->wall_torch->kid) {
                int d = dungeon_distance(x, y, xp, yp);
                if (d < closest) {
                    closest = d;
                }
            }
        }
    }
#line 219
    return closest;
}
void dungeon_light(Dungeon * self) {
    for (int y = 0; y < board_h; y += 1) {
        for (int x = 0; x < board_w; x += 1) {
            float d = dungeon_get_closest_light(self, x, y);
            float l = (1 + 7 - d) / 7;
            if (l < 0) {
#line 226
                l = 0;
            }
#line 227
            if (l > 1) {
#line 227
                l = 1;
            }
#line 228
            self->board [y * board_w + x].light = l;
        }
    }
}
#line 230
Creature* dungeon_creature_new(Dungeon * self, Kind * kind, int x, int y) {
    Creature * c;
#line 231
    land_alloc(c);
    c->dungeon = self;
    c->kid = kind->kid;
    c->x = x;
    c->y = y;
    c->px = x;
    c->py = y;
    c->d = c->pd = 4;
    c->cid = land_array_count(self->creatures);
    land_array_add(self->creatures, c);
    c->hidden = 1;
#line 243
    c->name = kind_create_name(kind);
#line 245
    dungeon_creature_update_stats(c);
#line 247
    if (c->ctype == 3) {
        c->to_exit = 1;
    }
    c->hp = c->hp_max;
    c->mp = c->mp_max;
    return c;
}
void dungeon_creature_update_stats(Creature * c) {
    Kind * kind = kind_get(c->kid);
    int old_hp_max = c->hp_max;
    if (kind == game->knight) {
        c->hp_max = 35;
        c->hitmin = 4;
        c->hitmax = 6;
        c->ctype = 3;
        if (c->equip [Main] == game->sword->kid) {
            c->hitmin = 8;
            c->hitmax = 12;
        }
#line 265
        if (c->equip [Head] == game->helmet->kid) {
            c->hp_max += 40;
        }
#line 267
        if (c->equip [Off] == game->shield->kid) {
            c->hp_max += 25;
        }
    }
#line 269
    if (kind == game->archer) {
        c->hp_max = 35;
        c->hitmin = 2;
        c->hitmax = 6;
        c->ctype = 3;
        if (c->equip [Main] == game->bow->kid) {
            c->hitmax = 12;
        }
#line 276
        if (c->equip [Neck] == game->quiver->kid) {
            c->hitmin = 6;
        }
#line 278
        if (c->equip [Head] == game->helmet2->kid) {
            c->hp_max += 40;
        }
    }
#line 280
    if (kind == game->mage) {
        c->hp_max = 35;
        c->hitmin = 3;
        c->hitmax = 9;
        c->ctype = 3;
        if (c->equip [Off] == game->book->kid) {
            c->hitmin = 9;
        }
#line 287
        if (c->equip [Main] == game->wand->kid) {
            c->hitmax = 19;
        }
#line 289
        if (c->equip [Head] == game->hat->kid) {
            c->hp_max += 40;
        }
    }
#line 291
    if (kind == game->elf) {
        c->hp_max = 75;
        c->hitmin = 2;
        c->hitmax = 8;
        c->ctype = 3;
        c->mp_max = 100;
    }
#line 297
    if (kind == game->rat) {
        c->hp_max = 50;
        c->hitmin = 5;
        c->hitmax = 10;
        c->ctype = 4;
    }
#line 302
    if (kind == game->troll) {
        c->hp_max = 250;
        c->hitmin = 2;
        c->hitmax = 20;
        c->ctype = 4;
    }
#line 307
    if (kind == game->troll2) {
        c->hp_max = 600;
        c->hitmin = 4;
        c->hitmax = 40;
        c->ctype = 4;
    }
#line 312
    if (kind == game->priest) {
        c->hp_max = 150;
        c->hitmin = 10;
        c->hitmax = 30;
        c->ctype = 4;
        c->pot_tel = 3;
    }
#line 318
    if (kind == game->dragon) {
        c->hp_max = 1800;
        c->hitmin = 20;
        c->hitmax = 60;
        c->ctype = 4;
    }
    if (c->hp_max > old_hp_max) {
        c->hp += c->hp_max - old_hp_max;
    }
#line 326
    if (c->hp > c->hp_max) {
        c->hp = c->hp_max;
    }
}
#line 329
int count_kinds(Dungeon * self, int x, int y, int k) {
    int count = 0;
    for (int d = 0; d < 6; d += 1) {
        int x2 = x, y2 = y;
        dungeon_move(& x2, & y2, d);
        if (dungeon_kind(self, x2, y2) == k) {
            count += 1;
        }
    }
#line 336
    return count;
}
bool is_walkable(Dungeon * self, int x, int y, int d) {
    int x2 = x, y2 = y;
    dungeon_move(& x2, & y2, d);
    Tile * tile = dungeon_tile(self, x2, y2);
    if (tile->kind == 1 && tile->creature == 0) {
        return 1;
    }
#line 344
    return 0;
}
int count_walkables(Dungeon * self, int x, int y) {
    int count = 0;
    for (int d = 0; d < 6; d += 1) {
        if (is_walkable(self, x, y, d)) {
            count += 1;
        }
    }
#line 351
    return count;
}
void check_attack(Creature * self) {
    int checkd [6] = {0, 1, 5, 2, 4, 3};
    for (int i = 0; i < 6; i += 1) {
        int x2 = self->x;
        int y2 = self->y;
        int d = (self->d + checkd [i]) % 6;
        dungeon_move(& x2, & y2, d);
        Tile * tile = dungeon_tile(self->dungeon, x2, y2);
        if (tile->creature) {
            Creature * c = dungeon_creature(self->dungeon, tile->creature);
            if (c->ctype != self->ctype) {
                self->d = d;
#line 366
                Kind * k = kind_get(self->kid);
                if (k->sound_attack) {
                    data_playq(k->sound_attack);
                }
                self->fighting = c->cid;
                if (! c->fighting) {
                    Kind * kc = kind_get(c->kid);
                    if (kc->sound_attack) {
                        data_playq(kc->sound_attack);
                    }
#line 375
                    c->fighting = self->cid;
                }
#line 375
                return ;
            }
        }
    }
}
// checks adjacent, then 2, 3, ... radius
#line 379
bool check_ranged(Creature * self, int x, int y, int d, int n, int radius, bool(* callback)(Creature * c, int p), int p, int * fx, int * fy) {
    int checkd [6] = {0, 1, 5, 2, 4, 3};
    for (int i = 0; i < n; i += 1) {
        int x2 = x;
        int y2 = y;
        int d2 = (d + checkd [i]) % 6;
        dungeon_move(& x2, & y2, d2);
        Tile * tile = dungeon_tile(self->dungeon, x2, y2);
        if (tile->kind == 1) {
            if (tile->creature) {
                Creature * c = dungeon_creature(self->dungeon, tile->creature);
                if (callback(c, p)) {
                    * fx = x2;
                    * fy = y2;
                    return 1;
                }
            }
#line 394
            if (radius > 1) {
                if (check_ranged(self, x2, y2, d2, 3, radius - 1, callback, p, fx, fy)) {
                    return 1;
                }
            }
        }
    }
#line 398
    return 0;
}
static bool _cb_ctype(Creature * c, int ctype) {
    return c->ctype == ctype && ! c->dead;
}
static bool _cb_injured(Creature * c, int ctype) {
    return c->ctype == ctype && c->hp < c->hp_max && ! c->dead;
}
void check_attack_ranged(Creature * self, int radius, int ctype) {
    int fx, fy;
    if (check_ranged(self, self->x, self->y, self->d, 6, radius, _cb_ctype, ctype, & fx, & fy)) {
        self->d = dungeon_dir(self->x, self->y, fx, fy);
        Tile * tile = dungeon_tile(self->dungeon, fx, fy);
        self->fighting = tile->creature;
        Creature * c = dungeon_creature(self->dungeon, self->fighting);
        if (! c->fighting) {
            c->fighting = self->cid;
        }
    }
}
#line 416
void check_healing_ranged(Creature * self, int radius, int ctype) {
    int fx, fy;
    if (check_ranged(self, self->x, self->y, self->d, 6, radius, _cb_injured, ctype, & fx, & fy)) {
        self->d = dungeon_dir(self->x, self->y, fx, fy);
        Tile * tile = dungeon_tile(self->dungeon, fx, fy);
        self->healing = tile->creature;
    }
}
#line 423
static void _hit(Creature * self, int hitmin, int hitmax) {
    int hit = land_rand(hitmin, hitmax);
    self->hp -= hit;
    print("%d gets hit %d -> %d/%d", self->cid, hit, self->hp, self->hp_max);
    if (self->hp <= 0) {
        dungeon_die(self);
    }
}
#line 430
bool dungeon_teleport(Creature * self, int r) {
    int x = self->x;
    int y = self->y;
    int d = land_rand(0, 5);
    for (int i = 0; i < r; i += 1) {
        dungeon_move(& x, & y, d);
    }
#line 436
    d = (d + 2) % 6;
    for (int j = 0; j < 6; j += 1) {
        for (int i = 0; i < r; i += 1) {
            dungeon_move(& x, & y, d);
            Tile * tile = dungeon_tile(self->dungeon, x, y);
            if (tile->creature == 0 && tile->kind == 1) {
                dungeon_remove(self);
                self->x = x;
                self->y = y;
                dungeon_appear(self);
                Kind * k = kind_get(self->kid);
                if (k->sound_special) {
                    data_playq(k->sound_special);
                }
#line 449
                return 1;
            }
        }
#line 450
        d = (d + 1) % 6;
    }
#line 451
    return 0;
}
void dungeon_remove(Creature * self) {
    Tile * tile = dungeon_tile(self->dungeon, self->x, self->y);
    tile->creature = 0;
}
void dungeon_appear(Creature * self) {
    Tile * tile = dungeon_tile(self->dungeon, self->x, self->y);
    tile->creature = self->cid;
}
#line 462
static bool _attack(Creature * self) {
    Creature * c = dungeon_creature(self->dungeon, self->fighting);
    if (c->dead) {
        self->fighting = 0;
        return 0;
    }
#line 467
    self->d = dungeon_dir(self->x, self->y, c->x, c->y);
#line 469
    bool in_range = 0;
    int distance = dungeon_distance(self->x, self->y, c->x, c->y);
    if (distance == 1) {
        in_range = 1;
    }
#line 473
    else if (distance == 2) {
        if (self->kid == game->archer->kid || self->kid == game->priest->kid || self->kid == game->mage->kid) {
            in_range = 1;
        }
#line 475
        else {
            // even if we can reach them with a step we don't want the
            // fighting animation yet
#line 479
            self->fighting = 0;
            // see if moving in a direction gets us to distance 1
#line 482
            for (int d = 0; d < 6; d += 1) {
                int x2 = self->x;
                int y2 = self->y;
                dungeon_move(& x2, & y2, d);
                Tile * tile = dungeon_tile(self->dungeon, x2, y2);
                if (tile->creature == 0 && tile->kind == 1) {
                    if (dungeon_distance(x2, y2, c->x, c->y) == 1) {
                        creature_move(self, d);
                        return 1;
                    }
                }
            }
#line 491
            return 0;
        }
    }
#line 492
    else if (distance == 3) {
        if (self->kid == game->mage->kid) {
            in_range = 1;
        }
#line 494
        else {
#line 496
            self->fighting = 0;
            return 0;
        }
    }
#line 497
    else {
#line 499
        self->fighting = 0;
        return 0;
    }
    if (in_range) {
        if (distance > 1) {
            if (self->kid == game->mage->kid) {
                game_projectile(game->fireball, self->cid, c->cid);
            }
#line 506
            if (self->kid == game->archer->kid) {
                game_projectile(game->arrow, self->cid, c->cid);
            }
#line 508
            if (self->kid == game->priest->kid) {
                game_projectile(game->missile, self->cid, c->cid);
            }
        }
#line 510
        Kind * k = kind_get(self->kid);
        if (k->sound_fight) {
            data_playq_vol(k->sound_fight, 0.5);
        }
#line 513
        _hit(c, self->hitmin, self->hitmax);
        if (c->hp <= 0) {
            self->fighting = 0;
            if (self->kid == game->priest->kid) {
                self->hp += 30;
                if (self->hp > self->hp_max) {
                    self->hp = self->hp_max;
                }
            }
        }
#line 520
        return 1;
    }
#line 521
    return 0;
}
void dungeon_die(Creature * self) {
    self->hp = 0;
    self->dead = 1;
    self->pd = self->d;
    self->fighting = 0;
    int r = land_rand(0, 3);
    self->equip [r] = 0;
#line 531
    Kind * k = kind_get(self->kid);
    if (k->sound_down) {
        data_playq(k->sound_down);
    }
    dungeon_remove(self);
}
static bool _heal(Creature * self) {
    if (self->mp == 0) {
        self->healing = 0;
        return 0;
    }
#line 541
    Creature * c = dungeon_creature(self->dungeon, self->healing);
    self->d = dungeon_dir(self->x, self->y, c->x, c->y);
    int distance = dungeon_distance(self->x, self->y, c->x, c->y);
    if (distance <= 3 && ! c->dead) {
        if (c->hp < c->hp_max) {
            Kind * k = kind_get(self->kid);
            if (k->sound_special) {
                data_playq(k->sound_special);
            }
#line 549
            int h = c->hp_max - c->hp;
            int roll = land_rand(10, 25);
            if (roll > h) {
                roll = h;
            }
#line 553
            if (roll > self->mp) {
                roll = self->mp;
            }
#line 555
            self->mp -= roll;
            c->hp += roll;
            return 1;
        }
    }
#line 558
    self->healing = 0;
    return 0;
}
void creature_move(Creature * self, int d) {
    dungeon_remove(self);
    dungeon_move(& self->x, & self->y, d);
    self->d = d;
    dungeon_appear(self);
}
bool check_equipment(Creature * self) {
#line 569
    if (self->ctype == 4) {
        // troll self heal
        if (self->kid == game->troll->kid || self->kid == game->troll2->kid) {
            if (self->hp < self->hp_max) {
                self->hp++;
                return 0 /* note: rest of turn continues */;
            }
        }
        // demon reanimate
#line 577
        if (self->kid == game->priest->kid) {
            {
#line 578
                LandArrayIterator __iter0__ = LandArrayIterator_first(self->dungeon->creatures);
#line 578
                for (Creature * c = LandArrayIterator_item(self->dungeon->creatures, &__iter0__); LandArrayIterator_next(self->dungeon->creatures, &__iter0__); c = LandArrayIterator_item(self->dungeon->creatures, &__iter0__)) {
                    if (c && c->dead && c->ctype == 4 && ! c->hidden) {
                        if (dungeon_distance(c->x, c->y, self->x, self->y) <= 1) {
                            c->hidden = 1;
                            c->dead = 0;
                            c->hp = 30 /* reanimated have almost no hp */;
                            self->hp += 30;
                            // but demon receives hp
#line 585
                            if (self->hp > self->hp_max) {
                                self->hp = self->hp_max;
                            }
#line 587
                            return 1;
                        }
                    }
                }
            }
        }
        // rat revive rat
#line 589
        if (self->kid == game->rat->kid) {
            {
#line 590
                LandArrayIterator __iter0__ = LandArrayIterator_first(self->dungeon->creatures);
#line 590
                for (Creature * c = LandArrayIterator_item(self->dungeon->creatures, &__iter0__); LandArrayIterator_next(self->dungeon->creatures, &__iter0__); c = LandArrayIterator_item(self->dungeon->creatures, &__iter0__)) {
                    if (c && c->dead && c->kid == game->rat->kid && ! c->hidden) {
                        if (dungeon_distance(c->x, c->y, self->x, self->y) == 0) {
                            c->hidden = 1;
                            c->dead = 0;
                            c->hp = 30 /* reanimated have almost no hp */;
                            return 1;
                        }
                    }
                }
            }
        }
#line 597
        return 0;
    }
    if ((self->hp < self->hp_max - 30 || self->hp < self->hp_max / 2) && self->pot_hp) {
        self->pot_hp -= 1;
        self->hp += 40;
        if (self->hp > self->hp_max) {
            self->hp = self->hp_max;
        }
#line 604
        game_use(game->potion_hp, self->x, self->y);
        data_playq(DataPotion);
        return 1;
    }
    if (self->mp < self->mp_max - 30 && self->pot_mp) {
        self->pot_mp -= 1;
        self->mp += 40;
        if (self->mp > self->mp_max) {
            self->mp = self->mp_max;
        }
#line 613
        game_use(game->potion_mp, self->x, self->y);
        data_playq(DataPotion);
        return 1;
    }
    if (self->pot_res) {
        {
#line 618
            LandArrayIterator __iter0__ = LandArrayIterator_first(self->dungeon->creatures);
#line 618
            for (Creature * c = LandArrayIterator_item(self->dungeon->creatures, &__iter0__); LandArrayIterator_next(self->dungeon->creatures, &__iter0__); c = LandArrayIterator_item(self->dungeon->creatures, &__iter0__)) {
                if (! c || c->ctype != 3) {
                    continue;
                }
#line 621
                if (dungeon_distance(self->x, self->y, c->x, c->y) <= 1) {
                    // resurrect
                    if (c->dead && ! c->hidden) {
                        self->pot_res -= 1;
                        c->hidden = 1;
                        c->dead = 0;
                        c->hp = c->hp_max;
                        game_use(game->potion_res, self->x, self->y);
                        data_playq(DataPotion);
                        return 1;
                    }
                }
            }
        }
    }
#line 631
    return 0;
}
bool buy_equipment(Creature * self, Kind * who, int where, Kind * what) {
    if (self->kid == who->kid) {
        if (self->equip [where] == 0) {
            self->equip [where] = what->kid;
            dungeon_creature_update_stats(self);
            game_buy(what, self->x, self->y);
            return 1;
        }
    }
#line 640
    return 0;
}
bool check_vendor(Creature * self) {
    if (self->ctype != 3) {
        return 0;
    }
#line 645
    for (int d = 0; d < 6; d += 1) {
        int x = self->x, y = self->y;
        dungeon_move(& x, & y, d);
        Tile * tile = dungeon_tile(self->dungeon, x, y);
        if (tile->kind == 2 && tile->kid == game->vendor_shield->kid) {
            // shield vendor
#line 650
            if (buy_equipment(self, game->knight, Off, game->shield)) {
#line 650
                return 1;
            }
#line 651
            if (buy_equipment(self, game->archer, Neck, game->quiver)) {
#line 651
                return 1;
            }
#line 652
            if (buy_equipment(self, game->mage, Off, game->book)) {
#line 652
                return 1;
            }
        }
#line 653
        if (tile->kind == 2 && tile->kid == game->vendor_head->kid) {
            // helmet vendor
#line 654
            if (buy_equipment(self, game->knight, Head, game->helmet)) {
#line 654
                return 1;
            }
#line 655
            if (buy_equipment(self, game->archer, Head, game->helmet2)) {
#line 655
                return 1;
            }
#line 656
            if (buy_equipment(self, game->mage, Head, game->hat)) {
#line 656
                return 1;
            }
        }
#line 657
        if (tile->kind == 2 && tile->kid == game->vendor_potion->kid) {
            // potions vendor
#line 658
            if (self->pot_hp == 0) {
                self->pot_hp += 1;
                game_buy(game->potion_hp, x, y);
                return 1;
            }
#line 662
            if (self->kid == game->elf->kid && self->pot_mp == 0) {
                self->pot_mp += 1;
                game_buy(game->potion_mp, x, y);
                return 1;
            }
#line 666
            if (self->kid == game->elf->kid && self->pot_res == 0) {
                self->pot_res += 1;
                game_buy(game->potion_res, x, y);
                return 1;
            }
        }
#line 670
        if (tile->kind == 2 && tile->kid == game->vendor_smith->kid) {
            // weapons vendor
#line 671
            if (buy_equipment(self, game->knight, Main, game->sword)) {
#line 671
                return 1;
            }
#line 672
            if (buy_equipment(self, game->archer, Main, game->bow)) {
#line 672
                return 1;
            }
#line 673
            if (buy_equipment(self, game->mage, Main, game->wand)) {
#line 673
                return 1;
            }
        }
    }
#line 674
    return 0;
}
bool check_trap(Creature * self) {
    Tile * tile = dungeon_tile(self->dungeon, self->x, self->y);
#line 679
    if (tile->kid == game->trap_box->kid && self->ctype == 3) {
        tile->kid = game->ground [0]->kid;
        self->dungeon->modified = 1;
        bool r = 1;
        if (self->to_loot) {
            self->to_loot = 0;
            r = 0;
        }
#line 685
        else {
#line 685
            ;
        }
#line 688
        game_buy(game->chest, self->x, self->y);
        return r;
    }
    if (tile->kid == game->trap_poison->kid) {
        tile->kid = game->ground [0]->kid;
        self->dungeon->modified = 1;
        if (self->kid != game->troll->kid && self->kid != game->troll2->kid) {
            _hit(self, 20, 30);
            return 1;
        }
#line 697
        return 0;
    }
    if (tile->kid == game->trap_fire->kid) {
        tile->kid = game->ground [0]->kid;
        self->dungeon->modified = 1;
        if (self->kid != game->dragon->kid) {
            _hit(self, 20, 30);
            return 1;
        }
#line 705
        return 0;
    }
    if (tile->kid == game->trap_lightning->kid) {
        if (self->ctype == 4) {
            tile->kid = game->ground [0]->kid;
            self->dungeon->modified = 1;
            _hit(self, 20, 30);
            return 1;
        }
#line 713
        return 0;
    }
#line 714
    return 0;
}
static void _creature_clone_from_to(Creature * self, Creature * copy) {
    copy->hp = self->hp;
    copy->hp_max = self->hp_max;
    copy->mp = self->mp;
    copy->mp_max = self->mp_max;
    copy->hitmin = self->hitmin;
    copy->hitmax = self->hitmax;
    for (int i = 0; i < 4; i += 1) {
#line 723
        copy->equip [i] = self->equip [i];
    }
#line 724
    copy->pot_hp = self->pot_hp;
    copy->pot_mp = self->pot_mp;
    copy->pot_res = self->pot_res;
    if (copy->name) {
#line 727
        land_free(copy->name);
    }
#line 728
    copy->name = land_strdup(self->name);
}
void hero_step(Creature * self) {
    self->px = self->x;
    self->py = self->y;
    self->pd = self->d;
#line 735
    int back = (self->d + 3) % 6;
#line 737
    bool turnaround = check_trap(self);
    if (self->dead) {
#line 738
        return ;
    }
#line 741
    if (self->kid == game->priest->kid) {
        if (self->hp < 30) {
            if (self->pot_tel > 0) {
                self->fighting = 0;
                // try distance 4 first else 3
                if (dungeon_teleport(self, 4)) {
                    self->hp += 60;
                    self->pot_tel -= 1;
#line 748
                    return ;
                }
                if (dungeon_teleport(self, 3)) {
                    self->hp += 60;
                    self->pot_tel -= 1;
#line 752
                    return ;
                }
            }
        }
    }
#line 755
    if (self->fighting) {
        if (_attack(self)) {
#line 756
            return ;
        }
    }
    if (self->healing) {
        if (_heal(self)) {
#line 760
            return ;
        }
    }
    check_attack(self);
    if (self->fighting) {
#line 764
        return ;
    }
    if (self->kid == game->archer->kid || self->kid == game->priest->kid) {
        int e = 4;
        if (self->ctype == 4) {
#line 768
            e = 3;
        }
#line 769
        check_attack_ranged(self, 2, e);
        if (self->fighting) {
#line 770
            return ;
        }
    }
#line 772
    if (self->kid == game->mage->kid) {
        int e = 4;
        if (self->ctype == 4) {
#line 774
            e = 3;
        }
#line 775
        check_attack_ranged(self, 3, e);
        if (self->fighting) {
#line 776
            return ;
        }
    }
    if (self->kid == game->elf->kid && self->mp > 0) {
        check_healing_ranged(self, 3, 3);
        if (self->healing) {
#line 781
            return ;
        }
    }
    if (check_equipment(self)) {
#line 784
        return ;
    }
    if (check_vendor(self)) {
#line 786
        return ;
    }
#line 789
    Tile * ptile = dungeon_tile(self->dungeon, self->px, self->py);
#line 791
    int i = 0;
    int w = count_walkables(self->dungeon, self->x, self->y);
    bool wb = is_walkable(self->dungeon, self->x, self->y, back);
#line 795
    if (self->to_exit) {
        if (self->x == self->dungeon->ex && self->y == self->dungeon->ey) {
            self->to_exit = 0;
            if (self->ctype == 3) {
                game_unlock_level();
                // advance to next level
                if (self->dungeon->level < 9) {
                    self->hidden = 1;
                    self->dead = 1;
                    dungeon_remove(self);
                    // in reality we create a duplicate
                    Dungeon * down = game->levels [self->dungeon->level + 1];
                    Creature * c = dungeon_creature_new(down, kind_get(self->kid), down->sx, down->sy);
                    _creature_clone_from_to(self, c);
                    data_play(DataWin);
                }
#line 809
                return ;
            }
        }
    }
#line 809
    else {
#line 812
        if (self->x == self->dungeon->sx && self->y == self->dungeon->sy) {
            self->to_exit = 1;
        }
    }
#line 815
    if (turnaround && wb) {
        creature_move(self, back);
#line 816
        return ;
    }
#line 819
    if (w > 2 || (! wb && w > 1)) {
        // move to loot box
        int lootd [] = {0, 1, 5, 2, 3};
        for (int di = 0; di < 5; di += 1) {
            int d = (self->d + lootd [di]) % 6;
            Tile * tile = dungeon_tile_dir(self->dungeon, self->x, self->y, d);
            if (tile->creature == 0 && tile->kid == game->trap_box->kid) {
                creature_move(self, d);
                self->to_loot = 1;
#line 827
                return ;
            }
        }
    }
#line 830
    if (w == 0) {
        // trapped
        self->d = land_rand(0, 5);
#line 832
        return ;
    }
    else if (w == 1) {
        i = 0;
    }
#line 835
    else {
        // Note: the back direction may be blocked since the last step,
        // e.g. someone walking behind us
#line 839
        if (wb) {
            i = land_rand(0, w - 2) /* exclude back if we can walk back */;
        }
#line 840
        else {
#line 842
            i = land_rand(0, w - 1);
        }
    }
#line 844
    if (w > 2) {
        if (ptile->path_step && ! turnaround) {
            int next_step = ptile->path_step;
            if (self->to_exit) {
                next_step += 1;
            }
#line 848
            else {
#line 850
                next_step -= 1;
            }
            // if we are on the main path, 50% of the time stay on it
#line 852
            if (land_rand(0, 1) == 0) {
                // follow the path
                for (int d = 0; d < 6; d += 1) {
                    Tile * tile = dungeon_tile_dir(self->dungeon, self->x, self->y, d);
                    if (tile->kind == 1 && tile->creature == 0 && tile->path_step == next_step) {
                        creature_move(self, d);
#line 857
                        return ;
                    }
                }
            }
        }
        // if we're in a party 50% of the time try to get close to the leader
#line 861
        if (self->leader && land_rand(0, 1) == 0) {
            Creature * l = dungeon_creature(self->dungeon, self->leader);
            int mindist = 1000;
            int mind = 6;
            for (int d = 0; d < 6; d += 1) {
                int x2 = self->x, y2 = self->y;
                dungeon_move(& x2, & y2, d);
                Tile * tile = dungeon_tile(self->dungeon, x2, y2);
                if (tile->creature == 0 && tile->kind == 1) {
                    int dist = dungeon_distance(x2, y2, l->x, l->y);
                    if (dist < mindist) {
                        mindist = dist;
                        mind = d;
                    }
                }
            }
#line 874
            if (mind != 6) {
                creature_move(self, mind);
#line 875
                return ;
            }
        }
    }
    for (int d = 0; d < 6; d += 1) {
        if (w > 1 && wb && d == back) {
            continue;
        }
#line 882
        if (is_walkable(self->dungeon, self->x, self->y, d)) {
            if (i == 0) {
                creature_move(self, d);
#line 884
                return ;
            }
            i -= 1;
        }
    }
}
#line 888
void dungeon_use(int kid) {
    for (int uid = 0; uid < 3; uid += 1) {
        Kind * k = kind_get(kid);
        game->used [uid] += k->upkeep [uid];
        game->used_stats [uid] [kid] += k->upkeep [uid];
    }
}
#line 894
void dungeon_step(Dungeon * self) {
    self->ticks++;
    bool reveal_hero = 0;
    bool reveal_monster = 0;
#line 899
    reveal_hero = 1;
    reveal_monster = 1;
#line 902
    {
#line 902
        LandArrayIterator __iter0__ = LandArrayIterator_first(self->creatures);
#line 902
        for (Creature * c = LandArrayIterator_item(self->creatures, &__iter0__); LandArrayIterator_next(self->creatures, &__iter0__); c = LandArrayIterator_item(self->creatures, &__iter0__)) {
            if (! c) {
#line 903
                continue;
            }
#line 904
            if (c->dead) {
                continue;
            }
#line 906
            if (c->hidden) {
                if ((c->ctype == 3 && reveal_hero) || (c->ctype == 4 && reveal_monster)) {
                    Tile * tile = dungeon_tile(self, c->x, c->y);
                    if (tile->creature == 0) {
                        tile->creature = c->cid;
                        if (c->ctype == 3) {
#line 911
                            reveal_hero = 0;
                        }
#line 912
                        if (c->ctype == 4) {
#line 912
                            reveal_monster = 0;
                        }
#line 913
                        c->hidden = 0;
                        print("New! %d %d %d", c->x, c->y, c->cid);
                    }
                }
#line 915
                continue;
            }
            dungeon_use(c->kid);
#line 919
            if (c->ctype == 3) {
                hero_step(c);
            }
#line 921
            if (c->ctype == 4) {
                hero_step(c);
            }
        }
    }
#line 924
    for (int y = 0; y < board_h; y += 1) {
        for (int x = 0; x < board_w; x += 1) {
            Tile * tile = dungeon_tile(self, x, y);
            if (tile->kid) {
                dungeon_use(tile->kid);
            }
        }
    }
}
#line 930
static int _cmp_cb(void * data1, void * data2) {
    PathNode * n1 = data1;
    PathNode * n2 = data2;
    if (n1->steps + n1->estimate < n2->steps + n2->estimate) {
        return - 1;
    }
#line 935
    if (n1->steps + n1->estimate > n2->steps + n2->estimate) {
        return 1;
    }
#line 937
    return 0;
}
int dungeon_path(Dungeon * self, int x1, int y1, int x2, int y2, int maxlen, int * dirs) {
    int n = board_w * board_h;
    PathNode nodes [n];
    char mark [n];
    memset(mark, 0, n);
    int used = 0;
#line 946
    if (! self->q) {
        self->q = land_queue_new(_cmp_cb);
    }
#line 948
    land_queue_clear(self->q);
    PathNode * node0 = nodes + used++;
    node0->steps = 0;
    node0->x = x1;
    node0->y = y1;
    node0->d = 0;
    node0->estimate = dungeon_distance(x1, y1, x2, y2);
    node0->parent = NULL;
    land_queue_add(self->q, node0);
    while (! land_queue_is_empty(self->q)) {
        PathNode * node = land_queue_pop(self->q);
#line 960
        for (int d = 0; d < 6; d += 1) {
            int x = node->x;
            int y = node->y;
            dungeon_move(& x, & y, d);
            if (mark [y * board_w + x] == 1) {
                continue;
            }
#line 966
            if (x == x2 && y == y2) {
                // Found it!
                PathNode * trace = node;
                int i = trace->steps;
                dirs [i] = d;
                while (i > 0) {
                    i--;
                    dirs [i] = trace->d;
                    trace = trace->parent;
                }
#line 975
                return node->steps + 1;
            }
#line 976
            mark [y * board_w + x] = 1;
            Tile * tile = dungeon_tile(self, x, y);
            if (tile->kind != 1) {
                continue;
            }
            PathNode * node1 = nodes + used++;
            node1->steps = node->steps + 1;
            node1->x = x;
            node1->y = y;
            node1->d = d;
            node1->parent = node;
            node1->estimate = dungeon_distance(x1, y1, x2, y2);
            if (node1->steps + node1->estimate < maxlen) {
                land_queue_add(self->q, node1);
            }
#line 989
            else {
#line 991
                print("path exceeded");
            }
        }
    }
#line 992
    return 0;
}
void dungeon_add_quest(Dungeon * dungeon, int q, bool spawn) {
    Creature * c1 = game_spawn_hero(dungeon, game->knight, spawn);
    if (q >= 2) {
        Creature * c2 = game_spawn_hero(dungeon, game->archer, spawn);
        c2->leader = c1->cid;
    }
#line 999
    if (q >= 3) {
        Creature * c3 = game_spawn_hero(dungeon, game->elf, spawn);
        c3->leader = c1->cid;
    }
#line 1002
    if (q >= 4) {
        Creature * c4 = game_spawn_hero(dungeon, game->mage, spawn);
        c4->leader = c1->cid;
    }
}
/* This file was generated by scramble.py. */
