mirror of
https://github.com/tbamud/tbamud.git
synced 2026-03-30 08:57:20 +02:00
Add mob equipment save function
This commit is contained in:
parent
fd58fc5f13
commit
542b01d71d
10 changed files with 386 additions and 53 deletions
142
src/act.wizard.c
142
src/act.wizard.c
|
|
@ -26,6 +26,7 @@
|
|||
#include "act.h"
|
||||
#include "genzon.h" /* for real_zone_by_thing */
|
||||
#include "class.h"
|
||||
#include "genmob.h"
|
||||
#include "genolc.h"
|
||||
#include "genobj.h"
|
||||
#include "fight.h"
|
||||
|
|
@ -5733,4 +5734,145 @@ ACMD(do_acaudit)
|
|||
#undef APPEND_FMT
|
||||
}
|
||||
|
||||
/* ====== Builder snapshot: save a staged mob's gear as its prototype loadout ====== */
|
||||
/* Put these helpers near the top of act.wizard.c (or a shared .c) */
|
||||
struct inv_count { obj_vnum vnum; int qty; struct inv_count *next; };
|
||||
|
||||
static void inv_add(struct inv_count **head, obj_vnum v, int q) {
|
||||
struct inv_count *p;
|
||||
if (q < 1) q = 1;
|
||||
for (p = *head; p; p = p->next)
|
||||
if (p->vnum == v) { p->qty += q; return; }
|
||||
CREATE(p, struct inv_count, 1);
|
||||
p->vnum = v; p->qty = q; p->next = *head; *head = p;
|
||||
}
|
||||
|
||||
static void inv_free_all(struct inv_count **head) {
|
||||
struct inv_count *n, *p = *head;
|
||||
while (p) { n = p->next; free(p); p = n; }
|
||||
*head = NULL;
|
||||
}
|
||||
|
||||
/* Add ACMD prototype to interpreter.h: ACMD(do_msave); */
|
||||
|
||||
ACMD(do_msave)
|
||||
{
|
||||
char a1[MAX_INPUT_LENGTH], a2[MAX_INPUT_LENGTH];
|
||||
char target[MAX_INPUT_LENGTH] = {0}, flags[MAX_INPUT_LENGTH] = {0};
|
||||
struct char_data *vict = NULL, *tmp = NULL;
|
||||
mob_rnum rnum;
|
||||
int include_inv = 0; /* -all */
|
||||
int clear_first = 1; /* default replace; -append flips this to 0 */
|
||||
int equips_added = 0, inv_entries = 0;
|
||||
struct inv_count *inv = NULL;
|
||||
int pos;
|
||||
struct obj_data *o;
|
||||
|
||||
two_arguments(argument, a1, a2);
|
||||
if (*a1 && *a1 == '-') {
|
||||
/* user wrote: msave -flags <mob> */
|
||||
strcpy(flags, a1);
|
||||
strcpy(target, a2);
|
||||
} else {
|
||||
/* user wrote: msave <mob> [-flags] */
|
||||
strcpy(target, a1);
|
||||
strcpy(flags, a2);
|
||||
}
|
||||
|
||||
/* Parse flags (space-separated, any order) */
|
||||
if (*flags) {
|
||||
char buf[MAX_INPUT_LENGTH], *p = flags;
|
||||
while (*p) {
|
||||
p = one_argument(p, buf);
|
||||
if (!*buf) break;
|
||||
if (!str_cmp(buf, "-all")) include_inv = 1;
|
||||
else if (!str_cmp(buf, "-append")) clear_first = 0;
|
||||
else if (!str_cmp(buf, "-clear")) clear_first = 1;
|
||||
else {
|
||||
send_to_char(ch, "Unknown flag '%s'. Try -all, -append, or -clear.\r\n", buf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Find target mob in the room */
|
||||
if (*target)
|
||||
vict = get_char_vis(ch, target, NULL, FIND_CHAR_ROOM);
|
||||
else {
|
||||
/* No name: pick the first NPC only if exactly one exists */
|
||||
for (tmp = world[IN_ROOM(ch)].people; tmp; tmp = tmp->next_in_room) {
|
||||
if (IS_NPC(tmp)) {
|
||||
if (vict) { vict = NULL; break; } /* more than one — force explicit name */
|
||||
vict = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!vict || !IS_NPC(vict)) {
|
||||
send_to_char(ch, "Target an NPC in this room: msave <mob> [-all] [-append|-clear]\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Resolve prototype and permission to edit its zone */
|
||||
rnum = GET_MOB_RNUM(vict);
|
||||
if (rnum < 0) {
|
||||
send_to_char(ch, "I can’t resolve that mob's prototype.\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CAN_EDIT_ZONE
|
||||
if (!can_edit_zone(ch, real_zone_by_thing(GET_MOB_VNUM(vict)))) {
|
||||
send_to_char(ch, "You don’t have permission to modify that mob’s zone.\r\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Build the new loadout into the PROTOTYPE */
|
||||
if (clear_first)
|
||||
loadout_free_list(&mob_proto[rnum].proto_loadout);
|
||||
|
||||
/* Capture equipment: one entry per worn slot */
|
||||
for (pos = 0; pos < NUM_WEARS; pos++) {
|
||||
o = GET_EQ(vict, pos);
|
||||
if (!o) continue;
|
||||
if (GET_OBJ_VNUM(o) <= 0) continue;
|
||||
loadout_add_entry(&mob_proto[rnum].proto_loadout, GET_OBJ_VNUM(o), (sh_int)pos, 1);
|
||||
equips_added++;
|
||||
}
|
||||
|
||||
/* Capture inventory (compressed by vnum) if requested */
|
||||
if (include_inv) {
|
||||
for (o = vict->carrying; o; o = o->next_content) {
|
||||
if (GET_OBJ_VNUM(o) <= 0) continue;
|
||||
inv_add(&inv, GET_OBJ_VNUM(o), 1);
|
||||
}
|
||||
{
|
||||
struct inv_count *p;
|
||||
for (p = inv; p; p = p->next) {
|
||||
loadout_add_entry(&mob_proto[rnum].proto_loadout, p->vnum, -1, MAX(1, p->qty));
|
||||
inv_entries++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Persist to disk: save the zone owning this mob vnum */
|
||||
{
|
||||
zone_rnum zr = real_zone_by_thing(GET_MOB_VNUM(vict));
|
||||
if (zr == NOWHERE) {
|
||||
mudlog(CMP, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE,
|
||||
"msave: could not resolve zone for mob %d", GET_MOB_VNUM(vict));
|
||||
send_to_char(ch, "Saved in memory, but couldn’t resolve zone to write disk.\r\n");
|
||||
} else {
|
||||
save_mobiles(zr);
|
||||
send_to_char(ch,
|
||||
"Loadout saved for mob [%d]. Equipped: %d, Inventory lines: %d%s\r\n",
|
||||
GET_MOB_VNUM(vict), equips_added, inv_entries, include_inv ? "" : " (use -all to include inventory)");
|
||||
mudlog(CMP, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE,
|
||||
"msave: %s saved loadout for mob %d (eq=%d, inv=%d) in zone %d",
|
||||
GET_NAME(ch), GET_MOB_VNUM(vict), equips_added, inv_entries,
|
||||
zone_table[zr].number);
|
||||
}
|
||||
}
|
||||
|
||||
inv_free_all(&inv);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue