Files
grenzland-mud/src/genobj.c
Rumble 047c5d0de3 Removal of outdated char_file_u warnings.
Adding of the appropropriate structs to the plrtoascii utility.
Incoorporation of changes from old circlemud CVS snapshot
this also gives more info on SYSERRors.
cleanup of zmalloc language (shit->tmp)
PRF_ROOMFLAGS has been renamed to PRF_SHOWVNUMS for clarity.
"Deaf" has been changed to "No_shout" in preference_bits, for clarity.
Addition of hindex (help index) command.
who command added argument -g and -l to check who are grouped (and 
leaders)
toggle has been expanded, and the commands nohassle, holylight, 
color, buildwalk, syslog and roomflags were moved to toggles.
renaming of some vars in dg files (xxx -> dg_xxx) for clarity.


set <player> password can now be used by other people than the first
 implementor - id check removed.


fix of a couple of minor bugs:
- crash bug related to freeing a pointer twice - ascii pfiles bug.
- host was not updated correctly after switch to ascii pfiles.

Todo: 
make "who #-#", "who #-" and "who -#" all work as "who -l #-#" did before 
Remove redundant commands which are now toggles.
Make script variables save to pfile instead of its own file.
2006-12-27 21:16:28 +00:00

512 lines
15 KiB
C

