man/victrix-abyssi.6
combat.cc
combat.hh
+coord.cc
coord.hh
core.hh
default.permobjs
GENERATED_OBJS:=permobj.o permons.o
GENERATED_SOURCE:=permobj.cc pobj_id.hh permons.cc pmon_id.hh
GENERATED_MAKES:=dirs.mk features.mk
-HANDWRITTEN_OBJS:=combat.o display-nc.o fov.o log.o main.o map.o monsters.o mon2.o notify-local-tty.o objects.o pmon2.o rng.o sorcery.o u.o util.o
+HANDWRITTEN_OBJS:=combat.o coord.o display-nc.o fov.o log.o main.o map.o monsters.o mon2.o notify-local-tty.o objects.o pmon2.o rng.o sorcery.o u.o util.o
OBJS:=$(GENERATED_OBJS) $(HANDWRITTEN_OBJS)
GAME:=victrix-abyssi
MAJVERS:=0
## Dependencies for the build
combat.o: $(srcdir)/combat.cc $(srcdir)/combat.hh $(srcdir)/victrix-abyssi.hh $(srcdir)/monsters.hh $(srcdir)/objects.hh $(srcdir)/notify.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
+coord.o: $(srcdir)/coord.cc $(srcdir)/coord.hh
+
display-nc.o: $(srcdir)/display-nc.cc $(srcdir)/victrix-abyssi.hh $(srcdir)/display.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
log.o: $(srcdir)/log.cc $(srcdir)/objects.hh $(srcdir)/monsters.hh $(srcdir)/player.hh $(srcdir)/map.hh $(srcdir)/util.h
main.o: $(srcdir)/main.cc $(srcdir)/combat.hh $(srcdir)/victrix-abyssi.hh $(srcdir)/monsters.hh $(srcdir)/notify.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
-map.o: $(srcdir)/map.cc $(srcdir)/victrix-abyssi.hh $(srcdir)/notify.hh $(srcdir)/objects.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
+map.o: $(srcdir)/map.cc $(srcdir)/victrix-abyssi.hh $(srcdir)/map.hh $(srcdir)/core.hh $(srcdir)/notify.hh $(srcdir)/objects.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
monsters.o: $(srcdir)/monsters.cc $(srcdir)/victrix-abyssi.hh $(srcdir)/monsters.hh $(srcdir)/notify.hh $(srcdir)/objects.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
notify-local-tty.o: $(srcdir)/notify-local-tty.cc $(srcdir)/victrix-abyssi.hh $(srcdir)/combat.hh $(srcdir)/monsters.hh $(srcdir)/notify.hh $(srcdir)/objects.hh $(srcdir)/sorcery.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
-# NOTICE: $(srcdir)/permobj.cc does not depend on ./pobj_id.hh because they are both
-# generated from the same input file and should not be hand-edited. If you
-# file a bug report over this, I will close it NOTABUG; if you submit a
-# patch to add such a dependency, I will reject it out of hand.
-
-permobj.o: $(srcdir)/permobj.cc $(srcdir)/core.hh $(srcdir)/permobj.hh ./pobj_id.hh
+permobj.o: ./permobj.cc $(srcdir)/core.hh $(srcdir)/permobj.hh
-permons.o: $(srcdir)/permons.cc $(srcdir)/core.hh $(srcdir)/permon.hh ./pmon_id.hh
+permons.o: ./permons.cc $(srcdir)/core.hh $(srcdir)/permon.hh
pmon2.o: $(srcdir)/pmon2.cc $(srcdir)/victrix-abyssi.hh $(srcdir)/notify.hh $(srcdir)/monsters.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
--- /dev/null
+/* \file coord.cc
+ * \brief Positions and offsets - common constants
+ */
+
+/* Copyright 2014 Martin Read
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "coord.hh"
+#include <limits.h>
+
+/* Coord/Offset constants */
+
+/*! \brief A Coord representing an invalid location */
+Coord const Nowhere = { INT_MIN, INT_MIN };
+/*! \brief One step northward */
+Offset const North = { -1, 0 };
+/*! \brief One step northeast */
+Offset const Northeast = { -1, 1 };
+/*! \brief One step east */
+Offset const East = { 0, 1 };
+/*! \brief One step southeast */
+Offset const Southeast = { 1, 1 };
+/*! \brief One step south */
+Offset const South = { 1, 0 };
+/*! \brief One step southwest */
+Offset const Southwest = { 1, -1 };
+/*! \brief One step west */
+Offset const West = { 0, -1 };
+/*! \brief One step northwest */
+Offset const Northwest = { -1, -1 };
+/*! \brief The additive identity offset */
+Offset const Stationary = { 0, 0 };
+
+/* coord.cc */
+// vim:cindent
utf8 "1"
colour l_green
rarity 90
+power 30
hp 250
mhit 20
mdam 20
utf8 "1"
colour purple
rarity 90
+power 30
hp 150
mhit 50
mdam 10
utf8 "1"
colour iron
rarity 90
+power 30
hp 300
mhit 30
mdam 30
* \brief main core of Victrix Abyssi
*/
-/* Copyright 2005-2013 Martin Read
+/* Copyright 2005-2014 Martin Read
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#include <deque>
#include <basedir.h>
-/* Coord/Offset constants */
-Coord const Nowhere = { INT_MIN, INT_MIN };
-Offset const North = { -1, 0 };
-Offset const Northeast = { -1, 1 };
-Offset const East = { 0, 1 };
-Offset const Southeast = { 1, 1 };
-Offset const South = { 1, 0 };
-Offset const Southwest = { 1, -1 };
-Offset const West = { 0, -1 };
-Offset const Northwest = { -1, -1 };
-Offset const Stationary = { 0, 0 };
-
-void save_game(void);
static void main_loop(void);
bool game_finished;
int32_t game_tick;
bool wizard_mode = WIZARD_MODE;
-/*! \brief pick a random Chebyshev cardinal
- */
-Offset random_step(void)
-{
- switch (zero_die(8))
- {
- case 0:
- return Northwest;
- case 1:
- return North;
- case 2:
- return Northwest;
- case 3:
- return West;
- case 4:
- return East;
- case 5:
- return Southwest;
- case 6:
- return South;
- case 7:
- return Southeast;
- }
- return Stationary;
-}
-
void new_game(char const *name)
{
u_init(name);
make_new_level();
}
-std::deque<Action> past_actions;
-
-enum Combo_phase
-{
- Combo_invalid,
- Combo_link,
- Combo_finisher
-};
-
-/* \brief Process action combos
- *
- * This function is responsible for detecting whether the most recently
- * attempted action is a possible step in a combo, a combo finisher, or a
- * combo-invalid move (for example, quaffing a potion is a combo breaker). It
- * uses the contents of the deque past_actions to make the decision.
- *
- * \param act Pointer to attempted action
- * \param revised_act Pointer to storage location for revised action
- * \return true if revised_act was written to; false otherwise
- */
-
-bool detect_combo(Action const *act, Action *revised_act)
-{
- //Combo_phase p;
- // for now, we use if rather than switch because there are only two
- // valid action types in a combo: move, and attack.
- if (act->cmd == WALK)
- {
- *revised_act = *act;
- return true;
- }
- else if (act->cmd == ATTACK)
- {
- *revised_act = *act;
- return true;
- }
- else
- {
- return false;
- }
-}
-
-Action_cost do_player_action(Action *act)
-{
- int slot;
- Offset step;
- Action redact;
- bool rewritten = detect_combo(act, &redact);
- if (rewritten)
- {
- act = &redact;
- }
- switch (act->cmd)
- {
- case WALK:
- step.y = act->details[0];
- step.x = act->details[1];
- return move_player(step);
-
- case ATTACK:
- step.y = act->details[0];
- step.x = act->details[1];
- return player_attack(step);
-
- case USE_ACTIVE_SKILL:
- debug_unimplemented();
- return Cost_none;
-
- case ALLOCATE_SKILL_POINT:
- debug_unimplemented();
- return Cost_none;
-
- case GET_ITEM:
- if (lvl.obj_at(u.pos) != NO_OBJ)
- {
- attempt_pickup();
- return Cost_std;
- }
- else
- {
- notify_nothing_to_get();
- return Cost_none;
- }
-
- case WIELD_WEAPON:
- slot = act->details[0];
- if (slot == SLOT_NOTHING)
- {
- return player_unwield(Noise_std);
- }
- else
- {
- return player_wield(slot, Noise_std);
- }
- break;
-
- case WEAR_ARMOUR:
- slot = act->details[0];
- return wear_armour(slot);
-
- case EMANATE_ARMOUR:
- if (u.armour == NO_OBJ)
- {
- notify_emanate_no_armour();
- return Cost_none;
- }
- return emanate_armour();
-
- case ZAP_WEAPON:
- if (u.weapon == NO_OBJ)
- {
- notify_zap_no_weapon();
- return Cost_none;
- }
- return zap_weapon();
-
- case MAGIC_RING:
- if (u.weapon == NO_OBJ)
- {
- notify_magic_no_ring();
- return Cost_none;
- }
- return magic_ring();
-
- case TAKE_OFF_ARMOUR:
- if (u.armour != NO_OBJ)
- {
- int saved_armour = u.armour;
- if ((u.resistances[DT_FIRE] == RESIST_ARMOUR) &&
- (lvl.terrain_at(u.pos) == LAVA))
- {
- notify_lava_blocks_unequip();
- return Cost_none;
- }
- u.armour = NO_OBJ;
- recalc_defence();
- notify_armour_unequip(saved_armour);
- return Cost_std;
- }
- else
- {
- debug_take_off_no_armour();
- return Cost_none;
- }
-
- case GO_DOWN_STAIRS:
- if (lvl.terrain_at(u.pos) == STAIRS)
- {
- leave_level();
- make_new_level();
- }
- else
- {
- debug_descend_non_stairs();
- }
- return Cost_none;
-
- case STAND_STILL:
- return Cost_std;
-
- case READ_SCROLL:
- slot = act->details[0];
- return read_scroll(u.inventory[slot]);
-
- case EAT_FOOD:
- slot = act->details[0];
- return eat_food(u.inventory[slot]);
-
- case QUAFF_POTION:
- slot = act->details[0];
- return quaff_potion(u.inventory[slot]);
-
- case THROW_FLASK:
- return Cost_none;
-
- case REMOVE_RING:
- return remove_ring();
-
- case PUT_ON_RING:
- slot = act->details[0];
- return put_on_ring(u.inventory[slot]);
-
- case DROP_ITEM:
- slot = act->details[0];
- return drop_obj(slot);
-
- case SAVE_GAME:
- game_finished = 1;
- save_game();
- return Cost_none;
-
- case QUIT:
- game_finished = 1;
- return Cost_none;
-
- case WIZARD_DESCEND:
- if (wizard_mode)
- {
- leave_level();
- make_new_level();
- }
- else
- {
- debug_wizmode_violation();
- }
- return Cost_none;
-
- case WIZARD_LEVELUP:
- if (wizard_mode)
- {
- if (lev_threshold(u.level) != INT_MAX)
- {
- gain_experience((lev_threshold(u.level) - u.experience) + 1);
- }
- }
- else
- {
- debug_wizmode_violation();
- }
- return Cost_none;
- }
- return Cost_none;
-}
-
void main_loop(void)
{
int i;
}
}
+/*! \brief main()
+ */
int main(void)
{
load_config();
}
/* main.cc */
-// vim:cindent
+// vim:cindent:expandtab
void leave_level(void)
{
int i;
- memset(lvl.objs, -1, sizeof lvl.objs);
- memset(lvl.mons, -1, sizeof lvl.mons);
- memset(lvl.terrain, 0, sizeof lvl.terrain);
- memset(lvl.flags, 0, sizeof lvl.flags);
for (i = 0; i < 100; i++)
{
/* Throw away each monster */
class Level
{
public:
- Chunk ***chunks;
- Offset origin_off;
- int chunks_high;
- int chunks_wide;
- int objs[DUN_HEIGHT][DUN_WIDTH];
- int mons[DUN_HEIGHT][DUN_WIDTH];
- Terrain terrain[DUN_HEIGHT][DUN_WIDTH];
- uint32_t flags[DUN_HEIGHT][DUN_WIDTH];
- uint32_t region_number[CHUNK_EDGE][CHUNK_EDGE];
- Terrain dead_space;
- level_theme theme;
- level_layout layout;
+ Chunk ***chunks; //!< 16x16 subsections of the level, not necessarily dense
+ Offset origin_off; //!< Don't force a map size change to recalculate all Coords
+ int chunks_high; //!< Chunkwise size of level in the y-direction
+ int chunks_wide; //!< Chunkwise size of level in the x-direction
+ Terrain dead_space; //!< Terrain to fill new chunks with and return for Coords in unpopulated chunks
+ level_theme theme; //!< Will affect monster and maybe item generation
+ level_layout layout; //!< Determines generation algorithm
Terrain terrain_at(Coord c) const
{
Coord rc = c + origin_off;
#define POF_DRESS 0x00010000u
/*! \brief The 'permanent object' database */
-struct Permobj {
+class Permobj {
+public:
char const *name; //!< English-language name of item
char const *plural; //!< English-language plural of item
char const *description; //!< English-language description of item
#include "core.hh"
#endif
-/* XXX struct permon */
#include "pmon_id.hh"
#define PMF_RESIST_FIRE 0x00000001
#define PMF_SMALL 0x80000000
#define PERMON_FLAG_FIELDS 2
-struct Permon {
+/*! \brief Describes the baseline stats of a specific kind of monster */
+class Permon {
+public:
char const *name;
char const *plural;
char const *description;
return rval;
}
+/*! \brief pick a random Chebyshev cardinal */
+Offset random_step(void)
+{
+ switch (zero_die(8))
+ {
+ case 0:
+ return Northwest;
+ case 1:
+ return North;
+ case 2:
+ return Northwest;
+ case 3:
+ return West;
+ case 4:
+ return East;
+ case 5:
+ return Southwest;
+ case 6:
+ return South;
+ case 7:
+ return Southeast;
+ }
+ return Stationary;
+}
+
/* rng.cc */
// vim:cindent
/*! \file u.cc
- * \brief player-character
+ * \brief Player-character functions and data
*/
/*
- * Copyright 2005-2013 Martin Read
+ * Copyright 2005-2014 Martin Read
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#include <limits.h>
#include <string.h>
#include <stdio.h>
+#include <deque>
struct Player u;
return resistances[dtype];
}
-// vim:cindent
-/* u.c */
-// vim:cindent
+/*! \brief Action history for combo detection */
+std::deque<Action> past_actions;
+
+/*! \brief Constants used in combo detection logic */
+enum Combo_phase
+{
+ Combo_invalid,
+ Combo_link,
+ Combo_finisher
+};
+
+/* \brief Process action combos
+ *
+ * This function is responsible for detecting whether the most recently
+ * attempted action is a possible step in a combo, a combo finisher, or a
+ * combo-invalid move (for example, quaffing a potion is a combo breaker). It
+ * uses the contents of the deque past_actions to make the decision.
+ *
+ * \todo Actually detect some combos
+ * \param act Pointer to attempted action
+ * \param revised_act Pointer to storage location for revised action
+ * \return true if revised_act was written to; false otherwise
+ */
+
+bool detect_combo(Action const *act, Action *revised_act)
+{
+ //Combo_phase p;
+ // for now, we use if rather than switch because there are only two
+ // valid action types in a combo: move, and attack.
+ if (act->cmd == WALK)
+ {
+ *revised_act = *act;
+ return true;
+ }
+ else if (act->cmd == ATTACK)
+ {
+ *revised_act = *act;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+/*! \brief Process a player action. */
+Action_cost do_player_action(Action *act)
+{
+ int slot;
+ Offset step;
+ Action redact;
+ bool rewritten = detect_combo(act, &redact);
+ if (rewritten)
+ {
+ act = &redact;
+ }
+ switch (act->cmd)
+ {
+ case WALK:
+ step.y = act->details[0];
+ step.x = act->details[1];
+ return move_player(step);
+
+ case ATTACK:
+ step.y = act->details[0];
+ step.x = act->details[1];
+ return player_attack(step);
+
+ case USE_ACTIVE_SKILL:
+ debug_unimplemented();
+ return Cost_none;
+
+ case ALLOCATE_SKILL_POINT:
+ debug_unimplemented();
+ return Cost_none;
+
+ case GET_ITEM:
+ if (lvl.obj_at(u.pos) != NO_OBJ)
+ {
+ attempt_pickup();
+ return Cost_std;
+ }
+ else
+ {
+ notify_nothing_to_get();
+ return Cost_none;
+ }
+
+ case WIELD_WEAPON:
+ slot = act->details[0];
+ if (slot == SLOT_NOTHING)
+ {
+ return player_unwield(Noise_std);
+ }
+ else
+ {
+ return player_wield(slot, Noise_std);
+ }
+ break;
+
+ case WEAR_ARMOUR:
+ slot = act->details[0];
+ return wear_armour(slot);
+
+ case EMANATE_ARMOUR:
+ if (u.armour == NO_OBJ)
+ {
+ notify_emanate_no_armour();
+ return Cost_none;
+ }
+ return emanate_armour();
+
+ case ZAP_WEAPON:
+ if (u.weapon == NO_OBJ)
+ {
+ notify_zap_no_weapon();
+ return Cost_none;
+ }
+ return zap_weapon();
+
+ case MAGIC_RING:
+ if (u.weapon == NO_OBJ)
+ {
+ notify_magic_no_ring();
+ return Cost_none;
+ }
+ return magic_ring();
+
+ case TAKE_OFF_ARMOUR:
+ if (u.armour != NO_OBJ)
+ {
+ int saved_armour = u.armour;
+ if ((u.resistances[DT_FIRE] == RESIST_ARMOUR) &&
+ (lvl.terrain_at(u.pos) == LAVA))
+ {
+ notify_lava_blocks_unequip();
+ return Cost_none;
+ }
+ u.armour = NO_OBJ;
+ recalc_defence();
+ notify_armour_unequip(saved_armour);
+ return Cost_std;
+ }
+ else
+ {
+ debug_take_off_no_armour();
+ return Cost_none;
+ }
+
+ case GO_DOWN_STAIRS:
+ if (lvl.terrain_at(u.pos) == STAIRS)
+ {
+ leave_level();
+ make_new_level();
+ }
+ else
+ {
+ debug_descend_non_stairs();
+ }
+ return Cost_none;
+
+ case STAND_STILL:
+ return Cost_std;
+
+ case READ_SCROLL:
+ slot = act->details[0];
+ return read_scroll(u.inventory[slot]);
+
+ case EAT_FOOD:
+ slot = act->details[0];
+ return eat_food(u.inventory[slot]);
+
+ case QUAFF_POTION:
+ slot = act->details[0];
+ return quaff_potion(u.inventory[slot]);
+
+ case THROW_FLASK:
+ return Cost_none;
+
+ case REMOVE_RING:
+ return remove_ring();
+
+ case PUT_ON_RING:
+ slot = act->details[0];
+ return put_on_ring(u.inventory[slot]);
+
+ case DROP_ITEM:
+ slot = act->details[0];
+ return drop_obj(slot);
+
+ case SAVE_GAME:
+ game_finished = 1;
+ save_game();
+ return Cost_none;
+
+ case QUIT:
+ game_finished = 1;
+ return Cost_none;
+
+ case WIZARD_DESCEND:
+ if (wizard_mode)
+ {
+ leave_level();
+ make_new_level();
+ }
+ else
+ {
+ debug_wizmode_violation();
+ }
+ return Cost_none;
+
+ case WIZARD_LEVELUP:
+ if (wizard_mode)
+ {
+ if (lev_threshold(u.level) != INT_MAX)
+ {
+ gain_experience((lev_threshold(u.level) - u.experience) + 1);
+ }
+ }
+ else
+ {
+ debug_wizmode_violation();
+ }
+ return Cost_none;
+ }
+ return Cost_none;
+}
+
+/* u.cc */
+// vim:cindent:expandtab
extern void wrapped_system(char const *cmd);
extern void wrapped_fread(void *buf, size_t size, size_t nmemb, FILE *stream);
extern int load_game(void);
+extern void save_game(void);
#endif