From: Martin Read Date: Tue, 18 Feb 2014 23:42:25 +0000 (+0000) Subject: Tech-demo combo system, and some other things. X-Git-Tag: stretchy-levels~7 X-Git-Url: http://git.blackswordsonics.com/?a=commitdiff_plain;h=dac49d497e6dada7c72180ddead9b8ce2c9c3b55;p=victrix-abyssi Tech-demo combo system, and some other things. * core.hh: New command CMD_POWER_ATTACK, and some Doxygenation. * default.permobjs: All weapons now flagged melee or ranged. * monsters.cc, monsters.hh: Elimination of newsym() calls and addition of new functions to adjust flow of updates. * notify-local-tty.cc, notify.hh: New notifications galore. * permobj.hh, pobj_comp: New item flags * player.hh: new boolean functions for examining player's wielding status * u.cc: Action rewriting system with tech-demo combo detection case. Sir Not Appearing In This Commit: Making a power attack be an actual thing instead of just an ordinary attack. --- diff --git a/core.hh b/core.hh index 61fe154..d2cbbe0 100644 --- a/core.hh +++ b/core.hh @@ -99,7 +99,7 @@ enum Gamecolour #define LAST_FIXED_COLOUR Gcol_silver #define LAST_COLOUR Gcol_prio_bug -/* XXX enum damtyp - types of damage. */ +/*! \brief Identification code for damage types */ enum Damtyp { DT_PHYS = 0, DT_COLD, DT_FIRE, DT_NECRO, DT_ELEC, DT_HELLFIRE, DT_POISON, @@ -107,30 +107,36 @@ enum Damtyp { }; #define DT_COUNT (1 + DT_DROWNING) -/* XXX enum Game_cmd - player actions. */ +/*! \brief Identification code for player actions */ enum Game_cmd { - WALK, STAND_STILL, GO_DOWN_STAIRS, ATTACK, + REJECTED_ACTION = -1, WALK, STAND_STILL, GO_DOWN_STAIRS, ATTACK, GET_ITEM, DROP_ITEM, WIELD_WEAPON, WEAR_ARMOUR, TAKE_OFF_ARMOUR, PUT_ON_RING, REMOVE_RING, QUAFF_POTION, READ_SCROLL, THROW_FLASK, EAT_FOOD, EMANATE_ARMOUR, ZAP_WEAPON, MAGIC_RING, USE_ACTIVE_SKILL, ALLOCATE_SKILL_POINT, SAVE_GAME, QUIT, - WIZARD_LEVELUP, WIZARD_DESCEND + WIZARD_LEVELUP, WIZARD_DESCEND, + /* combos begin here */ + CMD_POWER_ATTACK }; -/* XXX enum Death */ -/* Sadly, there are not 52 kinds of way to die. */ +/*! \brief Identification code for ways to die + * + * Sadly, there are not 52 kinds of way to die. + */ enum Death { DEATH_KILLED, DEATH_KILLED_MON, DEATH_BODY, DEATH_AGILITY, DEATH_LASH, DEATH_RIBBONS }; +/*! \brief Fell powers that might influence the Princess's fate + */ enum Fell_powers { - FePo_iron, // boosted by ironguard armour, hellglaive - FePo_decay, // boosted by foetid vestments, - FePo_bone, // boosted by lich's robe, vampire ring - FePo_flesh // boosted by t's lash or the ribbons, + FePo_iron, + FePo_decay, + FePo_bone, + FePo_flesh }; #define TOTAL_FELL_POWERS (1 + FePo_flesh) @@ -140,7 +146,9 @@ enum Fell_powers { #define RESIST_RING 0x00010000u #define RESIST_ARMOUR 0x00020000u -/*! \brief Represent an in-game action in more detail than Game_cmd +/*! \brief Represent an in-game action by the player + * + * This might, at some point, get adapted to */ struct Action { diff --git a/default.permobjs b/default.permobjs index b6858e2..27e441b 100644 --- a/default.permobjs +++ b/default.permobjs @@ -33,6 +33,7 @@ POWER 4 POWER2 0 DEPTH 1 DAMAGEABLE +MELEE_WEAPON WEAPON long sword PLURAL long swords @@ -45,6 +46,7 @@ POWER 10 POWER2 0 DEPTH 4 DAMAGEABLE +MELEE_WEAPON WEAPON mace PLURAL maces @@ -57,6 +59,7 @@ POWER 7 POWER2 0 DEPTH 2 DAMAGEABLE +MELEE_WEAPON WEAPON runesword PLURAL runeswords @@ -69,6 +72,7 @@ POWER 20 POWER2 0 DEPTH 12 DAMAGEABLE +MELEE_WEAPON WEAPON hellglaive PLURAL hellglaives @@ -83,6 +87,7 @@ DEPTH 30 NOTIFY_EQUIP DAMAGEABLE BREAK_REACT +MELEE_WEAPON WEAPON plague scythe PLURAL plague sycthes @@ -95,6 +100,7 @@ POWER 20 POWER2 0 DEPTH 30 NOTIFY_EQUIP +MELEE_WEAPON WEAPON tormentor's lash PLURAL tormentor's lashes @@ -109,6 +115,7 @@ DEPTH 30 NOTIFY_EQUIP DAMAGEABLE BREAK_REACT +MELEE_WEAPON WEAPON death staff PLURAL death staves @@ -121,6 +128,7 @@ POWER 18 POWER2 0 DEPTH 30 NOTIFY_EQUIP +MELEE_WEAPON WEAPON staff of fire PLURAL staves of fire @@ -134,6 +142,7 @@ POWER2 0 DEPTH 20 DAMAGEABLE ACTIVATABLE +MELEE_WEAPON WEAPON bow PLURAL bows @@ -146,7 +155,7 @@ POWER 8 POWER2 0 DEPTH 1 DAMAGEABLE - +RANGED_WEAPON WEAPON crossbow PLURAL crossbows DESC A crossbow. @@ -158,6 +167,7 @@ POWER 16 POWER2 0 DEPTH 6 DAMAGEABLE +RANGED_WEAPON WEAPON thunderbow PLURAL thunderbows @@ -170,6 +180,7 @@ POWER 16 POWER2 0 DEPTH 30 DAMAGEABLE +RANGED_WEAPON POTION healing potion PLURAL healing potions diff --git a/monsters.cc b/monsters.cc index 4c667a9..6f3d4cc 100644 --- a/monsters.cc +++ b/monsters.cc @@ -145,7 +145,10 @@ int create_mon(int pm_idx, Coord c) } monsters[mon].awake = false; lvl.set_mon_at(c, mon); - newsym(c); + if (mon_visible(mon)) + { + notify_new_mon_at(c, mon); + } return mon; } } @@ -298,26 +301,39 @@ void heal_mon(int mon, int amount, int cansee) } } +void unplace_mon(int mon) +{ + lvl.set_mon_at(monsters[mon].pos, NO_MON); + monsters[mon].used = false; +} + +/*! \brief Handle the death of a monster + * + * \todo Support special effects on monster death + */ +void kill_mon(int mon, bool by_you) +{ + death_drop(mon); // phat lewt! + monsters[mon].hpcur = -1; // Set HP to -1 so nothing will think it's alive + unplace_mon(mon); // cleanup + if (by_you) + { + notify_player_killed_mon(mon); + gain_experience(permons[monsters[mon].mon_id].exp); + } + else if (mon_visible(mon)) + { + notify_mon_dies(mon); + } +} + void damage_mon(int mon, int amount, bool by_you) { Mon *mptr; mptr = monsters + mon; if (amount >= mptr->hpcur) { - if (by_you) - { - notify_player_killed_mon(mon); - gain_experience(permons[mptr->mon_id].exp); - } - else if (mon_visible(mon)) - { - notify_mon_dies(mon); - } - death_drop(mon); - lvl.set_mon_at(mptr->pos, NO_MON); - newsym(mptr->pos); - mptr->used = 0; - map_updated = 1; + kill_mon(mon, by_you); display_update(); } else @@ -386,6 +402,7 @@ int knockback_mon(int mon, Offset step, bool cansee, bool by_you) /* 0 = blocked, 1 = knocked, 2 = killed */ Mon *mptr = monsters + mon; Coord c = mptr->pos + step; + Coord savedpos = mptr->pos; Terrain terr = lvl.terrain_at(c); if (mptr->resists(DT_KNOCKBACK)) @@ -404,6 +421,7 @@ int knockback_mon(int mon, Offset step, bool cansee, bool by_you) } return 0; } + reloc_mon(mon, c); switch (terr) { case LAVA: @@ -426,7 +444,7 @@ int knockback_mon(int mon, Offset step, bool cansee, bool by_you) } if (!mptr->resists(DT_FIRE)) { - damage_mon(mon, 9999, by_you); + kill_mon(mon, by_you); return 2; } } @@ -451,7 +469,7 @@ int knockback_mon(int mon, Offset step, bool cansee, bool by_you) } if (!mptr->resists(DT_DROWNING)) { - damage_mon(mon, 9999, by_you); + kill_mon(mon, by_you); return 2; } } @@ -459,7 +477,6 @@ int knockback_mon(int mon, Offset step, bool cansee, bool by_you) default: break; } - reloc_mon(mon, c); return 1; } @@ -467,10 +484,10 @@ void reloc_mon(int mon, Coord newpos) { Mon *mptr = monsters + mon; lvl.set_mon_at(mptr->pos, NO_MON); - newsym(mptr->pos); + notify_new_mon_at(mptr->pos, NO_MON); mptr->pos = newpos; lvl.set_mon_at(mptr->pos, mon); - newsym(mptr->pos); + notify_new_mon_at(mptr->pos, mon); } void move_mon(int mon, Coord c) diff --git a/monsters.hh b/monsters.hh index 535df27..fc8fd38 100644 --- a/monsters.hh +++ b/monsters.hh @@ -82,6 +82,8 @@ extern void reloc_mon(int mon, Coord c); extern Pass_fail teleport_mon(int mon); /* Randomly relocate monster. */ extern Pass_fail teleport_mon_to_you(int mon); /* Relocate monster to your vicinity. */ extern void heal_mon(int mon, int amount, int cansee); +extern void kill_mon(int mon, bool by_you); +extern void unplace_mon(int mon); /* XXX mon2.c data and funcs */ extern void select_space(int *py, int *px, int dy, int dx, int selection_mode); diff --git a/notify-local-tty.cc b/notify-local-tty.cc index 00b9f15..b9738c1 100644 --- a/notify-local-tty.cc +++ b/notify-local-tty.cc @@ -385,8 +385,9 @@ void notify_player_hurt_mon(int mon, int damage) void notify_player_killed_mon(int mon) { + newsym(monsters[mon].pos); print_msg("You kill "); - if (mon_visible(mon)) + if (occupant_visible(monsters[mon].pos)) { print_mon_name(mon, 1); } @@ -399,8 +400,12 @@ void notify_player_killed_mon(int mon) void notify_mon_dies(int mon) { - print_mon_name(mon, 2); - print_msg(" dies.\n"); + newsym(monsters[mon].pos); + if (occupant_visible(monsters[mon].pos)) + { + print_mon_name(mon, 2); + print_msg(" dies.\n"); + } } void notify_knockback_mon_resisted(int mon) @@ -915,6 +920,12 @@ void notify_pack_full(void) { print_msg(Msg_prio::Alert, "Your pack is full.\n"); } + +void notify_new_mon_at(Coord c, int mon) +{ + newsym(c); +} + /* Debugging notifications */ void debug_bad_monspell(int spell) @@ -1077,5 +1088,15 @@ void debug_save_unlink_failed(void) print_msg(Msg_prio::Alert, "NOTICE: savefile unlink() failed - are you trying to savescum?\n"); } +void debug_attacking_with_wielded_nonweapon(void) +{ + print_msg(Msg_prio::Bug, "BUG: attacking with wielded nonweapon\n"); +} + +void debug_control_flow(char const *func, int line) +{ + print_msg(Msg_prio::Bug, "BUG: control flow passed through unexpected line %d in function %s\n", line, func); +} + /* notify-local-tty.cc */ // vim:cindent diff --git a/notify.hh b/notify.hh index e91b523..67766f5 100644 --- a/notify.hh +++ b/notify.hh @@ -133,6 +133,7 @@ void notify_mon_ranged_hit_player(int mon); void notify_mon_ranged_missed_player(int mon); void notify_mon_ranged_hit_mon(int er, int ee); void notify_mon_dies(int mon); +void notify_new_mon_at(Coord c, int mon); void notify_player_damage_taken(int amount); void notify_player_touch_effect(Damtyp dt); @@ -184,6 +185,10 @@ void debug_unimplemented_activation(int po); void debug_unimplemented_break_reaction(int po); void debug_unimplemented_radiance_order(int order); void debug_save_unlink_failed(void); +void debug_attacking_with_wielded_nonweapon(void); +void debug_control_flow(char const *func, int line); + +#define DEBUG_CONTROL_FLOW() debug_control_flow(__FUNCTION__, __LINE__) // Provisional object designs class Notify_uattkm diff --git a/permobj.hh b/permobj.hh index b77d87d..985c8a0 100644 --- a/permobj.hh +++ b/permobj.hh @@ -64,7 +64,12 @@ enum poclass_num { #define POF_STACKABLE 0x00000004u // item can stack #define POF_DAMAGEABLE 0x00000008u // track durability #define POF_BREAK_REACT 0x00000010u // item reacts to breakage attempts +/* Yes, DRESS and MELEE_WEAPON have the same value. This is OK because + * only an ARMOUR can possibly be a DRESS, and only a WEAPON can possibly be + * a MELEE_WEAPON. */ #define POF_DRESS 0x00010000u +#define POF_MELEE_WEAPON 0x00010000u +#define POF_RANGED_WEAPON 0x00020000u /*! \brief The 'permanent object' database */ class Permobj { diff --git a/player.hh b/player.hh index 17c2693..4d46938 100644 --- a/player.hh +++ b/player.hh @@ -76,6 +76,7 @@ public: #define SLOT_NOTHING (-2) /* XXX u.c data and funcs */ +extern Player u; extern void u_init(char const *name); extern void write_char_dump(void); extern int do_death(Death d, char const *what); @@ -92,8 +93,9 @@ extern void reloc_player(Coord c); extern void recalc_defence(void); extern Pass_fail teleport_u(void); extern void update_player(void); - -extern Player u; +inline bool empty_handed(void) { return u.weapon == NO_OBJ; } +extern bool wielding_melee_weapon(void); +extern bool wielding_ranged_weapon(void); #endif diff --git a/pobj_comp b/pobj_comp index cf02534..a86e72d 100755 --- a/pobj_comp +++ b/pobj_comp @@ -27,6 +27,8 @@ our %flag_indices = 'DAMAGEABLE' => 0, 'BREAK_REACT' => 0, 'DRESS' => 0, + 'RANGED_WEAPON' => 0, + 'MELEE_WEAPON' => 0, ); diff --git a/u.cc b/u.cc index 74ce705..63c029a 100644 --- a/u.cc +++ b/u.cc @@ -35,8 +35,19 @@ #include #include +bool action_rewrite(Action const *act, Action *revised_act); struct Player u; +bool wielding_ranged_weapon(void) +{ + return permobjs[objects[u.weapon].obj_id].flags[0] & POF_RANGED_WEAPON; +} + +bool wielding_melee_weapon(void) +{ + return permobjs[objects[u.weapon].obj_id].flags[0] & POF_MELEE_WEAPON; +} + void recalc_defence(void) { int i; @@ -534,7 +545,7 @@ std::deque past_actions; enum Combo_phase { Combo_invalid, - Combo_link, + Combo_valid, Combo_finisher }; @@ -551,40 +562,146 @@ enum Combo_phase * \return true if revised_act was written to; false otherwise */ -bool detect_combo(Action const *act, Action *revised_act) +bool action_rewrite(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) + Coord c; + Offset o; + Action tmp_act = *act; + Combo_phase p; + bool rewrite_flag; + switch (tmp_act.cmd) { - *revised_act = *act; - return true; + case STAND_STILL: + p = Combo_valid; + break; + case ATTACK: + o.y = tmp_act.details[0]; + o.x = tmp_act.details[1]; + c = u.pos + o; + if (!lvl.in_bounds(c)) + { + debug_move_oob(c); // TODO notify_attack_oob() + tmp_act.cmd = REJECTED_ACTION; + rewrite_flag = true; + p = Combo_invalid; + break; + } + p = Combo_finisher; + break; + case WALK: + o.y = tmp_act.details[0]; + o.x = tmp_act.details[1]; + c = u.pos + o; + if (!lvl.in_bounds(c)) + { + debug_move_oob(c); + tmp_act.cmd = REJECTED_ACTION; + rewrite_flag = true; + p = Combo_invalid; + } + else if (lvl.mon_at(c) != NO_MON) + { + tmp_act.cmd = ATTACK; + rewrite_flag = true; + p = Combo_finisher; + } + else + { + p = Combo_valid; + } + break; + default: + rewrite_flag = false; + p = Combo_invalid; + break; } - else if (act->cmd == ATTACK) + switch (p) { - *revised_act = *act; - return true; + case Combo_invalid: + break; + case Combo_valid: + if (past_actions.empty()) + { + past_actions.push_front(tmp_act); + } + else + { + switch (tmp_act.cmd) + { + case STAND_STILL: + /* For now, no combo opens with more than one stand still, + * and no combo starts with something else then chains through + * a stand still */ + if (past_actions.front().cmd != STAND_STILL) + { + past_actions.clear(); + past_actions.push_front(tmp_act); + } + break; + case WALK: + /* For now, no combo chains through a WALK, but the charge + * combo will when I have the mental effort to write it. */ + past_actions.clear(); + break; + default: + DEBUG_CONTROL_FLOW(); + break; + } + } + break; + case Combo_finisher: + if (!past_actions.empty()) + { + switch (past_actions.front().cmd) + { + case STAND_STILL: + if (empty_handed() || wielding_melee_weapon()) + { + rewrite_flag = true; + tmp_act.cmd = CMD_POWER_ATTACK; + } + break; + case WALK: + break; + default: + DEBUG_CONTROL_FLOW(); + break; + } + } + past_actions.clear(); + break; } - else + if (rewrite_flag) { - return false; + *revised_act = tmp_act; } + return rewrite_flag; } -/*! \brief Process a player action. */ +/*! \brief Process a player action. + * + * \todo Make CMD_POWER_ATTACK do something special + */ Action_cost do_player_action(Action *act) { int slot; Offset step; Action redact; - bool rewritten = detect_combo(act, &redact); + bool rewritten = action_rewrite(act, &redact); if (rewritten) { act = &redact; } switch (act->cmd) { + case REJECTED_ACTION: + return Cost_none; + + case CMD_POWER_ATTACK: + step.y = act->details[0]; + step.x = act->details[1]; + return player_attack(step); + case WALK: step.y = act->details[0]; step.x = act->details[1];