Species update 1

This commit is contained in:
kinther 2025-12-28 16:56:57 -08:00
parent 1efb08dafd
commit 8018ed3fcf
14 changed files with 773 additions and 95 deletions

View file

@ -15,13 +15,14 @@ B
~
6218 0 0 0 0 0 0 0 0 E
1 3d20+40
8 8 1
Str: 16
Class: 3
SaveStr: 3
Species: 0
Skill 132 5
Skill 134 5
Skill 137 5
@ -33,17 +34,17 @@ Skill 145 5
Skill 146 5
Skill 147 5
E
L 17 127 1
L 16 117 1
L 15 117 1
L 11 111 1
L 10 107 1
L 9 124 1
L 8 115 1
L 7 108 1
L 6 110 1
L 5 131 1
L 3 118 1
L 5 131 1
L 6 110 1
L 7 108 1
L 8 115 1
L 9 124 1
L 10 107 1
L 11 111 1
L 15 117 1
L 16 117 1
L 17 127 1
#101
Sally~
slim lanky human soldier guard~
@ -62,32 +63,38 @@ B
~
6218 0 0 0 0 0 0 0 0 E
1 3d20+40
8 8 2
Class: 3
Species: 0
Skill 132 5
Skill 134 5
Skill 137 5
Skill 140 5
Skill 141 5
Skill 142 5
Skill 143 5
Skill 144 5
Skill 145 5
Skill 146 5
Skill 147 5
Skill 152 5
Skill 156 5
Skill 163 5
E
L 3 118 1
L 5 131 1
L 6 110 1
L 7 108 1
L 8 115 1
L 9 124 1
L 10 107 1
L 11 111 1
L 15 117 1
L 16 117 1
L 17 127 1
L 16 117 1
L 15 117 1
L 11 111 1
L 10 107 1
L 9 124 1
L 8 115 1
L 7 108 1
L 6 110 1
L 5 131 1
L 3 118 1
#102
Baldy~
barkeep stocky bald~
@ -106,13 +113,14 @@ B
~
10 0 0 0 0 0 0 0 0 E
1 3d12+60
8 8 1
E
L 9 112 1
L 14 113 1
L 9 112 1
#103
Lanky~
woman lanky scarred~
@ -132,6 +140,7 @@ B
~
10 0 0 0 0 0 0 0 0 E
1 3d8+60
@ -161,6 +170,7 @@ appear thick and ready to propel the animal if it feels threatened.
B
It's a rat.
~
8 0 0 0 0 0 0 0 0 E
@ -172,6 +182,7 @@ Int: 4
Wis: 4
Con: 6
Cha: 3
Species: 25
AtkT 4
E
$

View file

@ -26,6 +26,7 @@
#include "act.h"
#include "genzon.h" /* for real_zone_by_thing */
#include "class.h"
#include "species.h"
#include "genmob.h"
#include "genolc.h"
#include "genobj.h"
@ -1818,6 +1819,7 @@ static void do_stat_character(struct char_data *ch, struct char_data *k)
}
stat_table_row_fmt(ch, "Class", "%s", CLASS_NAME(k));
stat_table_row_fmt(ch, "Species", "%s", get_species_name(GET_SPECIES(k)));
stat_table_row_fmt(ch, "Attributes",
"Str %d Int %d Wis %d Dex %d Con %d Cha %d",
@ -3806,7 +3808,8 @@ static struct set_struct {
{ "weight", LVL_BUILDER, BOTH, NUMBER },
{ "wis", LVL_BUILDER, BOTH, NUMBER },
{ "questpoints", LVL_GOD, PC, NUMBER },
{ "questhistory", LVL_GOD, PC, NUMBER }, /* 55 */
{ "questhistory", LVL_GOD, PC, NUMBER },
{ "species", LVL_BUILDER, BOTH, MISC },
{ "\n", 0, BOTH, MISC }
};
@ -4316,6 +4319,16 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c
}
break;
}
case 54: /* species */
if ((i = parse_species(val_arg)) == SPECIES_UNDEFINED) {
send_to_char(ch, "That is not a species.\r\n");
return (0);
}
update_species(vict, i);
affect_total(vict);
send_to_char(ch, "You set %s's species to %s.\r\n",
get_char_sdesc(vict), get_species_name(GET_SPECIES(vict)));
break;
default:
send_to_char(ch, "Can't set that!\r\n");
return (0);
@ -4402,7 +4415,21 @@ ACMD(do_set)
} else if (!str_cmp(name, "mob"))
half_chop(buf, name, buf);
half_chop(buf, field, buf);
if (!is_file && !is_player && !str_cmp(name, "species")) {
char val[MAX_INPUT_LENGTH];
char target[MAX_INPUT_LENGTH];
half_chop(buf, val, target);
if (!*val || !*target) {
send_to_char(ch, "Usage: set species <type> <target>\r\n");
return;
}
strlcpy(field, "species", sizeof(field));
strlcpy(name, target, sizeof(name));
strlcpy(buf, val, sizeof(buf));
} else {
half_chop(buf, field, buf);
}
if (!*name || !*field) {
send_to_char(ch, "Usage: set <victim> <field> <value>\r\n");

View file

@ -23,6 +23,7 @@
#include "constants.h"
#include "act.h"
#include "class.h"
#include "species.h"
/* Names first */
const char *class_abbrevs[] = {
@ -231,7 +232,10 @@ void roll_real_abils(struct char_data *ch)
ch->real_abils.cha = table[5];
break;
}
ch->aff_abils = ch->real_abils;
if (HAS_VALID_SPECIES(ch))
apply_species_bonuses(ch);
else
ch->aff_abils = ch->real_abils;
}
/* Per-class skill caps */
@ -489,6 +493,7 @@ void do_start(struct char_data *ch)
GET_MAX_MOVE(ch) = 90;
grant_class_skills(ch, TRUE);
grant_species_skills(ch);
advance_level(ch);

