/**************************************************************************** * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | \\._.// * * -----------------------------------------------------------| (0...0) * * SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by Derek Snider | ).:.( * * -----------------------------------------------------------| {o o} * * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, | / ' ' \ * * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek, |~'~.VxvxV.~'~* * Tricops and Fireblade | * * ------------------------------------------------------------------------ * * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * ------------------------------------------------------------------------ * * Specific object creation module * ****************************************************************************/ #include <sys/types.h> #include <stdio.h> #include <string.h> #include <time.h> #include <math.h> #include "mud.h" int get_rank_by_pl( long double level ) { if( level < 5000 ) return 1; else if( level < 100000 ) return 2; else if( level < 1000000 ) return 3; else if( level < 10000000 ) return 4; else if( level < 100000000 ) return 5; else if( level < 1000000000 ) return 6; else if( level < 10000000000ULL ) return 7; else if( level < 50000000000ULL ) return 8; else if( level < 100000000000ULL ) return 9; else if( level < 300000000000ULL ) return 10; else if( level < 600000000000ULL ) return 11; else if( level < 1000000000000ULL ) return 12; else if( level < 10000000000000ULL ) return 13; else if( level < 50000000000000ULL ) return 14; else if( level < 100000000000000ULL ) return 15; else return 16; return 0; } int calc_zeni( long double level, CHAR_DATA * killer ) { long double chklvl = 0; int zeros = 0; int i; int zeniBase = 0; int prevZeni = 0; int zeni = 0; double ratio = 0.00; long double chklvl2 = 0; for( i = 0; i < 100; i++ ) // i'm "cheeping" out and caping this at 1 googol -Goku 10.05.04 { if( level / pow( 10, i ) < 10 ) { break; } } chklvl = pow( 10, i ); chklvl2 = pow( 10, i - 1 ); /* * double zero count to smooth out increase -Goku 10.05.04 */ if( level < chklvl - chklvl2 + chklvl2 ) zeros = i * 2 - 1; else zeros = i * 2; switch ( zeros ) { case 0: // 0 case 1: // 1 zeniBase = 1; prevZeni = 1; break; case 2: // 5 zeniBase = 5; prevZeni = 1; break; case 3: // 10 zeniBase = 10; prevZeni = 5; break; case 4: // 50 zeniBase = 20; prevZeni = 10; break; case 5: // 100 case 6: // 500 zeniBase = 30; prevZeni = 20; break; case 7: // 1000 case 8: // 5000 zeniBase = 40; prevZeni = 30; break; case 9: // 10k zeniBase = 60; prevZeni = 40; break; case 10: // 50k zeniBase = 90; prevZeni = 60; break; case 11: // 100k zeniBase = 150; prevZeni = 90; break; case 12: // 500k zeniBase = 170; prevZeni = 150; break; case 13: // 1m zeniBase = 200; prevZeni = 170; break; case 14: // 5m zeniBase = 300; prevZeni = 200; break; case 15: // 10m zeniBase = 400; prevZeni = 300; break; default: zeniBase = 500 + ( ( zeros - 15 ) * 100 ); prevZeni = 400 + ( ( zeros - 15 ) * 100 ); break; } ratio = level / chklvl; zeni = prevZeni + ( ( zeniBase - prevZeni ) * ratio ); zeni = ( dice( get_rank_by_pl( level ), zeni ) + ( dice( get_rank_by_pl( level ), zeni ) / 10 + dice( get_curr_lck( killer ), zeni / 3 ) ) ); return zeni / 4; } void generate_treasure( CHAR_DATA * killer, CHAR_DATA * ch, OBJ_DATA * corpse ) { int tchance; int zeni; /* * Rolling for the initial check to see if we should be generating anything at all */ tchance = number_range( 1, 100 ); if( tchance <= 35 ) { return; } else if( tchance <= 65 ) { zeni = calc_zeni( ch->exp, killer ); if( zeni < 0 ) { bug( "RTG Made less than 0 zeni: PC(%s) Mob(%d) Room(%d) Zeni(%d)", killer->name, ch->pIndexData->vnum, ch->in_room->vnum, zeni ); return; } if( ch->in_room ) { ch->in_room->area->gold_looted += zeni; sysdata.global_looted += zeni / 100; } if( economy_has( ch->in_room->area, zeni ) ) { lower_economy( ch->in_room->area, zeni ); obj_to_obj( create_money( zeni ), corpse ); } return; } } /* * Make a fire. */ void make_fire( ROOM_INDEX_DATA * in_room, sh_int timer ) { OBJ_DATA *fire; fire = create_object( get_obj_index( OBJ_VNUM_FIRE ), 0 ); fire->timer = number_fuzzy( timer ); obj_to_room( fire, in_room ); return; } /* * Make a trap. */ OBJ_DATA *make_trap( int v0, int v1, int v2, int v3 ) { OBJ_DATA *trap; trap = create_object( get_obj_index( OBJ_VNUM_TRAP ), 0 ); trap->timer = 0; trap->value[0] = v0; trap->value[1] = v1; trap->value[2] = v2; trap->value[3] = v3; return trap; } /* * Turn an object into scraps. -Thoric */ void make_scraps( OBJ_DATA * obj ) { char buf[MAX_STRING_LENGTH]; OBJ_DATA *scraps, *tmpobj; CHAR_DATA *ch = NULL; separate_obj( obj ); scraps = create_object( get_obj_index( OBJ_VNUM_SCRAPS ), 0 ); scraps->timer = number_range( 5, 15 ); /* * don't make scraps of scraps of scraps of ... */ if( obj->pIndexData->vnum == OBJ_VNUM_SCRAPS ) { STRFREE( scraps->short_descr ); scraps->short_descr = STRALLOC( "some debris" ); STRFREE( scraps->description ); scraps->description = STRALLOC( "Bits of debris lie on the ground here." ); } else { sprintf( buf, scraps->short_descr, obj->short_descr ); STRFREE( scraps->short_descr ); scraps->short_descr = STRALLOC( buf ); sprintf( buf, scraps->description, obj->short_descr ); STRFREE( scraps->description ); scraps->description = STRALLOC( buf ); } if( obj->carried_by ) { act( AT_OBJECT, "$p falls to the ground in scraps!", obj->carried_by, obj, NULL, TO_CHAR ); if( obj == get_eq_char( obj->carried_by, WEAR_WIELD ) && ( tmpobj = get_eq_char( obj->carried_by, WEAR_DUAL_WIELD ) ) != NULL ) tmpobj->wear_loc = WEAR_WIELD; obj_to_room( scraps, obj->carried_by->in_room ); } else if( obj->in_room ) { if( ( ch = obj->in_room->first_person ) != NULL ) { act( AT_OBJECT, "$p is reduced to little more than scraps.", ch, obj, NULL, TO_ROOM ); act( AT_OBJECT, "$p is reduced to little more than scraps.", ch, obj, NULL, TO_CHAR ); } obj_to_room( scraps, obj->in_room ); } if( ( obj->item_type == ITEM_CONTAINER || obj->item_type == ITEM_KEYRING || obj->item_type == ITEM_QUIVER || obj->item_type == ITEM_CORPSE_PC ) && obj->first_content ) { if( ch && ch->in_room ) { act( AT_OBJECT, "The contents of $p fall to the ground.", ch, obj, NULL, TO_ROOM ); act( AT_OBJECT, "The contents of $p fall to the ground.", ch, obj, NULL, TO_CHAR ); } if( obj->carried_by ) empty_obj( obj, NULL, obj->carried_by->in_room ); else if( obj->in_room ) empty_obj( obj, NULL, obj->in_room ); else if( obj->in_obj ) empty_obj( obj, obj->in_obj, NULL ); } extract_obj( obj ); } OBJ_DATA *make_deathCertificate( CHAR_DATA * ch, CHAR_DATA * killer ) { char buf[MAX_STRING_LENGTH]; OBJ_DATA *dc; EXTRA_DESCR_DATA *ed; dc = create_object( get_obj_index( 610 ), 1 ); sprintf( buf, "%s death certificate", ch->name ); STRFREE( dc->name ); dc->name = STRALLOC( buf ); sprintf( buf, "%s's death certificate", ch->name ); STRFREE( dc->short_descr ); dc->short_descr = STRALLOC( buf ); ed = SetOExtra( dc, dc->name ); sprintf( buf, "Certificate of Death\n\r" "--------------------\n\r" "Name: &W%s&w\n\r" "Rank: &W%s&w\n\r" "Sex : &W%s&w Race: &W%s&w\n\r" "Cause of Death: &WHomicide&w\n\r" "Time of Death : &W%s&w\r" "Area of the Crime : &W%s&w\n\r" "Scene of the Crime: &W%s&w\n\r" "Suspect Information\n\r" "-------------------\n\r" "Name: &W%s&w\n\r" "Rank: &W%s&w\n\r" "Sex : &W%s&w Race: &W%s&w\n\r" "Reason for Involvement:\n\r" " &W'Possible' Self Defense&w\n\r", ch->name, get_rank( ch ), ch->sex == SEX_MALE ? "Male" : ch->sex == SEX_FEMALE ? "Female" : "Neutral", capitalize( get_race( ch ) ), ctime( ¤t_time ), killer->in_room->area->name, killer->in_room->name, killer->name, get_rank( killer ), killer->sex == SEX_MALE ? "Male" : killer->sex == SEX_FEMALE ? "Female" : "Neutral", capitalize( get_race( killer ) ) ); STRFREE( ed->description ); ed->description = STRALLOC( buf ); return dc; } /* * Goku's global drop code. Checks if a mob will drop any of * the items defined when it's killed. -Goku 07.28.04 */ #define GLOBAL_DROP_OBJ_TOKEN 2 void global_drop_check( OBJ_DATA * corpse, CHAR_DATA * ch, CHAR_DATA * killer ) { int luckMod; luckMod = get_curr_lck( killer ); /* * if luck is lower than 0, no drops */ if( luckMod < 1 ) return; if( number_range( luckMod, 10000 ) <= 1 ) { obj_to_obj( create_object( get_obj_index( GLOBAL_DROP_OBJ_TOKEN ), 0 ), corpse ); } return; } #undef GLOBAL_DROP_OBJ_TOKEN /* * Make a corpse out of a character. */ void make_corpse( CHAR_DATA * ch, CHAR_DATA * killer ) { char buf[MAX_STRING_LENGTH]; OBJ_DATA *corpse; OBJ_DATA *obj; OBJ_DATA *obj_next; char *name; if( !ch ) { if( !killer ) bug( "make_corpse: NULL TARGET and NULL KILLER", 0 ); else bug( "make_corpse: NULL TARGET, %s is the KILLER", killer->name, 0 ); return; } if( !killer ) { if( !ch ) bug( "make_corpse: NULL KILLER and NULL TARGET", 0 ); else bug( "make_corpse: NULL KILLER, %s as TARGET", ch->name, 0 ); return; } if( IS_NPC( ch ) ) { name = ch->short_descr; corpse = create_object( get_obj_index( OBJ_VNUM_CORPSE_NPC ), 0 ); corpse->timer = 6; if( ch->gold > 0 ) { if( ch->in_room ) { ch->in_room->area->gold_looted += ch->gold; sysdata.global_looted += ch->gold / 100; } obj_to_obj( create_money( ch->gold ), corpse ); ch->gold = 0; } else if( ch->gold < 0 && !IS_NPC( killer ) ) generate_treasure( killer, ch, corpse ); /* Cannot use these! They are used. corpse->value[0] = (int)ch->pIndexData->vnum; corpse->value[1] = (int)ch->max_hit; */ /* Using corpse cost to cheat, since corpses not sellable */ corpse->cost = ( -( int )ch->pIndexData->vnum ); corpse->value[2] = corpse->timer; } else { name = ch->name; corpse = create_object( get_obj_index( OBJ_VNUM_CORPSE_PC ), 0 ); if( in_arena( ch ) ) corpse->timer = 30; else corpse->timer = 15; corpse->value[2] = ( int )( corpse->timer / 8 ); corpse->value[4] = ch->level; if( CAN_PKILL( ch ) && sysdata.pk_loot ) xSET_BIT( corpse->extra_flags, ITEM_CLANCORPSE ); /* * Pkill corpses get save timers, in ticks (approx 70 seconds) * This should be anough for the killer to type 'get all corpse'. */ if( !IS_NPC( ch ) && !IS_NPC( killer ) ) corpse->value[3] = 1; else corpse->value[3] = 0; } if( CAN_PKILL( ch ) && CAN_PKILL( killer ) && ch != killer ) { sprintf( buf, "%s", killer->name ); STRFREE( corpse->action_desc ); corpse->action_desc = STRALLOC( buf ); } /* * Added corpse name - make locate easier , other skills */ sprintf( buf, "corpse %s", name ); STRFREE( corpse->name ); corpse->name = STRALLOC( buf ); sprintf( buf, corpse->short_descr, name ); STRFREE( corpse->short_descr ); corpse->short_descr = STRALLOC( buf ); sprintf( buf, corpse->description, name ); STRFREE( corpse->description ); corpse->description = STRALLOC( buf ); for( obj = ch->first_carrying; obj; obj = obj_next ) { obj_next = obj->next_content; if( !IS_NPC( ch ) && obj->wear_loc != -1 ) continue; obj_from_char( obj ); if( obj->item_type == ITEM_DRAGONBALL ) { obj_to_room( obj, ch->in_room ); continue; } if( ( !IS_NPC( ch ) && IS_OBJ_STAT( obj, ITEM_INVENTORY ) ) || IS_OBJ_STAT( obj, ITEM_DEATHROT ) ) extract_obj( obj ); else obj_to_obj( obj, corpse ); } /* * global drop? -Goku 07.28.04 */ if( !IS_NPC( killer ) && IS_NPC( ch ) && !xIS_SET( ch->affected_by, AFF_NO_GLOBAL_DROP ) && killer->pl / ch->exp <= 5 ) global_drop_check( corpse, ch, killer ); /* if (!IS_NPC(ch) && !IS_NPC(killer)) { obj_to_obj( make_deathCertificate(ch, killer), corpse ); } */ if( spaceDeath ) obj_to_room( corpse, get_room_index( ROOM_CORPSE_DROPOFF ) ); else obj_to_room( corpse, ch->in_room ); spaceDeath = FALSE; return; } void make_blood( CHAR_DATA * ch ) { OBJ_DATA *obj; obj = create_object( get_obj_index( OBJ_VNUM_BLOOD ), 0 ); obj->timer = number_range( 2, 4 ); obj->value[1] = number_range( 3, UMIN( 5, ch->level ) ); obj_to_room( obj, ch->in_room ); } void make_bloodstain( CHAR_DATA * ch ) { OBJ_DATA *obj; obj = create_object( get_obj_index( OBJ_VNUM_BLOODSTAIN ), 0 ); obj->timer = number_range( 1, 2 ); obj_to_room( obj, ch->in_room ); } /* * make some coinage */ OBJ_DATA *create_money( int amount ) { char buf[MAX_STRING_LENGTH]; OBJ_DATA *obj; if( amount <= 0 ) { bug( "Create_money: zero or negative money %d.", amount ); amount = 1; } if( amount == 1 ) { obj = create_object( get_obj_index( OBJ_VNUM_MONEY_ONE ), 0 ); } else { obj = create_object( get_obj_index( OBJ_VNUM_MONEY_SOME ), 0 ); sprintf( buf, obj->short_descr, amount ); STRFREE( obj->short_descr ); obj->short_descr = STRALLOC( buf ); obj->value[0] = amount; } return obj; }