Skip to content

Commit

Permalink
Merge pull request #357 from stridera/race-spells
Browse files Browse the repository at this point in the history
Race spells
  • Loading branch information
daedela authored Jan 20, 2024
2 parents d71bbe1 + 6fd634e commit 0779abc
Show file tree
Hide file tree
Showing 13 changed files with 243 additions and 46 deletions.
11 changes: 5 additions & 6 deletions include/class.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "chars.hpp"
#include "objects.hpp"
#include "races.hpp"
#include "structs.hpp"
#include "sysdep.hpp"

Expand Down Expand Up @@ -132,12 +133,9 @@ extern ClassDef classes[NUM_CLASSES];
#define IS_WARRIOR(ch) \
(VALID_CLASS(ch) ? GET_CLASS(ch) == CLASS_WARRIOR || classes[(int)GET_CLASS(ch)].subclass_of == CLASS_WARRIOR \
: false)
#define IS_SPELLCASTER(ch) \
(VALID_CLASS(ch) ? GET_CLASS(ch) == CLASS_SORCERER || classes[(int)GET_CLASS(ch)].subclass_of == CLASS_SORCERER || \
GET_CLASS(ch) == CLASS_CLERIC || classes[(int)GET_CLASS(ch)].subclass_of == CLASS_CLERIC || \
GET_CLASS(ch) == CLASS_ANTI_PALADIN || GET_CLASS(ch) == CLASS_PALADIN || \
GET_CLASS(ch) == CLASS_RANGER || GET_CLASS(ch) == CLASS_SHAMAN || GET_CLASS(ch) == CLASS_BARD \
: false)

#define IS_SPELLCASTER_CLASS(ch) (VALID_CLASS(ch) ? classes[(int)GET_CLASS(ch)].magical : false)
#define IS_SPELLCASTER(ch) (IS_SPELLCASTER_CLASS(ch) || IS_SPELLCASTER_RACE(ch))

/* Is this character prohibited from wearing this equipment due to a class
* restriction? Would return true if, for example, a warrior tried to wear
Expand All @@ -147,6 +145,7 @@ extern ClassDef classes[NUM_CLASSES];
? classes[(int)GET_CLASS(ch)].nowear_flag && OBJ_FLAGGED(obj, classes[(int)GET_CLASS(ch)].nowear_flag) \
: 0)


enum level_action { LEVEL_GAIN, LEVEL_LOSE };

void init_classes(void);
Expand Down
5 changes: 5 additions & 0 deletions include/races.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@
#define RACE_DICEFACTOR(race) (VALID_RACENUM(race) ? races[race].dice_factor : 100)
#define RACE_COPPERFACTOR(race) (VALID_RACENUM(race) ? races[race].copper_factor : 100)
#define RACE_ACFACTOR(race) (VALID_RACENUM(race) ? races[race].ac_factor : 100)

#define IS_SPELLCASTER_RACE(ch) (VALID_RACE(ch) ? races[(int)GET_RACE(ch)].magical : false)

struct RaceDef {
const char *name; /* The basic name, uncapitalized and uncolored. */
const char *names; /* Additional names for searching purposes. */
Expand All @@ -99,6 +102,7 @@ struct RaceDef {
const char *plainname; /* The name with capitalization but no colors. */
bool playable; /* Available to mortals? */
bool humanoid; /* Is it humanoid? */
bool magical; /* Does it have racial spells? */
int racealign; /* Is it considered a good or evil race? */
int def_size; /* The default size for a member of this race. */
int def_align; /* Default alignment */
Expand Down Expand Up @@ -149,6 +153,7 @@ extern RaceDef races[NUM_RACES];
extern const char *race_align_abbrevs[];

void init_races(void);
void assign_race_skills(void);
int parse_race(CharData *ch, CharData *vict, char *arg);
int race_by_menu(char arg);
void send_race_menu(DescriptorData *d);
Expand Down
6 changes: 5 additions & 1 deletion include/skills.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ struct SkillDef {
int pages; /* base number of pages for spell in spellbook */
int quest; /* weather the spell is a quest spell or not */
const char *wearoff;
int min_race_level[NUM_RACES];
};

extern SkillDef skills[TOP_SKILL_DEFINE + 1];
Expand All @@ -57,7 +58,9 @@ extern SkillDef skills[TOP_SKILL_DEFINE + 1];
int level_to_circle(int level);
int circle_to_level(int circle);
#define IS_QUEST_SPELL(spellnum) (skills[(spellnum)].quest)
#define SKILL_LEVEL(ch, skillnum) (skills[(skillnum)].min_level[(int)GET_CLASS(ch)])
#define SKILL_LEVEL(ch, skillnum) \
((skills[(skillnum)].min_level[(int)GET_CLASS(ch)] <= skills[(skillnum)].min_race_level[(int)GET_RACE(ch)]) ? \
skills[(skillnum)].min_level[(int)GET_CLASS(ch)] : skills[(skillnum)].min_race_level[(int)GET_RACE(ch)])
#define SPELL_CIRCLE(ch, spellnum) (level_to_circle(SKILL_LEVEL(ch, spellnum)))
#define CIRCLE_ABBR(ch, spellnum) (circle_abbrev[SPELL_CIRCLE((ch), (spellnum))])
#define SKILL_IS_TARGET(skill, tartype) \
Expand All @@ -79,6 +82,7 @@ void improve_skill(CharData *ch, int skill);
void improve_skill_offensively(CharData *ch, CharData *victim, int skill);
void update_skills(CharData *ch);
void skill_assign(int skillnum, int class_code, int level);
void race_skill_assign(int skillnum, int race_code, int level);
int talent_type(int skill_num);
bool get_spell_assignment_circle(CharData *ch, int spell, int *circle_assignment, int *level_assignment);

Expand Down
15 changes: 12 additions & 3 deletions src/act.informative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3563,8 +3563,8 @@ ACMD(do_spells) {
}
}

