/***************************************************************************
* Mud20 1.0 by Todd H. Johnson (Kregor) a derivative of the Open Gaming *
* License by Wizards of the Coast. All comments referring to D20, OGL, *
* and SRD refer to the System Reference Document for the Open Gaming *
* system. Any inclusion of these derivatives must include credit to the *
* Mud20 system, the full and complete Open Gaming LIcense, and credit to *
* the respective authors. See ../doc/srd.txt for more information. *
* *
* Emud 2.2 by Igor van den Hoven, Michiel Lange, and Martin Bethlehem. *
* *
* MrMud 1.4 by David Bills, Dug Michael and Martin Gallwey *
* *
* 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{rfeld, Tom Madsen, and Katje Nyboe. *
***************************************************************************/
#include "mud.h"
/*
bounty.c
Scandum 20-05-2002
Modified to serve as area justice system by Kregor - 9-2011
*/
char * const crime_titles [] =
{
"none",
"thievery",
"assault",
"low murder",
"high murder",
"*"
};
void send_bounty_message(char *message)
{
NOTE_DATA *pnote;
FILE *fp;
push_call("send_bounty_message(%p)",message);
// disabling for now, maybe with a more robust message board - Kregor
pop_call();
return;
ALLOCMEM( pnote, NOTE_DATA, 1);
pnote->next = NULL;
pnote->sender = STRALLOC("Bounty Office");
pnote->date = STRALLOC(get_time_string(mud->current_time));
pnote->time = mud->current_time;
pnote->to_list = STRALLOC("All");
pnote->subject = STRALLOC("New Contract!");
pnote->room_vnum = 30961;
pnote->text = STRALLOC(message);
LINK(pnote, mud->f_note, mud->l_note, next, prev);
close_reserve();
fp = my_fopen (NOTE_FILE, "a",FALSE);
if (fp == NULL)
{
perror (NOTE_FILE);
}
else
{
fprintf (fp, "Sender %s~\nDate %s~\nTime %ld\nTo %s~\nSubject %s~\nTopic %d\nText\n%s~\nRoom %u\n\n", pnote->sender, pnote->date, pnote->time, pnote->to_list, pnote->subject, pnote->topic, fixer(pnote->text), pnote->room_vnum);
fflush (fp);
}
my_fclose(fp);
open_reserve();
pop_call();
return;
}
/*
* Get PC's criminal record for specified crime in an area.
* Pass -1 for record of ANY crime in area - Kregor
*/
BOUNTY_DATA *get_record( CHAR_DATA *ch, AREA_DATA *area, int crime )
{
BOUNTY_DATA *bounty;
push_call("is_wanted(%p)",ch);
if (IS_NPC(ch))
{
pop_call();
return NULL;
}
for (bounty = mud->f_bounty ; bounty ; bounty = bounty->next)
{
if (bounty->pvnum == ch->pcdata->pvnum
&& bounty->area == area->low_r_vnum
&& (crime == -1 || bounty->crime == crime))
{
pop_call();
return (bounty);
}
}
pop_call();
return NULL;
}
/*
* PC posting of bounties - Kregor
*/
void do_bounty( CHAR_DATA *ch, char *argument )
{
char arg[MAX_INPUT_LENGTH];
char buf[MAX_INPUT_LENGTH];
int amount = 0;
int crime, count;
CHAR_DATA *judge;
CHAR_DATA *victim;
BOUNTY_DATA *bounty;
bool loaded = FALSE;
push_call("do_bounty(%p,%p)",ch,argument);
if (IS_NPC(ch))
{
pop_call();
return;
}
/* make sure the judge for the area is present */
for (judge = ch->in_room->first_person ; judge ; judge = judge->next_in_room)
{
if (IS_NPC(judge) && judge->pIndexData->vnum == judge->in_room->area->judge)
{
break;
}
}
if (judge == NULL)
{
send_to_char( "You must be with the local judge to do that.\n\r", ch );
pop_call();
return;
}
if (*argument == '\0')
{
send_to_char("Syntax: bounty <post|list|info|register> [amount] [target]\n\r", ch);
pop_call();
return;
}
argument = one_argument(argument, arg);
if (!strcasecmp(arg, "post"))
{
argument = one_argument(argument, arg);
amount = atoi(arg);
if (amount <= 0)
{
send_to_char("You can't post a bounty with no money.\n\r", ch);
pop_call();
return;
}
argument = one_argument(argument, arg);
if ((victim = lookup_char(arg)) == NULL)
{
if ((victim = start_partial_load(ch, arg)) == NULL)
{
pop_call();
return;
}
loaded = TRUE;
}
if (IS_IMMORTAL(victim))
{
send_to_char("You may not post bounties on Immortals.\n\r", ch);
if (loaded)
{
clear_partial_load(victim);
}
pop_call();
return;
}
if (!IS_SET(victim->act, PLR_KILLER) && !IS_SET(victim->act, PLR_THIEF))
{
command(judge, do_say, "%s has committed no crimes against you.", victim->name);
if (loaded)
{
clear_partial_load(victim);
}
pop_call();
return;
}
if (IS_SET(victim->act, PLR_KILLER))
crime = CRIME_HIGH_MURDER;
else if (IS_SET(victim->act, PLR_THIEF))
crime = CRIME_MUGGING;
else
crime = 0;
if (amount < 10000 * crime * victim->level)
{
ch_printf_color(ch, "The minimum bounty is %s.\n\r", 10000 * victim->level);
pop_call();
return;
}
if (!gold_transaction(ch, 0 - amount))
{
do_say(judge, "You do not have that much gold.");
if (loaded)
{
clear_partial_load(victim);
}
pop_call();
return;
}
post_bounty(ch, victim, amount, crime);
save_bounties();
do_say(judge, "The bounty has been posted, and shall be noted.");
// if (!IS_IMMORTAL(ch))
// {
// bounty = get_bounty(victim->pcdata->pvnum);
//
// strftime(arg, 12, "%2e %b %Y", gmtime( (const time_t *) &bounty->expires));
//
// sprintf(buf, "\n\r{078}A bounty of %s has been posted on %s's head by %s.\n\r", format_coins(bounty->amount,FALSE), victim->name, ch->name);
//
// send_bounty_message(buf);
// }
//
if (loaded)
{
clear_partial_load(victim);
}
}
else if (!strcasecmp(arg, "info"))
{
argument = one_argument(argument, arg);
for (count = 0, bounty = mud->f_bounty ; bounty ; bounty = bounty->next)
{
if (bounty->area != judge->pIndexData->area->low_r_vnum)
{
continue;
}
count++;
if (is_number(arg) && count == atoi(arg))
{
break;
}
if (strcmp(bounty->name, arg))
{
break;
}
}
if (!bounty)
{
command(judge, do_say, "There is no bounty posted on '%s'.\n\r", arg);
pop_call();
return;
}
if (bounty->expires < mud->current_time)
{
send_to_char("That bounty has expired.\n\r", ch);
remove_bounty(bounty);
save_bounties();
pop_call();
return;
}
if (bounty->victim)
strcpy(arg, mob_index[bounty->victim]->short_descr);
else if (bounty->pcvictim && is_string(pvnum_index[bounty->victim]->name))
strcpy(arg, pvnum_index[bounty->victim]->name);
else
{
send_to_char("That bounty is invalid.\n\r", ch);
remove_bounty(bounty);
save_bounties();
pop_call();
return;
}
sprintf(buf, "%s is wanted for %s against %s.\n\r", bounty->name, crime_titles[bounty->crime], arg);
if ((victim = get_char_pvnum(bounty->pvnum)) == NULL)
{
if ((victim = start_partial_load(ch, arg)) == NULL)
{
pop_call();
return;
}
loaded = TRUE;
}
if (victim)
{
cat_sprintf(buf, "A description of the quarry follows:\n\r%s,\n\r%s", adjective(victim), victim->description);
}
else
{
cat_sprintf(buf, "The criminal is described as %s.\n\r", adjective(victim));
cat_sprintf(buf, "There is no further description available.\n\r");
}
if (loaded)
{
clear_partial_load(victim);
}
switch (bounty->punishment)
{
default:
cat_sprintf(buf, "The wanted individual must be brought back ALIVE!\n\r");
break;
case PUNISHMENT_SEVER:
cat_sprintf(buf, "You must bring the HAND of %s to this office.\n\r", bounty->name);
break;
case PUNISHMENT_DEATH:
cat_sprintf(buf, "You must present the HEAD of %s as proof of death!\n\r", bounty->name);
break;
}
cat_sprintf(buf, "Expiration date for this bounty is: %s.\n\r", get_time_string(bounty->expires));
send_to_char_color(buf, ch);
}
else if (!strcasecmp(arg, "list"))
{
for (count = 0, bounty = mud->f_bounty ; bounty ; bounty = bounty->next)
{
if (bounty->area != judge->pIndexData->area->low_r_vnum)
{
continue;
}
count++;
sprintf(arg, "%s, for %s", bounty->name, crime_titles[bounty->crime]);
cat_sprintf(buf, " {178}%2d{200}] {178}%-36s %s\n\r", count, arg, format_coins(bounty->amount,FALSE));
}
if (count == 0)
{
command(judge, do_sayto, "%s There are no outstanding bounties in %s.", ch->name, judge->pIndexData->area->name);
pop_call();
return;
}
if (str_suffix("\n\r", buf))
{
strncat(buf, "\n\r", MAX_STRING_LENGTH);
}
act( "$N shows you a list of the outstanding bounties in $t.", ch, judge->pIndexData->area->name, judge, TO_CHAR);
act( "$N shows $n a list of the outstanding bounties in $t.", ch, judge->pIndexData->area->name, judge, TO_ROOM);
send_to_char_color(buf, ch);
pop_call();
return;
}
else
{
send_to_char("Syntax: bounty <post|list|info> [amount] [target]\n\r", ch);
}
pop_call();
return;
}
/*
* Bounty posting for NPCs
*/
void set_bounty( CHAR_DATA *ch, CHAR_DATA *victim, int crime )
{
int amt;
push_call("do_bounty(%p,%p,%p)",ch,victim,crime);
if (!IS_NPC(ch))
{
pop_call();
return;
}
// NPC can only post bounty in his own area.
if (ch->in_room->area != ch->pIndexData->area)
{
pop_call();
return;
}
if (IS_IMMORTAL(victim))
{
pop_call();
return;
}
amt = crime * 10000 * victim->level;
post_bounty(ch, victim, amt, crime);
save_bounties();
// sprintf(buf, "\n\r{078}A bounty of %s has been posted on %s's head by %s of %s",
// format_coins(amt,FALSE), victim->name, get_name(ch), ch->in_room->area->name);
// cat_sprintf(buf, "\n\r{078}%s.\n\r", capitalize(adjective(victim)));
// cat_sprintf(buf, "\n\r{078}The description of the wanted is as follows:\n\r");
// cat_sprintf(buf, victim->description);
//
// send_bounty_message(buf);
//
pop_call();
return;
}
void post_bounty(CHAR_DATA *ch, CHAR_DATA *victim, int amount, int crime)
{
BOUNTY_DATA *bounty;
push_call("post_bounty(%p,%p,%p,%p)",ch,victim,amount,crime);
if (IS_NPC(victim))
{
pop_call();
return;
}
if (ch->in_room->area->punishment[crime] == PUNISHMENT_NOT_ENFORCED)
{
pop_call();
return;
}
if (IS_NPC(ch))
amount = crime * 10000 * victim->level;
/* Increase the value of a current bounty */
for (bounty = mud->f_bounty ; bounty ; bounty = bounty->next)
{
if (bounty->pvnum == victim->pcdata->pvnum && bounty->crime == crime && bounty->area == ch->in_room->area->low_r_vnum)
{
bounty->amount = UMIN(1000000000, bounty->amount + amount);
bounty->expires = mud->current_time + 2592000 + bounty->amount / 1000000 * 86400;
bounty->victim = IS_NPC(ch) ? ch->pIndexData->vnum : 0;
bounty->pcvictim = !IS_NPC(ch) ? ch->pcdata->pvnum : 0;
pop_call();
return;
}
}
ALLOCMEM(bounty, BOUNTY_DATA, 1);
bounty->name = STRALLOC(capitalize(victim->name));
bounty->pvnum = victim->pcdata->pvnum;
bounty->amount = amount;
bounty->expires = mud->current_time + 2592000 + bounty->amount / 1000000 * 86400;
bounty->area = ch->in_room->area->low_r_vnum;
bounty->crime = crime;
bounty->punishment = ch->in_room->area->punishment[crime];
bounty->victim = IS_NPC(ch) ? ch->pIndexData->vnum : 0;
bounty->pcvictim = !IS_NPC(ch) ? ch->pcdata->pvnum : 0;
sort_bounty(bounty);
pop_call();
return;
}
void sort_bounty(BOUNTY_DATA *bounty)
{
BOUNTY_DATA *temp_bounty;
push_call("sort_bounty(%p)",bounty);
for (temp_bounty = mud->f_bounty ; temp_bounty ; temp_bounty = temp_bounty->next)
{
if (strcmp(bounty->name, temp_bounty->name) < 0)
{
INSERT_LEFT(bounty, temp_bounty, mud->f_bounty, next, prev);
break;
}
}
if (temp_bounty == NULL)
{
LINK(bounty, mud->f_bounty, mud->l_bounty, next, prev);
}
pop_call();
return;
}
void remove_bounty(BOUNTY_DATA *bounty)
{
push_call("remove_bounty(%p)",bounty);
UNLINK(bounty, mud->f_bounty, mud->l_bounty, next, prev);
STRFREE(bounty->name);
FREEMEM(bounty);
pop_call();
return;
}
BOUNTY_DATA *get_bounty( int pvnum )
{
BOUNTY_DATA *bounty;
push_call("get_bounty(%p)",pvnum);
for (bounty = mud->f_bounty ; bounty ; bounty = bounty->next)
{
if (bounty->pvnum == pvnum)
{
pop_call();
return(bounty);
}
}
pop_call();
return NULL;
}
bool collect_bounty( CHAR_DATA *ch, CHAR_DATA *victim )
{
BOUNTY_DATA *bounty;
AREA_DATA *area;
OBJ_DATA *obj;
char buf[MAX_INPUT_LENGTH];
push_call("collect_bounty(%p,%p)",ch,victim);
if (IS_NPC(victim) || IS_NPC(ch))
{
pop_call();
return FALSE;
}
if ((bounty = get_bounty(victim->pcdata->pvnum)) == NULL)
{
pop_call();
return FALSE;
}
if ((area = get_area_from_vnum(bounty->area)) == NULL)
{
remove_bounty(bounty);
save_bounties();
pop_call();
return FALSE;
}
if (bounty->punishment == PUNISHMENT_DEATH)
{
act( "You sever $N's head to collect the bounty on it.", ch, NULL, victim, TO_CHAR);
act( "$n severs $N's head as a grisly trophy.", ch, NULL, victim, TO_NOTVICT);
obj = create_object(get_obj_index(OBJ_VNUM_BOUNTY_HEAD), 0);
obj->level = victim->level;
obj->cost = bounty->amount;
obj->weight = victim->weight / 30;
obj->owned_by = victim->pcdata->pvnum;
sprintf(buf, "%s %s", obj->name, victim->name);
RESTRING(obj->name, buf);
sprintf(buf, "%s %s", obj->short_descr, get_name(victim));
RESTRING(obj->short_descr, buf);
sprintf(buf, "The head of %s lies here.", get_name(victim));
RESTRING(obj->long_descr, buf);
sprintf(buf, "The head of %s stares up at you, frozen in a permanent gasp of surprise.", get_name(victim));
RESTRING(obj->description, justify(buf, 80));
obj_to_char(obj, ch);
}
else if (bounty->punishment == PUNISHMENT_SEVER)
{
act( "You sever $N's hand to collect the bounty on it.", ch, NULL, victim, TO_CHAR);
act( "$n severs $N's hand below the forearm.", ch, NULL, victim, TO_NOTVICT);
obj = create_object(get_obj_index(OBJ_VNUM_BOUNTY_HEAD), 0);
obj->level = victim->level;
obj->cost = bounty->amount;
obj->weight = 10;
obj->owned_by = victim->pcdata->pvnum;
sprintf(buf, "%s %s", obj->name, victim->name);
RESTRING(obj->name, buf);
sprintf(buf, "%s %s", obj->short_descr, get_name(victim));
RESTRING(obj->short_descr, buf);
sprintf(buf, "The hand of someone lies here.");
RESTRING(obj->long_descr, buf);
sprintf(buf, "The hand is crudely cut off from the forearm as a grisly trophy.");
RESTRING(obj->description, justify(buf, 80));
obj_to_char(obj, ch);
}
else if (victim->position == POS_DEAD || IS_PLR(victim, PLR_DEAD))
{
act("You can no longer collect a bounty on $N, as $E is dead.", ch, NULL, victim, TO_CHAR);
pop_call();
return FALSE;
}
else
{
int jailroom;
if (!IS_AWAKE(victim))
{
if (mob_index[area->guard] != NULL)
{
act("After $N's subdual, $t and a contingent come to drag $M to jail.", ch, mob_index[area->guard]->short_descr, victim, TO_ALL);
}
else
{
act("Mercenaries from $t come to drag $N away.", ch, area->name, victim, TO_ALL);
}
gold_transaction(ch, bounty->amount);
act("You receive a bounty of $t.", ch, format_coins(bounty->amount, FALSE), NULL, TO_CHAR);
remove_bounty(bounty);
save_bounties();
// take the victim to jail.
if ((jailroom = area->dungeon) == 0)
{
if ((jailroom = area->courtroom) == 0)
{
log_build_printf(bounty->area, "collect_bounty: dungeon and courtroom not set for area.");
pop_call();
return TRUE;
}
}
char_from_room(victim);
char_to_room(victim, jailroom, TRUE);
}
}
pop_call();
return TRUE;
}
bool confiscate( CHAR_DATA *ch, CHAR_DATA *victim )
{
OBJ_DATA *obj;
int vnum, pick, cnt;
push_call("confiscate(%p,%p)",ch, victim);
if ((vnum = ch->in_room->area->storeroom) == 0)
{
log_build_printf(ch->pIndexData->vnum, "No impound storeroom set for area.");
pop_call();
return FALSE;
}
for (cnt = 0, obj = victim->first_carrying ; obj ; obj = obj->next_content)
{
if (IS_OBJ_TYPE(obj, ITEM_CONTAINER)
|| IS_OBJ_TYPE(obj, ITEM_SPELLPOUCH)
|| IS_OBJ_TYPE(obj, ITEM_SHEATH))
continue;
if (IS_SET(obj->extra_flags, ITEM_CONCEALED))
continue;
if (IS_OBJ_STAT(obj, ITEM_NODROP|ITEM_NOREMOVE|ITEM_INVENTORY))
continue;
if (obj_cost(obj) < UMIN(victim->level * 5000, 100000))
continue;
cnt++;
}
pick = number_range(1,cnt);
for (cnt = 0, obj = victim->first_carrying ; obj ; obj = obj->next_content)
{
if (IS_OBJ_TYPE(obj, ITEM_CONTAINER)
|| IS_OBJ_TYPE(obj, ITEM_SPELLPOUCH)
|| IS_OBJ_TYPE(obj, ITEM_SHEATH))
continue;
if (IS_SET(obj->extra_flags, ITEM_CONCEALED))
continue;
if (IS_OBJ_STAT(obj, ITEM_NODROP|ITEM_NOREMOVE|ITEM_INVENTORY))
continue;
if (obj_cost(obj) < UMIN(victim->level * 5000, 100000))
continue;
if (pick == cnt)
break;
}
if (!obj)
{
act("$n frisks you, but takes nothing.", ch, NULL, victim, TO_VICT);
act("$n frisks $N, but takes nothing.", ch, NULL, victim, TO_NOTVICT);
pop_call();
return FALSE;
}
if (IS_WORN(obj))
unequip_char(victim, obj, FALSE);
obj_from_char(obj);
obj->owned_by = victim->pcdata->pvnum;
obj_to_room(obj, vnum);
act("$n frisks you, and confiscates $p!", ch, obj, victim, TO_VICT);
act("$n frisks $N, and confiscates $p!", ch, obj, victim, TO_NOTVICT);
act("$n informs you to see the judge, and pay the fine, if you want it back.", ch, NULL, victim, TO_VICT);
pop_call();
return TRUE;
}