View file

@ -1624,6 +1624,7 @@ static void parse_simple_mob(FILE *mob_f, int i, int nr)
GET_SEX(mob_proto + i) = t[2];
GET_CLASS(mob_proto + i) = CLASS_UNDEFINED;
GET_SPECIES(mob_proto + i) = SPECIES_UNDEFINED;
GET_WEIGHT(mob_proto + i) = 200;
GET_HEIGHT(mob_proto + i) = 198;
@ -1707,6 +1708,10 @@ static void interpret_espec(const char *keyword, const char *value, int i, int n
RANGE(CLASS_UNDEFINED, NUM_CLASSES - 1);
mob_proto[i].player.chclass = num_arg;
}
CASE("Species") {
RANGE(SPECIES_UNDEFINED, NUM_SPECIES - 1);
mob_proto[i].player.species = num_arg;
}
/* --- 5e-style Saving Throws --- */
CASE("SaveStr") {
@ -3766,6 +3771,7 @@ void clear_char(struct char_data *ch)
GET_PFILEPOS(ch) = -1;
GET_MOB_RNUM(ch) = NOBODY;
GET_CLASS(ch) = CLASS_UNDEFINED;
GET_SPECIES(ch) = SPECIES_UNDEFINED;
GET_WAS_IN(ch) = NOWHERE;
GET_POS(ch) = POS_STANDING;
ch->mob_specials.default_pos = POS_STANDING;

View file

@ -359,6 +359,10 @@ int write_mobile_espec(mob_vnum mvnum, struct char_data *mob, FILE *fd)
fprintf(fd, "Class: %d\n", (int)GET_CLASS(mob));
count++;
}
if (HAS_VALID_SPECIES(mob)) {
fprintf(fd, "Species: %d\n", (int)GET_SPECIES(mob));
count++;
}
/* --- 5e-style saving throws --- */
if (GET_SAVE(mob, ABIL_STR) != 0) {

View file

@ -27,6 +27,7 @@
#include "act.h" /* ACMDs located within the act*.c files */
#include "ban.h"
#include "class.h"
#include "species.h"
#include "graph.h"
#include "hedit.h"
#include "house.h"
@ -47,6 +48,7 @@ static int _parse_name(char *arg, char *name);
static bool perform_new_char_dupe_check(struct descriptor_data *d);
/* sort_commands utility */
static int sort_commands_helper(const void *a, const void *b);
static void show_species_menu(struct descriptor_data *d);
/* globals defined here, used here and elsewhere */
int *cmd_sort_info = NULL;
@ -1303,6 +1305,18 @@ static bool perform_new_char_dupe_check(struct descriptor_data *d)
return (found);
}
static void show_species_menu(struct descriptor_data *d)
{
int count = pc_species_count();
write_to_output(d, "Select a species:\r\n");
for (int i = 0; i < count; i++) {
int species = pc_species_list[i];
write_to_output(d, " %2d) %s\r\n", i + 1, species_types[species]);
}
write_to_output(d, "Species: ");
}
/* load the player, put them in the right room - used by copyover_recover too */
int enter_player_game (struct descriptor_data *d)
{
@ -1869,10 +1883,26 @@ void nanny(struct descriptor_data *d, char *arg)
return;
}
write_to_output(d, "%s\r\nClass: ", class_menu);
STATE(d) = CON_QCLASS;
show_species_menu(d);
STATE(d) = CON_QSPECIES;
break;
case CON_QSPECIES: {
int choice = atoi(arg);
int species = species_from_pc_choice(choice);
if (species == SPECIES_UNDEFINED) {
write_to_output(d, "\r\nThat's not a species.\r\n");
show_species_menu(d);
return;
}
GET_SPECIES(d->character) = species;
write_to_output(d, "%s\r\nClass: ", class_menu);
STATE(d) = CON_QCLASS;
break;
}
case CON_QCLASS:
load_result = parse_class(*arg);
if (load_result == CLASS_UNDEFINED) {

View file

@ -13,6 +13,7 @@
#include "comm.h"
#include "spells.h"
#include "class.h"
#include "species.h"
#include "db.h"
#include "shop.h"
#include "genolc.h"
@ -41,6 +42,7 @@ static void medit_disp_mob_flags(struct descriptor_data *d);
static void medit_disp_aff_flags(struct descriptor_data *d);
static void medit_disp_menu(struct descriptor_data *d);
static void medit_disp_class_menu(struct descriptor_data *d);
static void medit_disp_species_menu(struct descriptor_data *d);
/* utility functions */
ACMD(do_oasis_medit)
@ -419,13 +421,14 @@ static void medit_disp_menu(struct descriptor_data *d)
{
struct char_data *mob;
char flags[MAX_STRING_LENGTH], flag2[MAX_STRING_LENGTH];
const char *background, *classname;
const char *background, *classname, *speciesname;
mob = OLC_MOB(d);
get_char_colors(d->character);
clear_screen(d);
background = GET_BACKGROUND(mob) ? GET_BACKGROUND(mob) : "<None>\r\n";
classname = HAS_VALID_CLASS(mob) ? pc_class_types[GET_CLASS(mob)] : "Unassigned";
speciesname = HAS_VALID_SPECIES(mob) ? species_types[GET_SPECIES(mob)] : "Unassigned";
write_to_output(d,
"-- Mob Number: [%s%d%s]\r\n"
@ -452,6 +455,7 @@ static void medit_disp_menu(struct descriptor_data *d)
"%s8%s) Default : %s%s\r\n"
"%s9%s) Attack : %s%s\r\n"
"%sD%s) Class : %s%s\r\n"
"%sE%s) Species : %s%s\r\n"
"%sK%s) Skinning Menu...\r\n"
"%s0%s) Stats Menu...\r\n"
"%s-%s) Skills Menu...\r\n"
@ -468,6 +472,7 @@ static void medit_disp_menu(struct descriptor_data *d)
grn, nrm, yel, position_types[(int)GET_DEFAULT_POS(mob)],
grn, nrm, yel, attack_hit_text[(int)GET_ATTACK(mob)].singular,
grn, nrm, yel, classname,
grn, nrm, yel, speciesname,
grn, nrm,
grn, nrm,
grn, nrm,
@ -523,6 +528,46 @@ static void medit_disp_class_menu(struct descriptor_data *d)
OLC_MODE(d) = MEDIT_CLASS_MENU;
}
static void medit_disp_species_menu(struct descriptor_data *d)
{
struct char_data *mob = OLC_MOB(d);
const char *current = HAS_VALID_SPECIES(mob) ? species_types[GET_SPECIES(mob)] : "Unassigned";
get_char_colors(d->character);
clear_screen(d);
write_to_output(d,
"-- Mob Number: %s[%s%d%s]%s\r\n"
"Species selection for %s%s%s\r\n\r\n",
cyn, yel, OLC_NUM(d), cyn, nrm,
yel, GET_SDESC(mob), nrm);
for (int i = 0; i < NUM_SPECIES; i++) {
bool selected = HAS_VALID_SPECIES(mob) && (GET_SPECIES(mob) == i);
write_to_output(d, "%s%2d%s) %s%-12s%s%s\r\n",
cyn, i + 1, nrm,
selected ? grn : yel,
species_types[i],
nrm,
selected ? " (current)" : "");
}
write_to_output(d, "%s%2d%s) %sUnassigned%s%s\r\n",
cyn, NUM_SPECIES + 1, nrm,
!HAS_VALID_SPECIES(mob) ? grn : yel,
nrm,
!HAS_VALID_SPECIES(mob) ? " (current)" : "");
write_to_output(d,
"\r\nCurrent choice: %s%s%s\r\n"
"%s0%s) Return to main menu\r\n"
"Enter choice : ",
cyn, current, nrm,
cyn, nrm);
OLC_MODE(d) = MEDIT_SPECIES_MENU;
}
/* Display main menu. */
static void medit_disp_stats_menu(struct descriptor_data *d)
{
@ -757,6 +802,10 @@ void medit_parse(struct descriptor_data *d, char *arg)
case 'D':
medit_disp_class_menu(d);
return;
case 'e':
case 'E':
medit_disp_species_menu(d);
return;
case '0':
OLC_MODE(d) = MEDIT_STATS_MENU;
medit_disp_stats_menu(d);
@ -1165,6 +1214,30 @@ void medit_parse(struct descriptor_data *d, char *arg)
medit_disp_menu(d);
return;
case MEDIT_SPECIES_MENU:
i = atoi(arg);
if (i == 0) {
medit_disp_menu(d);
return;
}
if (i == NUM_SPECIES + 1) {
GET_SPECIES(OLC_MOB(d)) = SPECIES_UNDEFINED;
OLC_VAL(d) = TRUE;
write_to_output(d, "Species cleared.\r\n");
medit_disp_menu(d);
return;
}
if (i < 1 || i > NUM_SPECIES + 1) {
write_to_output(d, "Invalid choice!\r\n");
medit_disp_species_menu(d);
return;
}
GET_SPECIES(OLC_MOB(d)) = i - 1;
OLC_VAL(d) = TRUE;
write_to_output(d, "Species set to %s.\r\n", species_types[GET_SPECIES(OLC_MOB(d))]);
medit_disp_menu(d);
return;
case OLC_SCRIPT_EDIT:
if (dg_script_edit_parse(d, arg)) return;
break;

View file

@ -269,39 +269,40 @@ extern const char *nrm, *grn, *cyn, *yel;
#define MEDIT_SKILL_MENU 11
#define MEDIT_SKILL_EDIT 12
#define MEDIT_CLASS_MENU 13
#define MEDIT_SPECIES_MENU 14
/* Numerical responses. */
#define MEDIT_NUMERICAL_RESPONSE 14
#define MEDIT_SEX 15
#define MEDIT_NUM_HP_DICE 16
#define MEDIT_SIZE_HP_DICE 17
#define MEDIT_ADD_HP 18
#define MEDIT_POS 19
#define MEDIT_DEFAULT_POS 20
#define MEDIT_ATTACK 21
#define MEDIT_LEVEL 22
#define MEDIT_ALIGNMENT 23
#define MEDIT_DELETE 24
#define MEDIT_COPY 25
#define MEDIT_STR 26
#define MEDIT_INT 27
#define MEDIT_WIS 28
#define MEDIT_DEX 29
#define MEDIT_CON 30
#define MEDIT_CHA 31
#define MEDIT_SAVE_STR 32
#define MEDIT_SAVE_DEX 33
#define MEDIT_SAVE_CON 34
#define MEDIT_SAVE_INT 35
#define MEDIT_SAVE_WIS 36
#define MEDIT_SAVE_CHA 37
#define MEDIT_SKILL_VALUE 38
#define MEDIT_NUMERICAL_RESPONSE 15
#define MEDIT_SEX 16
#define MEDIT_NUM_HP_DICE 17
#define MEDIT_SIZE_HP_DICE 18
#define MEDIT_ADD_HP 19
#define MEDIT_POS 20
#define MEDIT_DEFAULT_POS 21
#define MEDIT_ATTACK 22
#define MEDIT_LEVEL 23
#define MEDIT_ALIGNMENT 24
#define MEDIT_DELETE 25
#define MEDIT_COPY 26
#define MEDIT_STR 27
#define MEDIT_INT 28
#define MEDIT_WIS 29
#define MEDIT_DEX 30
#define MEDIT_CON 31
#define MEDIT_CHA 32
#define MEDIT_SAVE_STR 33
#define MEDIT_SAVE_DEX 34
#define MEDIT_SAVE_CON 35
#define MEDIT_SAVE_INT 36
#define MEDIT_SAVE_WIS 37
#define MEDIT_SAVE_CHA 38
#define MEDIT_SKILL_VALUE 39
/* Skinning yield editor */
#define MEDIT_SKIN_MENU 39
#define MEDIT_SKIN_ADD_VNUM 40
#define MEDIT_SKIN_ADD_DC 41
#define MEDIT_SKIN_DELETE 42
#define MEDIT_SKIN_MENU 40
#define MEDIT_SKIN_ADD_VNUM 41
#define MEDIT_SKIN_ADD_DC 42
#define MEDIT_SKIN_DELETE 43
/* Submodes of SEDIT connectedness. */
#define SEDIT_MAIN_MENU 0

View file

@ -15,6 +15,7 @@
#define PFDEF_SEX 0
#define PFDEF_CLASS 0
#define PFDEF_SPECIES SPECIES_UNDEFINED
#define PFDEF_LEVEL 0
#define PFDEF_HEIGHT 0
#define PFDEF_WEIGHT 0

View file

@ -255,6 +255,7 @@ int load_char(const char *name, struct char_data *ch)
ch->player_specials->saved.skills[i] = 0;
GET_SEX(ch) = PFDEF_SEX;
GET_CLASS(ch) = PFDEF_CLASS;
GET_SPECIES(ch) = PFDEF_SPECIES;
GET_LEVEL(ch) = PFDEF_LEVEL;
GET_HEIGHT(ch) = PFDEF_HEIGHT;
GET_WEIGHT(ch) = PFDEF_WEIGHT;
@ -437,7 +438,13 @@ int load_char(const char *name, struct char_data *ch)
break;
case 'S':
if (!strcmp(tag, "Sex ")) GET_SEX(ch) = atoi(line);
if (!strcmp(tag, "Spec")) {
int val = atoi(line);
if (val < SPECIES_UNDEFINED || val >= NUM_SPECIES)
val = SPECIES_UNDEFINED;
GET_SPECIES(ch) = val;
}
else if (!strcmp(tag, "Sex ")) GET_SEX(ch) = atoi(line);
else if (!strcmp(tag, "Sdsc")) {
/* Clear any existing sdesc to avoid leaks */
if (GET_SHORT_DESC(ch))
@ -614,6 +621,7 @@ void save_char(struct char_data * ch)
if (POOFOUT(ch)) fprintf(fl, "PfOt: %s\n", POOFOUT(ch));
if (GET_SEX(ch) != PFDEF_SEX) fprintf(fl, "Sex : %d\n", GET_SEX(ch));
if (GET_CLASS(ch) != PFDEF_CLASS) fprintf(fl, "Clas: %d\n", GET_CLASS(ch));
if (GET_SPECIES(ch) != PFDEF_SPECIES) fprintf(fl, "Spec: %d\n", GET_SPECIES(ch));
if (GET_LEVEL(ch) != PFDEF_LEVEL) fprintf(fl, "Levl: %d\n", GET_LEVEL(ch));
fprintf(fl, "Id : %ld\n", GET_IDNUM(ch));

446
src/species.c Normal file
View file

@ -0,0 +1,446 @@
/**
* @file species.c
* Race/species related configuration, skill bonuses, modifiers, and stat limitations.
*
* This set of code was not originally part of the circlemud distribution.
*/
#include "conf.h"
#include "sysdep.h"
#include "structs.h"
#include "utils.h"
#include "db.h"
#include "spells.h"
#include "species.h"
struct species_skill_bonus {
int skill;
int start;
};
/* Keep species ordering in sync with the SPECIES_* defines. */
const char *species_types[NUM_SPECIES] = {
"Human",
"City Elf",
"Desert Elf",
"Half-Elf",
"Dwarf",
"Mul",
"Half-Giant",
"Mantis",
"Gith",
"Aarakocra",
"Dray",
"Kenku",
"Jozhal",
"Pterran",
"Tarek",
"Aprig",
"Carru",
"Crodlu",
"Erdlu",
"Inix",
"Jhakar",
"Kank",
"Mekillot",
"Worm",
"Renk",
"Rat",
"Undead",
"Dragon"
};
/* PC creation options (1-based ordering in menus). */
const int pc_species_list[] = {
SPECIES_HUMAN,
SPECIES_CITY_ELF,
SPECIES_DESERT_ELF,
SPECIES_HALF_ELF,
SPECIES_DWARF,
SPECIES_MUL,
SPECIES_HALF_GIANT,
SPECIES_MANTIS,
SPECIES_GITH,
-1
};
static const struct species_skill_bonus species_skill_none[] = {
{ -1, 0 }
};
/* Per-species skill bonuses.
* Usage:
* 1) Define a bonus list for a species (see commented example below).
* 2) In species_skill_bonuses[], point that species at the new list.
* 3) Keep the { -1, 0 } terminator as the final entry.
*
* Example (commented out):
*
* static const struct species_skill_bonus species_skill_human[] = {
* { SKILL_PERCEPTION, 5 },
* { -1, 0 }
* };
*/
static const struct species_skill_bonus *species_skill_bonuses[NUM_SPECIES] = {
/* species_skill_human, */ /* Human (example if you enable the list above) */
species_skill_none, /* Human */
species_skill_none, /* City Elf */
species_skill_none, /* Desert Elf */
species_skill_none, /* Half-Elf */
species_skill_none, /* Dwarf */
species_skill_none, /* Mul */
species_skill_none, /* Half-Giant */
species_skill_none, /* Mantis */
species_skill_none, /* Gith */
species_skill_none, /* Aarakocra */
species_skill_none, /* Dray */
species_skill_none, /* Kenku */
species_skill_none, /* Jozhal */
species_skill_none, /* Pterran */
species_skill_none, /* Tarek */
species_skill_none, /* Aprig */
species_skill_none, /* Carru */
species_skill_none, /* Crodlu */
species_skill_none, /* Erdlu */
species_skill_none, /* Inix */
species_skill_none, /* Jhakar */
species_skill_none, /* Kank */
species_skill_none, /* Mekillot */
species_skill_none, /* Worm */
species_skill_none, /* Renk */
species_skill_none, /* Rat */
species_skill_none, /* Undead */
species_skill_none /* Dragon */
};
/* Ability minimums by species (STR, DEX, CON, INT, WIS, CHA). Zero = no min. */
static const int species_ability_mins[NUM_SPECIES][NUM_ABILITIES] = {
{ 0, 0, 0, 0, 0, 0 }, /* Human */
{ 0, 0, 0, 0, 0, 0 }, /* City Elf */
{ 0, 0, 0, 0, 0, 0 }, /* Desert Elf */
{ 0, 0, 0, 0, 0, 0 }, /* Half-Elf */
{ 0, 0, 0, 0, 0, 0 }, /* Dwarf */
{ 0, 0, 0, 0, 0, 0 }, /* Mul */
{ 0, 0, 0, 0, 0, 0 }, /* Half-Giant */
{ 0, 0, 0, 0, 0, 0 }, /* Mantis */
{ 0, 0, 0, 0, 0, 0 }, /* Gith */
{ 0, 0, 0, 0, 0, 0 }, /* Aarakocra */
{ 0, 0, 0, 0, 0, 0 }, /* Dray */
{ 0, 0, 0, 0, 0, 0 }, /* Kenku */
{ 0, 0, 0, 0, 0, 0 }, /* Jozhal */
{ 0, 0, 0, 0, 0, 0 }, /* Pterran */
{ 0, 0, 0, 0, 0, 0 }, /* Tarek */
{ 0, 0, 0, 0, 0, 0 }, /* Aprig */
{ 0, 0, 0, 0, 0, 0 }, /* Carru */
{ 0, 0, 0, 0, 0, 0 }, /* Crodlu */
{ 0, 0, 0, 0, 0, 0 }, /* Erdlu */
{ 0, 0, 0, 0, 0, 0 }, /* Inix */
{ 0, 0, 0, 0, 0, 0 }, /* Jhakar */
{ 0, 0, 0, 0, 0, 0 }, /* Kank */
{ 0, 0, 0, 0, 0, 0 }, /* Mekillot */
{ 0, 0, 0, 0, 0, 0 }, /* Worm */
{ 0, 0, 0, 0, 0, 0 }, /* Renk */
{ 0, 0, 0, 0, 0, 0 }, /* Rat */
{ 0, 0, 0, 0, 0, 0 }, /* Undead */
{ 0, 0, 0, 0, 0, 0 } /* Dragon */
};
/* Ability modifiers by species (STR, DEX, CON, INT, WIS, CHA). */
static const int species_ability_mods[NUM_SPECIES][NUM_ABILITIES] = {
{ 0, 0, 0, 0, 0, 0 }, /* Human */
{ 0, 0, 0, 0, 0, 0 }, /* City Elf */
{ 0, 0, 0, 0, 0, 0 }, /* Desert Elf */
{ 0, 0, 0, 0, 0, 0 }, /* Half-Elf */
{ 0, 0, 0, 0, 0, 0 }, /* Dwarf */
{ 0, 0, 0, 0, 0, 0 }, /* Mul */
{ 0, 0, 0, 0, 0, 0 }, /* Half-Giant */
{ 0, 0, 0, 0, 0, 0 }, /* Mantis */
{ 0, 0, 0, 0, 0, 0 }, /* Gith */
{ 0, 0, 0, 0, 0, 0 }, /* Aarakocra */
{ 0, 0, 0, 0, 0, 0 }, /* Dray */
{ 0, 0, 0, 0, 0, 0 }, /* Kenku */
{ 0, 0, 0, 0, 0, 0 }, /* Jozhal */
{ 0, 0, 0, 0, 0, 0 }, /* Pterran */
{ 0, 0, 0, 0, 0, 0 }, /* Tarek */
{ 0, 0, 0, 0, 0, 0 }, /* Aprig */
{ 0, 0, 0, 0, 0, 0 }, /* Carru */
{ 0, 0, 0, 0, 0, 0 }, /* Crodlu */
{ 0, 0, 0, 0, 0, 0 }, /* Erdlu */
{ 0, 0, 0, 0, 0, 0 }, /* Inix */
{ 0, 0, 0, 0, 0, 0 }, /* Jhakar */
{ 0, 0, 0, 0, 0, 0 }, /* Kank */
{ 0, 0, 0, 0, 0, 0 }, /* Mekillot */
{ 0, 0, 0, 0, 0, 0 }, /* Worm */
{ 0, 0, 0, 0, 0, 0 }, /* Renk */
{ 0, 0, 0, 0, 0, 0 }, /* Rat */
{ 0, 0, 0, 0, 0, 0 }, /* Undead */
{ 0, 0, 0, 0, 0, 0 } /* Dragon */
};
/* Ability caps by species (STR, DEX, CON, INT, WIS, CHA). Zero = no cap. */
static const int species_ability_caps[NUM_SPECIES][NUM_ABILITIES] = {
{ 16, 0, 0, 0, 0, 0 }, /* Human */
{ 14, 0, 0, 0, 0, 0 }, /* City Elf */
{ 14, 0, 0, 0, 0, 0 }, /* Desert Elf */
{ 14, 0, 0, 0, 0, 0 }, /* Half-Elf */
{ 18, 0, 0, 0, 0, 0 }, /* Dwarf */
{ 20, 0, 0, 0, 0, 0 }, /* Mul */
{ 24, 0, 0, 0, 0, 0 }, /* Half-Giant */
{ 0, 0, 0, 0, 0, 0 }, /* Mantis */
{ 0, 0, 0, 0, 0, 0 }, /* Gith */
{ 0, 0, 0, 0, 0, 0 }, /* Aarakocra */
{ 0, 0, 0, 0, 0, 0 }, /* Dray */
{ 0, 0, 0, 0, 0, 0 }, /* Kenku */
{ 0, 0, 0, 0, 0, 0 }, /* Jozhal */
{ 0, 0, 0, 0, 0, 0 }, /* Pterran */
{ 0, 0, 0, 0, 0, 0 }, /* Tarek */
{ 0, 0, 0, 0, 0, 0 }, /* Aprig */
{ 0, 0, 0, 0, 0, 0 }, /* Carru */
{ 0, 0, 0, 0, 0, 0 }, /* Crodlu */
{ 0, 0, 0, 0, 0, 0 }, /* Erdlu */
{ 0, 0, 0, 0, 0, 0 }, /* Inix */
{ 0, 0, 0, 0, 0, 0 }, /* Jhakar */
{ 0, 0, 0, 0, 0, 0 }, /* Kank */
{ 0, 0, 0, 0, 0, 0 }, /* Mekillot */
{ 0, 0, 0, 0, 0, 0 }, /* Worm */
{ 0, 0, 0, 0, 0, 0 }, /* Renk */
{ 0, 0, 0, 0, 0, 0 }, /* Rat */
{ 0, 0, 0, 0, 0, 0 }, /* Undead */
{ 0, 0, 0, 0, 0, 0 } /* Dragon */
};
const char *get_species_name(int species)
{
if (species >= 0 && species < NUM_SPECIES)
return species_types[species];
return "Unassigned";
}
int pc_species_count(void)
{
int count = 0;
while (pc_species_list[count] != -1)
count++;
return count;
}
bool species_is_pc_selectable(int species)
{
int i = 0;
while (pc_species_list[i] != -1) {
if (pc_species_list[i] == species)
return TRUE;
i++;
}
return FALSE;
}
int species_from_pc_choice(int choice)
{
int count = pc_species_count();
if (choice < 1 || choice > count)
return SPECIES_UNDEFINED;
return pc_species_list[choice - 1];
}
int species_ability_mod(int species, int ability)
{
if (species < 0 || species >= NUM_SPECIES)
return 0;
if (ability < 0 || ability >= NUM_ABILITIES)
return 0;
return species_ability_mods[species][ability];
}
int species_ability_min(int species, int ability)
{
if (species < 0 || species >= NUM_SPECIES)
return 0;
if (ability < 0 || ability >= NUM_ABILITIES)
return 0;
return species_ability_mins[species][ability];
}
int species_ability_cap(int species, int ability)
{
if (species < 0 || species >= NUM_SPECIES)
return 0;
if (ability < 0 || ability >= NUM_ABILITIES)
return 0;
return species_ability_caps[species][ability];
}
static void apply_species_ranges(struct char_data *ch)
{
int species;
int cap, min;
if (!ch)
return;
species = GET_SPECIES(ch);
if (species < 0 || species >= NUM_SPECIES)
return;
min = species_ability_min(species, ABIL_STR);
if (min > 0 && ch->real_abils.str < min)
ch->real_abils.str = min;
cap = species_ability_cap(species, ABIL_STR);
if (cap > 0 && ch->real_abils.str > cap)
ch->real_abils.str = cap;
min = species_ability_min(species, ABIL_DEX);
if (min > 0 && ch->real_abils.dex < min)
ch->real_abils.dex = min;
cap = species_ability_cap(species, ABIL_DEX);
if (cap > 0 && ch->real_abils.dex > cap)
ch->real_abils.dex = cap;
min = species_ability_min(species, ABIL_CON);
if (min > 0 && ch->real_abils.con < min)
ch->real_abils.con = min;
cap = species_ability_cap(species, ABIL_CON);
if (cap > 0 && ch->real_abils.con > cap)
ch->real_abils.con = cap;
min = species_ability_min(species, ABIL_INT);
if (min > 0 && ch->real_abils.intel < min)
ch->real_abils.intel = min;
cap = species_ability_cap(species, ABIL_INT);
if (cap > 0 && ch->real_abils.intel > cap)
ch->real_abils.intel = cap;
min = species_ability_min(species, ABIL_WIS);
if (min > 0 && ch->real_abils.wis < min)
ch->real_abils.wis = min;
cap = species_ability_cap(species, ABIL_WIS);
if (cap > 0 && ch->real_abils.wis > cap)
ch->real_abils.wis = cap;
min = species_ability_min(species, ABIL_CHA);
if (min > 0 && ch->real_abils.cha < min)
ch->real_abils.cha = min;
cap = species_ability_cap(species, ABIL_CHA);
if (cap > 0 && ch->real_abils.cha > cap)
ch->real_abils.cha = cap;
}
void apply_species_bonuses(struct char_data *ch)
{
int species;
if (!ch)
return;
species = GET_SPECIES(ch);
if (species < 0 || species >= NUM_SPECIES)
return;
apply_species_ranges(ch);
ch->real_abils.str += species_ability_mod(species, ABIL_STR);
ch->real_abils.dex += species_ability_mod(species, ABIL_DEX);
ch->real_abils.con += species_ability_mod(species, ABIL_CON);
ch->real_abils.intel += species_ability_mod(species, ABIL_INT);
ch->real_abils.wis += species_ability_mod(species, ABIL_WIS);
ch->real_abils.cha += species_ability_mod(species, ABIL_CHA);
apply_species_ranges(ch);
ch->aff_abils = ch->real_abils;
}
void grant_species_skills(struct char_data *ch)
{
int species;
const struct species_skill_bonus *bonus;
if (!ch)
return;
species = GET_SPECIES(ch);
if (species < 0 || species >= NUM_SPECIES)
return;
for (bonus = species_skill_bonuses[species]; bonus->skill != -1; bonus++) {
if (bonus->skill >= 0 && bonus->skill <= MAX_SKILLS) {
if (GET_SKILL(ch, bonus->skill) < bonus->start)
SET_SKILL(ch, bonus->skill, bonus->start);
}
}
}
static void remove_species_skills(struct char_data *ch, int species)
{
const struct species_skill_bonus *bonus;
if (!ch)
return;
if (species < 0 || species >= NUM_SPECIES)
return;
for (bonus = species_skill_bonuses[species]; bonus->skill != -1; bonus++) {
if (bonus->skill >= 0 && bonus->skill <= MAX_SKILLS) {
if (GET_SKILL(ch, bonus->skill) <= bonus->start)
SET_SKILL(ch, bonus->skill, 0);
}
}
}
static void remove_species_bonuses(struct char_data *ch, int species)
{
if (!ch)
return;
if (species < 0 || species >= NUM_SPECIES)
return;
ch->real_abils.str -= species_ability_mod(species, ABIL_STR);
ch->real_abils.dex -= species_ability_mod(species, ABIL_DEX);
ch->real_abils.con -= species_ability_mod(species, ABIL_CON);
ch->real_abils.intel -= species_ability_mod(species, ABIL_INT);
ch->real_abils.wis -= species_ability_mod(species, ABIL_WIS);
ch->real_abils.cha -= species_ability_mod(species, ABIL_CHA);
}
int parse_species(const char *arg)
{
int i;
if (!arg || !*arg)
return SPECIES_UNDEFINED;
for (i = 0; i < NUM_SPECIES; i++) {
if (!str_cmp(arg, species_types[i]))
return i;
}
return SPECIES_UNDEFINED;
}
void update_species(struct char_data *ch, int new_species)
{
int old_species;
if (!ch)
return;
old_species = GET_SPECIES(ch);
if (old_species == new_species)
return;
if (old_species >= 0 && old_species < NUM_SPECIES) {
remove_species_skills(ch, old_species);
remove_species_bonuses(ch, old_species);
}
GET_SPECIES(ch) = new_species;
if (new_species >= 0 && new_species < NUM_SPECIES) {
apply_species_bonuses(ch);
grant_species_skills(ch);
} else {
ch->aff_abils = ch->real_abils;
}
}

29
src/species.h Normal file
View file

@ -0,0 +1,29 @@
/**
* @file species.h
* Race/species related header.
*
* This set of code was not originally part of the circlemud distribution.
*/
#ifndef _SPECIES_H_
#define _SPECIES_H_
struct char_data;
const char *get_species_name(int species);
int species_from_pc_choice(int choice);
int pc_species_count(void);
bool species_is_pc_selectable(int species);
int species_ability_mod(int species, int ability);
int species_ability_min(int species, int ability);
int species_ability_cap(int species, int ability);
void apply_species_bonuses(struct char_data *ch);
void grant_species_skills(struct char_data *ch);
int parse_species(const char *arg);
void update_species(struct char_data *ch, int new_species);
extern const char *species_types[];
extern const int pc_species_list[];
#endif /* _SPECIES_H_ */

View file

@ -164,6 +164,38 @@
/** Total number of available PC Classes */
#define NUM_CLASSES 8
/* Species */
#define SPECIES_UNDEFINED (-1) /**< Species undefined */
#define SPECIES_HUMAN 0
#define SPECIES_CITY_ELF 1
#define SPECIES_DESERT_ELF 2
#define SPECIES_HALF_ELF 3
#define SPECIES_DWARF 4
#define SPECIES_MUL 5
#define SPECIES_HALF_GIANT 6
#define SPECIES_MANTIS 7
#define SPECIES_GITH 8
#define SPECIES_AARAKOCRA 9
#define SPECIES_DRAY 10
#define SPECIES_KENKU 11
#define SPECIES_JOZHAL 12
#define SPECIES_PTERRAN 13
#define SPECIES_TAREK 14
#define SPECIES_APRIG 15
#define SPECIES_CARRU 16
#define SPECIES_CRODLU 17
#define SPECIES_ERDLU 18
#define SPECIES_INIX 19
#define SPECIES_JHAKAR 20
#define SPECIES_KANK 21
#define SPECIES_MEKILLOT 22
#define SPECIES_WORM 23
#define SPECIES_RENK 24
#define SPECIES_RAT 25
#define SPECIES_UNDEAD 26
#define SPECIES_DRAGON 27
#define NUM_SPECIES 28
/* NPC classes (currently unused - feel free to implement!) */
#define CLASS_OTHER 0 /**< NPC Class Other (or undefined) */
#define CLASS_UNDEAD 1 /**< NPC Class Undead */
@ -313,42 +345,43 @@
#define CON_NEWPASSWD 5 /**< New character, create password */
#define CON_CNFPASSWD 6 /**< New character, confirm password */
#define CON_QSEX 7 /**< Choose character sex */
#define CON_QCLASS 8 /**< Choose character class */
#define CON_QSHORTDESC 9 /**< Enter a new character short description prompt */
#define CON_RMOTD 10 /**< Reading the message of the day */
#define CON_MENU 11 /**< At the main menu */
#define CON_PLR_DESC 12 /**< Enter a new character description prompt */
#define CON_CHPWD_GETOLD 13 /**< Changing passwd: Get old */
#define CON_CHPWD_GETNEW 14 /**< Changing passwd: Get new */
#define CON_CHPWD_VRFY 15 /**< Changing passwd: Verify new password */
#define CON_DELCNF1 16 /**< Character Delete: Confirmation 1 */
#define CON_DELCNF2 17 /**< Character Delete: Confirmation 2 */
#define CON_DISCONNECT 18 /**< In-game link loss (leave character) */
#define CON_OEDIT 19 /**< OLC mode - object editor */
#define CON_REDIT 20 /**< OLC mode - room editor */
#define CON_ZEDIT 21 /**< OLC mode - zone info editor */
#define CON_MEDIT 22 /**< OLC mode - mobile editor */
#define CON_SEDIT 23 /**< OLC mode - shop editor */
#define CON_TEDIT 24 /**< OLC mode - text editor */
#define CON_CEDIT 25 /**< OLC mode - conf editor */
#define CON_AEDIT 26 /**< OLC mode - social (action) edit */
#define CON_TRIGEDIT 27 /**< OLC mode - trigger edit */
#define CON_HEDIT 28 /**< OLC mode - help edit */
#define CON_QEDIT 29 /**< OLC mode - quest edit */
#define CON_PREFEDIT 30 /**< OLC mode - preference edit */
#define CON_IBTEDIT 31 /**< OLC mode - idea/bug/typo edit */
#define CON_MSGEDIT 32 /**< OLC mode - message editor */
#define CON_PLR_BACKGROUND 33 /**< Entering a new character background */
#define CON_GET_PROTOCOL 33 /**< Used at log-in while attempting to get protocols > */
#define CON_GET_CONNECT 34 /**< Login connect/disconnect menu */
#define CON_GET_ACCOUNT 35 /**< Login with account name */
#define CON_ACCOUNT_CNFRM 36 /**< New account, confirm name */
#define CON_ACCOUNT_PASSWORD 37 /**< Login with account password */
#define CON_ACCOUNT_NEWPASSWD 38 /**< New account, create password */
#define CON_ACCOUNT_CNFPASSWD 39 /**< New account, confirm password */
#define CON_ACCOUNT_EMAIL 40 /**< New account, optional email */
#define CON_ACCOUNT_MENU 41 /**< Account main menu */
#define CON_ACCOUNT_LIST 42 /**< Viewing account character list */
#define CON_QSPECIES 8 /**< Choose character species */
#define CON_QCLASS 9 /**< Choose character class */
#define CON_QSHORTDESC 10 /**< Enter a new character short description prompt */
#define CON_RMOTD 11 /**< Reading the message of the day */
#define CON_MENU 12 /**< At the main menu */
#define CON_PLR_DESC 13 /**< Enter a new character description prompt */
#define CON_CHPWD_GETOLD 14 /**< Changing passwd: Get old */
#define CON_CHPWD_GETNEW 15 /**< Changing passwd: Get new */
#define CON_CHPWD_VRFY 16 /**< Changing passwd: Verify new password */
#define CON_DELCNF1 17 /**< Character Delete: Confirmation 1 */
#define CON_DELCNF2 18 /**< Character Delete: Confirmation 2 */
#define CON_DISCONNECT 19 /**< In-game link loss (leave character) */
#define CON_OEDIT 20 /**< OLC mode - object editor */
#define CON_REDIT 21 /**< OLC mode - room editor */
#define CON_ZEDIT 22 /**< OLC mode - zone info editor */
#define CON_MEDIT 23 /**< OLC mode - mobile editor */
#define CON_SEDIT 24 /**< OLC mode - shop editor */
#define CON_TEDIT 25 /**< OLC mode - text editor */
#define CON_CEDIT 26 /**< OLC mode - conf editor */
#define CON_AEDIT 27 /**< OLC mode - social (action) edit */
#define CON_TRIGEDIT 28 /**< OLC mode - trigger edit */
#define CON_HEDIT 29 /**< OLC mode - help edit */
#define CON_QEDIT 30 /**< OLC mode - quest edit */
#define CON_PREFEDIT 31 /**< OLC mode - preference edit */
#define CON_IBTEDIT 32 /**< OLC mode - idea/bug/typo edit */
#define CON_MSGEDIT 33 /**< OLC mode - message editor */
#define CON_PLR_BACKGROUND 34 /**< Entering a new character background */
#define CON_GET_PROTOCOL 34 /**< Used at log-in while attempting to get protocols > */
#define CON_GET_CONNECT 35 /**< Login connect/disconnect menu */
#define CON_GET_ACCOUNT 36 /**< Login with account name */
#define CON_ACCOUNT_CNFRM 37 /**< New account, confirm name */
#define CON_ACCOUNT_PASSWORD 38 /**< Login with account password */
#define CON_ACCOUNT_NEWPASSWD 39 /**< New account, create password */
#define CON_ACCOUNT_CNFPASSWD 40 /**< New account, confirm password */
#define CON_ACCOUNT_EMAIL 41 /**< New account, optional email */
#define CON_ACCOUNT_MENU 42 /**< Account main menu */
#define CON_ACCOUNT_LIST 43 /**< Viewing account character list */
/* OLC States range - used by IS_IN_OLC and IS_PLAYING */
#define FIRST_OLC_STATE CON_OEDIT /**< The first CON_ state that is an OLC */
@ -907,6 +940,7 @@ struct char_player_data
char *background; /**< PC / NPC background / history text */
byte sex; /**< PC / NPC sex */
byte chclass; /**< PC / NPC class */
byte species; /**< PC / NPC species */
byte level; /**< PC / NPC level */
struct time_data time; /**< PC AGE in days */
ubyte weight; /**< PC / NPC weight */

View file

@ -556,6 +556,8 @@ do \
/** Class of ch. */
#define GET_CLASS(ch) ((ch)->player.chclass)
/** Species of ch. */
#define GET_SPECIES(ch) ((ch)->player.species)
/** Height of ch. */
#define GET_HEIGHT(ch) ((ch)->player.height)
/** Weight of ch. */
@ -936,6 +938,7 @@ do \
/** True if ch has a valid player class assigned. */
#define HAS_VALID_CLASS(ch) ((GET_CLASS(ch) >= CLASS_SORCEROR) && (GET_CLASS(ch) < NUM_CLASSES))
#define HAS_VALID_SPECIES(ch) ((GET_SPECIES(ch) >= 0) && (GET_SPECIES(ch) < NUM_SPECIES))
/** Return the class abbreviation for ch. */
#define CLASS_ABBR(ch) (HAS_VALID_CLASS(ch) ? class_abbrevs[(int)GET_CLASS(ch)] : "--")