/**************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* Much time and thought has gone into this software and you are *
* benefiting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************
* ROM 2.4 is copyright 1993-1998 Russ Taylor *
* ROM has been brought to you by the ROM consortium *
* Russ Taylor (rtaylor@hypercube.org) *
* Gabrielle Taylor (gtaylor@hypercube.org) *
* Brian Moore (zump@rom.org) *
* By using this code, you have agreed to follow the terms of the *
* ROM license, in the file Rom24/doc/rom.license *
***************************************************************************
* 1stMUD ROM Derivative (c) 2001-2002 by Ryan Jennings *
* http://1stmud.dlmud.com/ <r-jenn@shaw.ca> *
***************************************************************************/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "merc.h"
CH_CMD(do_remor)
{
chprintln(ch, "If you want to REMORT, you must spell it out.");
return;
}
CH_CMD(do_remort)
{
DESCRIPTOR_DATA *d;
CHAR_DATA *mob;
AFFECT_DATA *af, *af_next;
char buf[MAX_INPUT_LENGTH];
int x, sn;
if (IS_NPC(ch) || (d = ch->desc) == NULL)
return;
/*
* check for priest or special mob
*/
for (mob = ch->in_room->first_person; mob; mob = mob->next_in_room)
{
if (IS_NPC(mob) && IS_SET(mob->act, ACT_IS_HEALER)) /* setup to do at healer's for now */
break;
}
if (mob == NULL)
{
chprintln(ch, "You can't do that here.");
return;
}
if (ch->level != calc_max_level(ch))
{
chprintlnf(ch, "You must be a %s to remort.",
high_level_name(calc_max_level(ch), TRUE));
return;
}
if (number_classes(ch) == MAX_REMORT || number_classes(ch) == maxClass)
{
chprintln(ch, "You can't remort any more!");
return;
}
/* Remove high level eq since we're going back to level 1 */
for (x = 0; x < MAX_WEAR; x++)
{
if (get_eq_char(ch, x) != NULL)
{
chprintln(ch,
"Remove all of your eq first. (heal uncurse for cursed items)");
return;
}
}
if (ch->pcdata->confirm_remort)
{
if (argument[0] != '\0')
{
chprintln(ch, "Remort status removed.");
ch->pcdata->confirm_remort = FALSE;
return;
}
else
{
chprintlnf(ch,
"You have chosen to remort. You will now be dropped in at the %s",
!ch->pcdata->stay_race ? "RACE" : "CLASS");
chprintln(ch,
"selection section of character creation, and will be allowed recreate");
chprintln(ch,
"your character with an additional class and bonuses.\n\r");
chprintln(ch,
"In the unlikely event that you are disconnected or the MUD");
chprintln(ch,
"crashes while you are creating your character, log back on and write a");
chprintln(ch, "note to 'immortal' who will retrieve your backup.");
wiznet("$N has remorted.", ch, NULL, 0, 0, 0);
for (af = ch->first_affect; af != NULL; af = af_next)
{
af_next = af->next;
affect_remove(ch, af);
}
SET_BIT(ch->act, PLR_REMORT);
SET_BIT(ch->comm, COMM_QUIET);
char_from_room(ch);
char_to_room(ch, get_room_index(ROOM_VNUM_LIMBO));
ch->level = 1;
ch->exp = 0;
ch->pcdata->points = 0;
ch->max_hit = 100 * (number_classes(ch) + 1);
ch->max_mana = 100 * (number_classes(ch) + 1);
ch->max_move = 100 * (number_classes(ch) + 1);
ch->hit = ch->max_hit;
ch->mana = ch->max_move;
ch->move = ch->max_mana;
ch->pcdata->perm_hit = ch->max_hit;
ch->pcdata->perm_mana = ch->max_mana;
ch->pcdata->perm_move = ch->max_move;
ch->wimpy = ch->max_hit / 5;
ch->train = 5 * (number_classes(ch) + 1);
ch->practice = 7 * (number_classes(ch) + 1);
ch->exp = exp_per_level(ch, ch->pcdata->points);
reset_char(ch);
/* nuke any high level pets */
if (ch->pet != NULL)
{
nuke_pets(ch);
ch->pet = NULL;
}
/* Race skills are lost.
100% skills are kept at 100%.
All other skills are reset back to 1%. */
for (sn = 0; sn < maxSkill; sn++)
{
if (ch->pcdata->learned[sn] > 0
&& ch->pcdata->learned[sn] < 100)
{
if (is_race_skill(ch, sn) && !ch->pcdata->stay_race)
ch->pcdata->learned[sn] = 0;
else
ch->pcdata->learned[sn] = 1;
}
}
/* send char to race selection, customize this as you see fit */
chprintln(ch, "\n\rNow beginning the remorting process.\n\r");
if (!ch->pcdata->stay_race)
{
RACE_DATA *race;
chprintln(ch, "The following races are available:");
for (race = race_first; race != NULL; race = race->next)
{
if (!race->pc_race)
break;
chprint(ch, race->name);
chprint(ch, " ");
}
chprint
(ch, "\n\rWhat is your race (help for more information)?");
d->connected = CON_GET_NEW_RACE;
}
else
{
int iClass;
ch->pcdata->points = ch->race->points;
sprintf(buf, "Select class number %d [ ",
(number_classes(ch) + 1));
for (iClass = 0; iClass < maxClass; iClass++)
{
if (is_class(ch, iClass))
continue;
strcat(buf, class_table[iClass].name);
}
strcat(buf, "]: ");
chprint(ch, buf);
d->connected = CON_GET_NEW_CLASS;
}
return;
}
}
if (argument[0] != '\0')
{
chprintln(ch, "Just type remort. No argument.");
return;
}
chprintln(ch, "Typing remort with an argument will undo remort status.");
chprintln(ch,
"Remorting is not reversable, make sure you read help REMORT");
chprintln(ch, "and have an idea of what class you want to remort into.");
chprintln(ch, "Type remort again to confirm this command.");
ch->pcdata->confirm_remort = TRUE;
if (!ch->pcdata->stay_race)
chprintln(ch,
"WARNING: IF YOU CHOOSE A RACE DIFFERENT FROM YOUR RACE NOW YOU WILL BE THAT RACE FOREVER.\n\r");
wiznet("$N is contemplating remorting.", ch, NULL, 0, 0, get_trust(ch));
}
/* Use for things like:
* ch->level >= skill_table[sn].skill_level[ch->Class]
*/
bool can_use_skpell(CHAR_DATA * ch, int sn)
{
int iClass;
if (IS_NPC(ch))
return TRUE;
if (is_race_skill(ch, sn))
return TRUE;
if (is_deity_skill(ch, sn))
return TRUE;
for (iClass = 0; ch->Class[iClass] != -1; iClass++)
if (ch->level >= skill_table[sn].skill_level[ch->Class[iClass]])
return TRUE;
return FALSE;
}
/* Used for things like:
* class_table[ch->Class].fMana
*/
bool has_spells(CHAR_DATA * ch)
{
int iClass;
if (IS_NPC(ch))
return FALSE;
for (iClass = 0; ch->Class[iClass] != -1; iClass++)
if (class_table[iClass].fMana)
return TRUE;
return FALSE;
}
/* Used for things like
* ch->Class == 2
*/
bool is_class(CHAR_DATA * ch, int Class)
{
int iClass;
if (IS_NPC(ch))
return FALSE;
for (iClass = 0; ch->Class[iClass] != -1; iClass++)
{
if (ch->Class[iClass] == Class)
return TRUE;
}
return FALSE;
}
/* Used for things like:
* ch->Class == victim->Class
*/
bool is_same_class(CHAR_DATA * ch, CHAR_DATA * victim)
{
int iClass, jClass;
if (IS_NPC(ch) || IS_NPC(victim))
return FALSE;
for (iClass = 0; ch->Class[iClass] != -1; iClass++)
{
for (jClass = 0; victim->Class[jClass] != -1; jClass++)
if (ch->Class[iClass] == victim->Class[jClass])
return TRUE;
}
return FALSE;
}
/* Returns a users prime class (first class) */
int prime_class(CHAR_DATA * ch)
{
return ch->Class[0];
}
/* Returns the number of classes a user has */
int number_classes(CHAR_DATA * ch)
{
int iClass;
if (IS_NPC(ch))
return 0;
for (iClass = 0; ch->Class[iClass] != -1; iClass++);
return iClass;
}
/* Outputs class names in long format */
char *class_long(CHAR_DATA * ch)
{
static char buf[512];
int iClass;
buf[0] = '\0';
if (IS_NPC(ch))
return "Mobile";
for (iClass = 0; ch->Class[iClass] != -1; iClass++)
{
strcat(buf, "/");
strcat(buf, class_table[ch->Class[iClass]].name);
}
return buf + 1;
}
/* Outputs class names in a 3 letter who format
* Ex. W+3 mean Warrior plus 3 remorts (4 classes in total)
*/
char *class_who(CHAR_DATA * ch)
{
static char buf[512];
buf[0] = '\0';
if (IS_NPC(ch))
return "Mob";
if (number_classes(ch) > 1)
sprintf(buf, "%c+%d", class_table[ch->Class[0]].name[0],
number_classes(ch) - 1);
else
sprintf(buf, "%3.3s", class_table[ch->Class[0]].name);
return buf;
}
/* Outputs class names in short format */
char *class_short(CHAR_DATA * ch)
{
static char buf[512];
int iClass;
buf[0] = '\0';
if (IS_NPC(ch))
return "Mob";
for (iClass = 0; ch->Class[iClass] != -1; iClass++)
{
strcat(buf, "/");
strcat(buf, FORMATF("%3.3s", class_table[ch->Class[iClass]].name));
}
return buf + 1;
}
/* Sends number of classes to a string, Used for saving. */
char *class_numbers(CHAR_DATA * ch, bool pSave)
{
static char buf[512];
char buf2[10];
int iClass;
buf[0] = '\0';
if (IS_NPC(ch))
return "0";
for (iClass = 0; ch->Class[iClass] != -1; iClass++)
{
strcat(buf, " ");
sprintf(buf2, "%d", ch->Class[iClass]);
strcat(buf, buf2);
}
if (pSave)
strcat(buf, " -1");
return buf + 1;
}
/* Used for things like:
* level = skill_table[sn].skill_level[ch->Class]
* Finds the lowest skill level for all classes.
*/
int skill_level(CHAR_DATA * ch, int sn)
{
int iClass;
int tempskill = 999;
if (is_race_skill(ch, sn))
return 1;
if (is_deity_skill(ch, sn))
return 1;
for (iClass = 0; ch->Class[iClass] != -1; iClass++)
tempskill =
UMIN(tempskill, skill_table[sn].skill_level[ch->Class[iClass]]);
return tempskill == 999 ? LEVEL_IMMORTAL : tempskill;
}
/* Used for things like:
* train = skill_table[sn].rating[ch->Class]
* Finds the lowest skill rating for all classes.
*/
int skill_rating(CHAR_DATA * ch, int sn)
{
int iClass;
int temprate = 999;
if (is_race_skill(ch, sn))
return 2;
if (is_deity_skill(ch, sn))
return 2;
for (iClass = 0; ch->Class[iClass] != -1; iClass++)
{
if (skill_table[sn].rating[ch->Class[iClass]] < 1)
continue;
temprate = UMIN(temprate, skill_table[sn].rating[ch->Class[iClass]]);
}
return temprate == 999 ? 0 : temprate;
}
/* Used for things like:
* train = group_table[sn].rating[ch->Class]
* Finds the lowest group rating for all classes.
*/
int group_rating(CHAR_DATA * ch, int gn)
{
int iClass;
int temprate = 999;
if (is_race_skill(ch, gn))
return 2;
if (is_deity_skill(ch, gn))
return 2;
for (iClass = 0; ch->Class[iClass] != -1; iClass++)
{
if (group_table[gn].rating[ch->Class[iClass]] < 1)
continue;
temprate = UMIN(temprate, group_table[gn].rating[ch->Class[iClass]]);
}
return temprate == 999 ? 0 : temprate;
}
/* Used to find the max amount of hp gain for a class in advance_level() */
int get_hp_gain(CHAR_DATA * ch)
{
int iClass = 0;
int gain = 0;
int count = 0;
for (iClass = 0; ch->Class[iClass] != -1; iClass++)
{
gain =
UMAX(gain,
number_range(class_table[ch->Class[iClass]].hp_min,
class_table[ch->Class[iClass]].hp_max));
count++;
}
return number_range(gain, gain + count);
}
int hp_max(CHAR_DATA * ch)
{
int iClass;
int tmp = 0;
for (iClass = 0; ch->Class[iClass] != -1; iClass++)
tmp = UMAX(tmp, class_table[ch->Class[iClass]].hp_max);
return tmp;
}
/* Used to find if a stat is a prime of a users classes */
bool is_prime_stat(CHAR_DATA * ch, int stat)
{
int iClass = 0;
if (IS_NPC(ch))
return TRUE;
for (iClass = 0; ch->Class[iClass] != -1; iClass++)
{
if (class_table[ch->Class[iClass]].attr_prime == stat)
return TRUE;
}
return FALSE;
}
/* Adds all class default groups while keeping the charge at 40 */
void add_default_groups(CHAR_DATA * ch)
{
int iClass = 0;
if (IS_NPC(ch))
return;
for (iClass = 0; ch->Class[iClass] != -1; iClass++)
if (class_table[ch->Class[iClass]].default_group != NULL)
group_add(ch, class_table[ch->Class[iClass]].default_group, FALSE);
ch->pcdata->points += 40;
}
/* Adds all class base groups */
void add_base_groups(CHAR_DATA * ch)
{
int iClass = 0;
if (IS_NPC(ch))
return;
for (iClass = 0; ch->Class[iClass] != -1; iClass++)
if (class_table[ch->Class[iClass]].base_group != NULL)
group_add(ch, class_table[ch->Class[iClass]].base_group, FALSE);
}
/* Returns TRUE if a group number is a class base group
used in creation so base groups never get dropped */
bool check_base_group(CHAR_DATA * ch, int gn)
{
int iClass = 0;
if (IS_NPC(ch))
return FALSE;
if (gn < 0 || gn >= maxGroup)
return FALSE;
for (iClass = 0; ch->Class[iClass] != -1; iClass++)
{
if (class_table[ch->Class[iClass]].base_group == NULL)
continue;
if (group_lookup(class_table[ch->Class[iClass]].base_group) == gn)
return TRUE;
}
return FALSE;
}
/* returns TRUE if a skill number is a class base skill
Used in creation so base skills never get dropped */
bool is_base_skill(CHAR_DATA * ch, int sn)
{
int iClass = 0;
int gn, x;
if (IS_NPC(ch))
return FALSE;
if (sn < 0 || sn >= maxSkill)
return FALSE;
for (iClass = 0; ch->Class[iClass] != -1; iClass++)
{
if (class_table[ch->Class[iClass]].base_group == NULL)
continue;
if ((gn =
group_lookup(class_table[ch->Class[iClass]].base_group)) != -1)
{
for (x = 0; x < MAX_IN_GROUP; x++)
{
if (group_table[gn].spells[x] == NULL)
break;
if (skill_lookup(group_table[gn].spells[x]) == sn)
return TRUE;
}
}
}
return FALSE;
}
/* Gets lowest thac00 for all classes */
int get_thac00(CHAR_DATA * ch)
{
int temp = 0, iClass = 0;
if (IS_NPC(ch))
return 0;
for (iClass = 0; ch->Class[iClass] != -1; iClass++)
temp = UMAX(temp, class_table[ch->Class[iClass]].thac0_00);
return temp;
}
/* gets lowest thac32 for all classes */
int get_thac32(CHAR_DATA * ch)
{
int temp = 999, iClass = 0;
if (IS_NPC(ch))
return 0;
for (iClass = 0; ch->Class[iClass] != -1; iClass++)
temp = UMIN(temp, class_table[ch->Class[iClass]].thac0_32);
return temp;
}
/* Used for race exp multiplications */
int class_mult(CHAR_DATA * ch)
{
int temp = 999, iClass = 0;
if (IS_NPC(ch))
return 0;
for (iClass = 0; ch->Class[iClass] != -1; iClass++)
temp = UMIN(temp, ch->race->class_mult[ch->Class[iClass]]);
return temp;
}
/* Simple bonus function for eq levels */
int lvl_bonus(CHAR_DATA * ch)
{
return maxClass + number_classes(ch);
}
/* Returns TRUE if skill number is a race skill
If you have clan skills you can do something simalar
for those */
bool is_race_skill(CHAR_DATA * ch, int sn)
{
int i;
for (i = 0; i < 5; i++)
{
if (ch->race->skills[i] == NULL)
continue;
if (skill_lookup(ch->race->skills[i]) == sn)
return TRUE;
if (group_lookup(ch->race->skills[i]) == sn)
return TRUE;
}
return FALSE;
}
bool is_deity_skill(CHAR_DATA * ch, int sn)
{
if (ch->deity == NULL || IS_NPC(ch))
return FALSE;
if (IS_NULLSTR(ch->deity->skillname))
return FALSE;
if (skill_lookup(ch->deity->skillname) == sn)
return TRUE;
if (group_lookup(ch->deity->skillname) == sn)
return TRUE;
return FALSE;
}