From 1b7a53f9534e807d9114e35e26c334459444de90 Mon Sep 17 00:00:00 2001 From: kinther Date: Tue, 30 Dec 2025 18:07:00 -0800 Subject: [PATCH] Mount update 2 --- README.md | 5 +- src/act.h | 4 + src/act.informative.c | 3 + src/act.movement.c | 405 +++++++++++++++++++++++++++++++++++++++++- src/act.wizard.c | 3 + src/handler.c | 17 +- src/interpreter.c | 4 + src/players.c | 4 + src/structs.h | 1 + src/utils.c | 2 + src/utils.h | 2 + 11 files changed, 447 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index de12984..0f186fe 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,8 @@ Changes in v1.1.0-alpha: Features to be implemented in the next few releases: +* Height and weight normalized to species +* Stables will take mounts and provide tickets to get them out * Updated door code so that it can be closed/locked/saved with rsave code * SECTOR/ROOM type changes to make terrain movement easier or more difficult * Subclass selection to personalize character further @@ -73,7 +75,8 @@ Features to be implemented in the next few releases: * Wagons added to help with caravans * BUILDING object type created to allow enter/leave * Updated BUILDING object type so that it can be damaged and no longer enterable (but someone can leave at cost to health) -* Plantlife introduced +* Plantlife introduced, allowing a plant object to produce fruit or herbs every few hours/days +* Plantlife can be refreshed to spawn fruits/herbs more frequently by watering it * Updated lockpicking skill * Trap as a skill - one focused on city and one focused on desert * Poisons and antidotes diff --git a/src/act.h b/src/act.h index 38971b9..02d27f2 100644 --- a/src/act.h +++ b/src/act.h @@ -175,14 +175,18 @@ ACMD(do_gen_door); /* Functions without subcommands */ ACMD(do_enter); ACMD(do_follow); +ACMD(do_hitch); ACMD(do_leave); ACMD(do_mount); ACMD(do_move); +ACMD(do_pack); ACMD(do_rest); ACMD(do_dismount); ACMD(do_sit); ACMD(do_sleep); ACMD(do_stand); +ACMD(do_unhitch); +ACMD(do_unpack); ACMD(do_unfollow); ACMD(do_wake); /* Global variables from act.movement.c */ diff --git a/src/act.informative.c b/src/act.informative.c index 3de0139..22d256c 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -1435,6 +1435,9 @@ ACMD(do_score) send_to_char(ch, "Sdesc: %s\r\n", sdesc && *sdesc ? sdesc : "someone"); send_to_char(ch, "Ldesc: %s\r\n", *ldesc ? ldesc : "None"); + send_to_char(ch, "Weight: %d Height: %d\r\n", + GET_WEIGHT(ch), GET_HEIGHT(ch)); + send_to_char(ch, "HP: %d/%d Mana: %d/%d Stamina: %d/%d\r\n", GET_HIT(ch), GET_MAX_HIT(ch), diff --git a/src/act.movement.c b/src/act.movement.c index 036c5ab..295cae4 100644 --- a/src/act.movement.c +++ b/src/act.movement.c @@ -47,6 +47,10 @@ static const char *position_gerund(int pos); static void clear_mount_state(struct char_data *ch); static bool mount_skill_check(struct char_data *ch, int dc); static bool resolve_mounted_move(struct char_data *ch, struct char_data **mount); +static int count_hitched_mounts(struct char_data *ch); +static int max_hitched_mounts(struct char_data *ch); +static struct char_data *first_hitched_mount_in_room(struct char_data *ch); +static struct char_data *find_hitched_mount_for_pack(struct char_data *ch, struct obj_data *obj); /* simple function to determine if char can walk on water */ @@ -275,8 +279,11 @@ static void clear_mount_state(struct char_data *ch) return; mount = MOUNT(ch); - if (mount && RIDDEN_BY(mount) == ch) + if (mount && RIDDEN_BY(mount) == ch) { + int rider_weight = GET_WEIGHT(ch) + IS_CARRYING_W(ch); + IS_CARRYING_W(mount) = MAX(0, IS_CARRYING_W(mount) - rider_weight); RIDDEN_BY(mount) = NULL; + } MOUNT(ch) = NULL; REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_MOUNTED); } @@ -327,6 +334,74 @@ static bool resolve_mounted_move(struct char_data *ch, struct char_data **mount) *mount = mount_ch; return TRUE; } + +static int count_hitched_mounts(struct char_data *ch) +{ + struct follow_type *follow; + int count = 0; + + if (!ch) + return 0; + + for (follow = ch->followers; follow; follow = follow->next) { + if (HITCHED_TO(follow->follower) == ch && + MOB_FLAGGED(follow->follower, MOB_MOUNT)) + count++; + } + + return count; +} + +static int max_hitched_mounts(struct char_data *ch) +{ + int skill = GET_SKILL(ch, SKILL_ANIMAL_HANDLING); + + if (skill > 59) + return 2; + return 1; +} + +static struct char_data *first_hitched_mount_in_room(struct char_data *ch) +{ + struct follow_type *follow; + + if (!ch) + return NULL; + + for (follow = ch->followers; follow; follow = follow->next) { + if (HITCHED_TO(follow->follower) == ch && + MOB_FLAGGED(follow->follower, MOB_MOUNT) && + IN_ROOM(follow->follower) == IN_ROOM(ch)) + return follow->follower; + } + + return NULL; +} + +static struct char_data *find_hitched_mount_for_pack(struct char_data *ch, struct obj_data *obj) +{ + struct follow_type *follow; + + if (!ch || !obj) + return NULL; + + for (follow = ch->followers; follow; follow = follow->next) { + struct char_data *mount = follow->follower; + + if (HITCHED_TO(mount) != ch || !MOB_FLAGGED(mount, MOB_MOUNT)) + continue; + if (IN_ROOM(mount) != IN_ROOM(ch)) + continue; + if ((IS_CARRYING_N(mount) + 1) > CAN_CARRY_N(mount)) + continue; + if ((IS_CARRYING_W(mount) + GET_OBJ_WEIGHT(obj)) > CAN_CARRY_W(mount)) + continue; + + return mount; + } + + return NULL; +} /** Move a PC/NPC character from their current location to a new location. This * is the standard movement locomotion function that all normal walking * movement by characters should be sent through. This function also defines @@ -1022,10 +1097,64 @@ ACMD(do_stand) { char token[MAX_INPUT_LENGTH]; struct obj_data *furniture = NULL, *current_furniture = SITTING(ch); + struct char_data *mount = NULL; + char arg[MAX_INPUT_LENGTH]; bool has_target = FALSE, used_number = FALSE; int ordinal = 0; int orig_pos = GET_POS(ch); + if (*argument) { + one_argument(argument, arg); + if (*arg && !is_abbrev(arg, "at")) + mount = get_char_vis(ch, arg, NULL, FIND_CHAR_ROOM); + if (mount && MOB_FLAGGED(mount, MOB_MOUNT) && HITCHED_TO(mount) != ch) { + act("You don't have $N hitched.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + if (mount && HITCHED_TO(mount) == ch && MOB_FLAGGED(mount, MOB_MOUNT)) { + if (FIGHTING(mount)) { + act("$N is fighting right now.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + if (GET_POS(mount) == POS_RESTING) { + act("You get $N to stand up.", FALSE, ch, 0, mount, TO_CHAR); + act("$n gets $N to stand up.", TRUE, ch, 0, mount, TO_ROOM); + GET_POS(mount) = POS_STANDING; + clear_custom_ldesc(mount); + return; + } + if (GET_POS(mount) == POS_SLEEPING) { + act("$N has to wake up first.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + act("$N is already standing.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + } + + if (!*argument && AFF_FLAGGED(ch, AFF_MOUNTED) && MOUNT(ch)) { + mount = MOUNT(ch); + if (IN_ROOM(mount) != IN_ROOM(ch) || RIDDEN_BY(mount) != ch) { + clear_mount_state(ch); + send_to_char(ch, "You aren't mounted on anything.\r\n"); + return; + } + if (FIGHTING(mount)) { + send_to_char(ch, "Your mount is fighting right now.\r\n"); + return; + } + if (GET_POS(mount) != POS_SLEEPING) { + act("You get $N to rest and dismount.", FALSE, ch, 0, mount, TO_CHAR); + act("$n gets $N to rest and dismounts.", TRUE, ch, 0, mount, TO_ROOM); + GET_POS(mount) = POS_RESTING; + clear_custom_ldesc(mount); + } else { + act("$N is already asleep.", FALSE, ch, 0, mount, TO_CHAR); + } + clear_mount_state(ch); + return; + } + if (AFF_FLAGGED(ch, AFF_MOUNTED)) { send_to_char(ch, "You must dismount first.\r\n"); return; @@ -1267,9 +1396,64 @@ ACMD(do_rest) { char token[MAX_INPUT_LENGTH]; struct obj_data *furniture = NULL, *current_furniture = SITTING(ch); + struct char_data *mount = NULL; + char arg[MAX_INPUT_LENGTH]; bool has_target = FALSE, used_number = FALSE; int ordinal = 0; + if (*argument) { + one_argument(argument, arg); + if (*arg && !is_abbrev(arg, "at")) + mount = get_char_vis(ch, arg, NULL, FIND_CHAR_ROOM); + if (mount && MOB_FLAGGED(mount, MOB_MOUNT) && HITCHED_TO(mount) != ch) { + act("You don't have $N hitched.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + if (mount && HITCHED_TO(mount) == ch && MOB_FLAGGED(mount, MOB_MOUNT)) { + if (FIGHTING(mount)) { + act("$N is fighting right now.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + if (GET_POS(mount) == POS_RESTING) { + act("$N is already resting.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + if (GET_POS(mount) == POS_SLEEPING) { + act("$N is already asleep.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + act("You pull on $N's reins, forcing it to rest.", FALSE, ch, 0, mount, TO_CHAR); + act("$n pulls on $N's reins, forcing it to rest.", TRUE, ch, 0, mount, TO_ROOM); + GET_POS(mount) = POS_RESTING; + clear_custom_ldesc(mount); + return; + } + } + + if (!*argument && AFF_FLAGGED(ch, AFF_MOUNTED) && MOUNT(ch)) { + mount = MOUNT(ch); + if (IN_ROOM(mount) != IN_ROOM(ch) || RIDDEN_BY(mount) != ch) { + clear_mount_state(ch); + send_to_char(ch, "You aren't mounted on anything.\r\n"); + return; + } + if (FIGHTING(mount)) { + send_to_char(ch, "Your mount is fighting right now.\r\n"); + return; + } + if (GET_POS(mount) == POS_SLEEPING) { + act("$N is already asleep.", FALSE, ch, 0, mount, TO_CHAR); + clear_mount_state(ch); + return; + } + act("You pull on $N's reins, forcing it to rest.", FALSE, ch, 0, mount, TO_CHAR); + act("$n pulls on $N's reins, forcing it to rest and dismounts.", TRUE, ch, 0, mount, TO_ROOM); + GET_POS(mount) = POS_RESTING; + clear_custom_ldesc(mount); + clear_mount_state(ch); + return; + } + if (AFF_FLAGGED(ch, AFF_MOUNTED)) { send_to_char(ch, "You must dismount first.\r\n"); return; @@ -1621,14 +1805,25 @@ ACMD(do_mount) return; } + if (HITCHED_TO(mount) && HITCHED_TO(mount) != ch) { + act("$N is already hitched to someone else.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + if (RIDDEN_BY(mount)) { act("$N is already being ridden.", FALSE, ch, 0, mount, TO_CHAR); return; } + if ((GET_WEIGHT(ch) + IS_CARRYING_W(ch) + IS_CARRYING_W(mount)) > CAN_CARRY_W(mount)) { + act("$N can't carry that much weight.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + SET_BIT_AR(AFF_FLAGS(ch), AFF_MOUNTED); MOUNT(ch) = mount; RIDDEN_BY(mount) = ch; + IS_CARRYING_W(mount) += GET_WEIGHT(ch) + IS_CARRYING_W(ch); act("You mount $N.", FALSE, ch, 0, mount, TO_CHAR); act("$n mounts $N.", TRUE, ch, 0, mount, TO_ROOM); @@ -1649,6 +1844,214 @@ ACMD(do_dismount) clear_mount_state(ch); } +ACMD(do_hitch) +{ + char arg[MAX_INPUT_LENGTH]; + struct char_data *mount; + int max_hitched; + + one_argument(argument, arg); + + if (!*arg) { + send_to_char(ch, "Hitch what?\r\n"); + return; + } + + if (!(mount = get_char_vis(ch, arg, NULL, FIND_CHAR_ROOM))) { + send_to_char(ch, "%s", CONFIG_NOPERSON); + return; + } + + if (mount == ch) { + send_to_char(ch, "You can't hitch yourself.\r\n"); + return; + } + + if (!IS_NPC(mount) || !MOB_FLAGGED(mount, MOB_MOUNT)) { + send_to_char(ch, "You can't hitch %s!\r\n", get_char_sdesc(mount)); + return; + } + + if (RIDDEN_BY(mount) && RIDDEN_BY(mount) != ch) { + act("$N is already being ridden.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + + if (HITCHED_TO(mount) == ch) { + act("$N is already hitched to you.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + + if (HITCHED_TO(mount) && HITCHED_TO(mount) != ch) { + act("$N is already hitched to someone else.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + + if (mount->master && mount->master != ch) { + act("$N is already following someone else.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + + max_hitched = max_hitched_mounts(ch); + if (count_hitched_mounts(ch) >= max_hitched) { + send_to_char(ch, "You can't hitch any more mounts.\r\n"); + return; + } + + if (!mount->master) + add_follower(mount, ch); + + HITCHED_TO(mount) = ch; + act("You hitch $N to you.", FALSE, ch, 0, mount, TO_CHAR); + act("$n hitches $N to $m.", TRUE, ch, 0, mount, TO_ROOM); +} + +ACMD(do_unhitch) +{ + char arg[MAX_INPUT_LENGTH]; + struct char_data *mount; + + one_argument(argument, arg); + + if (!*arg) { + send_to_char(ch, "Unhitch what?\r\n"); + return; + } + + if (!(mount = get_char_vis(ch, arg, NULL, FIND_CHAR_ROOM))) { + send_to_char(ch, "%s", CONFIG_NOPERSON); + return; + } + + if (HITCHED_TO(mount) != ch || !MOB_FLAGGED(mount, MOB_MOUNT)) { + act("You don't have $N hitched.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + + if (mount->master == ch) + stop_follower(mount); + else + HITCHED_TO(mount) = NULL; + + act("You unhitch $N.", FALSE, ch, 0, mount, TO_CHAR); + act("$n unhitches $N.", TRUE, ch, 0, mount, TO_ROOM); +} + +ACMD(do_pack) +{ + char arg[MAX_INPUT_LENGTH]; + struct char_data *mount; + struct obj_data *obj; + struct follow_type *follow; + bool found_mount = FALSE; + + one_argument(argument, arg); + + if (!*arg) { + for (follow = ch->followers; follow; follow = follow->next) { + bool found_item = FALSE; + + mount = follow->follower; + if (HITCHED_TO(mount) != ch || !MOB_FLAGGED(mount, MOB_MOUNT)) + continue; + if (IN_ROOM(mount) != IN_ROOM(ch)) + continue; + + found_mount = TRUE; + send_to_char(ch, "Packed on %s:\r\n", get_char_sdesc(mount)); + + for (obj = mount->carrying; obj; obj = obj->next_content) { + if (GET_OBJ_TYPE(obj) != ITEM_CONTAINER) + continue; + if (!CAN_SEE_OBJ(ch, obj)) + continue; + send_to_char(ch, " %s\r\n", obj->short_description ? obj->short_description : "something"); + found_item = TRUE; + } + + if (!found_item) + send_to_char(ch, " Nothing.\r\n"); + } + + if (!found_mount) + send_to_char(ch, "You don't have any mounts hitched.\r\n"); + return; + } + + if (!(obj = get_obj_in_list_vis(ch, arg, NULL, ch->carrying))) { + send_to_char(ch, "You don't seem to have that.\r\n"); + return; + } + + if (GET_OBJ_TYPE(obj) != ITEM_CONTAINER) { + send_to_char(ch, "You can only pack containers onto a mount.\r\n"); + return; + } + + mount = find_hitched_mount_for_pack(ch, obj); + if (!mount) { + if (!first_hitched_mount_in_room(ch)) + send_to_char(ch, "You don't have any mounts hitched here.\r\n"); + else + send_to_char(ch, "Your mount can't carry that much.\r\n"); + return; + } + + obj_from_char(obj); + obj_to_char(obj, mount); + + act("You pack $p onto $N.", FALSE, ch, obj, mount, TO_CHAR); + act("$n packs $p onto $N.", TRUE, ch, obj, mount, TO_ROOM); +} + +ACMD(do_unpack) +{ + char arg[MAX_INPUT_LENGTH]; + struct char_data *mount; + struct obj_data *obj; + struct follow_type *follow; + + one_argument(argument, arg); + + if (!*arg) { + send_to_char(ch, "Unpack what?\r\n"); + return; + } + + for (follow = ch->followers; follow; follow = follow->next) { + mount = follow->follower; + + if (HITCHED_TO(mount) != ch || !MOB_FLAGGED(mount, MOB_MOUNT)) + continue; + if (IN_ROOM(mount) != IN_ROOM(ch)) + continue; + + obj = get_obj_in_list_vis(ch, arg, NULL, mount->carrying); + if (!obj) + continue; + if (GET_OBJ_TYPE(obj) != ITEM_CONTAINER) + continue; + + if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch)) { + send_to_char(ch, "You can't carry any more items.\r\n"); + return; + } + if ((IS_CARRYING_W(ch) + GET_OBJ_WEIGHT(obj)) > CAN_CARRY_W(ch)) { + send_to_char(ch, "You can't carry that much weight.\r\n"); + return; + } + + obj_from_char(obj); + obj_to_char(obj, ch); + + act("You unpack $p from $N.", FALSE, ch, obj, mount, TO_CHAR); + act("$n unpacks $p from $N.", TRUE, ch, obj, mount, TO_ROOM); + return; + } + + send_to_char(ch, "You don't have that packed on a hitched mount.\r\n"); +} + ACMD(do_unfollow) { if (ch->master) { diff --git a/src/act.wizard.c b/src/act.wizard.c index 67d6b70..487d2fd 100644 --- a/src/act.wizard.c +++ b/src/act.wizard.c @@ -1829,6 +1829,9 @@ static void do_stat_character(struct char_data *ch, struct char_data *k) GET_STR(k), GET_INT(k), GET_WIS(k), GET_DEX(k), GET_CON(k), GET_CHA(k)); + stat_table_row_fmt(ch, "Size", "Weight %d, Height %d", + GET_WEIGHT(k), GET_HEIGHT(k)); + stat_table_row_fmt(ch, "Saving Throws", "Str %+d Dex %+d Con %+d Int %+d Wis %+d Cha %+d", get_save_mod(k, ABIL_STR), diff --git a/src/handler.c b/src/handler.c index ec6c3d1..814e43b 100644 --- a/src/handler.c +++ b/src/handler.c @@ -446,6 +446,8 @@ void obj_to_char(struct obj_data *object, struct char_data *ch) RoomSave_mark_dirty_room(__rs_room); IS_CARRYING_W(ch) += GET_OBJ_WEIGHT(object); IS_CARRYING_N(ch)++; + if (AFF_FLAGGED(ch, AFF_MOUNTED) && MOUNT(ch) && RIDDEN_BY(MOUNT(ch)) == ch) + IS_CARRYING_W(MOUNT(ch)) += GET_OBJ_WEIGHT(object); autoquest_trigger_check(ch, NULL, object, AQ_OBJ_FIND); @@ -487,6 +489,11 @@ void obj_from_char(struct obj_data *object) IS_CARRYING_W(object->carried_by) -= GET_OBJ_WEIGHT(object); IS_CARRYING_N(object->carried_by)--; + if (AFF_FLAGGED(object->carried_by, AFF_MOUNTED) && + MOUNT(object->carried_by) && + RIDDEN_BY(MOUNT(object->carried_by)) == object->carried_by) + IS_CARRYING_W(MOUNT(object->carried_by)) = + MAX(0, IS_CARRYING_W(MOUNT(object->carried_by)) - GET_OBJ_WEIGHT(object)); object->carried_by = NULL; object->next_content = NULL; if (__rs_room != NOWHERE) @@ -559,6 +566,8 @@ void equip_char(struct char_data *ch, struct obj_data *obj, int pos) obj->worn_by = ch; obj->worn_on = pos; IS_CARRYING_W(ch) += GET_OBJ_WEIGHT(obj); + if (AFF_FLAGGED(ch, AFF_MOUNTED) && MOUNT(ch) && RIDDEN_BY(MOUNT(ch)) == ch) + IS_CARRYING_W(MOUNT(ch)) += GET_OBJ_WEIGHT(obj); if (GET_OBJ_TYPE(obj) == ITEM_ARMOR) GET_AC(ch) -= apply_ac(ch, pos); @@ -592,6 +601,9 @@ struct obj_data *unequip_char(struct char_data *ch, int pos) obj->worn_by = NULL; obj->worn_on = -1; IS_CARRYING_W(ch) -= GET_OBJ_WEIGHT(obj); + if (AFF_FLAGGED(ch, AFF_MOUNTED) && MOUNT(ch) && RIDDEN_BY(MOUNT(ch)) == ch) + IS_CARRYING_W(MOUNT(ch)) = + MAX(0, IS_CARRYING_W(MOUNT(ch)) - GET_OBJ_WEIGHT(obj)); if (GET_OBJ_TYPE(obj) == ITEM_ARMOR) GET_AC(ch) += apply_ac(ch, pos); @@ -1005,8 +1017,11 @@ void extract_char_final(struct char_data *ch) if (AFF_FLAGGED(ch, AFF_MOUNTED) || MOUNT(ch)) { struct char_data *mount = MOUNT(ch); - if (mount && RIDDEN_BY(mount) == ch) + if (mount && RIDDEN_BY(mount) == ch) { + int rider_weight = GET_WEIGHT(ch) + IS_CARRYING_W(ch); + IS_CARRYING_W(mount) = MAX(0, IS_CARRYING_W(mount) - rider_weight); RIDDEN_BY(mount) = NULL; + } MOUNT(ch) = NULL; REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_MOUNTED); } diff --git a/src/interpreter.c b/src/interpreter.c index 99a938a..ec99df7 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -181,6 +181,7 @@ cpp_extern const struct command_info cmd_info[] = { { "hold" , "hold" , POS_RESTING , do_grab , 1, 0 }, { "holylight", "holy" , POS_DEAD , do_gen_tog , LVL_IMMORT, SCMD_HOLYLIGHT }, { "house" , "house" , POS_RESTING , do_house , 0, 0 }, + { "hitch" , "hitc" , POS_STANDING, do_hitch , 0, 0 }, { "inventory", "i" , POS_DEAD , do_inventory, 0, 0 }, { "idea" , "ide" , POS_DEAD , do_ibt , 0, SCMD_IDEA }, @@ -233,6 +234,7 @@ cpp_extern const struct command_info cmd_info[] = { { "ocopy" , "ocopy" , POS_DEAD , do_oasis_copy, LVL_GOD, CON_OEDIT }, { "put" , "p" , POS_RESTING , do_put , 0, 0 }, + { "pack" , "pac" , POS_RESTING , do_pack , 0, 0 }, { "peace" , "pe" , POS_DEAD , do_peace , LVL_BUILDER, 0 }, { "pemote" , "pem" , POS_SLEEPING, do_pemote , 0, SCMD_PEMOTE }, { "phemote" , "phem" , POS_SLEEPING, do_phemote , 0, SCMD_PHEMOTE }, @@ -329,7 +331,9 @@ cpp_extern const struct command_info cmd_info[] = { { "unlock" , "unlock" , POS_SITTING , do_gen_door , 0, SCMD_UNLOCK }, { "unban" , "unban" , POS_DEAD , do_unban , LVL_GRGOD, 0 }, { "unaffect" , "unaffect", POS_DEAD , do_wizutil , LVL_GOD, SCMD_UNAFFECT }, + { "unhitch" , "unh" , POS_STANDING, do_unhitch , 0, 0 }, { "unfollow" , "unf" , POS_RESTING , do_unfollow , 0, 0 }, + { "unpack" , "unpa" , POS_RESTING , do_unpack , 0, 0 }, { "uptime" , "uptime" , POS_DEAD , do_date , LVL_GOD, SCMD_UPTIME }, { "use" , "use" , POS_SITTING , do_use , 1, SCMD_USE }, { "users" , "users" , POS_DEAD , do_users , LVL_GOD, 0 }, diff --git a/src/players.c b/src/players.c index eace528..9fffa7c 100644 --- a/src/players.c +++ b/src/players.c @@ -551,6 +551,10 @@ int load_char(const char *name, struct char_data *ch) update_roleplay_age(ch); ch->player.time.birth = time(0) - get_total_played_seconds(ch); affect_total(ch); + MOUNT(ch) = NULL; + RIDDEN_BY(ch) = NULL; + HITCHED_TO(ch) = NULL; + REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_MOUNTED); /* initialization for imms */ if (GET_LEVEL(ch) >= LVL_IMMORT) { diff --git a/src/structs.h b/src/structs.h index ce16dcb..9b3318f 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1009,6 +1009,7 @@ struct char_special_data struct obj_data *furniture; /**< Object being sat on/in; else NULL */ struct char_data *mount; /**< Mount being ridden; else NULL */ struct char_data *rider; /**< Rider, if being mounted; else NULL */ + struct char_data *hitched_to; /**< Person this mount is hitched to; else NULL */ struct char_data *next_in_furniture; /**< Next person sitting, else NULL */ byte position; /**< Standing, fighting, sleeping, etc. */ diff --git a/src/utils.c b/src/utils.c index 894c1e9..7f63726 100644 --- a/src/utils.c +++ b/src/utils.c @@ -654,6 +654,8 @@ void stop_follower(struct char_data *ch) } ch->master = NULL; + if (HITCHED_TO(ch)) + HITCHED_TO(ch) = NULL; REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_CHARM); } diff --git a/src/utils.h b/src/utils.h index cc7bbab..0b5f12e 100644 --- a/src/utils.h +++ b/src/utils.h @@ -200,6 +200,8 @@ void char_from_furniture(struct char_data *ch); #define MOUNT(ch) ((ch)->char_specials.mount) /** Rider currently mounted on ch. */ #define RIDDEN_BY(ch) ((ch)->char_specials.rider) +/** Person ch is hitched to. */ +#define HITCHED_TO(ch) ((ch)->char_specials.hitched_to) /** Who is sitting next to ch, if anyone. */ #define NEXT_SITTING(ch) ((ch)->char_specials.next_in_furniture) /** Who is sitting on this obj */