/* Is this character in a class with spells? */
if (MEM_MODE(tch) == MEM_NONE) {
/* Is this character in a class or a race with spells? */
if (!IS_SPELLCASTER(tch)) {
if (tch == ch)
char_printf(ch, "You don't know any spells.\n");
else {
Expand All @@ -3574,6 +3574,7 @@ ACMD(do_spells) {
return;
}


/* Collect and count the spells known by the victim. */

memset(&circle_spells, 0, sizeof(circle_spells));
Expand All @@ -3582,13 +3583,21 @@ ACMD(do_spells) {
i = skill_sort_info[k];
if (!IS_SPELL(i))
continue;
if (skills[i].min_level[GET_CLASS(tch)] < LVL_IMMORT && GET_SKILL(tch, i) > 0) {
if (skills[i].min_level[GET_CLASS(tch)] < LVL_IMMORT && GET_SKILL(tch, i) > 0 && skills[i].min_level[GET_CLASS(tch)] <= skills[i].min_race_level[GET_RACE(tch)]) {
circle = (skills[i].min_level[GET_CLASS(tch)] - 1) / 8;
for (j = 0; circle_spells[circle][j] && j < MAX_SPELLS_PER_CIRCLE && circle < max_vis_circle; ++j)
;
if (!xcircle || xcircle == circle + 1)
numspellsknown++;
circle_spells[circle][j] = i;

} else if (skills[i].min_race_level[GET_RACE(tch)] < LVL_IMMORT && GET_SKILL(tch, i) > 0) {
circle = (skills[i].min_race_level[GET_RACE(tch)] - 1) / 8;
for (j = 0; circle_spells[circle][j] && j < MAX_SPELLS_PER_CIRCLE && circle < max_vis_circle; ++j)
;
if (!xcircle || xcircle == circle + 1)
numspellsknown++;
circle_spells[circle][j] = i;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/act.other.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ ACMD(do_shapechange) {
char_to_room(mob, ch->in_room);

/* Transfer hover slot items to new mob */
if GET_EQ (ch, WEAR_HOVER) {
if GET_EQ(ch, WEAR_HOVER) {

obj = GET_EQ(ch, WEAR_HOVER);
unequip_char(ch, WEAR_HOVER);
Expand Down
2 changes: 1 addition & 1 deletion src/cleric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ bool cleric_ai_action(CharData *ch, CharData *victim) {
case SPELL_SILENCE:
for (victim = world[ch->in_room].people; victim; victim = next_victim) {
next_victim = victim->next_in_room;
if (IS_SPELLCASTER(victim) && FIGHTING(victim) == ch &&
if ((IS_SPELLCASTER(victim)) && FIGHTING(victim) == ch &&
!has_effect(victim, &mob_cleric_hindrances[i]) && GET_LEVEL(victim) < (GET_LEVEL(ch) + 20)) {
if (mob_cast(ch, victim, nullptr, mob_cleric_hindrances[i].spell))
return true;
Expand Down
5 changes: 4 additions & 1 deletion src/db.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -557,10 +557,13 @@ void boot_db(void) {

log(" Skills.");
init_skills();

log("Assigning skills and spells to classes.");
assign_class_skills();

log("Assigning skills and spells to races.");
assign_race_skills();

/* Command sorting needs to happen before many other loading
* activities, because sorting the commands initializes the
* num_of_cmds variable.
Expand Down
Loading

0 comments on commit 0779abc

Please sign in to comment.