/*
* file: limits.c , Limit and gain control module. Part of DIKUMUD
* Usage: Procedures controling gain and limit.
* Copyright (C) 1990, 1991 - see 'license.doc' for complete information.
*/
#include <stdio.h>
#include <stdlib.h>
/* #include <unistd.h> */
#include <sys/types.h>
#include <signal.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>
#include "global.h"
#include "bug.h"
#include "spells.h"
#include "comm.h"
#include "db.h"
#include "spell_parser.h"
#include "constants.h"
#include "utils.h"
#include "multiclass.h"
#include "fight.h"
#include "reception.h"
#include "interpreter.h"
#include "handler.h"
#include "act_obj.h"
#include "act_other.h"
#define _DIKU_LIMITS_C
#include "mudlimits.h"
#undef BOOT_IDLE /* define this to kick idle people, undefine to let them stay idle all day */
char *ClassTitles(struct char_data *ch)
{
int i = 0;
int count = 0;
static char buf[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
if (DEBUG > 2)
log_info("called %s with %s", __PRETTY_FUNCTION__, SAFE_NAME(ch));
for (i = MAGE_LEVEL_IND; i <= DRUID_LEVEL_IND; i++) {
if (GET_LEVEL(ch, i)) {
count++;
if (count > 1) {
sprintf(buf + strlen(buf), "/%s", GET_CLASS_TITLE(ch, i, GET_LEVEL(ch, i)));
} else {
sprintf(buf, "%s", GET_CLASS_TITLE(ch, i, GET_LEVEL(ch, i)));
}
}
}
return (buf);
}
/* When age < 15 return the value p0 */
/* When age in 15..29 calculate the line between p1 & p2 */
/* When age in 30..44 calculate the line between p2 & p3 */
/* When age in 45..59 calculate the line between p3 & p4 */
/* When age in 60..79 calculate the line between p4 & p5 */
/* When age >= 80 return the value p6 */
int graf(int char_age, int p0, int p1, int p2, int p3, int p4, int p5, int p6)
{
if (DEBUG > 2)
log_info("called %s with %d, %d, %d, %d, %d, %d, %d, %d", __PRETTY_FUNCTION__, char_age,
p0, p1, p2, p3, p4, p5, p6);
if (char_age < 15)
return (p0); /* < 15 */
else if (char_age <= 29)
return (int)(p1 + (((char_age - 15) * (p2 - p1)) / 15)); /* 15..29 */
else if (char_age <= 44)
return (int)(p2 + (((char_age - 30) * (p3 - p2)) / 15)); /* 30..44 */
else if (char_age <= 59)
return (int)(p3 + (((char_age - 45) * (p4 - p3)) / 15)); /* 45..59 */
else if (char_age <= 79)
return (int)(p4 + (((char_age - 60) * (p5 - p4)) / 20)); /* 60..79 */
else
return (p6); /* >= 80 */
}
/* The three MAX functions define a characters Effective maximum */
/* Which is NOT the same as the ch->points.max_xxxx !!! */
int mana_limit(struct char_data *ch)
{
int max = 100;
int extra = 0;
int cl = 0;
if (DEBUG > 2)
log_info("called %s with %s", __PRETTY_FUNCTION__, SAFE_NAME(ch));
if (IS_PC(ch)) {
if (HasClass(ch, CLASS_MAGIC_USER))
extra += GET_LEVEL(ch, MAGE_LEVEL_IND) * 5;
if (HasClass(ch, CLASS_CLERIC))
extra += GET_LEVEL(ch, CLERIC_LEVEL_IND) * 4;
if (HasClass(ch, CLASS_DRUID))
extra += GET_LEVEL(ch, DRUID_LEVEL_IND) * 3;
if (HasClass(ch, CLASS_RANGER))
extra += (GET_LEVEL(ch, RANGER_LEVEL_IND) * 5) / 2;
if (HasClass(ch, CLASS_THIEF))
extra += (GET_LEVEL(ch, THIEF_LEVEL_IND) * 4) / 2;
if (HasClass(ch, CLASS_WARRIOR))
extra += (GET_LEVEL(ch, WARRIOR_LEVEL_IND) * 3) / 2;
cl = HowManyClasses(ch);
if ((cl = HowManyClasses(ch)) > 1)
extra = ((extra * 10) / ((cl * 10) + 5));
max += extra;
}
max += ch->points.max_mana; /* bonus mana */
return (max);
}
int hit_limit(struct char_data *ch)
{
int max = 0;
if (DEBUG > 2)
log_info("called %s with %s", __PRETTY_FUNCTION__, SAFE_NAME(ch));
if (IS_PC(ch))
max = (ch->points.max_hit) + (graf(age(ch).year, 2, 4, 17, 14, 8, 4, 3));
else
max = (ch->points.max_hit);
/*
* Class/Level calculations
*/
if (HowManyClasses(ch) == 1) {
if (HasClass(ch, CLASS_RANGER))
max += (GET_LEVEL(ch, RANGER_LEVEL_IND) / 5) + 2;
else if (HasClass(ch, CLASS_WARRIOR))
max += (GET_LEVEL(ch, WARRIOR_LEVEL_IND) / 2) + 1;
}
/*
* Skill/Spell calculations
*/
return (max);
}
int move_limit(struct char_data *ch)
{
int max = 0;
if (DEBUG > 2)
log_info("called %s with %s", __PRETTY_FUNCTION__, SAFE_NAME(ch));
if (!IS_NPC(ch))
max = 70 + age(ch).year + (int)GET_CON(ch) + GetTotLevel(ch);
else
max = ch->points.max_move;
switch (GET_RACE(ch)) {
case RACE_DWARF:
max -= 15;
break;
case RACE_GNOME:
max -= 10;
break;
case RACE_HALFLING:
max += 5;
break;
case RACE_ELVEN:
max += 10;
break;
}
return (max);
}
int mana_gain(struct char_data *ch)
{
int gain = 0;
if (DEBUG > 2)
log_info("called %s with %s", __PRETTY_FUNCTION__, SAFE_NAME(ch));
if (IS_NPC(ch)) {
/*
* Neat and fast
*/
gain = GetTotLevel(ch);
} else {
gain = graf(age(ch).year, 2, 4, 6, 8, 10, 12, 16);
if (GET_RACE(ch) == RACE_ELVEN)
gain += 5;
if (GET_RACE(ch) == RACE_GNOME)
gain += 2;
/*
* Class calculations
*/
if (HasClass(ch, CLASS_MAGIC_USER))
gain += 2;
if (HasClass(ch, CLASS_CLERIC))
gain += 2;
if (HasClass(ch, CLASS_DRUID))
gain += 1;
/*
* Skill/Spell calculations
*/
/*
* Position calculations
*/
switch (GET_POS(ch)) {
case POSITION_SLEEPING:
gain += gain;
break;
case POSITION_RESTING:
gain += (gain >> 1); /* Divide by 2 */
break;
case POSITION_SITTING:
gain += (gain >> 2); /* Divide by 4 */
break;
}
if (HasClass(ch, CLASS_MAGIC_USER) ||
HasClass(ch, CLASS_CLERIC) || HasClass(ch, CLASS_DRUID))
gain += gain;
}
if (number(1, 101) < ch->skills[SKILL_MEDITATION].learned)
gain += 10;
if (IS_AFFECTED(ch, AFF_POISON))
gain >>= 2;
if (GET_COND(ch, FULL) < 2) /* starving */
gain >>= 2;
if (GET_COND(ch, THIRST) < 2) /* parched */
gain >>= 2;
return (gain);
}
int hit_gain(struct char_data *ch)
{
int gain = 0;
if (DEBUG > 2)
log_info("called %s with %s", __PRETTY_FUNCTION__, SAFE_NAME(ch));
if (IS_NPC(ch)) {
gain = 8;
} else {
if (GET_POS(ch) == POSITION_FIGHTING) {
gain = 1;
} else {
gain = graf(age(ch).year, 2, 5, 10, 18, 6, 4, 2);
}
/*
* Class/Level calculations
*/
if (HasClass(ch, CLASS_MAGIC_USER))
gain -= 2;
if (HasClass(ch, CLASS_CLERIC))
gain -= 1;
if (HasClass(ch, CLASS_WARRIOR))
gain += 3;
if (HasClass(ch, CLASS_RANGER))
gain += 2;
/*
* Skill/Spell calculations
*/
/*
* Position calculations
*/
switch (GET_POS(ch)) {
case POSITION_SLEEPING:
gain += gain >> 1;
break;
case POSITION_RESTING:
gain += gain >> 2;
break;
case POSITION_SITTING:
gain += gain >> 3;
break;
}
if (GET_POS(ch) == POSITION_SLEEPING)
if (number(1, 101) < ch->skills[SKILL_MEDITATION].learned)
gain += 3;
}
if (GET_RACE(ch) == RACE_DWARF)
gain += 5;
if (GET_RACE(ch) == RACE_HALFLING)
gain += 2;
if (GET_RACE(ch) == RACE_ELVEN)
gain -= 1;
if (GET_RACE(ch) == RACE_GNOME)
gain += 1;
if (IS_AFFECTED(ch, AFF_POISON)) {
gain >>= 2;
/* damage(ch, ch, 15, SPELL_POISON); */
}
if (IS_PC(ch) && IS_STARVING(ch)) {
gain >>= 2;
/* damage(ch, ch, number(1, 3), TYPE_HUNGER); */
}
if (IS_PC(ch) && IS_PARCHED(ch)) {
gain >>= 2;
/* damage(ch, ch, number(1, 3), TYPE_HUNGER); */
}
gain = MAX(gain, 1);
//if (IS_PC(ch)) cprintf(ch, "You should be gaining %d hit points.\r\n", gain);
return (gain);
}
/*
* move gain pr. game hour
*/
int move_gain(struct char_data *ch)
{
int gain = 0;
if (DEBUG > 2)
log_info("called %s with %s", __PRETTY_FUNCTION__, SAFE_NAME(ch));
if (IS_NPC(ch))
return (GetTotLevel(ch));
else {
if (GET_POS(ch) != POSITION_FIGHTING)
gain = 5 + (int)GET_CON(ch);
else {
if (number(1, 101) < ch->skills[SKILL_ENDURANCE].learned)
gain = 2;
else
gain = 0;
}
if (HasClass(ch, CLASS_RANGER))
gain += 3;
if (HasClass(ch, CLASS_DRUID))
gain += 2;
/*
* Position calculations
*/
switch (GET_POS(ch)) {
case POSITION_SLEEPING:
gain += (gain >> 1); /* Divide by 2 */
break;
case POSITION_RESTING:
gain += (gain >> 2); /* Divide by 4 */
break;
case POSITION_SITTING:
gain += (gain >> 3); /* Divide by 8 */
break;
}
}
if (GET_RACE(ch) == RACE_DWARF)
gain += 4;
if (GET_RACE(ch) == RACE_HALFLING)
gain += 3;
if (GET_RACE(ch) == RACE_ELVEN)
gain += 1;
if (number(1, 101) < ch->skills[SKILL_ENDURANCE].learned)
gain += 5;
if (IS_AFFECTED(ch, AFF_POISON))
gain >>= 2;
if (GET_COND(ch, FULL) < 2) /* starving */
gain = 1;
if (GET_COND(ch, THIRST) < 2) /* parched */
gain = 1;
return (gain);
}
/* Gain maximum in various points */
void advance_level(struct char_data *ch, int class)
{
int add_hp = 0;
int i = 0;
if (DEBUG > 1)
log_info("called %s with %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch), class);
if (GET_LEVEL(ch, class) > 0 && GET_EXP(ch) <
#ifdef MOB_LEVELING
((IS_PC(ch) || (IS_SET(ch->specials.act, ACT_POLYSELF) ||
IS_SET(ch->specials.act, ACT_POLYSELF))) ?
titles[class][GET_LEVEL(ch, class) + 1].exp :
(titles[class][GET_LEVEL(ch, class) + 1].exp / 20))
#else
titles[class][GET_LEVEL(ch, class) + 1].exp
#endif
) {
log_info("Bad advance_level");
return;
}
GET_LEVEL(ch, class) += 1;
/* Constitution Bonus only for Fighter types */
if ((class == RANGER_LEVEL_IND) || (class == WARRIOR_LEVEL_IND))
add_hp = con_app[(int)GET_CON(ch)].hitp;
else
add_hp = MIN(con_app[(int)GET_CON(ch)].hitp, 2);
switch (class) {
case MAGE_LEVEL_IND:
{
ch->specials.pracs += MAX(3, wis_app[(int)GET_INT(ch)].bonus);
if (GET_LEVEL(ch, MAGE_LEVEL_IND) < 30)
add_hp += number(2, 4);
else
add_hp += 1;
}
break;
case DRUID_LEVEL_IND:
{
if (GET_LEVEL(ch, DRUID_LEVEL_IND) < 20)
add_hp += number(2, 8);
else
add_hp += 3;
}
break;
case CLERIC_LEVEL_IND:
{
ch->specials.pracs += MAX(3, wis_app[(int)GET_WIS(ch)].bonus);
if (GET_LEVEL(ch, CLERIC_LEVEL_IND) < 30)
add_hp += number(2, 8);
else
add_hp += 3;
}
break;
case THIEF_LEVEL_IND:
{
ch->specials.pracs += MAX(3, wis_app[(int)GET_DEX(ch)].bonus);
if (GET_LEVEL(ch, THIEF_LEVEL_IND) < 30)
add_hp += number(2, 6);
else
add_hp += 2;
}
break;
case RANGER_LEVEL_IND:
{
ch->specials.pracs +=
MAX(3,
wis_app[((int)GET_DEX(ch) >=
(int)GET_STR(ch) ? (int)GET_DEX(ch) : (int)
GET_STR(ch))].bonus);
if (GET_LEVEL(ch, RANGER_LEVEL_IND) < 30)
add_hp += number(2, 10);
else
add_hp += 4;
}
break;
case WARRIOR_LEVEL_IND:
{
ch->specials.pracs += MAX(3, wis_app[(int)GET_STR(ch)].bonus);
if (GET_LEVEL(ch, WARRIOR_LEVEL_IND) < 30)
add_hp += number(2, 10);
else
add_hp += 4;
}
break;
}
add_hp /= HowManyClasses(ch);
add_hp++;
if (GET_LEVEL(ch, class) <= 5)
add_hp++;
ch->points.max_hit += MAX(1, add_hp);
if (GetMaxLevel(ch) >= LOW_IMMORTAL)
for (i = 0; i < 3; i++)
ch->specials.conditions[i] = -1;
ch->points.max_move = GET_MAX_MOVE(ch);
// if (IS_PC(ch))
// update_player_list_entry(ch->desc);
log_info("%s advances to level %d.\r\n", GET_NAME(ch), GetMaxLevel(ch));
}
/* Lose in various points */
/*
* ** Damn tricky for multi-class...
*/
void drop_level(struct char_data *ch, int class)
{
int add_hp = 0;
int lin_class = 0;
int old_style = 0;
if (DEBUG > 1)
log_info("called %s with %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch), class);
/*
* if (GetMaxLevel(ch) >= LOW_IMMORTAL)
* return;
*/
if (GetMaxLevel(ch) == 1)
return;
add_hp = con_app[(int)GET_CON(ch)].hitp;
switch (class) {
case CLASS_MAGIC_USER:{
lin_class = MAGE_LEVEL_IND;
if (GET_LEVEL(ch, MAGE_LEVEL_IND) < 30)
add_hp += number(2, 4);
else
add_hp += 1;
}
break;
case CLASS_DRUID:{
lin_class = DRUID_LEVEL_IND;
if (GET_LEVEL(ch, DRUID_LEVEL_IND) < 30)
add_hp += number(2, 8);
else
add_hp += 3;
}
break;
case CLASS_CLERIC:{
lin_class = CLERIC_LEVEL_IND;
if (GET_LEVEL(ch, CLERIC_LEVEL_IND) < 30)
add_hp += number(2, 8);
else
add_hp += 3;
}
break;
case CLASS_THIEF:{
lin_class = THIEF_LEVEL_IND;
if (GET_LEVEL(ch, THIEF_LEVEL_IND) < 30)
add_hp += number(2, 6);
else
add_hp += 2;
}
break;
case CLASS_WARRIOR:{
lin_class = WARRIOR_LEVEL_IND;
if (GET_LEVEL(ch, WARRIOR_LEVEL_IND) < 30)
add_hp += number(2, 10);
else
add_hp += 4;
}
break;
case CLASS_RANGER:{
lin_class = RANGER_LEVEL_IND;
if (GET_LEVEL(ch, RANGER_LEVEL_IND) < 30)
add_hp += number(2, 10);
else
add_hp += 4;
}
break;
}
add_hp /= HowManyClasses(ch);
if (IS_NPC(ch)) {
gain_exp(ch, -GET_EXP(ch) / 4);
} else if (GetMaxLevel(ch) < 7) {
gain_exp(ch, -GET_EXP(ch) / (12 * HowManyClasses(ch)));
} else if (GetMaxLevel(ch) < 14) {
gain_exp(ch, -GET_EXP(ch) / (10 * HowManyClasses(ch)));
} else if (GetMaxLevel(ch) < 21) {
gain_exp(ch, -GET_EXP(ch) / (8 * HowManyClasses(ch)));
} else if (GetMaxLevel(ch) < 28) {
gain_exp(ch, -GET_EXP(ch) / (6 * HowManyClasses(ch)));
} else
gain_exp(ch, -GET_EXP(ch) / (4 * HowManyClasses(ch)));
GET_LEVEL(ch, class) -= 1;
if (GET_LEVEL(ch, class) < 1)
GET_LEVEL(ch, class) = 1;
ch->points.max_hit -= MAX(1, add_hp);
if (ch->points.max_hit < 1)
ch->points.max_hit = 1;
ch->specials.pracs -= MAX(3, wis_app[(int)GET_WIS(ch)].bonus);
if (old_style) {
ch->points.exp = MIN(titles[lin_class][(int)GET_LEVEL(ch, lin_class)].exp, GET_EXP(ch));
}
if (ch->points.exp < 0)
ch->points.exp = 0;
// update_player_list_entry(ch->desc);
log_info("%s drops to level %d.\r\n", GET_NAME(ch), GetMaxLevel(ch));
}
void set_title(struct char_data *ch)
{
char buf[MAX_INPUT_LENGTH] = "\0\0\0\0\0\0\0";
if (DEBUG > 1)
log_info("called %s with %s", __PRETTY_FUNCTION__, SAFE_NAME(ch));
sprintf(buf, "the %s %s", RaceName[ch->race], ClassTitles(ch));
if (GET_TITLE(ch)) {
DESTROY(GET_TITLE(ch));
CREATE(GET_TITLE(ch), char, strlen (buf) + 1);
} else {
CREATE(GET_TITLE(ch), char, strlen (buf) + 1);
}
strcpy(GET_TITLE(ch), buf);
}
void gain_exp(struct char_data *ch, int gain)
{
int i = 0;
if (DEBUG > 2)
log_info("called %s with %s, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch), gain);
/* save_char(ch,NOWHERE); */
if (!IS_IMMORTAL(ch)) {
if (gain > 0) {
gain = MIN(100000, gain);
if (IS_PC(ch) || (IS_SET(ch->specials.act, ACT_POLYSELF) ||
IS_SET(ch->specials.act, ACT_POLYSELF))) {
gain /= HowManyClasses(ch);
} else {
#ifdef MOB_LEVELING
GET_EXP(ch) += gain;
for (i = MAGE_LEVEL_IND; i <= DRUID_LEVEL_IND; i++) {
if (GET_LEVEL(ch, i)) {
if (GET_EXP(ch) >= ((titles[i][GET_LEVEL(ch, i) + 1].exp / 20))) {
advance_level(ch, i);
act("$n seems to be looking more healthy today.", FALSE, ch, 0, 0,
TO_ROOM);
}
}
}
return;
#endif
}
if (IS_PC(ch) && (GetMaxLevel(ch) == 1))
gain *= 2;
if (IS_PC(ch) || (IS_SET(ch->specials.act, ACT_POLYSELF) ||
IS_SET(ch->specials.act, ACT_POLYSELF))) {
for (i = MAGE_LEVEL_IND; i <= DRUID_LEVEL_IND; i++) {
if (GET_LEVEL(ch, i)) {
if (GET_EXP(ch) >= titles[i][GET_LEVEL(ch, i) + 2].exp) {
cprintf(ch,
"You will not gain anymore exp until you practice at a guild.\r\n");
GET_EXP(ch) = titles[i][GET_LEVEL(ch, i) + 2].exp - 1;
return;
} else if (GET_EXP(ch) >= titles[i][GET_LEVEL(ch, i) + 1].exp) {
/*
* do nothing..this is cool
*/
} else if (GET_EXP(ch) + gain >= titles[i][GET_LEVEL(ch, i) + 1].exp) {
cprintf(ch, "You have gained enough to be a(n) %s\r\n",
GET_CLASS_TITLE(ch, i, GET_LEVEL(ch, i) + 1));
cprintf(ch,
"You will not gain anymore exp until you practice at a guild.\r\n");
if (GET_EXP(ch) + gain >= titles[i][GET_LEVEL(ch, i) + 2].exp) {
GET_EXP(ch) = titles[i][GET_LEVEL(ch, i) + 2].exp - 1;
return;
}
}
}
}
}
GET_EXP(ch) += gain;
if (IS_PC(ch) || IS_SET(ch->specials.act, ACT_POLYSELF)) {
for (i = MAGE_LEVEL_IND; i <= DRUID_LEVEL_IND; i++) {
if (GET_LEVEL(ch, i)) {
if (GET_EXP(ch) > titles[i][GET_LEVEL(ch, i) + 2].exp) {
GET_EXP(ch) = titles[i][GET_LEVEL(ch, i) + 2].exp - 1;
}
}
}
}
}
if (gain < 0) {
GET_EXP(ch) += gain;
if (GET_EXP(ch) < 0)
GET_EXP(ch) = 0;
}
}
}
void gain_exp_regardless(struct char_data *ch, int gain, int class)
{
int i = 0;
int is_altered = FALSE;
if (DEBUG > 2)
log_info("called %s with %s, %d, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch), gain, class);
save_char(ch, NOWHERE);
if (!IS_NPC(ch)) {
if (gain > 0) {
GET_EXP(ch) += gain;
for (i = 0; (i < ABS_MAX_LVL) && (titles[class][i].exp <= GET_EXP(ch)); i++) {
if (i > GET_LEVEL(ch, class)) {
cprintf(ch, "You raise a level\r\n");
/* GET_LEVEL(ch,class) = i; */
advance_level(ch, class);
is_altered = TRUE;
}
}
}
if (gain < 0)
GET_EXP(ch) += gain;
if (GET_EXP(ch) < 0)
GET_EXP(ch) = 0;
}
if (is_altered)
set_title(ch);
}
void gain_condition(struct char_data *ch, int condition, int value)
{
int intoxicated = FALSE;
if (DEBUG > 2)
log_info("called %s with %s, %d, %d", __PRETTY_FUNCTION__, SAFE_NAME(ch), condition,
value);
if (GET_COND(ch, condition) == -1) /* No change */
return;
intoxicated = (GET_COND(ch, DRUNK) > 0);
GET_COND(ch, condition) += value;
GET_COND(ch, condition) = MAX(0, GET_COND(ch, condition));
GET_COND(ch, condition) = MIN(24, GET_COND(ch, condition));
/*
* if (GET_COND(ch, condition)) return;
*/
switch (condition) {
case FULL:
if (IS_GETTING_HUNGRY(ch)) {
if (IS_HUNGRY(ch)) {
if (IS_STARVING(ch)) {
cprintf(ch, "You are starving!\r\n");
} else {
cprintf(ch, "You are hungry.\r\n");
}
} else {
cprintf(ch, "You are getting hungry.\r\n");
}
}
break;
case THIRST:
if (IS_GETTING_THIRSTY(ch)) {
if (IS_THIRSTY(ch)) {
if (IS_PARCHED(ch)) {
cprintf(ch, "You are parched!\r\n");
} else {
cprintf(ch, "You are thirsty.\r\n");
}
} else {
cprintf(ch, "You are getting thirsty.\r\n");
}
}
break;
case DRUNK:
if (IS_HOPELESSLY_DRUNK(ch)) {
cprintf(ch, "You are homelessly DRUNK!\r\n");
} else if (intoxicated && GET_COND(ch, DRUNK) < 1) {
cprintf(ch, "You are now sober.\r\n");
}
break;
default:
break;
}
}
void check_idling(struct char_data *ch)
{
#ifdef BOOT_IDLE
struct obj_cost cost;
#endif
if (DEBUG > 2)
log_info("called %s with %s", __PRETTY_FUNCTION__, SAFE_NAME(ch));
++(ch->specials.timer);
/*
* if (ch->specials.timer > 5 && ch->specials.timer < 10) {
*/
if (!ch->specials.timer % 5) {
do_save(ch, "", 0);
return;
}
#ifdef BOOT_IDLE
if (ch->specials.timer >= 15) {
log_info("LOG:%s AUTOSAVE:Timer %d.", GET_NAME(ch), ch->specials.timer);
if (ch->specials.fighting) {
stop_fighting(ch->specials.fighting);
stop_fighting(ch);
}
GET_POS(ch) = POSITION_STANDING;
char_from_room(ch);
char_to_room(ch, 0);
if (IS_IMMORTAL(ch))
GET_HOME(ch) = 1000;
else
GET_HOME(ch) = 3008;
if (recep_offer(ch, NULL, &cost)) {
cost.total_cost = 0;
new_save_equipment(ch, &cost, FALSE);
save_obj(ch, &cost, TRUE);
}
extract_char(ch);
if (ch->desc)
close_socket(ch->desc);
/*
* ch->desc = 0; already done inside close_socket, thanks valgrind!
*/
log_info("Done Auto-Saving.");
}
#endif
}
/* Update both PC's & NPC's and objects */
void point_update(int current_pulse)
{
struct char_data *i = NULL;
struct char_data *next_dude = NULL;
struct obj_data *j = NULL;
struct obj_data *next_thing = NULL;
int count = 0;
if (DEBUG > 2)
log_info("called %s with %d", __PRETTY_FUNCTION__, current_pulse);
/*
* characters
*/
for (i = character_list; i; i = next_dude) {
next_dude = i->next;
/* So, the first thing we need to do is apply damage() effects
* so that poison, hunger, thirst, or other spells can do their
* periodic damage BEFORE all the calculations below happen.
*/
if (IS_AFFECTED(i, AFF_POISON)) {
damage(i, i, 15, SPELL_POISON);
}
if (IS_PC(i) && IS_STARVING(i)) {
damage(i, i, number(1, 3), TYPE_HUNGER);
}
if (IS_PC(i) && IS_PARCHED(i)) {
damage(i, i, number(1, 3), TYPE_HUNGER);
}
if (GET_POS(i) >= POSITION_STUNNED) {
if (!affected_by_spell(i, SPELL_AID)) {
/* A problem here... damage() calls within hit_gain() are being
* overridden, because this code calls GET_HIT() before the call to
* hit_gain(), and thus no damage can happen.
*
* Basically, the damage() calls for spells/poison/hunger need
* to be moved in here, so they happen BEFORE hit_gain() is
* calculated.
*/
GET_HIT(i) = MIN(GET_HIT(i) + hit_gain(i), hit_limit(i));
} else {
if (GET_HIT(i) < hit_limit(i)) {
GET_HIT(i) = MIN(GET_HIT(i) + hit_gain(i), hit_limit(i));
}
}
GET_MANA(i) = MIN(GET_MANA(i) + mana_gain(i), mana_limit(i));
GET_MOVE(i) = MIN(GET_MOVE(i) + move_gain(i), move_limit(i));
//if (GET_POS(i) == POSITION_STUNNED)
//update_pos(i);
} else if (GET_POS(i) == POSITION_INCAP) {
/*
* damage(i, i, 0, TYPE_SUFFERING);
*/
GET_HIT(i) += 1;
//update_pos(i);
} else if (IS_PC(i) && (GET_POS(i) == POSITION_MORTALLYW)) {
damage(i, i, 1, TYPE_SUFFERING);
}
update_pos(i);
if (!IS_NPC(i)) {
update_char_objects(i);
if (GetMaxLevel(i) < CREATOR)
check_idling(i);
}
if (GET_POS(i) != POSITION_DEAD) {
gain_condition(i, FULL, -1);
gain_condition(i, DRUNK, -1);
gain_condition(i, THIRST, -1);
}
}
/*
* objects
*/
for (j = object_list; j; j = next_thing) {
next_thing = j->next;
count++;
if ((GET_ITEM_TYPE(j) == ITEM_FOOD) && IS_OBJ_STAT(j, ITEM_PARISH)) {
if (j->obj_flags.value[0] > 0)
j->obj_flags.value[0]--;
switch (j->obj_flags.value[0]) {
case 3:
{
if (j->carried_by)
act("$p begins to look a little brown.", FALSE, j->carried_by, j, 0,
TO_CHAR);
else if (j->in_room != NOWHERE && (real_roomp(j->in_room)->people)) {
act("$p begins to look a little brown.", TRUE,
real_roomp(j->in_room)->people, j, 0, TO_CHAR);
act("$p begins to look a little brown.", TRUE,
real_roomp(j->in_room)->people, j, 0, TO_ROOM);
}
}
break;
case 2:
{
if (j->carried_by)
act("$p begins to smell funny.", FALSE, j->carried_by, j, 0,
TO_CHAR);
else if (j->in_room != NOWHERE && (real_roomp(j->in_room)->people)) {
act("$p begins to smell funny.", TRUE,
real_roomp(j->in_room)->people, j, 0, TO_CHAR);
act("$p begins to smell funny.", TRUE,
real_roomp(j->in_room)->people, j, 0, TO_ROOM);
}
}
break;
case 1:
{
j->obj_flags.value[3] = 1; /* poison the sucker */
if (j->carried_by)
act("$p begins to smell spoiled.", FALSE, j->carried_by, j, 0,
TO_CHAR);
else if (j->in_room != NOWHERE && (real_roomp(j->in_room)->people)) {
act("$p begins to smell spoiled.", TRUE,
real_roomp(j->in_room)->people, j, 0, TO_CHAR);
act("$p begins to smell spoiled.", TRUE,
real_roomp(j->in_room)->people, j, 0, TO_ROOM);
}
}
break;
case 0:
{
if (j->carried_by)
act("$p dissolves into dust...", FALSE, j->carried_by, j, 0,
TO_CHAR);
else if ((j->in_room != NOWHERE) && (real_roomp(j->in_room)->people)) {
act("$p dissolves into dust...", TRUE,
real_roomp(j->in_room)->people, j, 0, TO_ROOM);
act("$p dissolves into dust...", TRUE,
real_roomp(j->in_room)->people, j, 0, TO_CHAR);
}
extract_obj(j);
}
}
}
if ((GET_ITEM_TYPE(j) == ITEM_CONTAINER) && (j->obj_flags.value[3])) {
if (j->obj_flags.timer > 0)
j->obj_flags.timer--;
if (!j->obj_flags.timer) {
if (j->carried_by) {
act("$p biodegrades in your hands.", FALSE, j->carried_by, j, 0, TO_CHAR);
ObjFromCorpse(j);
} else if (j->in_room != NOWHERE) {
if ((number(0, 99) < 40) && (real_roomp(j->in_room)->zone != 10)
&& (real_roomp(j->in_room)->zone != 11)) {
struct char_data *mob;
struct obj_data *obj_object,
*next_obj;
int mobset[] =
{ 9002, 9001, 4616, 4615, 4613, 9003, 4603 };
char newbuffer[MAX_INPUT_LENGTH],
newtmp[MAX_INPUT_LENGTH];
mob = read_mobile(mobset[number(0, 6)], VIRTUAL);
strcpy(newtmp, j->short_description);
if (!strncmp(newtmp, "the corpse of ", 14)) {
newtmp[14] = tolower(newtmp[14]);
sprintf(newbuffer, "%s of %s has arisen to KILL!\r\n",
GET_SDESC(mob), &newtmp[14]);
} else {
sprintf(newbuffer, "%s has recently risen to KILL!\r\n",
GET_SDESC(mob));
}
/*
* this loses memory... can we free it first?
*/
if (mob->player.long_descr)
DESTROY(mob->player.long_descr);
mob->player.long_descr = strdup(newbuffer);
char_to_room(mob, j->in_room);
GET_EXP(mob) = 75 * GetMaxLevel(mob);
IS_CARRYING_W(mob) = 0;
IS_CARRYING_N(mob) = 0;
for (obj_object = j->contains; obj_object; obj_object = next_obj) {
next_obj = obj_object->next_content;
obj_from_obj(obj_object);
obj_to_char(obj_object, mob);
}
mob->points.max_hit =
dice(GetMaxLevel(mob), 8) + number(20, 10 * GetMaxLevel(mob));
GET_HIT(mob) = GET_MAX_HIT(mob);
GET_EXP(mob) =
dice(GetMaxLevel(mob), 10) * 10 + number(1, 10 * GetMaxLevel(mob));
mob->player.sex = 0;
GET_RACE(mob) = RACE_UNDEAD;
if (!IS_SET(mob->specials.act, ACT_AGGRESSIVE)) {
SET_BIT(mob->specials.act, ACT_AGGRESSIVE);
}
if (IS_SET(mob->specials.act, ACT_SENTINEL)) {
REMOVE_BIT(mob->specials.act, ACT_SENTINEL);
}
if (real_roomp(j->in_room)->people) {
act("$p slowly rises as $N and screams 'DIE!'", TRUE,
real_roomp(j->in_room)->people, j, mob, TO_ROOM);
act("$p slowly rises as $N and screams 'DIE!'", TRUE,
real_roomp(j->in_room)->people, j, mob, TO_CHAR);
}
do_wear(mob, "all", 0);
extract_obj(j);
} else if (real_roomp(j->in_room)->people) {
act("$p dissolves into a lump of fertile soil.", TRUE,
real_roomp(j->in_room)->people, j, 0, TO_ROOM);
act("$p dissolves into a lump of fertile soil.", TRUE,
real_roomp(j->in_room)->people, j, 0, TO_CHAR);
ObjFromCorpse(j);
} else
ObjFromCorpse(j);
}
}
}
}
}
int ObjFromCorpse(struct obj_data *c)
{
struct obj_data *jj = NULL;
struct obj_data *next_thing = NULL;
if (DEBUG > 2)
log_info("called %s with %s", __PRETTY_FUNCTION__, SAFE_ONAME(c));
for (jj = c->contains; jj; jj = next_thing) {
next_thing = jj->next_content; /* Next in inventory */
if (jj->in_obj) {
obj_from_obj(jj);
if (c->in_obj)
obj_to_obj(jj, c->in_obj);
else if (c->carried_by)
obj_to_room(jj, c->carried_by->in_room);
else if (c->in_room != NOWHERE)
obj_to_room(jj, c->in_room);
else
return (FALSE);
} else {
/*
* ** hmm.. it isn't in the object it says it is in.
* ** deal with the memory lossage
*/
c->contains = 0;
extract_obj(c);
log_error("Memory lost in ObjFromCorpse.");
return (TRUE);
}
}
extract_obj(c);
return TRUE;
}