/************************************************************************
* Generic OLC Library - Objects / genobj.c v1.0 *
* Original author: Levork *
* Copyright 1996 by Harvey Gilpin *
* Copyright 1997-2001 by George Greer (greerga@circlemud.org) *
************************************************************************/
#include "conf.h"
#include "sysdep.h"
#include "structs.h"
#include "utils.h"
#include "db.h"
#include "boards.h"
#include "shop.h"
#include "genolc.h"
#include "genobj.h"
#include "genzon.h"
#include "dg_olc.h"
#include "handler.h"
/* extern functions */
extern struct board_info_type board_info[];
/* local functions */
void free_object_strings_proto(struct obj_data *obj);
obj_rnum add_object(struct obj_data *newobj, obj_vnum ovnum)
{
int found = NOTHING;
zone_rnum rznum = real_zone_by_thing(ovnum);
/*
* Write object to internal tables.
*/
if ((newobj->item_number = real_object(ovnum)) != NOTHING) {
copy_object(&obj_proto[newobj->item_number], newobj);
update_objects(&obj_proto[newobj->item_number]);
add_to_save_list(zone_table[rznum].number, SL_OBJ);
return newobj->item_number;
}
found = insert_object(newobj, ovnum);
adjust_objects(found);
add_to_save_list(zone_table[rznum].number, SL_OBJ);
return found;
}
/* ------------------------------------------------------------------------------------------------------------------------------ */
/*
* Fix all existing objects to have these values.
* We need to run through each and every object currently in the
* game to see which ones are pointing to this prototype.
* if object is pointing to this prototype, then we need to replace it
* with the new one.
*/
int update_objects(struct obj_data *refobj)
{
struct obj_data *obj, swap;
int count = 0;
for (obj = object_list; obj; obj = obj->next) {
if (obj->item_number != refobj->item_number)
continue;
count++;
/* Update the existing object but save a copy for private information. */
swap = *obj;
*obj = *refobj;
/* Copy game-time dependent variables over. */
IN_ROOM(obj) = swap.in_room;
obj->carried_by = swap.carried_by;
obj->worn_by = swap.worn_by;
obj->worn_on = swap.worn_on;
obj->in_obj = swap.in_obj;
obj->contains = swap.contains;
obj->next_content = swap.next_content;
obj->next = swap.next;
}
return count;
}
/* ------------------------------------------------------------------------------------------------------------------------------ */
/*
* Adjust the internal values of other objects as if something was inserted at the given array index.
* Might also be useful to make 'holes' in the array for some reason.
*/
obj_rnum adjust_objects(obj_rnum refpt)
{
int shop, i, zone, cmd_no;
struct obj_data *obj;
#if CIRCLE_UNSIGNED_INDEX
if (refpt == NOTHING || refpt > top_of_objt)
#else
if (refpt < 0 || refpt > top_of_objt)
#endif
return NOTHING;
/*
* Renumber live objects.
*/
for (obj = object_list; obj; obj = obj->next)
GET_OBJ_RNUM(obj) += (GET_OBJ_RNUM(obj) >= refpt);
/*
* Renumber zone table.
*/
for (zone = 0; zone <= top_of_zone_table; zone++) {
for (cmd_no = 0; ZCMD(zone, cmd_no).command != 'S'; cmd_no++) {
switch (ZCMD(zone, cmd_no).command) {
case 'P':
ZCMD(zone, cmd_no).arg3 += (ZCMD(zone, cmd_no).arg3 >= refpt);
/*
* No break here - drop into next case.
*/
case 'O':
case 'G':
case 'E':
ZCMD(zone, cmd_no).arg1 += (ZCMD(zone, cmd_no).arg1 >= refpt);
break;
case 'R':
ZCMD(zone, cmd_no).arg2 += (ZCMD(zone, cmd_no).arg2 >= refpt);
break;
}
}
}
/*
* Renumber notice boards.
*/
for (i = 0; i < NUM_OF_BOARDS; i++)
BOARD_RNUM(i) += (BOARD_RNUM(i) >= refpt);
/*
* Renumber shop produce.
*/
for (shop = 0; shop <= top_shop - top_shop_offset; shop++)
for (i = 0; SHOP_PRODUCT(shop, i) != NOTHING; i++)
SHOP_PRODUCT(shop, i) += (SHOP_PRODUCT(shop, i) >= refpt);
return refpt;
}
/* ------------------------------------------------------------------------------------------------------------------------------ */
/*
* Function handle the insertion of an object within the prototype framework. Note that this does not adjust internal values
* of other objects, use add_object() for that.
*/
obj_rnum insert_object(struct obj_data *obj, obj_vnum ovnum)
{
obj_rnum i;
top_of_objt++;
RECREATE(obj_index, struct index_data, top_of_objt + 1);
RECREATE(obj_proto, struct obj_data, top_of_objt + 1);
/*
* Start counting through both tables.
*/
for (i = top_of_objt; i > 0; i--) {
/*
* Check if current virtual is bigger than our virtual number.
*/
if (ovnum > obj_index[i - 1].vnum)
return index_object(obj, ovnum, i);
/* Copy over the object that should be here. */
obj_index[i] = obj_index[i - 1];
obj_proto[i] = obj_proto[i - 1];
obj_proto[i].item_number = i;
}
/* Not found, place at 0. */
return index_object(obj, ovnum, 0);
}
/* ------------------------------------------------------------------------------------------------------------------------------ */
obj_rnum index_object(struct obj_data *obj, obj_vnum ovnum, obj_rnum ornum)
{
#if CIRCLE_UNSIGNED_INDEX
if (obj == NULL || ornum == NOTHING || ornum > top_of_objt)
#else
if (obj == NULL || ovnum < 0 || ornum < 0 || ornum > top_of_objt)
#endif
return NOWHERE;
obj->item_number = ornum;
obj_index[ornum].vnum = ovnum;
obj_index[ornum].number = 0;
obj_index[ornum].func = NULL;
copy_object_preserve(&obj_proto[ornum], obj);
obj_proto[ornum].in_room = NOWHERE;
return ornum;
}
/* ------------------------------------------------------------------------------------------------------------------------------ */
int save_objects(zone_rnum zone_num)
{
char fname[128], buf[MAX_STRING_LENGTH], bit1[64], bit2[64];
int counter, counter2, realcounter;
FILE *fp;
struct obj_data *obj;
struct extra_descr_data *ex_desc;
#if CIRCLE_UNSIGNED_INDEX
if (zone_num == NOWHERE || zone_num > top_of_zone_table) {
#else
if (zone_num < 0 || zone_num > top_of_zone_table) {
#endif
log("SYSERR: GenOLC: save_objects: Invalid real zone number %d. (0-%d)", zone_num, top_of_zone_table);
return FALSE;
}
snprintf(fname, sizeof(fname), "%s/%d.new", OBJ_PREFIX, zone_table[zone_num].number);
if (!(fp = fopen(fname, "w+"))) {
mudlog(BRF, LVL_IMMORT, TRUE, "SYSERR: OLC: Cannot open objects file %s!", fname);
return FALSE;
}
/*
* Start running through all objects in this zone.
*/
for (counter = genolc_zone_bottom(zone_num); counter <= zone_table[zone_num].top; counter++) {
if ((realcounter = real_object(counter)) != NOTHING) {
if ((obj = &obj_proto[realcounter])->action_description) {
strncpy(buf, obj->action_description, sizeof(buf) - 1);
strip_cr(buf);
} else
*buf = '\0';
fprintf(fp,
"#%d\n"
"%s~\n"
"%s~\n"
"%s~\n"
"%s~\n",
GET_OBJ_VNUM(obj),
(obj->name && *obj->name) ? obj->name : "undefined",
(obj->short_description && *obj->short_description) ? obj->short_description : "undefined",
(obj->description && *obj->description) ? obj->description : "undefined",
buf);
sprintascii(buf, GET_OBJ_EXTRA(obj));
sprintascii(bit1, GET_OBJ_WEAR(obj));
sprintascii(bit2, GET_OBJ_PERM(obj));
fprintf(fp,
"%d %s %s %s\n"
"%d %d %d %d\n"
"%d %d %d %d\n",
GET_OBJ_TYPE(obj), buf, bit1, bit2,
GET_OBJ_VAL(obj, 0), GET_OBJ_VAL(obj, 1), GET_OBJ_VAL(obj, 2), GET_OBJ_VAL(obj, 3),
GET_OBJ_WEIGHT(obj), GET_OBJ_COST(obj), GET_OBJ_RENT(obj), GET_OBJ_LEVEL(obj)
);
/*
* Do we have script(s) attached ?
*/
script_save_to_disk(fp, obj, OBJ_TRIGGER);
/*
* Do we have extra descriptions?
*/
if (obj->ex_description) { /* Yes, save them too. */
for (ex_desc = obj->ex_description; ex_desc; ex_desc = ex_desc->next) {
/*
* Sanity check to prevent nasty protection faults.
*/
if (!ex_desc->keyword || !ex_desc->description || !*ex_desc->keyword || !*ex_desc->description) {
mudlog(BRF, LVL_IMMORT, TRUE, "SYSERR: OLC: oedit_save_to_disk: Corrupt ex_desc!");
continue;
}
strncpy(buf, ex_desc->description, sizeof(buf) - 1);
strip_cr(buf);
fprintf(fp, "E\n"
"%s~\n"
"%s~\n", ex_desc->keyword, buf);
}
}
/*
* Do we have affects?
*/
for (counter2 = 0; counter2 < MAX_OBJ_AFFECT; counter2++)
if (obj->affected[counter2].modifier)
fprintf(fp, "A\n"
"%d %d\n", obj->affected[counter2].location,
obj->affected[counter2].modifier);
}
}
/*
* Write the final line, close the file.
*/
fprintf(fp, "$~\n");
fclose(fp);
snprintf(buf, sizeof(buf), "%s/%d.obj", OBJ_PREFIX, zone_table[zone_num].number);
remove(buf);
rename(fname, buf);
if (in_save_list(zone_table[zone_num].number, SL_OBJ))
remove_from_save_list(zone_table[zone_num].number, SL_OBJ);
return TRUE;
}
/*
* Free all, unconditionally.
*/
void free_object_strings(struct obj_data *obj)
{
if (obj->name)
free(obj->name);
if (obj->description)
free(obj->description);
if (obj->short_description)
free(obj->short_description);
if (obj->action_description)
free(obj->action_description);
if (obj->ex_description)
free_ex_descriptions(obj->ex_description);
}
/*
* For object instances that are not the prototype.
*/
void free_object_strings_proto(struct obj_data *obj)
{
int robj_num = GET_OBJ_RNUM(obj);
if (obj->name && obj->name != obj_proto[robj_num].name)
free(obj->name);
if (obj->description && obj->description != obj_proto[robj_num].description)
free(obj->description);
if (obj->short_description && obj->short_description != obj_proto[robj_num].short_description)
free(obj->short_description);
if (obj->action_description && obj->action_description != obj_proto[robj_num].action_description)
free(obj->action_description);
if (obj->ex_description) {
struct extra_descr_data *thised, *plist, *next_one; /* O(horrible) */
int ok_key, ok_desc, ok_item;
for (thised = obj->ex_description; thised; thised = next_one) {
next_one = thised->next;
for (ok_item = ok_key = ok_desc = 1, plist = obj_proto[robj_num].ex_description; plist; plist = plist->next) {
if (plist->keyword == thised->keyword)
ok_key = 0;
if (plist->description == thised->description)
ok_desc = 0;
if (plist == thised)
ok_item = 0;
}
if (thised->keyword && ok_key)
free(thised->keyword);
if (thised->description && ok_desc)
free(thised->description);
if (ok_item)
free(thised);
}
}
}
void copy_object_strings(struct obj_data *to, struct obj_data *from)
{
to->name = from->name ? strdup(from->name) : NULL;
to->description = from->description ? strdup(from->description) : NULL;
to->short_description = from->short_description ? strdup(from->short_description) : NULL;
to->action_description = from->action_description ? strdup(from->action_description) : NULL;
if (from->ex_description)
copy_ex_descriptions(&to->ex_description, from->ex_description);
else
to->ex_description = NULL;
}
int copy_object(struct obj_data *to, struct obj_data *from)
{
free_object_strings(to);
return copy_object_main(to, from, TRUE);
}
int copy_object_preserve(struct obj_data *to, struct obj_data *from)
{
return copy_object_main(to, from, FALSE);
}
int copy_object_main(struct obj_data *to, struct obj_data *from, int free_object)
{
*to = *from;
copy_object_strings(to, from);
return TRUE;
}
int delete_object(obj_rnum rnum)
{
obj_rnum i;
struct obj_data *obj, *tmp;
int shop, j;
if (rnum == NOWHERE || rnum > top_of_objt)
return FALSE;
obj = &obj_proto[rnum];
zone_rnum zrnum = real_zone_by_thing(GET_OBJ_VNUM(obj));
/* This is something you might want to read about in the logs. */
log("GenOLC: delete_object: Deleting object #%d (%s).", GET_OBJ_VNUM(obj), obj->short_description);
for (tmp = object_list; tmp; tmp = tmp->next) {
if (tmp->item_number != obj->item_number)
continue;
// extract_obj() will just axe contents.
if (tmp->contains) {
struct obj_data *this_content, *next_content;
for (this_content = tmp->contains; this_content; this_content = next_content) {
next_content = this_content->next_content;
if (IN_ROOM(tmp)) {
// transfer stuff from object to room
obj_from_obj(this_content);
obj_to_room(this_content, IN_ROOM(tmp));
} else if (tmp->worn_by || tmp->carried_by) {
// transfer stuff from object to person inventory
obj_from_char(this_content);
obj_to_char(this_content, tmp->carried_by);
} else if (tmp->in_obj) {
// transfer stuff from object to containing object
obj_from_obj(this_content);
obj_to_obj(this_content, tmp->in_obj);
}
}
}
// remove from object_list, etc. - handles weightchanges, and similar.
extract_obj(tmp);
}
// make sure all are removed.
assert(obj_index[rnum].number == 0);
// adjust rnums of all other objects.
for (tmp = object_list; tmp; tmp = tmp->next) {
GET_OBJ_RNUM(tmp) -= (GET_OBJ_RNUM(tmp) > rnum);
}
for (i = rnum; i < top_of_objt; i++) {
obj_index[i] = obj_index[i + 1];
obj_proto[i] = obj_proto[i + 1];
obj_proto[i].item_number = i;
}
top_of_objt--;
RECREATE(obj_index, struct index_data, top_of_objt + 1);
RECREATE(obj_proto, struct obj_data, top_of_objt + 1);
/*
* Renumber notice boards.
*/
for (j = 0; j < NUM_OF_BOARDS; j++)
BOARD_RNUM(j) -= (BOARD_RNUM(j) > rnum);
/*
* Renumber shop produce;
*/
for (shop = 0; shop <= top_shop - top_shop_offset; shop++)
for (j = 0; SHOP_PRODUCT(shop, j) != NOTHING; j++)
SHOP_PRODUCT(shop, j) -= (SHOP_PRODUCT(shop, j) > rnum);
/*
* Renumber zone table.
*/
int zone, cmd_no;
for (zone = 0; zone <= top_of_zone_table; zone++) {
for (cmd_no = 0; ZCMD(zone, cmd_no).command != 'S'; cmd_no++) {
switch (ZCMD(zone, cmd_no).command) {
case 'P':
if (ZCMD(zone, cmd_no).arg3 == rnum) {
delete_command(&zone_table[zone], cmd_no);
} else
ZCMD(zone, cmd_no).arg3 -= (ZCMD(zone, cmd_no).arg3 > rnum);
break;
case 'O':
case 'G':
case 'E':
if (ZCMD(zone, cmd_no).arg1 == rnum) {
delete_command(&zone_table[zone], cmd_no);
} else
ZCMD(zone, cmd_no).arg1 -= (ZCMD(zone, cmd_no).arg1 > rnum);
break;
case 'R':
if (ZCMD(zone, cmd_no).arg2 == rnum) {
delete_command(&zone_table[zone], cmd_no);
} else
ZCMD(zone, cmd_no).arg2 -= (ZCMD(zone, cmd_no).arg2 > rnum);
break;
}
}
}
save_objects(zrnum);
return TRUE;
}