/*********************************************************** Realms of Aurealis Online Creation System version 2.1 RoAOLCv2.1 - James Rhone aka Vall of RoA olc.c (online creation system - mob/room/object/house edit files) Adopted from Realms of Imagination's original version of OLC (7/95) ******** Heavily modified and expanded ******** *** BE AWARE OF ALL RIGHTS AND RESERVATIONS *** ******** Heavily modified and expanded ******** All rights reserved henceforth. Author: James Rhone Original Running Version: 0.5beta Please note that no guarantees are associated with any code from Realms of Aurealis. All code which has been released to the general public has been done so with an 'as is' pretense. Thanks to Jeremy Elson who has provided a stable base for Realms of Aurealis. RoA was originally created from a CircleMUD 2.2 base, back in the dark ages, when even that release was considered new wave. Since RoA is a perpetual BETA MUD, all code from it is also in BETA stages. I personally feel this is the best OLC ever made available for CircleMUD and its derivatives. My experienced builders agree. How you feel depends on how well you can fit into your mud. Good luck. There are no patch files, no step by step instructions, and no hand holders. All code written for Realms of Aurealis, including that contained in this file was written by me, James Rhone, so nobody is very familiar with it except me. Perhaps that will change. :) *** If you do not know C, I suggest getting to know it before you attempt to plug this into your mud. This is not a trivial addition to any mud and without someone there to guide you, you will inevitably get frustrated. ** note: RoAOLC base source file can be found in roaolc.c note: zone OLC can be found in z_olc.c note: room OLC can be found in r_olc.c note: mobile OLC can be found in m_olc.c note: object OLC can be found in o_olc.c **********************************************************/ #include "conf.h" #include "sysdep.h" #include "structures.h" #include "comm.h" #include "interpreter.h" #include "acmd.h" #include "db.h" #include "utils.h" #include "mudlimits.h" #include "handler.h" #include "roaolc.h" #include "magic.h" #include "house.h" #include "lists.h" #include "global.h" /* for chars */ extern char *material_types[]; extern int material_hits[]; extern char *affected_bits[]; extern char *affected2_bits[]; extern char *apply_types[]; extern char *item_types[]; extern char *wear_bits[]; extern char *wv_bits[]; extern char *extra_bits[]; extern char *extra_bits2[]; extern char *container_bits[]; extern char *drinks[]; char *weapon_strs[] = { "hits, hit", "pounds, pound", "pierces, pierce", "slashes, slash", "blasts, blast", "whips, whip", "pierce (non BS)", "claws, claw", "bites, bite", "stings, sting", "crushes, crush", "BUILDER DEFINED", "\n", }; char *value_strs[][4] = { { "*", "*", "*", "*" }, // UNDEFINED { "*", "*", "Duration", "*" }, // LIGHT { "Spell level", "Spell 1", "Spell 2", "Spell 3" }, // SCROLL { "Spell level", "Max charges", "Charges left", "Spell" }, // WAND { "Spell level", "Max charges", "Charges left", "Spell" }, // STAFF { "*", "# of damage dice", "Size of damage dice", "Weapon type" }, // WEAPON { "*", "*", "*", "*" }, // RANGED { "*", "*", "*", "*" }, // OINTMENT { "*", "*", "*", "*" }, // TREASURE { "Armor class", "*", "*", "*" }, // type ARMOR { "Spell level", "Spell 1", "Spell 2", "Spell 3" }, // type POTION { "*", "*", "*", "*" }, // type +BOARD { "*", "*", "*", "*" }, // OTHER { "*", "*", "*", "*" }, // TRASH { "*", "*", "*", "*" }, // TRAP { "Max weight of contents", "Flags", "Key type", "*" }, // CONTAINER { "*", "*", "*", "*" }, // NOTE { "Max # of drinks", "# of drinks left", "Liquid type", "Poisoned? / Pure Poison level" }, // LIQUID CONT { "Key type", "*", "*", "*" }, // KEY { "Food hours", "*", "*", "Poisoned?" }, // FOOD { "# of coins", "*", "*", "*" }, // MONEY { "*", "*", "*", "*" }, // PEN { "*", "*", "*", "*" }, // BOAT { "Max # of drinks", "# of drinks left", "Liquid type", "Poisoned?" }, // FOUNTAIN { "*", "Max charges", "Charges left", "Teleport to(vnum)" }, // PORTAL { "Gate is an", "INTERNAL", "OBJECT TYPE", "Do Not Use" }, // GATEWAY { "Max charges", "# of charges left", "Num Mana Dice", "Size Mana Dice" }, // HARMONIC GEM { "Skill 1", "Skill 2", "Skill 3", "Skill 4" }, // TOME OF LEARNING }; #define VTYPE_INT 1 #define VTYPE_SPELL 2 #define VTYPE_WEAPON 3 #define VTYPE_CONFLAGS 4 #define VTYPE_LIQUID 5 int value_types[][4] = { { 0, 0, 0, 0 }, { 0, 0, VTYPE_INT, 0 }, { VTYPE_INT, VTYPE_SPELL, VTYPE_SPELL, VTYPE_SPELL }, { VTYPE_INT, VTYPE_INT, VTYPE_INT, VTYPE_SPELL }, { VTYPE_INT, VTYPE_INT, VTYPE_INT, VTYPE_SPELL }, { 0, VTYPE_INT, VTYPE_INT, VTYPE_WEAPON }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { VTYPE_INT, 0, 0, 0 }, { VTYPE_INT, VTYPE_SPELL, VTYPE_SPELL, VTYPE_SPELL }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { VTYPE_INT, VTYPE_CONFLAGS, VTYPE_INT, 0 }, { 0, 0, 0, 0 }, { VTYPE_INT, VTYPE_INT, VTYPE_LIQUID, VTYPE_INT }, { VTYPE_INT, 0, 0, 0 }, { VTYPE_INT, 0, 0, VTYPE_INT }, { VTYPE_INT, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { VTYPE_INT, VTYPE_INT, VTYPE_LIQUID, VTYPE_INT }, { 0, VTYPE_INT, VTYPE_INT, VTYPE_INT}, { 0, 0, 0, 0 }, { VTYPE_INT, VTYPE_INT, VTYPE_INT, VTYPE_INT}, // HARMONIC GEM { VTYPE_SPELL, VTYPE_SPELL, VTYPE_SPELL, VTYPE_SPELL}, // TOME OF LEARNING }; // internal functions to this file void oedit_top_menu(chdata *ch, char *input_str); void oedit_confirm_quit(chdata *ch, char *input_str); void oedit_confirm_save(chdata *ch, char *input_str); // external functions extern exdescdata *correct_extra_descrips(exdescdata *ths); extern exdescdata *free_extra_descrips(exdescdata *head); extern exdescdata *dupe_exdesc_over(exdescdata *ths); // OBLITERATE an object, NOTE this will not remove the object from // the proto list should it be a part of it... // its primary use is to wax those OBJ_EDITTED ptrs on char void wax_object(obdata *trg) { FREENULL(trg->name); FREENULL(trg->description); FREENULL(trg->shdesc); FREENULL(trg->actdesc); FREENULL(trg->wear_mesg); FREENULL(trg->rem_mesg); FREENULL(trg->weap_sing); FREENULL(trg->weap_plur); trg->exdesc = free_extra_descrips(trg->exdesc); } // dupe EVERYTHING over, first the strings from trg get // waxed, and extra descrip list // then it gets a copy of all src's things void dupe_object_over(obdata *src, obdata *trg) { chdata *carried_by; obdata *in_obj, *contains, *next_content, *next; int timer; BOOL viewed, lit, touched, original; // save data in use before we transfer carried_by = trg->carried_by; in_obj = trg->in_obj; contains = trg->contains; next_content = trg->next_content; next = trg->next; timer = trg->timer; viewed = trg->viewed; lit = trg->lit; touched = trg->touched; original = trg->original; wax_object(trg); *trg = *src; trg->name = STR_DUP(src->name); trg->shdesc = STR_DUP(src->shdesc); trg->description = STR_DUP(src->description); trg->actdesc = STR_DUP(src->actdesc); trg->wear_mesg = STR_DUP(src->wear_mesg); trg->rem_mesg = STR_DUP(src->rem_mesg); trg->weap_sing = STR_DUP(src->weap_sing); trg->weap_plur = STR_DUP(src->weap_plur); trg->exdesc = dupe_exdesc_over(src->exdesc); // transfer saved data back over trg->carried_by = carried_by; trg->in_obj = in_obj; trg->contains = contains; trg->next_content = next_content; trg->next = next; trg->timer = timer; trg->viewed = viewed; trg->lit = lit; trg->touched = touched; trg->original = original; } void default_object_out(obdata *obj, int vnum) { obj->item_number = vnum; obj->name = STR_DUP("BLANK"); obj->shdesc = STR_DUP("BLANK"); obj->description = STR_DUP("BLANK"); obj->actdesc = STR_DUP("BLANK"); obj->wear_mesg = STR_DUP("BLANK"); obj->rem_mesg = STR_DUP("BLANK"); obj->weap_sing = STR_DUP("BLANK"); obj->weap_plur = STR_DUP("BLANK"); obj->exdesc = NULL; obj->objsave_self = -1; obj->objsave_parent = -1; obj->objsave_where = -1; obj->tmp1 = -1; obj->tmp2 = -1; OBJ_HITS(obj) = 10000; MAX_OBJ_HITS(obj) = 10000; obj->in_room = NOWHERE; obj->total_game_limit = -1; obj->percent_load = 10000; obj->alternate_load = 0; obj->min_level = 1; obj->made_of = OBJ_UNDEFINED; obj->touched = FALSE; obj->lit = FALSE; obj->original = FALSE; obj->eqspell = -1; obj->eqaffbit = 0; } // player interface to oedit ACMD(do_oedit) { int vnum, rnum, zone; char *argu = argument; if (IS_NPC(ch)) return; skip_spaces(&argu); if (!*argu || !is_number(argu)) { send_to_char("Usage: oedit <object vnum>.\n\r",ch); return; } vnum = atoi(argu); zone = vnum / 100; /* check permissions on zone and objects -roa */ if (GET_LEVEL(ch) < LEV_CIMP && (!zone || zone < ch->pc_specials->saved.olc_min_zone || zone > ch->pc_specials->saved.olc_max_zone)) { send_to_char("You don't have privileges to edit that object.\n\r", ch); return; } /* if the object exists, copy from the existing proto */ /* NOTE: we store the vnum of this object in obj->item_number */ /* for later use -roa */ if ((rnum = real_object(vnum)) >= 0) { CREATE(OBJ_EDITTED(ch), obdata, 1); dupe_object_over(&obj_proto[rnum], OBJ_EDITTED(ch)); OBJ_EDITTED(ch)->item_number = vnum; } else /* make a whole new one, initializing the strings to non NULL */ { if (!OBJ_SLOTS_LEFT) { send_to_char("Max object creation for this runtime reached.\n\r",ch); send_to_char("You must wait for reboot to create more protos.\n\r",ch); return; } CREATE(OBJ_EDITTED(ch), obdata, 1); default_object_out(OBJ_EDITTED(ch), vnum); } SET_BIT(PLR_FLAGS(ch), PLR_BUILDING); MENU_DEPTH(ch) = 0; ch->pc_specials->field_changed = FALSE; menu_jump(ch, oedit_top_menu); } /* sends a list of spells that have function pointers -roa */ /* note: i have to make this screen pause if builder has refresh on */ void send_spell_listing(chdata *ch) { int i, count; for (i=1, count=0, *buf = '\0'; i < MAX_SPELLS; i++) if (*skill_names[i] && spell_info[i].spell_pointer) { count++; sprintf(buf+strlen(buf), "(%2d.) %%6%-17.17s%%0%s", i, skill_names[i], ((count % 3) ? "" : "\n\r")); } page_string(ch->desc, buf, TRUE); } void oedit_get_value(chdata *ch, int i) { char *p; obdata *o = OBJ_EDITTED(ch); p = MENU_PROMPT_BUF(ch); sprintf(p, "Enter %s: ", value_strs[(int)ITEM_TYPE(o)][i]); switch(value_types[(int)ITEM_TYPE(o)][i]) { case VTYPE_INT: GET_INTEGER_ARG(ch, p, o->value[i], -30000, 30000); break; case VTYPE_SPELL: send_spell_listing(ch); GET_INTEGER_ARG(ch, "Enter Spell/Skill number: ", o->value[i], -1, MAX_SKILLS-1); break; case VTYPE_WEAPON: get_integer_list(ch, p, &o->value[i], sizeof(o->value[i]), weapon_strs); break; case VTYPE_CONFLAGS: toggle_menu(ch, "Enter container bit to toggle: ", &o->value[i], container_bits); break; case VTYPE_LIQUID: get_integer_list(ch, p, &o->value[i], sizeof(o->value[i]), drinks); break; default: break; } } ROA_MENU(oedit_add_extradesc_menu) { obdata *o = OBJ_EDITTED(ch); exdescdata *e = NULL; switch ((int) MENU_HANDLER_ARG(ch)) { case 0: CREATE(e, exdescdata, 1); e->next = o->exdesc; o->exdesc = e; e = NULL; MENU_HANDLER_ARG(ch) = (void *) 1; do_string_arg(ch, "Enter keywords: ", &o->exdesc->keyword,""); break; case 1: MENU_HANDLER_ARG(ch) = (void *) 2; do_long_string_arg(ch, "Enter new description (@):\n\r", &o->exdesc->description); break; default: menu_pop(ch); (*MENU_HANDLER(ch))(ch, NULL); break; } } void delete_obj_extra(chdata *ch) { obdata *o = OBJ_EDITTED(ch); exdescdata *e, *temp; int i; /* advance to the one we want to delete */ for (i = 1, e = o->exdesc; (i < (int) MENU_RETURN(ch)) && e; e = e->next, i++) ; if (e) { REMOVE_FROM_LIST(e, o->exdesc, next); if(e->keyword) free_log(e->keyword, "delete_obj_extra"); if(e->description) free_log(e->description, "delete_obj_extra"); free_log(e, "delete_obj_extra"); e = NULL; } MENU_RETURN(ch) = 0; } ROA_MENU(oedit_extradesc_menu) { char buf[MAX_STRING_LENGTH]; obdata *o = OBJ_EDITTED(ch); exdescdata *e = NULL; char *p; int i; if (!input_str) { /* if we have one to delete from earlier */ if ((int) MENU_RETURN(ch) > 0) delete_obj_extra(ch); menu_title_send("Extra Descrip Main Menu", ch); for (i = 1, e = o->exdesc; e; e = e->next, i++) { sprintf(buf, "%2d.) %%6%s%%0\n\r", i, e->keyword); S2C(); sprintf(buf, " %s\n\r", e->description); S2C(); } i--; MENU_PROMPT(ch) = "(D)elete, (A)dd, (Q)uit/<return>: "; return; } strcpy(buf, input_str); p = strtok(buf, " \n\r"); if (p) { if (!strncasecmp("delete", p, strlen(p))) { if (!o->exdesc) GET_INTEGER_ARG(ch, "No descriptions to delete (hit return): ", MENU_RETURN(ch), 0, 0); else { for (i = 1, e = o->exdesc; e; e = e->next, i++) ; GET_INTEGER_ARG(ch, "Enter desc number to delete (return for none): ", MENU_RETURN(ch), 1, i-1); } } else if (!strncasecmp("add", p, strlen(p))) { menu_push(ch); MENU_HANDLER_ARG(ch) = (void *) 0; menu_jump(ch, oedit_add_extradesc_menu); } else if (!strncasecmp("quit", p, strlen(p)) || !p || !atoi(p)) { menu_back(ch); return; } } else if (!p || !atoi(p)) { menu_back(ch); return; } } ROA_MENU(oedit_affects_menu) { obdata *o = OBJ_EDITTED(ch); int aff_n; int aff_field; int *i = (int *) &MENU_HANDLER_ARG(ch); aff_n = *i / 2; aff_field = *i & 1; (*i)++; if (!aff_field) { if (aff_n == MAX_OBJ_AFFECT) { menu_back(ch); return; } get_integer_list(ch, "Enter affect application: ", &o->affected[aff_n].location, sizeof(o->affected[aff_n].location), apply_types); } else { if (!o->affected[aff_n].location) { for(; aff_n < MAX_OBJ_AFFECT; aff_n++) o->affected[aff_n].location = APPLY_NONE; menu_back(ch); return; } else { sprinttype(o->affected[aff_n].location, apply_types, buf2); sprintf(MENU_PROMPT_BUF(ch), "Enter modification value for %s: ", buf2); GET_INTEGER_ARG(ch, MENU_PROMPT_BUF(ch), o->affected[aff_n].modifier, -1000, 1000); } } } // add a menu for throw objects dice ROA_MENU(oedit_throwdice_menu) { char buf[MAX_STRING_LENGTH]; obdata *o = OBJ_EDITTED(ch); char *p; int field; if (!input_str) { menu_title_send("ObjectEdit ThrowDice Menu", ch); sprintf(buf, "1.) %%6To Hit modifier%%0 : %d\n\r",o->throw_plushit); S2C(); sprintf(buf, "2.) %%6To Damage NumDice%%0 : %d\n\r",o->throw_numdam); S2C(); sprintf(buf, "3.) %%6To Damage SizeDice%%0: %d\n\r",o->throw_sizedam); S2C(); sprintf(buf, "4.) %%6To Damage Bonus%%0 : %d\n\r",o->throw_plusdam); S2C(); send_to_char("\n\r",ch); MENU_PROMPT(ch) = "Enter field number to change or 0 to end: "; return; } strcpy(buf, input_str); p = strtok(buf, " \n\r"); if (p) field = atoi(p); else field = 0; switch (field) { case 0: menu_back(ch); break; case 1: GET_INTEGER_ARG(ch, "Enter Throw Hit modifier: ", o->throw_plushit, -20, 20); break; case 2: GET_INTEGER_ARG(ch, "Enter Num Damage Dice: ", o->throw_numdam, 1, 10); break; case 3: GET_INTEGER_ARG(ch, "Enter Size Damage Dice: ", o->throw_sizedam, 1, 10); break; case 4: GET_INTEGER_ARG(ch, "Enter Damage Bonus: ", o->throw_plusdam, -10, 20); break; default: send_to_char("That field cannot be changed.\n\r", ch); break; } } /* add extra menu for strings RoA jtrhone*/ ROA_MENU(oedit_string_menu) { char buf[MAX_STRING_LENGTH]; char *p; int field; obdata *o = OBJ_EDITTED(ch); extern char *delete_doubledollar(char *str); if (!input_str) { menu_title_send("ObjectEdit String Menu", ch); sprintf(buf, "1.) %%6Long description%%0:\n\r%s\n\r",o->actdesc); S2C(); if (o->wear_mesg) o->wear_mesg = delete_doubledollar(o->wear_mesg); sprintf(buf, "2.) %%6Wear Message%%0 :\n\r%s\n\r",o->wear_mesg); S2C(); if (o->rem_mesg) o->rem_mesg = delete_doubledollar(o->rem_mesg); sprintf(buf, "3.) %%6Removal Message%%0 :\n\r%s\n\r",o->rem_mesg); S2C(); if (IS_WEAPON(o) && o->value[3] == TYPE_BDEFINED - TYPE_HIT) { sprintf(buf, "4.) %%6Singular weapon noun%%0: %s\n\r",o->weap_sing); S2C(); sprintf(buf, "5.) %%6Plural weapon verb%%0 : %s\n\r",o->weap_plur); S2C(); } send_to_char("\n\r", ch); MENU_PROMPT(ch) = "Enter field number to change or 0 to end: "; return; } strcpy(buf, input_str); p = strtok(buf, " \n\r"); if (p) field = atoi(p); else field = 0; switch (field) { case 0: menu_back(ch); return; break; case 1: do_long_string_arg(ch, "Enter long description (@):\n\r", &o->actdesc); break; case 2: do_long_string_arg(ch, "Enter object wear message (@):\n\r", &o->wear_mesg); break; case 3: do_long_string_arg(ch, "Enter object removal message (@):\n\r", &o->rem_mesg); break; case 4: if (!IS_WEAPON(o) || o->value[3] != TYPE_BDEFINED - TYPE_HIT) break; do_string_arg(ch, "Enter SINGULAR weapon noun: ", &o->weap_sing, ""); break; case 5: if (!IS_WEAPON(o) || o->value[3] != TYPE_BDEFINED - TYPE_HIT) break; do_string_arg(ch, "Enter PLURAL weapon verb: ", &o->weap_plur, ""); break; default: send_to_char("That field cannot be changed.\n\r", ch); break; } } /* ROA OLC object edit main menu */ ROA_MENU(oedit_top_menu) { char buf[MAX_STRING_LENGTH]; char buf2[MAX_STRING_LENGTH]; char *p; int field; int i; obdata *o = OBJ_EDITTED(ch); int maxhits; if (!input_str) { menu_title_send("ObjectEdit Main Menu", ch); sprintf(buf, " 1.) %%6Nr%%0 : %%1%%B%d%%0 ", o->item_number); S2C(); sprintf(buf, " 2.) %%6NameList%%0 : %s\n\r", o->name); S2C(); sprintf(buf, " 3.) %%6ShortDesc%%0: %s\n\r", o->shdesc); S2C(); sprintf(buf, " 4.) %%6Descrip %%0 : %s\n\r", o->description); S2C(); sprintf(buf, " 5.) %%6String Menu%%0...\n\r"); S2C(); sprinttype(ITEM_TYPE(o), item_types, buf2); sprintf(buf, " 6.) %%6TypeFlag%%0 : %%5%s%%0\n\r", buf2); S2C(); sprintbit(OBJ_WEARS(o), wear_bits, buf2); sprintf(buf, " 7.) %%6WearFlag%%0 : %%5%s%%0\n\r", buf2); S2C(); sprintbit(OBJ_EXTRAS(o), extra_bits, buf2); sprintf(buf, " 8.) %%6XtraFlag%%0 : %%5%s%%0\n\r", buf2); S2C(); sprintbit(OBJ_EXTRAS2(o), extra_bits2, buf2); sprintf(buf, " 9.) %%6XtraFlags2%%0: %%5%s%%0\n\r", buf2); S2C(); for (i = 0; i < 4; i++) if (*value_strs[(int)ITEM_TYPE(o)][i] == '*') o->value[i] = 0; else if (*value_strs[(int)ITEM_TYPE(o)][i] != '*') { switch(value_types[(int)ITEM_TYPE(o)][i]) { case VTYPE_INT: sprintf(buf2, "%d", o->value[i]); break; case VTYPE_SPELL: if (o->value[i] > 0 && o->value[i] < MAX_SKILLS) sprintf(buf2, "%s", skill_names[o->value[i]]); else *buf2 = '\0'; break; case VTYPE_WEAPON: sprintf(buf2, "%s", weapon_strs[o->value[i]]); break; case VTYPE_CONFLAGS: sprintbit(o->value[i], container_bits, buf2); break; case VTYPE_LIQUID: sprinttype(o->value[i], drinks, buf2); break; default: *buf2 = '\0'; break; } sprintf(buf, "%2d.) %%6%s%%0: %s\n\r", i + 10, value_strs[(int)ITEM_TYPE(o)][i], buf2); S2C(); } /* end for/if used */ sprintf(buf, "14.) %%6Weight%%0: %d, 15.) %%6Value%%0: %d\n", o->weight, o->cost); S2C(); sprintf(buf, "16.) %%6Extra Descriptions%%0: %s\n\r", o->exdesc?"Exist":"None"); S2C(); send_to_char("17.) %6Affections%0: ", ch); for (i = 0; i < MAX_OBJ_AFFECT; i++) if (o->affected[i].location) { sprinttype(o->affected[i].location, apply_types, buf2); sprintf(buf, "%%5%+d to %s%%0, ", o->affected[i].modifier, buf2); S2C(); } send_to_char("\n\r", ch); sprintf(buf, "18.) %%6%%BLoad Prob%%0 (chance in 10000): %d ", o->percent_load); S2C(); sprintf(buf, "19.) %%6Alt Obj Load%%0: %d\n\r", o->alternate_load); S2C(); sprintf(buf, "21.) %%6%%BGame limit%%0: %d ", o->total_game_limit); S2C(); sprintf(buf, "22.) %%6Min level%%0: %d\n\r", o->min_level); S2C(); /* start with spell eq stuff here JTRHONE */ if (OBJ_FLAGGED(o, ITEM_SPELLEQ)) { sprintf(buf, "23.) %%6SpellEQ SPELL%%0: %s\n\r", (o->eqspell > 0) ? skill_names[o->eqspell] : ""); S2C(); sprintbit(o->eqaffbit, affected_bits, buf2); sprintf(buf, "24.) %%6SpellEQ Aff%%0: %%5%s%%0\n\r", buf2); S2C(); sprintbit(o->eqaff2bit, affected2_bits, buf2); sprintf(buf, "25.) %%6SpellEQ Aff2%%0: %%5%s%%0\n\r", buf2); S2C(); } else { o->eqaffbit = 0; o->eqaff2bit = 0; o->eqspell = 0; } if (!OBJ_FLAGGED(o, ITEM_MAGIC)) { MAX_OBJ_HITS(o) = material_hits[MADE_OF(o)]; OBJ_HITS(o) = MIN(MAX_OBJ_HITS(o), OBJ_HITS(o)); } sprintf(buf, "26.) %%6Obj Hits%%0: %%5%d%%0 ",OBJ_HITS(o)); S2C(); sprintf(buf, "27.) %%6MAX Obj Hits%%0: %%5%d%%0\n\r",MAX_OBJ_HITS(o)); S2C(); sprinttype(MADE_OF(o), material_types, buf2); sprintf(buf, "28.) %%6Material%%0: %%5%s%%0\n\r", buf2); S2C(); sprintf(buf, "29.) %%6Success Rate%%0: %%5%d%%0\n\r", SUCCESS_RATE(o)); S2C(); if (THROWABLE(o)) { sprintf(buf, "30.) %%6Throw stats menu...%%0\n\r"); S2C(); } sprintbit(WV_FLAGS(o), wv_bits, buf2); sprintf(buf, "31.) %%6Wear Vector%%0 : %%5%s%%0\n\r", buf2); S2C(); MENU_PROMPT(ch) = "Enter field number to change or 0 to end: "; return; } strcpy(buf, input_str); p = strtok(buf, " \n\r"); if (p) field = atoi(p); else field = 0; switch (field) { case 0: menu_jump(ch, oedit_confirm_quit); break; case 1: // DUPE the object into another proto if (ch->pc_specials->field_changed) { send_to_char("That field cannot be changed after another field is changed.\n\r", ch); break; } if (GET_LEVEL(ch) >= LEV_CIMP) { get_integer_arg(ch, "Enter object virtual number: ", &o->item_number, sizeof(o->item_number), 0, 89999); } else { get_integer_arg(ch, "Enter object virtual number: ", &o->item_number, sizeof(o->item_number), ch->pc_specials->saved.olc_min_zone * 100, ch->pc_specials->saved.olc_max_zone * 100 + 99); } break; case 2: do_string_arg(ch, "Enter new name list:\n\r", &o->name, ""); break; case 3: do_string_arg(ch, "Enter new short description:\n\r", &o->shdesc, ""); break; case 4: do_string_arg(ch, "Enter new description:\n\r", &o->description, ""); break; case 5: menu_push(ch); MENU_RETURN(ch) = 0; MENU_HANDLER_ARG(ch) = (void *) 0; menu_jump(ch, oedit_string_menu); break; case 6: get_integer_list(ch, "Enter number of the desired type: ", &o->type_flag, sizeof(o->type_flag), item_types); break; case 7: toggle_menu(ch, "Enter wear bit to toggle: ", &OBJ_WEARS(o), wear_bits); break; case 8: toggle_menu(ch, "Enter extra bit to toggle: ", &OBJ_EXTRAS(o), extra_bits); break; case 9: toggle_menu(ch, "Enter extra bit to toggle: ", &OBJ_EXTRAS2(o), extra_bits2); break; case 10: case 11: case 12: case 13: oedit_get_value(ch, field - 10); break; case 14: GET_INTEGER_ARG(ch, "Enter object weight: ", o->weight, 0, 10000000); break; case 15: GET_INTEGER_ARG(ch, "Enter object value: ", o->cost, 0, 10000000); break; case 16: menu_push(ch); MENU_RETURN(ch) = 0; MENU_HANDLER_ARG(ch) = (void *) 0; menu_jump(ch, oedit_extradesc_menu); break; case 17: menu_push(ch); MENU_HANDLER_ARG(ch) = (void *) 0; menu_jump(ch, oedit_affects_menu); break; case 18: GET_INTEGER_ARG(ch, "Chance in 10000 that object will load on reset: ", o->percent_load, 1, 10000); break; case 19: GET_INTEGER_ARG(ch, "Alternate object to load if this one fails: ", o->alternate_load, 0, 99999); break; // huh? case 20: break; case 21: GET_INTEGER_ARG(ch, "Total number allowed in game at one time: ", o->total_game_limit, 0, 9999); break; case 22: GET_INTEGER_ARG(ch, "Minimum level to use/wear/hold/wield/etc: ", o->min_level, 0, 74); break; case 23: if (!OBJ_FLAGGED(o, ITEM_SPELLEQ)) break; if (GET_LEVEL(ch) < LEV_GOD) { sprintf(buf, "See a GOD+ to change spelleq attributes.\n\r"); S2C(); break; } send_spell_listing(ch); GET_INTEGER_ARG(ch, "Enter SpellEQ offensive number: ", o->eqspell, -1, MAX_SPELLS-1); break; case 24: if (!OBJ_FLAGGED(o, ITEM_SPELLEQ)) break; if (GET_LEVEL(ch) < LEV_GOD) { sprintf(buf, "See a GOD+ to change spelleq attributes.\n\r"); S2C(); break; } toggle_menu_long(ch, "Enter affect bits to toggle: ", &o->eqaffbit, affected_bits); break; case 25: if (!OBJ_FLAGGED(o, ITEM_SPELLEQ)) break; if (GET_LEVEL(ch) < LEV_GOD) { sprintf(buf, "See a GOD+ to change spelleq attributes.\n\r"); S2C(); break; } toggle_menu_long(ch, "Enter AFF2 bits to toggle: ", &o->eqaff2bit, affected2_bits); break; case 26: if (!OBJ_FLAGGED(o, ITEM_MAGIC) && MAX_OBJ_HITS(o) >= 0) maxhits = MAX_OBJ_HITS(o); else maxhits = 30000; GET_INTEGER_ARG(ch, "Enter Object Hits (0 for broken): ", OBJ_HITS(o), 0, maxhits); break; case 27: if (!OBJ_FLAGGED(o, ITEM_MAGIC)) { send_to_char("Item must be flagged MAGIC to manually edit MAX_HITS.\n\r", ch); break; } GET_INTEGER_ARG(ch, "Enter MAX Object Hits (-1 for indestruct): ", MAX_OBJ_HITS(o), -1, 30000); break; case 28: get_integer_list(ch, "Enter the number of desired material: ", &MADE_OF(o), sizeof(MADE_OF(o)), material_types); break; case 29: GET_INTEGER_ARG(ch, "Enter object success percentage (0-100): ", SUCCESS_RATE(o), 0, 100); break; case 30: if (!THROWABLE(o)) break; menu_push(ch); MENU_RETURN(ch) = 0; MENU_HANDLER_ARG(ch) = (void *) 0; menu_jump(ch, oedit_throwdice_menu); break; case 31: toggle_menu(ch, "Enter wear vector bit to toggle: ", &WV_FLAGS(o), wv_bits); break; default: send_to_char("That field cannot be changed, yet.\n\r", ch); break; } ch->pc_specials->field_changed = TRUE; } ROA_MENU(oedit_confirm_quit) { char buf[MAX_STRING_LENGTH]; char *p; if (!input_str) { MENU_PROMPT(ch) = "Quit editting object (yes/NO)? "; return; } strcpy(buf, input_str); p = strtok(buf, " \n\r"); if (p && strncasecmp("yes", p, strlen(p)) == 0) menu_jump(ch, oedit_confirm_save); else menu_jump(ch, oedit_top_menu); } /* now go thru object list and alter all the objs pointing to the old proto to point to this new protos stuff */ void update_objs_in_game(int rnum) { obdata *o; sprintf(buf, "SYSUPD: Attempting olc object list update rnum: %d, vnum: %d.", rnum, obj_index[rnum].vnum); mudlog(buf, BUG, LEV_IMM, TRUE); for (o = object_list; o; o = o->next) if (o->item_number == rnum) { o->name = obj_proto[rnum].name; o->shdesc = obj_proto[rnum].shdesc; o->description = obj_proto[rnum].description; o->actdesc = obj_proto[rnum].actdesc; o->wear_mesg = obj_proto[rnum].wear_mesg; o->rem_mesg = obj_proto[rnum].rem_mesg; o->weap_sing = obj_proto[rnum].weap_sing; o->weap_plur = obj_proto[rnum].weap_plur; o->exdesc = obj_proto[rnum].exdesc; // COULD add further updates of existing objects in the // future, but for now, only strings are that vital -jtrhone } } // check an object for null strings -roa void check_invalid_object(obdata *o) { BOOL dolog = FALSE; if (!o->name || !*o->name) { o->name = STR_DUP("invalid object"); dolog = TRUE; } if (!o->shdesc || !*o->shdesc) { o->shdesc = STR_DUP("an invalid object"); dolog = TRUE; } if (!o->description || !*o->description) { o->description = STR_DUP("an invalid object lies here"); dolog = TRUE; } if (!o->actdesc || !*o->actdesc) { o->actdesc = STR_DUP("I'm a lonely invalid object. Tell an immortal about me:)\n\r"); dolog = TRUE; } if (!o->wear_mesg || !*o->wear_mesg) { o->wear_mesg = STR_DUP("BLANK"); dolog = TRUE; } if (!o->rem_mesg || !*o->rem_mesg) { o->rem_mesg = STR_DUP("BLANK"); dolog = TRUE; } if (!o->weap_sing || !*o->weap_sing) { o->weap_sing = STR_DUP("BLANK"); dolog = TRUE; } if (!o->weap_plur || !*o->weap_plur) { o->weap_plur = STR_DUP("BLANK"); dolog = TRUE; } o->exdesc = correct_extra_descrips(o->exdesc); if (dolog) { sprintf(buf, "SYSERR: Invalid object string detected and fixed: #%d.", GET_OBJ_VNUM(o)); mudlog(buf, BRF, LEV_IMM, TRUE); } } ROA_MENU(oedit_confirm_save) { char buf[MAX_STRING_LENGTH]; char *p; int rnum, vnum; obdata *o = OBJ_EDITTED(ch); if (!input_str) { MENU_PROMPT(ch) = "Save editted object (YES/no)? "; return; } strcpy(buf, input_str); p = strtok(buf, " \n\r"); if (!p || strncasecmp("no", p, strlen(p)) != 0) { vnum = o->item_number; if ((rnum = real_object(vnum)) >= 0) { o->item_number = rnum; check_invalid_object(o); dupe_object_over(o, &obj_proto[rnum]); update_objs_in_game(rnum); strcpy(buf2, "editted"); } else { obj_index[top_of_objt].vnum = vnum; obj_index[top_of_objt].number = 0; obj_index[top_of_objt].func = 0; o->item_number = top_of_objt; o->in_room = NOWHERE; check_invalid_object(o); dupe_object_over(o, &obj_proto[top_of_objt]); top_of_objt++; strcpy(buf2, "created"); } sprintf(buf, "PLRUPD: %s has %s object #%d", GET_NAME(ch), buf2, vnum); mudlog(buf, BRF, GET_LEVEL(ch), TRUE); } /* end of if SAVE confirmed */ wax_object(OBJ_EDITTED(ch)); FREENULL(OBJ_EDITTED(ch)); MENU_PROMPT(ch) = NULL; MENU_HANDLER(ch) = NULL; MENU_DEPTH(ch) = 0; REMOVE_BIT(PLR_FLAGS(ch), PLR_BUILDING); } ACMD(do_olist) { obdata *o; char aname[20]; int zone, i, j, top, set; BOOL found = FALSE; BOOL flag = FALSE; BOOL spelleq = FALSE; BOOL weapon = FALSE; char buf[20000]; char arg1[MAX_INPUT_LENGTH]; long flg; if (IS_NPC(ch)) return; half_chop(argument, buf, buf2); if (!*buf || *buf == '.') zone = world[ch->in_room].zone; else zone = real_zone(atoi(buf)); if (zone < 0) { send_to_char("That zone does not exist.\n\r",ch); return; } if (!olc_perms(ch, LEV_GOD, zone)) return; top = zone_table[zone].top; for (i = zone * 100; i <= top; i++) { if (real_object(i) >= 0) break; } if (i > top) { send_to_char("No objects in that zone.\n\r",ch); return; } half_chop(buf2, buf, arg1); // added flag subcmd to this, search for flags on objects... 1/19/98 -jtrhone if (*buf && is_abbrev(buf, "flag")) { if ((flg = search_block(arg1, extra_bits, TRUE)) < 0) { if ((flg = search_block(arg1, extra_bits2, TRUE)) < 0) { send_to_char("Unable to locate flag.\n\r",ch); return; } else set = 2; } else set = 1; flag = TRUE; } else if (*buf && is_abbrev(buf, "spelleq")) spelleq = TRUE; else if (*buf && is_abbrev(buf, "weapon")) weapon = TRUE; buf[0] = '\0'; while (i <= top) { if (real_object(i) < 0) { i++; continue; } o = &obj_proto[real_object(i)]; if (flag) { switch (set) { case 1: if (!OBJ_FLAGGED(o, (1 << flg))) { i++; continue; } break; case 2: if (!OBJ_FLAGGED2(o, (1 << flg))) { i++; continue; } break; } } if (spelleq && !OBJ_FLAGGED(o, ITEM_SPELLEQ)) { i++; continue; } else if (weapon && !IS_WEAPON(o)) { i++; continue; } found = TRUE; sprintf(buf1, "[%5d] %-20.20s%%0 ", i, o->name); sprinttype(ITEM_TYPE(o), item_types, buf2); switch (ITEM_TYPE(o)) { case ITEM_ARMOR: sprintf(buf2, "%s AC%d ", buf2, o->value[0]); break; case ITEM_WEAPON: sprintf(buf2, "%s %dd%d ", buf2, o->value[1], o->value[2]); break; } strcat(buf1, buf2); *buf2 = '\0'; for (j = 0; j < MAX_OBJ_AFFECT; j++) if (o->affected[j].location) { sprinttype(o->affected[j].location, apply_types, aname); sprintf(buf2, " %+d %s ", o->affected[j].modifier, aname); sprintf(buf1 + strlen(buf1), "%s", buf2); if (!j) strcat(buf1, " "); } if (GET_LEVEL(ch) >= LEV_CIMP) { sprintf(buf2, " #%d",obj_index[GET_OBJ_RNUM(o)].number); strcat(buf1, buf2); } strcat(buf, buf1); strcat(buf, "\n\r"); strcpy(buf2, ""); i++; } if (found) page_string(ch->desc, buf, TRUE); else if (flag) send_to_char("No objects with that flag found in that zone.\n\r",ch); else if (spelleq) send_to_char("No SPELLEQ objects in that zone.\n\r",ch); else if (weapon) send_to_char("No WEAPON objects in that zone.\n\r",ch); else send_to_char("No objects in that zone.\n\r",ch); } ACMD(do_oquery) { send_to_char("Oquery is no longer implemented due to a mem leak.\n\r",ch); send_to_char("... heh, and the fact it was useless :P\n\r",ch); }