#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "define.h"
#include "struct.h"
/*
* LOCAL_CONSTANTS
*/
const char* item_type_name [] = { "other", "light", "scroll", "wand",
"staff", "weapon", "gem", "spellbook", "treasure", "armor", "potion",
"reagent", "furniture", "trash", "cross", "container", "lock pick",
"drink_container", "key", "food", "money", "key_ring", "boat",
"corpse", "unused", "fountain", "whistle", "trap",
"light_perm", "bandage", "bounty", "gate", "arrow", "skin",
"body_part", "chair", "table", "book", "pipe", "tobacco", "deck_cards",
"fire", "garrote" };
const char* item_values [] = { "unused",
"unused | unused | life time | unused",
"spell | level | duration | unused",
"spell | level | duration | charges",
"??",
"enchantment | damdice | damside | weapon class",
"hardness | condition",
"??", "unused",
"enchantment | armor value | bracer ac | unused",
"spell | level | duration | unused",
"charges | unused",
"??", "??", "??",
"capacity | container flags | key vnum | unused",
"pick modifier | unused",
"capacity | contains | liquid | poisoned == -1", "??",
"food value | cooked? | unused | poisoned == -1",
"??", "??", "??", "??", "??",
"required to be -1 | unused | liquid | poisoned == -1",
"range | unused",
"trap flags | damdice | damside | unused",
"unused | unused | lifetime | unused", "unused",
"unused", "lifetime | unused", "unused | damdice | damside | unused",
"unused", "unused",
"seats | unused", "unused", "unused",
"unused", "unused", "unused",
"timer | next item | unused" };
const char *cont_flag_name [] = { "closeable", "pickproof", "closed",
"locked", "holding" };
/*
* OBJ_CLSS_DATA CLASS
*/
Obj_Clss_Data :: Obj_Clss_Data( )
{
record_new( sizeof( obj_clss_data ), MEM_OBJ_CLSS );
oprog = NULL;
date = -1;
count = 0;
}
Obj_Clss_Data :: ~Obj_Clss_Data( )
{
record_delete( sizeof( obj_clss_data ), MEM_OBJ_CLSS );
}
/*
* OBJ_DATA
*/
int compare_vnum( obj_data* obj1, obj_data* obj2 )
{
int a = obj1->pIndexData->vnum;
int b = obj2->pIndexData->vnum;
return( a < b ? -1 : ( a > b ? 1 : 0 ) );
}
Obj_Data :: Obj_Data( obj_clss_data* obj_clss )
{
record_new( sizeof( obj_data ), MEM_OBJECT );
valid = OBJ_DATA;
extra_descr = NULL;
array = NULL;
save = NULL;
owner = NULL;
source = empty_string;
label = empty_string;
position = WEAR_NONE;
layer = 0;
pIndexData = obj_clss;
insert( obj_list, this,
binary_search( obj_list, this, compare_vnum ) );
}
Obj_Data :: ~Obj_Data( )
{
record_delete( sizeof( obj_data ), MEM_OBJECT );
obj_list -= this;
}
/*
* SUPPORT FUNCTIONS
*/
bool can_extract( obj_clss_data* obj_clss, char_data* ch )
{
custom_data* custom;
shop_data* shop;
for( int i = 0; i < obj_list; i++ )
if( obj_list[i]->pIndexData == obj_clss ) {
send( ch, "You must destroy all examples of %s first.\n\r",
obj_clss );
return FALSE;
}
if( has_reset( obj_clss ) ) {
send( ch, "You must remove all resets of that object.\n\r" );
return FALSE;
}
for( shop = shop_list; shop != NULL; shop = shop->next )
for( custom = shop->custom; custom != NULL; custom = custom->next ) {
if( custom->item == obj_clss ) {
send( ch, "A custom in room %d creates that item.\n\r",
shop->room->vnum );
return FALSE;
}
for( int i = 0; i < MAX_INGRED; i++ )
if( custom->ingred[i] == obj_clss ) {
send( ch,
"A custom in room %d requires that item as an ingrediant.\n\r",
shop->room->vnum );
return FALSE;
}
}
return TRUE;
}
/*
* LOW LEVEL OBJECT ROUTINES
*/
bool is_same( obj_data* obj1, obj_data* obj2 )
{
obj_array* array;
if( obj1->pIndexData != obj2->pIndexData )
return FALSE;
if( !is_empty( obj1->contents ) || !is_empty( obj2->contents )
|| !is_empty( obj1->affected ) || !is_empty( obj2->affected )
|| !is_empty( obj1->events ) || !is_empty( obj2->events )
|| obj1->extra_flags[0] != obj2->extra_flags[0]
|| obj1->extra_flags[1] != obj2->extra_flags[1]
|| obj1->timer != obj2->timer
|| obj1->condition != obj2->condition
|| obj1->materials != obj2->materials
|| obj1->rust != obj2->rust
|| obj1->owner != obj2->owner
|| obj1->weight != obj2->weight )
return FALSE;
for( int i = 0; i < 4; i++ )
if( obj1->value[i] != obj2->value[i] )
return FALSE;
if( obj2->save != NULL ) {
if( obj1->save == NULL ) {
obj1->save = obj2->save;
obj2->save = NULL;
array = &obj1->save->save_list;
for( int i = 0; ; i++ ) {
if( i >= array->size )
panic( "Is_Same: Object not in save array." );
if( obj2 == array->list[i] ) {
array->list[i] = obj1;
break;
}
}
}
else if( obj1->save != obj2->save )
return FALSE;
}
return( !strcmp( obj1->label, obj2->label ) );
}
/*
* OWNERSHIP
*/
bool Obj_Data :: Belongs( char_data* ch )
{
return( owner == NULL || ( ch != NULL && ch->pcdata != NULL
&& ch->pcdata->pfile == owner ) );
}
void set_owner( pfile_data* pfile, thing_array& array )
{
obj_data* obj;
for( int i = 0; i < array; i++ ) {
if( ( obj = object( array[i] ) ) != NULL ) {
if( obj->owner == NULL
&& obj->pIndexData->item_type != ITEM_MONEY )
obj->owner = pfile;
set_owner( pfile, obj->contents );
}
}
}
void set_owner( obj_data* obj, pfile_data* buyer )
{
obj_data* content;
if( obj->pIndexData->item_type != ITEM_MONEY )
obj->owner = buyer;
for( int i = 0; i < obj->contents; i++ )
if( ( content = object( obj->contents[i] ) ) != NULL )
set_owner( content, buyer );
}
void set_owner( obj_data* obj, char_data* buyer, char_data* seller )
{
obj_data* content;
if( obj->Belongs( seller ) && obj->pIndexData->item_type != ITEM_MONEY )
obj->owner = ( ( buyer != NULL && buyer->pcdata != NULL )
? buyer->pcdata->pfile : NULL );
for( int i = 0; i < obj->contents; i++ )
if( ( content = object( obj->contents[i] ) ) != NULL )
set_owner( content, buyer, seller );
}
/*
* MISC ROUTINES
*/
void condition_abbrev( char* tmp, obj_data* obj, char_data* ch )
{
const char* abbrev [] = { "wls", "dmg", "vwn", "wrn", "vsc", "scr",
"rea", "goo", "vgo", "exc" };
int i;
i = 1000*obj->condition/obj->pIndexData->durability;
i = range( 0, i/100, 9 );
sprintf( tmp, "%s%s%s", i > 4 ? ( i > 7 ? blue( ch ) : green( ch ) )
: ( i > 2 ? yellow( ch ) : red( ch ) ), abbrev[i], normal( ch ) );
return;
}
void age_abbrev( char* tmp, obj_data*, char_data* )
{
sprintf( tmp, " " );
return;
}
const char* obj_data :: condition_name( char_data* ch, bool ansi )
{
static char tmp [ ONE_LINE ];
int i;
const char* txt;
i = 1000*condition/pIndexData->durability;
i = range( 0, i/100, 9 );
if( i == 0 ) txt = "worthless";
else if( i == 1 ) txt = "damaged";
else if( i == 2 ) txt = "very worn";
else if( i == 3 ) txt = "worn";
else if( i == 4 ) txt = "very scratched";
else if( i == 5 ) txt = "scratched";
else if( i == 6 ) txt = "reasonable";
else if( i == 7 ) txt = "good";
else if( i == 8 ) txt = "very good";
else txt = "excellent";
if( !ansi || ch->pcdata == NULL || ch->pcdata->terminal != TERM_ANSI )
return txt;
sprintf( tmp, "%s%s%s", i > 4 ? ( i > 7 ? blue( ch ) : green( ch ) )
: ( i > 2 ? yellow( ch ) : red( ch ) ), txt, normal( ch ) );
return tmp;
}
/*
* WEIGHT/NUMBER ROUTINES
*/
int Obj_Data :: Cost( )
{
int cost = pIndexData->cost;
int i;
if( ( pIndexData->item_type == ITEM_WEAPON
|| pIndexData->item_type == ITEM_ARMOR )
&& is_set( extra_flags, OFLAG_IDENTIFIED ) ) {
if( value[0] < 0 )
return 0;
cost += cost*sqr( value[0] )/2;
}
if( ( pIndexData->item_type != ITEM_WEAPON
&& pIndexData->item_type != ITEM_ARMOR )
|| !is_set( pIndexData->extra_flags, OFLAG_RANDOM_METAL ) )
return cost;
for( i = MAT_BRONZE; i <= MAT_ADAMANTINE; i++ )
if( is_set( &pIndexData->materials, i ) )
return cost*material_table[i].cost;
return cost;
}
/*
* OBJECT UTILITY ROUTINES
*/
void enchant_object( obj_data* obj )
{
int i;
if( obj->pIndexData->item_type == ITEM_WAND
|| obj->pIndexData->item_type == ITEM_STAFF )
obj->value[3] = number_range( 0, obj->pIndexData->value[3] );
if( ( obj->pIndexData->item_type == ITEM_WEAPON
|| obj->pIndexData->item_type == ITEM_ARMOR )
&& !is_set( obj->extra_flags, OFLAG_NO_ENCHANT ) ) {
if( ( i = number_range( 0, 1000 ) ) >= 900 ) {
obj->value[0] = ( i > 950 ? ( i > 990 ? ( i == 1000 ? 3 : 2 ) : 1 )
: ( i < 910 ? ( i == 900 ? -3 : -2 ) : -1 ) );
set_bit( obj->extra_flags, OFLAG_MAGIC );
if( obj->value[0] < 0 )
set_bit( obj->extra_flags, OFLAG_NOREMOVE );
}
}
}
void rust_object( obj_data* obj, int chance )
{
int i;
if( obj->metal( )
&& !is_set( obj->extra_flags, OFLAG_RUST_PROOF )
&& number_range( 0, 100 ) < chance ) {
i = number_range( 0, 1000 );
obj->rust = ( i > 700 ? 1 : ( i > 400 ? 2 : 3 ) );
}
if( obj->pIndexData->item_type == ITEM_WEAPON
|| obj->pIndexData->item_type == ITEM_ARMOR ) {
obj->age = number_range( 0, obj->pIndexData->durability/25-1 );
obj->condition = number_range( 1, repair_condition( obj ) );
}
}
void set_alloy( obj_data* obj, int level )
{
int metal;
if( !is_set( obj->pIndexData->extra_flags, OFLAG_RANDOM_METAL ) )
return;
for( metal = MAT_BRONZE; metal <= MAT_ADAMANTINE; metal++ )
if( is_set( &obj->materials, metal ) )
break;
if( metal > MAT_ADAMANTINE ) {
metal = MAT_BRONZE;
for( ; ; ) {
if( metal == MAT_ADAMANTINE
|| number_range( 0, level+75 ) > level-10*(metal-MAT_BRONZE) )
break;
metal++;
}
set_bit( &obj->materials, metal );
}
if( obj->pIndexData->item_type == ITEM_ARMOR )
obj->value[1] = obj->pIndexData->value[1]-MAT_BRONZE+metal;
}
obj_data* create( obj_clss_data* obj_clss, int number )
{
obj_data* obj;
if( obj_clss == NULL ) {
roach( "Create_object: NULL obj_clss." );
return NULL;
}
obj = new obj_data( obj_clss );
obj->singular = obj_clss->singular;
obj->plural = obj_clss->plural;
obj->after = obj_clss->after;
obj->before = obj_clss->before;
obj->extra_flags[0] = obj_clss->extra_flags[0];
obj->extra_flags[1] = obj_clss->extra_flags[1];
if( is_set( &obj_clss->size_flags, SFLAG_CUSTOM ) )
obj->size_flags = -1;
else
obj->size_flags = obj_clss->size_flags;
obj->value[0] = obj_clss->value[0];
obj->value[1] = obj_clss->value[1];
obj->value[2] = obj_clss->value[2];
obj->value[3] = obj_clss->value[3];
obj->weight = obj_clss->weight;
obj->condition = obj_clss->durability;
obj->materials = obj_clss->materials;
obj->age = 0;
obj->rust = 0;
obj->timer = 0;
if( number > 0 )
obj_clss->count += number;
else
number = -number;
obj->number = number;
obj->selected = number;
switch( obj_clss->item_type ) {
case ITEM_MONEY:
obj->value[0] = obj->pIndexData->cost;
break;
case ITEM_FIRE:
case ITEM_GATE:
obj->timer = obj->value[0];
break;
}
if( obj_clss->item_type != ITEM_ARMOR && obj_clss->item_type != ITEM_WEAPON
&& !strcmp( obj_clss->before, obj_clss->after )
&& obj_clss->plural[0] != '{' && obj_clss->singular[0] != '{' )
set_bit( obj->extra_flags, OFLAG_IDENTIFIED );
return obj;
}
obj_data* duplicate( obj_data* copy, int num )
{
obj_data* obj;
obj_clss_data* obj_clss = copy->pIndexData;
obj = new obj_data( obj_clss );
char* string_copy [] = { copy->singular, copy->plural,
copy->before, copy->after };
char** string_obj [] = { &obj->singular, &obj->plural,
&obj->before, &obj->after };
char* string_index [] = { obj_clss->singular,
obj_clss->plural, obj_clss->before, obj_clss->after };
for( int i = 0; i < 4; i++ )
*string_obj[i] = ( string_copy[i] != string_index[i]
? alloc_string( string_copy[i], MEM_OBJECT ) : string_index[i] );
obj->age = copy->age;
obj->extra_flags[0] = copy->extra_flags[0];
obj->extra_flags[1] = copy->extra_flags[1];
obj->size_flags = copy->size_flags;
obj->value[0] = copy->value[0];
obj->value[1] = copy->value[1];
obj->value[2] = copy->value[2];
obj->value[3] = copy->value[3];
obj->weight = copy->weight;
obj->condition = copy->condition;
obj->rust = copy->rust;
obj->timer = copy->timer;
obj->materials = copy->materials;
obj->owner = copy->owner;
obj->temp = copy->temp;
obj->number = num;
obj->selected = num;
obj_clss->count += num;
if( copy->save != NULL ) {
copy->save->save_list += obj;
obj->save = copy->save;
}
return obj;
}
/*
* OBJECT TRANSFER FUNCTIONS
*/
void drop_contents( obj_data* obj )
{
/*
int i;
list_data* list;
room_data* room;
obj_data* content;
if( obj->array == NULL
|| ( room = obj->array->room( ) ) == NULL )
return;
list = content_list( obj );
for( i = 0; i < list->length; i++ ) {
content = (obj_data*) list->pntr[i];
if( content->timer == -2 || content->where != obj
|| obj->array != room )
continue;
remove( content, content->number );
put_obj( content, room );
}
delete list;
*/
return;
}
/*
* OBJECT EXTRACTION ROUTINES
*/
void Obj_Data :: Extract( int i )
{
if( i < number ) {
remove_weight( this, i );
number -= i;
if( boot_stage == 2 )
pIndexData->count -= i;
return;
}
if( i > number ) {
roach( "Extract( Obj ): number > amount." );
roach( "-- Obj = %s", this );
roach( "-- Number = %d", i );
roach( "-- Amount = %d", number );
}
Extract( );
}
void Obj_Data :: Extract( )
{
obj_array* array;
int i;
if( !Is_Valid( ) ) {
roach( "Extracting invalid object." );
roach( "-- Valid = %d", valid );
roach( "-- Obj = %s", this );
return;
}
if( this->array != NULL )
From( number );
extract( contents );
if( boot_stage == 2 )
pIndexData->count -= number;
clear_queue( this );
stop_events( this );
if( save != NULL ) {
array = &save->save_list;
for( i = 0; ; i++ ) {
if( i >= array->size )
panic( "Extract: Object not found in save array." );
if( this == array->list[i] ) {
array->list[i] = NULL;
save = NULL;
break;
}
}
}
delete_list( affected );
free_string( source, MEM_OBJECT );
if( singular != pIndexData->singular )
free_string( singular, MEM_OBJECT );
if( plural != pIndexData->plural )
free_string( plural, MEM_OBJECT );
if( after != pIndexData->after )
free_string( after, MEM_OBJECT );
if( before != pIndexData->before )
free_string( before, MEM_OBJECT );
timer = -2;
valid = -1;
extracted += this;
}
/*
* DISK ROUTINES
*/
void fix( obj_clss_data* obj_clss )
{
if( obj_clss->item_type == ITEM_SCROLL )
set_bit( &obj_clss->materials, MAT_PAPER );
for( int i = 0; i < MAX_ANTI; i++ )
if( !strncasecmp( anti_flags[i], "unused", 6 ) )
remove_bit( &obj_clss->anti_flags, i );
return;
}
void load_objects( void )
{
FILE* fp;
obj_clss_data* obj_clss;
oprog_data* oprog;
char letter;
int i;
int vnum;
echo( "Loading Objects ...\n\r" );
vzero( obj_index_list, MAX_OBJ_INDEX );
fp = open_file( AREA_DIR, OBJECT_FILE, "r", TRUE );
if( strcmp( fread_word( fp ), "#OBJECTS" ) )
panic( "Load_objects: header not found" );
for( ; ; ) {
letter = fread_letter( fp );
if( letter != '#' )
panic( "Load_objects: # not found." );
if( ( vnum = fread_number( fp ) ) == 0 )
break;
if( vnum < 0 || vnum >= MAX_OBJ_INDEX )
panic( "Load_objects: vnum out of range." );
if( obj_index_list[vnum] != NULL )
panic( "Load_objects: vnum %d duplicated.", vnum );
obj_clss = new obj_clss_data;
obj_index_list[vnum] = obj_clss;
obj_clss->vnum = vnum;
obj_clss->fakes = vnum;
obj_clss->singular = fread_string( fp, MEM_OBJ_CLSS );
obj_clss->plural = fread_string( fp, MEM_OBJ_CLSS );
obj_clss->before = fread_string( fp, MEM_OBJ_CLSS );
obj_clss->after = fread_string( fp, MEM_OBJ_CLSS );
obj_clss->long_s = fread_string( fp, MEM_OBJ_CLSS );
obj_clss->long_p = fread_string( fp, MEM_OBJ_CLSS );
obj_clss->prefix_singular = fread_string( fp, MEM_OBJ_CLSS );
obj_clss->prefix_plural = fread_string( fp, MEM_OBJ_CLSS );
obj_clss->creator = fread_string( fp, MEM_OBJ_CLSS );
obj_clss->last_mod = fread_string( fp, MEM_OBJ_CLSS );
obj_clss->item_type = fread_number( fp );
obj_clss->fakes = fread_number( fp );
obj_clss->extra_flags[0] = fread_number( fp );
obj_clss->extra_flags[1] = fread_number( fp );
obj_clss->wear_flags = fread_number( fp );
obj_clss->anti_flags = fread_number( fp );
obj_clss->restrictions = fread_number( fp );
obj_clss->size_flags = fread_number( fp );
obj_clss->materials = fread_number( fp );
obj_clss->affect_flags[0] = fread_number( fp );
obj_clss->affect_flags[1] = fread_number( fp );
obj_clss->affect_flags[2] = fread_number( fp );
obj_clss->layer_flags = fread_number( fp );
obj_clss->value[0] = fread_number( fp );
obj_clss->value[1] = fread_number( fp );
obj_clss->value[2] = fread_number( fp );
obj_clss->value[3] = fread_number( fp );
obj_clss->weight = fread_number( fp );
obj_clss->cost = fread_number( fp );
obj_clss->level = fread_number( fp );
obj_clss->limit = fread_number( fp );
obj_clss->repair = fread_number( fp );
obj_clss->durability = fread_number( fp );
obj_clss->blocks = fread_number( fp );
obj_clss->light = fread_number( fp );
obj_clss->date = fread_number( fp );
read_affects( fp, obj_clss );
read_extra( fp, obj_clss->extra_descr );
fread_letter( fp );
for( ; ; ) {
int number = fread_number( fp );
if( number == -1 )
break;
oprog = new oprog_data;
append( obj_clss->oprog, oprog );
oprog->trigger = number;
oprog->obj_vnum = fread_number( fp );
oprog->command = fread_string( fp, MEM_OPROG );
oprog->target = fread_string( fp, MEM_OPROG );
oprog->code = fread_string( fp, MEM_OPROG );
read_extra( fp, oprog->data );
}
fix( obj_clss );
}
fclose( fp );
for( i = 0; i < MAX_OBJ_INDEX; i++ )
if( obj_index_list[i] != NULL )
for( oprog = obj_index_list[i]->oprog; oprog != NULL;
oprog = oprog->next )
if( oprog->obj_vnum > 0 )
oprog->obj_act = get_obj_index( oprog->obj_vnum );
return;
}