coord.cc
coord.hh
core.hh
+deeds.cc
default.permobjs
default.permons
display.hh
map.cc
map.hh
mapgen.hh
+mon1.cc
mon2.cc
-monsters.cc
+mon3.cc
monsters.hh
notes.txt
notify.hh
notify-local-tty.cc
-objects.cc
objects.hh
+obj1.cc
+obj2.cc
permobj.hh
permon.hh
player.hh
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:=cave.o 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 shrine.o sorcery.o u.o util.o
+HANDWRITTEN_OBJS:=cave.o combat.o coord.o deeds.o display-nc.o fov.o log.o main.o map.o mon1.o mon2.o mon3.o notify-local-tty.o obj1.o obj2.o pmon2.o rng.o shrine.o sorcery.o u.o util.o
OBJS:=$(GENERATED_OBJS) $(HANDWRITTEN_OBJS)
GAME:=obumbrata
MAJVERS:=1
coord.o: $(srcdir)/coord.cc $(srcdir)/coord.hh
+deeds.o: $(srcdir)/deeds.cc $(srcdir)/combat.hh $(srcdir)/$(GAME).hh $(srcdir)/notify.hh $(srcdir)/monsters.hh $(srcdir)/objects.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
+
display-nc.o: $(srcdir)/display-nc.cc $(srcdir)/$(GAME).hh $(srcdir)/display.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh $(srcdir)/map.hh $(srcdir)/objects.hh $(srcdir)/monsters.hh $(srcdir)/permon.hh $(srcdir)/permobj.hh
log.o: $(srcdir)/log.cc $(srcdir)/objects.hh $(srcdir)/monsters.hh $(srcdir)/player.hh $(srcdir)/map.hh $(srcdir)/util.h
map.o: $(srcdir)/map.cc $(srcdir)/$(GAME).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)/$(GAME).hh $(srcdir)/monsters.hh $(srcdir)/notify.hh $(srcdir)/objects.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
+mon1.o: $(srcdir)/mon1.cc $(srcdir)/$(GAME).hh $(srcdir)/monsters.hh $(srcdir)/notify.hh $(srcdir)/objects.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
+
+mon2.o: $(srcdir)/mon2.cc $(srcdir)/$(GAME).hh $(srcdir)/sorcery.hh $(srcdir)/monsters.hh $(srcdir)/map.hh $(srcdir)/notify.hh $(srcdir)/objects.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
-mon2.o: $(srcdir)/mon2.cc $(srcdir)/$(GAME).hh $(srcdir)/sorcery.hh $(srcdir)/monsters.hh $(srcdir)/notify.hh $(srcdir)/objects.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
+mon3.o: $(srcdir)/mon3.cc $(srcdir)/$(GAME).hh $(srcdir)/monsters.hh $(srcdir)/notify.hh $(srcdir)/map.hh $(srcdir)/objects.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
notify-local-tty.o: $(srcdir)/notify-local-tty.cc $(srcdir)/$(GAME).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
pmon2.o: $(srcdir)/pmon2.cc $(srcdir)/$(GAME).hh $(srcdir)/notify.hh $(srcdir)/monsters.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
-objects.o: $(srcdir)/objects.cc $(srcdir)/$(GAME).hh $(srcdir)/notify.hh $(srcdir)/objects.hh $(srcdir)/monsters.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
+obj1.o: $(srcdir)/obj1.cc $(srcdir)/$(GAME).hh $(srcdir)/notify.hh $(srcdir)/objects.hh $(srcdir)/monsters.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
+
+obj2.o: $(srcdir)/obj2.cc $(srcdir)/$(GAME).hh $(srcdir)/notify.hh $(srcdir)/objects.hh $(srcdir)/monsters.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
shrine.o: $(srcdir)/shrine.cc $(srcdir)/$(GAME).hh $(srcdir)/notify.hh $(srcdir)/objects.hh $(srcdir)/monsters.hh $(srcdir)/map.hh $(srcdir)/mapgen.hh
sorcery.o: $(srcdir)/sorcery.cc $(srcdir)/$(GAME).hh $(srcdir)/notify.hh $(srcdir)/sorcery.hh $(srcdir)/objects.hh $(srcdir)/monsters.hh ./pobj_id.hh ./pmon_id.hh $(srcdir)/player.hh
c = l->random_point(1);
} while (!(terrain_props[l->terrain_at(c)].flags & TFLAG_floor) ||
(l->flags_at(c) & MAPFLAG_HARDWALL));
- l->add_stairs_at(c, STAIRS_DOWN, l->self.naive_next());
+ l->add_stairs_at(c, PORTAL_ONWARD, l->self.naive_next());
do
{
d = l->random_point(1);
} while (!(terrain_props[l->terrain_at(d)].flags & TFLAG_floor) ||
(l->flags_at(d) & MAPFLAG_HARDWALL) ||
(d.dist_cheb(c) < (10 - (stair_tries / 40))));
- l->add_stairs_at(d, STAIRS_UP, l->self.naive_prev());
+ l->add_stairs_at(d, PORTAL_LANDING, l->self.naive_prev());
}
/*! \brief Excavate a cave level.
/* combos begin here */
CMD_POWER_ATTACK
};
+#define LAST_COMMAND (CMD_POWER_ATTACK)
+#define NUM_COMMANDS (1 + LAST_COMMAND)
/*! \brief Identification code for ways to die
*
--- /dev/null
+/*! \file deeds.cc
+ * \brief Player-character action implementations
+ */
+
+/*
+ * 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 "obumbrata.hh"
+#include "combat.hh"
+#include "objects.hh"
+#include "player.hh"
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <deque>
+
+static Action_cost deed_walk(Action const *act)
+{
+ Offset step = { (int32_t) act->details[0], (int32_t) act->details[1] };
+ return move_player(step);
+}
+
+static Action_cost deed_stand_still(Action const *act)
+{
+ return Cost_std;
+}
+
+static Action_cost deed_ascend(Action const *act)
+{
+ Terrain t = lvl.terrain_at(u.pos);
+ if (terrain_props[t].flags & TFLAG_portal)
+ {
+ if (terrain_props[t].flags & TFLAG_ascend)
+ {
+ notify_inert_portal();
+ }
+ else
+ {
+ leave_level();
+ make_new_level();
+ }
+ }
+ else
+ {
+ if (terrain_props[t].flags & TFLAG_ascend)
+ {
+ notify_ascent_blocked();
+ }
+ else
+ {
+ debug_ascend_non_stairs();
+ }
+ }
+ return Cost_none;
+}
+
+static Action_cost deed_descend(Action const *act)
+{
+ Terrain t = lvl.terrain_at(u.pos);
+ if (terrain_props[t].flags & TFLAG_descend)
+ {
+ leave_level();
+ make_new_level();
+ }
+ else
+ {
+ debug_descend_non_stairs();
+ }
+ return Cost_none;
+}
+
+static Action_cost deed_attack(Action const *act)
+{
+ Offset step = { (int32_t) act->details[0], (int32_t) act->details[1] };
+ return player_attack(step);
+}
+
+static Action_cost deed_get(Action const *act)
+{
+ if (lvl.obj_at(u.pos) != NO_OBJ)
+ {
+ attempt_pickup();
+ return Cost_std;
+ }
+ else
+ {
+ notify_nothing_to_get();
+ return Cost_none;
+ }
+}
+
+static Action_cost deed_drop(Action const *act)
+{
+ int slot = (int) act->details[0];
+ return drop_obj(slot);
+}
+
+static Action_cost deed_wield(Action const *act)
+{
+ int slot = (int) act->details[0];
+ if (slot == SLOT_NOTHING)
+ {
+ return player_unwield(Noise_std);
+ }
+ else
+ {
+ return player_wield(u.inventory[slot], Noise_std);
+ }
+}
+
+static Action_cost deed_armour_on(Action const *act)
+{
+ int slot = (int) act->details[0];
+ return wear_armour(u.inventory[slot]);
+}
+
+static Action_cost deed_armour_off(Action const *act)
+{
+ if (u.armour != NO_OBJ)
+ {
+ /* this actually belongs in a sensible place. */
+ 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;
+ }
+}
+
+static Action_cost deed_ring_on(Action const *act)
+{
+ int slot = act->details[0];
+ return put_on_ring(u.inventory[slot]);
+}
+
+static Action_cost deed_ring_off(Action const *act)
+{
+ return remove_ring();
+}
+
+static Action_cost deed_quaff(Action const *act)
+{
+ int slot = act->details[0];
+ return quaff_potion(u.inventory[slot]);
+}
+
+static Action_cost deed_read(Action const *act)
+{
+ int slot = act->details[0];
+ return read_scroll(u.inventory[slot]);
+}
+
+static Action_cost deed_ringmagic(Action const *act)
+{
+ if (u.ring == NO_OBJ)
+ {
+ notify_magic_no_ring();
+ return Cost_none;
+ }
+ return magic_ring();
+}
+
+static Action_cost deed_zap(Action const *act)
+{
+ if (u.weapon == NO_OBJ)
+ {
+ notify_zap_no_weapon();
+ return Cost_none;
+ }
+ return zap_weapon();
+}
+
+static Action_cost deed_emanate(Action const *act)
+{
+ if (u.armour == NO_OBJ)
+ {
+ notify_emanate_no_armour();
+ return Cost_none;
+ }
+ return emanate_armour();
+}
+
+static Action_cost deed_eat(Action const *act)
+{
+ int slot = act->details[0];
+ return eat_food(u.inventory[slot]);
+}
+
+static Action_cost deed_combo_powatk(Action const *act)
+{
+ Offset step = { (int32_t) act->details[0], (int32_t) act->details[1] };
+ return player_power_attack(step);
+}
+
+static Action_cost deed_wiz_descend(Action const *act)
+{
+ if (wizard_mode)
+ {
+ leave_level();
+ make_new_level();
+ }
+ else
+ {
+ debug_wizmode_violation();
+ }
+ return Cost_none;
+}
+
+static Action_cost deed_wiz_levup(Action const *act)
+{
+ 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;
+}
+
+static Action_cost deed_quit(Action const *act)
+{
+ game_finished = 1;
+ return Cost_none;
+}
+
+static Action_cost deed_save(Action const *act)
+{
+ game_finished = 1;
+ save_game();
+ return Cost_none;
+}
+
+deed_func deed_funcs[NUM_COMMANDS] =
+{
+ deed_walk,
+ deed_stand_still,
+ deed_ascend,
+ deed_descend,
+ deed_attack,
+ deed_get,
+ deed_drop,
+ deed_wield,
+ deed_armour_on,
+ deed_armour_off,
+ deed_ring_on,
+ deed_ring_off,
+ deed_quaff,
+ deed_read,
+ nullptr, // deed_throw
+ deed_eat,
+ deed_emanate,
+ deed_zap,
+ deed_ringmagic,
+ nullptr, // deed_use_skill
+ nullptr, // deed_alloc_skill
+ deed_save,
+ deed_quit,
+ deed_wiz_levup,
+ deed_wiz_descend,
+ deed_combo_powatk
+};
+
+/* deeds.cc */
+// vim:cindent:expandtab
break;
case '<':
{
- Terrain t = lvl.terrain_at(u.pos);
- if (terrain_props[t].flags & TFLAG_ascend)
+ Terrain t = lvl.terrain_at(u.pos);
+ if (terrain_props[t].flags & TFLAG_portal)
+ {
+ if (terrain_props[t].flags & TFLAG_ascend)
+ {
+ act->cmd = GO_UP_STAIRS;
+ return;
+ }
+ else
+ {
+ act->cmd = GO_DOWN_STAIRS;
+ return;
+ }
+ }
+ else if (terrain_props[t].flags & TFLAG_ascend)
{
- act->cmd = GO_UP_STAIRS;
- return;
+ act->cmd = GO_UP_STAIRS;
+ return;
}
else
{
- print_msg("There are no stairs here.\n");
+ print_msg("There are no portals or upward stairs here.\n");
}
- // TODO accept this keystroke as "enter portal" too
}
break;
case '>':
}
else
{
- print_msg("There are no stairs here.\n");
+ print_msg("There are no stairs or portals here.\n");
}
- // TODO accept this keystroke as "enter portal" too
}
break;
case '5':
print_msg("e eat something edible\n");
print_msg("g pick up an item (also 0 or comma)\n");
print_msg("d drop an item\n");
- print_msg("> go down stairs\n");
+ print_msg("< go down stairs or enter a magic portal\n");
+ print_msg("> go down stairs or enter a magic portal\n");
print_msg("5 do nothing (wait until next action)\n");
print_msg(". do nothing (wait until next action)\n");
print_msg("\nPress any key to continue...\n");
print_msg("z activate your weapon's magical power (if any)\n");
print_msg("m activate your ring's magical power (if any)\n");
print_msg("E activate your armour's magical power (if any)\n");
- print_msg("\nPress any key to continue...\n");
- wgetch(message_window);
+ print_msg("\n");
print_msg("OTHER COMMANDS\n");
print_msg("S save and exit\n");
print_msg("X quit without saving\n");
print_msg("SYMBOLS\n");
print_msg("@ you\n");
print_msg(". floor\n");
- print_msg("> stairs down\n");
+ print_msg("☊ magic portal\n");
print_msg("# wall\n");
print_msg("+ a door\n");
print_msg(") a weapon\n");
{ "altar", '_', "_", Gcol_l_grey, 0 },
{ "upward stairs", '<', "<", Gcol_l_grey, TFLAG_ascend },
{ "downward stairs", '>', ">", Gcol_l_grey, TFLAG_descend },
+ { "inert portal", '^', "☊", Gcol_d_grey, TFLAG_portal | TFLAG_ascend },
+ { "active portal", '^', "☊", Gcol_white, TFLAG_portal | TFLAG_descend },
{ "lava", '}', "≈", Gcol_red, TFLAG_fire_hazard },
{ "water", '}', "≈", Gcol_blue, TFLAG_drown_hazard },
};
#include <deque>
/* XXX enum terrain_num */
enum Terrain {
- WALL = 0, MASONRY_WALL, AMETHYST_WALL, IRON_WALL, SKIN_WALL, BONE_WALL, DOOR, FLOOR, AMETHYST_FLOOR, IRON_FLOOR, SKIN_FLOOR, BONE_FLOOR, ALTAR, STAIRS_UP, STAIRS_DOWN, LAVA, WATER
+ WALL = 0, MASONRY_WALL, AMETHYST_WALL, IRON_WALL, SKIN_WALL, BONE_WALL, DOOR, FLOOR, AMETHYST_FLOOR, IRON_FLOOR, SKIN_FLOOR, BONE_FLOOR, ALTAR, STAIRS_UP, STAIRS_DOWN, PORTAL_LANDING, PORTAL_ONWARD, LAVA, WATER
};
#define MAX_TERRAIN (WATER)
#define NUM_TERRAINS (1 + MAX_TERRAIN)
return NO_MON;
}
-/* The rules:
- * A monster gets eight entries.
- */
-
-struct Death_drop_entry
-{
- int pm_ref;
- void (*func)(Coord c);
-};
-
-void goblin_death_drop(Coord c)
-{
- if (!zero_die(4))
- {
- create_obj_near(PO_DAGGER, 1, c);
- }
-}
-
-void thug_death_drop(Coord c)
-{
- if (!zero_die(4))
- {
- create_obj_near(PO_MACE, 1, c);
- }
- else if (!zero_die(3))
- {
- create_obj_near(PO_LEATHER_ARMOUR, 1, c);
- }
-}
-
-void hunter_death_drop(Coord c)
-{
- if (!zero_die(6))
- {
- create_obj_near(PO_BOW, 1, c);
- }
-}
-
-void duellist_death_drop(Coord c)
-{
- if (!zero_die(6))
- {
- create_obj_near(PO_LONG_SWORD, 1, c);
- }
-}
-
-void wizard_death_drop(Coord c)
-{
- if (!zero_die(4))
- {
- create_obj_class_near(POCLASS_SCROLL, 1, false, c);
- }
- else if (!zero_die(3))
- {
- create_obj_class_near(POCLASS_POTION, 1, false, c);
- }
-}
-
-void warlord_death_drop(Coord c)
-{
- if (!zero_die(3))
- {
- create_obj_near(PO_RUNESWORD, 1, c);
- }
-}
-
-void demon_death_drop(Coord c)
-{
- if (!zero_die(100))
- {
- create_obj_near(PO_DEVIL_SPLEEN, 1, c);
- }
-}
-
-Death_drop_entry death_drops[] =
-{
- { PM_GOBLIN, goblin_death_drop },
- { PM_THUG, thug_death_drop },
- { PM_GOON, thug_death_drop },
- { PM_HUNTER, hunter_death_drop },
- { PM_DUELLIST, duellist_death_drop },
- { PM_WIZARD, wizard_death_drop },
- { PM_WARLORD, warlord_death_drop },
- { PM_DEMON, demon_death_drop },
- { NO_PMON, nullptr }
-};
-
+/*! \brief Handle a monster's death drop. */
void death_drop(Mon_handle mon)
{
Mon const *mptr = mon_snap(mon);
--- /dev/null
+/*! \file mon3.cc
+ * \brief Death drop tables and similar things
+ */
+
+/* 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.
+ */
+
+#define MON3_CC
+#include "obumbrata.hh"
+#include "monsters.hh"
+#include "objects.hh"
+
+static void goblin_death_drop(Coord c)
+{
+ if (!zero_die(4))
+ {
+ create_obj_near(PO_DAGGER, 1, c);
+ }
+}
+
+static void thug_death_drop(Coord c)
+{
+ if (!zero_die(4))
+ {
+ create_obj_near(PO_MACE, 1, c);
+ }
+ else if (!zero_die(3))
+ {
+ create_obj_near(PO_LEATHER_ARMOUR, 1, c);
+ }
+}
+
+static void hunter_death_drop(Coord c)
+{
+ if (!zero_die(6))
+ {
+ create_obj_near(PO_BOW, 1, c);
+ }
+}
+
+static void duellist_death_drop(Coord c)
+{
+ if (!zero_die(6))
+ {
+ create_obj_near(PO_LONG_SWORD, 1, c);
+ }
+}
+
+static void wizard_death_drop(Coord c)
+{
+ if (!zero_die(4))
+ {
+ create_obj_class_near(POCLASS_SCROLL, 1, false, c);
+ }
+ else if (!zero_die(3))
+ {
+ create_obj_class_near(POCLASS_POTION, 1, false, c);
+ }
+}
+
+static void warlord_death_drop(Coord c)
+{
+ if (!zero_die(3))
+ {
+ create_obj_near(PO_RUNESWORD, 1, c);
+ }
+}
+
+static void demon_death_drop(Coord c)
+{
+ if (!zero_die(100))
+ {
+ create_obj_near(PO_DEVIL_SPLEEN, 1, c);
+ }
+}
+
+Death_drop_entry death_drops[] =
+{
+ { PM_GOBLIN, goblin_death_drop },
+ { PM_THUG, thug_death_drop },
+ { PM_GOON, thug_death_drop },
+ { PM_HUNTER, hunter_death_drop },
+ { PM_DUELLIST, duellist_death_drop },
+ { PM_WIZARD, wizard_death_drop },
+ { PM_WARLORD, warlord_death_drop },
+ { PM_DEMON, demon_death_drop },
+ { NO_PMON, nullptr }
+};
+
+/* mon3.cc */
+// vim:cindent
return ((iter == monsters.end()) ? nullptr : &(iter->second));
}
+struct Death_drop_entry
+{
+ int pm_ref;
+ void (*func)(Coord c);
+};
+
+extern Death_drop_entry death_drops[];
+
#define PLAYER_MON (-2)
-/* XXX monsters.c data and funcs */
void update_mon(Mon_handle mon);
void mon_acts(Mon_handle mon);
void death_drop(Mon_handle mon);
print_msg("A mysterious force prevents you climbing the stairs.\n");
}
+void notify_inert_portal(void)
+{
+ print_msg("This side of the portal is completely inert.\n");
+}
+
void notify_wasted_gain(void)
{
print_msg("You feel disappointed.\n");
void notify_change_of_depth(void)
{
status_updated = true;
- print_msg("Welcome to level %d of the Abyss.\n", depth);
+ print_msg("Welcome to level %d.\n", depth);
}
void notify_load_complete(void)
void notify_change_of_depth(void);
void notify_load_complete(void);
void notify_ascent_blocked(void);
+void notify_inert_portal(void);
// Debugging notifications
void debug_move_oob(Coord c);
return Cost_std;
}
-/*! \brief Effect of quaffing a body potion */
-static void body_potion_quaff(void)
-{
- gain_body(1);
-}
-
-/*! \brief Effect of quaffing a agility potion */
-static void agility_potion_quaff(void)
-{
- gain_agility(1);
-}
-
-/*! \brief Effect of quaffing a healing potion */
-static void healing_potion_quaff(void)
-{
- int healpercent = inc_flat(30, 50);
- int healamount = (healpercent * ((u.hpmax > 60) ? u.hpmax : 60)) / 100;
- heal_u(healamount, 1, 1);
-}
-
-/*! \brief Effect of quaffing a restoration potion */
-static void restoration_potion_quaff(void)
-{
- notify_quaff_potion_restoration();
- if (u.bdam && ((!u.adam) || zero_die(2)))
- {
- u.bdam = 0;
- notify_body_restore();
- }
- else if (u.adam)
- {
- u.adam = 0;
- notify_agility_restore();
- }
-}
-
-struct Potion_table_entry
-{
- int pobj;
- void (*quaff_func)(void);
-};
-
-static Potion_table_entry quaff_table[] =
-{
- { PO_BODY_POTION, body_potion_quaff },
- { PO_AGILITY_POTION, agility_potion_quaff },
- { PO_HEALING_POTION, healing_potion_quaff },
- { PO_RESTORATION_POTION, restoration_potion_quaff },
- { NO_POBJ, nullptr },
-};
-
/*! \brief Consume a potion */
Action_cost quaff_potion(Obj_handle obj)
{
Obj *optr = obj_snapv(obj);
int i;
- for (i = 0; quaff_table[i].pobj != NO_POBJ; ++i)
+ for (i = 0; potion_table[i].pobj != NO_POBJ; ++i)
{
- if (quaff_table[i].pobj == optr->po_ref)
+ if (potion_table[i].pobj == optr->po_ref)
{
- quaff_table[i].quaff_func();
+ potion_table[i].quaff_func();
consume_obj(obj);
return Cost_std;
}
--- /dev/null
+/* \file obj2.cc
+ * \brief Per-PO object use functions for Obumbrata et Velata
+ */
+
+/* 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.
+ */
+
+#define OBJ2_CC
+#include "obumbrata.hh"
+#include "objects.hh"
+#include "monsters.hh"
+
+#include <string.h>
+
+/*! \brief Effect of quaffing a body potion */
+static void body_potion_quaff(void)
+{
+ gain_body(1);
+}
+
+/*! \brief Effect of quaffing a agility potion */
+static void agility_potion_quaff(void)
+{
+ gain_agility(1);
+}
+
+/*! \brief Effect of quaffing a healing potion */
+static void healing_potion_quaff(void)
+{
+ int healpercent = inc_flat(30, 50);
+ int healamount = (healpercent * ((u.hpmax > 60) ? u.hpmax : 60)) / 100;
+ heal_u(healamount, 1, 1);
+}
+
+/*! \brief Effect of quaffing a restoration potion */
+static void restoration_potion_quaff(void)
+{
+ notify_quaff_potion_restoration();
+ if (u.bdam && ((!u.adam) || zero_die(2)))
+ {
+ u.bdam = 0;
+ notify_body_restore();
+ }
+ else if (u.adam)
+ {
+ u.adam = 0;
+ notify_agility_restore();
+ }
+}
+
+/*! \brief Lookup table for effects of operations involving potions */
+Potion_table_entry potion_table[] =
+{
+ { PO_BODY_POTION, body_potion_quaff },
+ { PO_AGILITY_POTION, agility_potion_quaff },
+ { PO_HEALING_POTION, healing_potion_quaff },
+ { PO_RESTORATION_POTION, restoration_potion_quaff },
+ { NO_POBJ, nullptr }
+};
+
+/*! \brief Lookup table for effects of reading scrolls */
+Scroll_table_entry scroll_table[] =
+{
+ { NO_POBJ, nullptr }
+};
+
+/* obj2.cc */
+// vim:cindent
extern std::map<Obj_handle, Obj> objects;
extern Obj_handle first_free_obj_handle;
+struct Potion_table_entry
+{
+ int pobj;
+ void (*quaff_func)(void);
+};
+extern Potion_table_entry potion_table[];
+
+struct Scroll_table_entry
+{
+ int pobj;
+ void (*read_func)(void);
+};
+
+extern Scroll_table_entry scroll_table[];
+
/* XXX objects.cc data and funcs */
void asprint_obj_name(char **s, Obj_handle obj);
void sprint_obj_name(char *s, Obj_handle obj, int len);
#define SLOT_CANCEL (-1)
#define SLOT_NOTHING (-2)
-/* XXX u.c data and funcs */
extern Player u;
+typedef Action_cost (*deed_func)(Action const *act);
+
+extern deed_func deed_funcs[NUM_COMMANDS];
+
void u_init(char const *name);
void write_char_dump(void);
int do_death(Death d, char const *what);
case DOOR:
case STAIRS_UP:
case STAIRS_DOWN:
+ case PORTAL_LANDING:
+ case PORTAL_ONWARD:
case ALTAR:
reloc_player(c);
return Cost_std;
*/
Action_cost do_player_action(Action *act)
{
- int slot;
- Offset step;
Action redact;
bool rewritten = action_rewrite(act, &redact);
if (rewritten)
{
act = &redact;
}
- switch (act->cmd)
+ if (act->cmd == REJECTED_ACTION)
{
- case REJECTED_ACTION:
return Cost_none;
-
- case CMD_POWER_ATTACK:
- step.y = act->details[0];
- step.x = act->details[1];
- return player_power_attack(step);
-
- 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();
+ }
+ if (act->cmd > LAST_COMMAND)
+ {
return Cost_none;
-
- case ALLOCATE_SKILL_POINT:
+ }
+ if (deed_funcs[act->cmd] == nullptr)
+ {
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(u.inventory[slot], Noise_std);
- }
- break;
-
- case WEAR_ARMOUR:
- slot = act->details[0];
- return wear_armour(u.inventory[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_UP_STAIRS:
- if (lvl.terrain_at(u.pos) == STAIRS_UP)
- {
- notify_ascent_blocked();
- }
- else
- {
- debug_ascend_non_stairs();
- }
- return Cost_none;
-
- case GO_DOWN_STAIRS:
- if (lvl.terrain_at(u.pos) == STAIRS_DOWN)
- {
- 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;
+ return deed_funcs[act->cmd](act);
}
void player_cleanup(void)