mirror of
https://github.com/tbamud/tbamud.git
synced 2026-03-20 19:26:33 +01:00
Add NPC skills, update medit menu
This commit is contained in:
parent
cc342ef45c
commit
ed8ee4aa5f
11 changed files with 375 additions and 178 deletions
|
|
@ -130,7 +130,7 @@ ACMD(do_backstab)
|
|||
int roll, atk_bonus, total, target_ac;
|
||||
bool crit_success = FALSE, crit_fail = FALSE;
|
||||
|
||||
if (IS_NPC(ch) || !GET_SKILL(ch, SKILL_BACKSTAB)) {
|
||||
if (!GET_SKILL(ch, SKILL_BACKSTAB)) {
|
||||
send_to_char(ch, "You have no idea how to do that.\r\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -314,7 +314,7 @@ ACMD(do_bash)
|
|||
|
||||
one_argument(argument, arg);
|
||||
|
||||
if (IS_NPC(ch) || !GET_SKILL(ch, SKILL_BASH)) {
|
||||
if (!GET_SKILL(ch, SKILL_BASH)) {
|
||||
send_to_char(ch, "You have no idea how.\r\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -405,7 +405,7 @@ ACMD(do_rescue)
|
|||
struct char_data *vict, *tmp_ch;
|
||||
int roll, bonus, total, dc;
|
||||
|
||||
if (IS_NPC(ch) || !GET_SKILL(ch, SKILL_RESCUE)) {
|
||||
if (!GET_SKILL(ch, SKILL_RESCUE)) {
|
||||
send_to_char(ch, "You have no idea how to do that.\r\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -576,7 +576,7 @@ EVENTFUNC(event_whirlwind)
|
|||
ACMD(do_whirlwind)
|
||||
{
|
||||
|
||||
if (IS_NPC(ch) || !GET_SKILL(ch, SKILL_WHIRLWIND)) {
|
||||
if (!GET_SKILL(ch, SKILL_WHIRLWIND)) {
|
||||
send_to_char(ch, "You have no idea how.\r\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -618,7 +618,7 @@ ACMD(do_kick)
|
|||
int roll, atk_bonus, total, target_ac;
|
||||
bool crit_success = FALSE, crit_miss = FALSE;
|
||||
|
||||
if (IS_NPC(ch) || !GET_SKILL(ch, SKILL_KICK)) {
|
||||
if (!GET_SKILL(ch, SKILL_KICK)) {
|
||||
send_to_char(ch, "You have no idea how.\r\n");
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ ACMD(do_sneak)
|
|||
int rolla, rollb, roll, bonus, total, dc;
|
||||
bool disadv = FALSE;
|
||||
|
||||
if (IS_NPC(ch) || !GET_SKILL(ch, SKILL_SNEAK)) {
|
||||
if (!GET_SKILL(ch, SKILL_SNEAK)) {
|
||||
send_to_char(ch, "You have no idea how to do that.\r\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -259,7 +259,7 @@ ACMD(do_hide)
|
|||
int rolla, rollb, roll, bonus, total, dc;
|
||||
bool disadv = FALSE;
|
||||
|
||||
if (IS_NPC(ch) || !GET_SKILL(ch, SKILL_HIDE)) {
|
||||
if (!GET_SKILL(ch, SKILL_HIDE)) {
|
||||
send_to_char(ch, "You have no idea how to do that.\r\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -323,7 +323,7 @@ ACMD(do_perception)
|
|||
int roll, bonus, total;
|
||||
int found_chars = 0, found_objs = 0;
|
||||
|
||||
if (IS_NPC(ch) || !GET_SKILL(ch, SKILL_PERCEPTION)) {
|
||||
if (!GET_SKILL(ch, SKILL_PERCEPTION)) {
|
||||
send_to_char(ch, "You have no idea how to do that.\r\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -404,7 +404,7 @@ ACMD(do_steal)
|
|||
char vict_name[MAX_INPUT_LENGTH], obj_name[MAX_INPUT_LENGTH];
|
||||
int percent, gold, eq_pos, pcsteal = 0, ohoh = 0;
|
||||
|
||||
if (IS_NPC(ch) || !GET_SKILL(ch, SKILL_STEAL)) {
|
||||
if (!GET_SKILL(ch, SKILL_STEAL)) {
|
||||
send_to_char(ch, "You have no idea how to do that.\r\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -525,9 +525,6 @@ ACMD(do_steal)
|
|||
ACMD(do_skills)
|
||||
{
|
||||
|
||||
if (IS_NPC(ch))
|
||||
return;
|
||||
|
||||
list_skills(ch);
|
||||
|
||||
}
|
||||
|
|
|
|||
120
src/db.c
120
src/db.c
|
|
@ -1597,44 +1597,28 @@ static void parse_simple_mob(FILE *mob_f, int i, int nr)
|
|||
}
|
||||
|
||||
/* interpret_espec is the function that takes espec keywords and values and
|
||||
* assigns the correct value to the mob as appropriate. Adding new e-specs is
|
||||
* absurdly easy -- just add a new CASE statement to this function! No other
|
||||
* changes need to be made anywhere in the code.
|
||||
* CASE : Requires a parameter through 'value'. */
|
||||
#define CASE(test) \
|
||||
if (value && !matched && !str_cmp(keyword, test) && (matched = TRUE))
|
||||
#define RANGE(low, high) \
|
||||
(num_arg = MAX((low), MIN((high), (num_arg))))
|
||||
* assigns the correct value to the mob as appropriate. Adding new e-specs is
|
||||
* straightforward: just add a new CASE() block. */
|
||||
#define CASE(test) \
|
||||
if (value && !matched && !str_cmp(keyword, test) && (matched = TRUE))
|
||||
#define RANGE(low, high) \
|
||||
(num_arg = MAX((low), MIN((high), (num_arg))))
|
||||
|
||||
static void interpret_espec(const char *keyword, const char *value, int i, int nr)
|
||||
{
|
||||
int num_arg = 0, matched = FALSE;
|
||||
int num_arg = 0;
|
||||
bool matched = FALSE;
|
||||
|
||||
/* If there isn't a colon, there is no value. While Boolean options are
|
||||
* possible, we don't actually have any. Feel free to make some. */
|
||||
/* Defensive check: if there's a value, convert to int */
|
||||
if (value)
|
||||
num_arg = atoi(value);
|
||||
|
||||
CASE("BareHandAttack") {
|
||||
RANGE(0, NUM_ATTACK_TYPES - 1);
|
||||
mob_proto[i].mob_specials.attack_type = num_arg;
|
||||
}
|
||||
|
||||
/* --- Ability Scores --- */
|
||||
CASE("Str") {
|
||||
RANGE(3, 25);
|
||||
mob_proto[i].real_abils.str = num_arg;
|
||||
}
|
||||
|
||||
CASE("Int") {
|
||||
RANGE(3, 25);
|
||||
mob_proto[i].real_abils.intel = num_arg;
|
||||
}
|
||||
|
||||
CASE("Wis") {
|
||||
RANGE(3, 25);
|
||||
mob_proto[i].real_abils.wis = num_arg;
|
||||
}
|
||||
|
||||
CASE("Dex") {
|
||||
RANGE(3, 25);
|
||||
mob_proto[i].real_abils.dex = num_arg;
|
||||
|
|
@ -1645,12 +1629,22 @@ static void interpret_espec(const char *keyword, const char *value, int i, int n
|
|||
mob_proto[i].real_abils.con = num_arg;
|
||||
}
|
||||
|
||||
CASE("Int") {
|
||||
RANGE(3, 25);
|
||||
mob_proto[i].real_abils.intel = num_arg;
|
||||
}
|
||||
|
||||
CASE("Wis") {
|
||||
RANGE(3, 25);
|
||||
mob_proto[i].real_abils.wis = num_arg;
|
||||
}
|
||||
|
||||
CASE("Cha") {
|
||||
RANGE(3, 25);
|
||||
mob_proto[i].real_abils.cha = num_arg;
|
||||
}
|
||||
|
||||
/* --- New 5e-style saving throw keywords --- */
|
||||
/* --- 5e-style Saving Throws --- */
|
||||
CASE("SaveStr") {
|
||||
RANGE(0, 100);
|
||||
mob_proto[i].char_specials.saved.saving_throws[ABIL_STR] = num_arg;
|
||||
|
|
@ -1681,42 +1675,100 @@ static void interpret_espec(const char *keyword, const char *value, int i, int n
|
|||
mob_proto[i].char_specials.saved.saving_throws[ABIL_CHA] = num_arg;
|
||||
}
|
||||
|
||||
/* --- Debug + Fallback --- */
|
||||
if (!matched) {
|
||||
log("DEBUG: Unmatched espec line '%s' value '%s' in mob #%d",
|
||||
keyword, value ? value : "(null)", nr);
|
||||
log("SYSERR: Warning: unrecognized espec keyword %s in mob #%d",
|
||||
keyword, nr);
|
||||
keyword, nr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Prevent macro bleed outside this function’s scope */
|
||||
#undef CASE
|
||||
#undef BOOL_CASE
|
||||
#undef RANGE
|
||||
|
||||
static void parse_espec(char *buf, int i, int nr)
|
||||
{
|
||||
char *ptr;
|
||||
int value;
|
||||
|
||||
/* Split on ':' if present (e.g., "Str: 16") */
|
||||
if ((ptr = strchr(buf, ':')) != NULL) {
|
||||
*(ptr++) = '\0';
|
||||
while (isspace(*ptr))
|
||||
ptr++;
|
||||
}
|
||||
interpret_espec(buf, ptr, i, nr);
|
||||
|
||||
/* Trim leading spaces from keyword */
|
||||
while (isspace(*buf))
|
||||
buf++;
|
||||
|
||||
/* --- Handle ability score lines --- */
|
||||
if (!str_cmp(buf, "Str") && sscanf(ptr, "%d", &value) == 1)
|
||||
GET_STR(mob_proto + i) = LIMIT(value, 3, 25);
|
||||
else if (!str_cmp(buf, "Dex") && sscanf(ptr, "%d", &value) == 1)
|
||||
GET_DEX(mob_proto + i) = LIMIT(value, 3, 25);
|
||||
else if (!str_cmp(buf, "Int") && sscanf(ptr, "%d", &value) == 1)
|
||||
GET_INT(mob_proto + i) = LIMIT(value, 3, 25);
|
||||
else if (!str_cmp(buf, "Wis") && sscanf(ptr, "%d", &value) == 1)
|
||||
GET_WIS(mob_proto + i) = LIMIT(value, 3, 25);
|
||||
else if (!str_cmp(buf, "Con") && sscanf(ptr, "%d", &value) == 1)
|
||||
GET_CON(mob_proto + i) = LIMIT(value, 3, 25);
|
||||
else if (!str_cmp(buf, "Cha") && sscanf(ptr, "%d", &value) == 1)
|
||||
GET_CHA(mob_proto + i) = LIMIT(value, 3, 25);
|
||||
|
||||
/* --- Optional saving throw support (if you use these in files) --- */
|
||||
else if (!str_cmp(buf, "SaveStr") && sscanf(ptr, "%d", &value) == 1)
|
||||
GET_SAVE(mob_proto + i, ABIL_STR) = value;
|
||||
else if (!str_cmp(buf, "SaveDex") && sscanf(ptr, "%d", &value) == 1)
|
||||
GET_SAVE(mob_proto + i, ABIL_DEX) = value;
|
||||
else if (!str_cmp(buf, "SaveCon") && sscanf(ptr, "%d", &value) == 1)
|
||||
GET_SAVE(mob_proto + i, ABIL_CON) = value;
|
||||
else if (!str_cmp(buf, "SaveInt") && sscanf(ptr, "%d", &value) == 1)
|
||||
GET_SAVE(mob_proto + i, ABIL_INT) = value;
|
||||
else if (!str_cmp(buf, "SaveWis") && sscanf(ptr, "%d", &value) == 1)
|
||||
GET_SAVE(mob_proto + i, ABIL_WIS) = value;
|
||||
else if (!str_cmp(buf, "SaveCha") && sscanf(ptr, "%d", &value) == 1)
|
||||
GET_SAVE(mob_proto + i, ABIL_CHA) = value;
|
||||
|
||||
/* --- Fallback: hand off anything else to the old interpreter --- */
|
||||
else
|
||||
interpret_espec(buf, ptr, i, nr);
|
||||
}
|
||||
|
||||
static void parse_enhanced_mob(FILE *mob_f, int i, int nr)
|
||||
{
|
||||
char line[READ_SIZE];
|
||||
|
||||
/* Step 1: parse the standard numeric lines (level, dice, pos, sex, etc.) */
|
||||
parse_simple_mob(mob_f, i, nr);
|
||||
|
||||
/* Step 2: read extended attributes until 'E' line encountered */
|
||||
while (get_line(mob_f, line)) {
|
||||
if (!strcmp(line, "E")) /* end of the enhanced section */
|
||||
if (!strcmp(line, "E")) /* end of the enhanced section */
|
||||
return;
|
||||
else if (*line == '#') { /* we've hit the next mob, maybe? */
|
||||
else if (*line == '#') { /* premature next mob start */
|
||||
log("SYSERR: Unterminated E section in mob #%d", nr);
|
||||
exit(1);
|
||||
} else
|
||||
parse_espec(line, i, nr);
|
||||
}
|
||||
|
||||
/* --- Begin NPC Skill Extension --- */
|
||||
else if (!strncmp(line, "Skill", 5)) {
|
||||
int snum = 0, sval = 0;
|
||||
if (sscanf(line, "Skill %d %d", &snum, &sval) == 2) {
|
||||
if (snum >= 0 && snum < MAX_SKILLS)
|
||||
SET_SKILL(&mob_proto[i], snum, (byte)MIN(MAX(0, sval), 100));
|
||||
else
|
||||
log("SYSERR: Invalid skill index %d in mob #%d", snum, nr);
|
||||
} else
|
||||
log("SYSERR: Malformed Skill line in mob #%d: '%s'", nr, line);
|
||||
continue;
|
||||
}
|
||||
/* --- End NPC Skill Extension --- */
|
||||
|
||||
else
|
||||
parse_espec(line, i, nr); /* interpret Str:, Dex:, Save*, etc. */
|
||||
}
|
||||
|
||||
log("SYSERR: Unexpected end of file reached after mob #%d", nr);
|
||||
|
|
|
|||
173
src/genmob.c
173
src/genmob.c
|
|
@ -327,37 +327,62 @@ int save_mobiles(zone_rnum rznum)
|
|||
|
||||
int write_mobile_espec(mob_vnum mvnum, struct char_data *mob, FILE *fd)
|
||||
{
|
||||
if (GET_ATTACK(mob) != 0)
|
||||
fprintf(fd, "BareHandAttack: %d\n", GET_ATTACK(mob));
|
||||
if (GET_STR(mob) != 11)
|
||||
int count = 0;
|
||||
|
||||
/* --- Ability scores (only write non-defaults) --- */
|
||||
if (GET_STR(mob) != 11) {
|
||||
fprintf(fd, "Str: %d\n", GET_STR(mob));
|
||||
if (GET_DEX(mob) != 11)
|
||||
count++;
|
||||
}
|
||||
if (GET_DEX(mob) != 11) {
|
||||
fprintf(fd, "Dex: %d\n", GET_DEX(mob));
|
||||
if (GET_INT(mob) != 11)
|
||||
count++;
|
||||
}
|
||||
if (GET_INT(mob) != 11) {
|
||||
fprintf(fd, "Int: %d\n", GET_INT(mob));
|
||||
if (GET_WIS(mob) != 11)
|
||||
count++;
|
||||
}
|
||||
if (GET_WIS(mob) != 11) {
|
||||
fprintf(fd, "Wis: %d\n", GET_WIS(mob));
|
||||
if (GET_CON(mob) != 11)
|
||||
count++;
|
||||
}
|
||||
if (GET_CON(mob) != 11) {
|
||||
fprintf(fd, "Con: %d\n", GET_CON(mob));
|
||||
if (GET_CHA(mob) != 11)
|
||||
count++;
|
||||
}
|
||||
if (GET_CHA(mob) != 11) {
|
||||
fprintf(fd, "Cha: %d\n", GET_CHA(mob));
|
||||
count++;
|
||||
}
|
||||
|
||||
/* --- New ability-based saving throws --- */
|
||||
if (GET_SAVE(mob, ABIL_STR) != 0)
|
||||
/* --- 5e-style saving throws --- */
|
||||
if (GET_SAVE(mob, ABIL_STR) != 0) {
|
||||
fprintf(fd, "SaveStr: %d\n", GET_SAVE(mob, ABIL_STR));
|
||||
if (GET_SAVE(mob, ABIL_DEX) != 0)
|
||||
count++;
|
||||
}
|
||||
if (GET_SAVE(mob, ABIL_DEX) != 0) {
|
||||
fprintf(fd, "SaveDex: %d\n", GET_SAVE(mob, ABIL_DEX));
|
||||
if (GET_SAVE(mob, ABIL_CON) != 0)
|
||||
count++;
|
||||
}
|
||||
if (GET_SAVE(mob, ABIL_CON) != 0) {
|
||||
fprintf(fd, "SaveCon: %d\n", GET_SAVE(mob, ABIL_CON));
|
||||
if (GET_SAVE(mob, ABIL_INT) != 0)
|
||||
count++;
|
||||
}
|
||||
if (GET_SAVE(mob, ABIL_INT) != 0) {
|
||||
fprintf(fd, "SaveInt: %d\n", GET_SAVE(mob, ABIL_INT));
|
||||
if (GET_SAVE(mob, ABIL_WIS) != 0)
|
||||
count++;
|
||||
}
|
||||
if (GET_SAVE(mob, ABIL_WIS) != 0) {
|
||||
fprintf(fd, "SaveWis: %d\n", GET_SAVE(mob, ABIL_WIS));
|
||||
if (GET_SAVE(mob, ABIL_CHA) != 0)
|
||||
count++;
|
||||
}
|
||||
if (GET_SAVE(mob, ABIL_CHA) != 0) {
|
||||
fprintf(fd, "SaveCha: %d\n", GET_SAVE(mob, ABIL_CHA));
|
||||
count++;
|
||||
}
|
||||
|
||||
fputs("E\n", fd);
|
||||
return TRUE;
|
||||
/* DO NOT print "E" here — handled by write_mobile_record() */
|
||||
return count;
|
||||
}
|
||||
|
||||
int write_mobile_record(mob_vnum mvnum, struct char_data *mob, FILE *fd)
|
||||
|
|
@ -371,60 +396,78 @@ int write_mobile_record(mob_vnum mvnum, struct char_data *mob, FILE *fd)
|
|||
strip_cr(strncpy(ldesc, GET_LDESC(mob), MAX_STRING_LENGTH - 1));
|
||||
strip_cr(strncpy(ddesc, GET_DDESC(mob), MAX_STRING_LENGTH - 1));
|
||||
|
||||
int n = snprintf(buf, MAX_STRING_LENGTH, "#%d\n"
|
||||
"%s%c\n"
|
||||
"%s%c\n"
|
||||
"%s%c\n"
|
||||
"%s%c\n",
|
||||
mvnum,
|
||||
GET_ALIAS(mob), STRING_TERMINATOR,
|
||||
GET_SDESC(mob), STRING_TERMINATOR,
|
||||
ldesc, STRING_TERMINATOR,
|
||||
ddesc, STRING_TERMINATOR
|
||||
);
|
||||
int n = snprintf(buf, MAX_STRING_LENGTH,
|
||||
"#%d\n"
|
||||
"%s%c\n"
|
||||
"%s%c\n"
|
||||
"%s%c\n"
|
||||
"%s%c\n",
|
||||
mvnum,
|
||||
GET_ALIAS(mob), STRING_TERMINATOR,
|
||||
GET_SDESC(mob), STRING_TERMINATOR,
|
||||
ldesc, STRING_TERMINATOR,
|
||||
ddesc, STRING_TERMINATOR);
|
||||
|
||||
if (n < MAX_STRING_LENGTH) {
|
||||
fprintf(fd, "%s", convert_from_tabs(buf));
|
||||
|
||||
fprintf(fd, "%d %d %d %d %d %d %d %d %d E\n"
|
||||
"%d %dd%d+%d\n",
|
||||
MOB_FLAGS(mob)[0], MOB_FLAGS(mob)[1],
|
||||
MOB_FLAGS(mob)[2], MOB_FLAGS(mob)[3],
|
||||
AFF_FLAGS(mob)[0], AFF_FLAGS(mob)[1],
|
||||
AFF_FLAGS(mob)[2], AFF_FLAGS(mob)[3],
|
||||
GET_ALIGNMENT(mob),
|
||||
GET_LEVEL(mob), GET_HIT(mob),
|
||||
GET_MANA(mob), GET_MOVE(mob));
|
||||
|
||||
fprintf(fd, "%d %d %d\n",
|
||||
GET_POS(mob), GET_DEFAULT_POS(mob), GET_SEX(mob)
|
||||
);
|
||||
|
||||
/* Write any E-specs */
|
||||
if (write_mobile_espec(mvnum, mob, fd) < 0)
|
||||
log("SYSERR: GenOLC: Error writing E-specs for mobile #%d.", mvnum);
|
||||
|
||||
/* --- Persist prototype loadout lines (one per entry) --- */
|
||||
for (struct mob_loadout *e = mob->proto_loadout; e; e = e->next) {
|
||||
fprintf(fd, "L %d %d %d\n",
|
||||
(int)e->wear_pos,
|
||||
(int)e->vnum,
|
||||
MAX(1, e->quantity));
|
||||
}
|
||||
|
||||
/* DG scripts after loadout lines */
|
||||
script_save_to_disk(fd, mob, MOB_TRIGGER);
|
||||
|
||||
#if CONFIG_GENOLC_MOBPROG
|
||||
if (write_mobile_mobprog(mvnum, mob, fd) < 0)
|
||||
log("SYSERR: GenOLC: Error writing MobProgs for mobile #%d.", mvnum);
|
||||
#endif
|
||||
} else {
|
||||
if (n >= MAX_STRING_LENGTH) {
|
||||
mudlog(BRF, LVL_BUILDER, TRUE,
|
||||
"SYSERR: Could not save mobile #%d due to size (%d > maximum of %d)",
|
||||
mvnum, n, MAX_STRING_LENGTH);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
fprintf(fd, "%s", convert_from_tabs(buf));
|
||||
|
||||
/* --- FLAGS/AFFECT/ALIGN line --- */
|
||||
fprintf(fd,
|
||||
"%d %d %d %d %d %d %d %d %d E\n",
|
||||
MOB_FLAGS(mob)[0], MOB_FLAGS(mob)[1],
|
||||
MOB_FLAGS(mob)[2], MOB_FLAGS(mob)[3],
|
||||
AFF_FLAGS(mob)[0], AFF_FLAGS(mob)[1],
|
||||
AFF_FLAGS(mob)[2], AFF_FLAGS(mob)[3],
|
||||
GET_ALIGNMENT(mob));
|
||||
|
||||
/* --- Level, hitdice, mana, move --- */
|
||||
fprintf(fd, "%d %dd%d+%d\n",
|
||||
GET_LEVEL(mob),
|
||||
GET_HIT(mob),
|
||||
GET_MANA(mob),
|
||||
GET_MOVE(mob));
|
||||
|
||||
/* --- Position / default position / sex --- */
|
||||
fprintf(fd, "%d %d %d\n",
|
||||
GET_POS(mob),
|
||||
GET_DEFAULT_POS(mob),
|
||||
GET_SEX(mob));
|
||||
|
||||
/* --- Enhanced (E-spec + Skills) --- */
|
||||
if (write_mobile_espec(mvnum, mob, fd) < 0)
|
||||
log("SYSERR: GenOLC: Error writing E-specs for mobile #%d.", mvnum);
|
||||
|
||||
/* Write NPC skills (if any set) */
|
||||
for (int s = 0; s < MAX_SKILLS; s++) {
|
||||
if (mob->mob_specials.skills[s] > 0)
|
||||
fprintf(fd, "Skill %d %d\n", s, mob->mob_specials.skills[s]);
|
||||
}
|
||||
|
||||
/* Single proper terminator */
|
||||
fprintf(fd, "E\n");
|
||||
|
||||
/* --- Loadout lines --- */
|
||||
for (struct mob_loadout *e = mob->proto_loadout; e; e = e->next) {
|
||||
fprintf(fd, "L %d %d %d\n",
|
||||
(int)e->wear_pos,
|
||||
(int)e->vnum,
|
||||
MAX(1, e->quantity));
|
||||
}
|
||||
|
||||
/* --- DG Scripts --- */
|
||||
script_save_to_disk(fd, mob, MOB_TRIGGER);
|
||||
|
||||
#if CONFIG_GENOLC_MOBPROG
|
||||
if (write_mobile_mobprog(mvnum, mob, fd) < 0)
|
||||
log("SYSERR: GenOLC: Error writing MobProgs for mobile #%d.", mvnum);
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ ACMD(do_track)
|
|||
int dir;
|
||||
|
||||
/* The character must have the track skill. */
|
||||
if (IS_NPC(ch) || !GET_SKILL(ch, SKILL_TRACK)) {
|
||||
if (!GET_SKILL(ch, SKILL_TRACK)) {
|
||||
send_to_char(ch, "You have no idea how.\r\n");
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
133
src/medit.c
133
src/medit.c
|
|
@ -432,6 +432,7 @@ static void medit_disp_menu(struct descriptor_data *d)
|
|||
"%s7%s) Default : %s%s\r\n"
|
||||
"%s8%s) Attack : %s%s\r\n"
|
||||
"%s9%s) Stats Menu...\r\n"
|
||||
"%s0%s) Skills Menu...\r\n"
|
||||
"%sA%s) NPC Flags : %s%s\r\n"
|
||||
"%sB%s) AFF Flags : %s%s\r\n"
|
||||
"%sS%s) Script : %s%s\r\n"
|
||||
|
|
@ -444,6 +445,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,
|
||||
grn, nrm,
|
||||
grn, nrm, cyn, flags,
|
||||
grn, nrm, cyn, flag2,
|
||||
grn, nrm, cyn, OLC_SCRIPT(d) ?"Set.":"Not Set.",
|
||||
|
|
@ -491,27 +493,27 @@ static void medit_disp_stats_menu(struct descriptor_data *d)
|
|||
if (CONFIG_MEDIT_ADVANCED) {
|
||||
/* Bottom section - non-standard stats, togglable in cedit */
|
||||
write_to_output(d,
|
||||
" %sAttributes%s %sSaving Throws%s\r\n"
|
||||
"(%sF%s) Str: %s[%s%2d%s]%s (%sR%s) Save STR %s[%s%3d%s]%s\r\n"
|
||||
"(%sG%s) Int: %s[%s%3d%s]%s (%sS%s) Save DEX %s[%s%3d%s]%s\r\n"
|
||||
"(%sH%s) Wis: %s[%s%3d%s]%s (%sT%s) Save CON %s[%s%3d%s]%s\r\n"
|
||||
"(%sI%s) Dex: %s[%s%3d%s]%s (%sU%s) Save INT %s[%s%3d%s]%s\r\n"
|
||||
"(%sJ%s) Con: %s[%s%3d%s]%s (%sV%s) Save WIS %s[%s%3d%s]%s\r\n"
|
||||
"%sAttributes Saving Throws\r\n"
|
||||
"(%sF%s) Str: %s[%s%3d%s]%s (%sR%s) Save STR %s[%s%3d%s]%s\r\n"
|
||||
"(%sG%s) Dex: %s[%s%3d%s]%s (%sS%s) Save DEX %s[%s%3d%s]%s\r\n"
|
||||
"(%sH%s) Con: %s[%s%3d%s]%s (%sT%s) Save CON %s[%s%3d%s]%s\r\n"
|
||||
"(%sI%s) Int: %s[%s%3d%s]%s (%sU%s) Save INT %s[%s%3d%s]%s\r\n"
|
||||
"(%sJ%s) Wis: %s[%s%3d%s]%s (%sV%s) Save WIS %s[%s%3d%s]%s\r\n"
|
||||
"(%sK%s) Cha: %s[%s%3d%s]%s (%sW%s) Save CHA %s[%s%3d%s]%s\r\n\r\n",
|
||||
nrm, cyn, nrm, cyn,
|
||||
nrm,
|
||||
cyn, nrm, cyn, yel, GET_STR(mob), cyn, nrm,
|
||||
cyn, nrm, cyn, yel, GET_SAVE(mob, ABIL_STR), cyn, nrm,
|
||||
|
||||
cyn, nrm, cyn, yel, GET_INT(mob), cyn, nrm,
|
||||
cyn, nrm, cyn, yel, GET_DEX(mob), cyn, nrm,
|
||||
cyn, nrm, cyn, yel, GET_SAVE(mob, ABIL_DEX), cyn, nrm,
|
||||
|
||||
cyn, nrm, cyn, yel, GET_WIS(mob), cyn, nrm,
|
||||
cyn, nrm, cyn, yel, GET_CON(mob), cyn, nrm,
|
||||
cyn, nrm, cyn, yel, GET_SAVE(mob, ABIL_CON), cyn, nrm,
|
||||
|
||||
cyn, nrm, cyn, yel, GET_DEX(mob), cyn, nrm,
|
||||
cyn, nrm, cyn, yel, GET_INT(mob), cyn, nrm,
|
||||
cyn, nrm, cyn, yel, GET_SAVE(mob, ABIL_INT), cyn, nrm,
|
||||
|
||||
cyn, nrm, cyn, yel, GET_CON(mob), cyn, nrm,
|
||||
cyn, nrm, cyn, yel, GET_WIS(mob), cyn, nrm,
|
||||
cyn, nrm, cyn, yel, GET_SAVE(mob, ABIL_WIS), cyn, nrm,
|
||||
|
||||
cyn, nrm, cyn, yel, GET_CHA(mob), cyn, nrm,
|
||||
|
|
@ -525,6 +527,37 @@ static void medit_disp_stats_menu(struct descriptor_data *d)
|
|||
OLC_MODE(d) = MEDIT_STATS_MENU;
|
||||
}
|
||||
|
||||
static void medit_disp_skill_menu(struct descriptor_data *d)
|
||||
{
|
||||
struct char_data *mob = OLC_MOB(d);
|
||||
int count = 0;
|
||||
|
||||
clear_screen(d);
|
||||
write_to_output(d, "-- %sSkill Editor%s for %s%s%s\r\n",
|
||||
cyn, nrm, yel, GET_SDESC(mob), nrm);
|
||||
|
||||
/* List all skills that exist (non-zero entries only) */
|
||||
for (int i = 0; i < MAX_SKILLS; i++) {
|
||||
if (mob->mob_specials.skills[i] > 0) {
|
||||
write_to_output(d, "%3d) %-25s : %3d%%\r\n",
|
||||
i, spell_info[i].name, mob->mob_specials.skills[i]);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
write_to_output(d, "No skills set.\r\n");
|
||||
|
||||
write_to_output(d, "\r\n"
|
||||
"%sA%s) Add / modify skill\r\n"
|
||||
"%sD%s) Delete skill\r\n"
|
||||
"%sQ%s) Return to main menu\r\n"
|
||||
"Enter choice : ",
|
||||
grn, nrm, grn, nrm, grn, nrm);
|
||||
|
||||
OLC_MODE(d) = MEDIT_SKILL_MENU;
|
||||
}
|
||||
|
||||
void medit_parse(struct descriptor_data *d, char *arg)
|
||||
{
|
||||
int i = -1, j;
|
||||
|
|
@ -625,6 +658,10 @@ void medit_parse(struct descriptor_data *d, char *arg)
|
|||
OLC_MODE(d) = MEDIT_STATS_MENU;
|
||||
medit_disp_stats_menu(d);
|
||||
return;
|
||||
case '0': /* Enter skill sub-menu */
|
||||
OLC_MODE(d) = MEDIT_SKILL_MENU;
|
||||
medit_disp_skill_menu(d);
|
||||
return;
|
||||
case 'a':
|
||||
case 'A':
|
||||
OLC_MODE(d) = MEDIT_NPC_FLAGS;
|
||||
|
|
@ -711,7 +748,7 @@ void medit_parse(struct descriptor_data *d, char *arg)
|
|||
write_to_output(d, "Invalid Choice!\r\nEnter Choice : ");
|
||||
return;
|
||||
}
|
||||
OLC_MODE(d) = MEDIT_INT;
|
||||
OLC_MODE(d) = MEDIT_DEX;
|
||||
i++;
|
||||
break;
|
||||
case 'h':
|
||||
|
|
@ -720,7 +757,7 @@ void medit_parse(struct descriptor_data *d, char *arg)
|
|||
write_to_output(d, "Invalid Choice!\r\nEnter Choice : ");
|
||||
return;
|
||||
}
|
||||
OLC_MODE(d) = MEDIT_WIS;
|
||||
OLC_MODE(d) = MEDIT_CON;
|
||||
i++;
|
||||
break;
|
||||
case 'i':
|
||||
|
|
@ -729,7 +766,7 @@ void medit_parse(struct descriptor_data *d, char *arg)
|
|||
write_to_output(d, "Invalid Choice!\r\nEnter Choice : ");
|
||||
return;
|
||||
}
|
||||
OLC_MODE(d) = MEDIT_DEX;
|
||||
OLC_MODE(d) = MEDIT_INT;
|
||||
i++;
|
||||
break;
|
||||
case 'j':
|
||||
|
|
@ -738,7 +775,7 @@ void medit_parse(struct descriptor_data *d, char *arg)
|
|||
write_to_output(d, "Invalid Choice!\r\nEnter Choice : ");
|
||||
return;
|
||||
}
|
||||
OLC_MODE(d) = MEDIT_CON;
|
||||
OLC_MODE(d) = MEDIT_WIS;
|
||||
i++;
|
||||
break;
|
||||
case 'k':
|
||||
|
|
@ -830,6 +867,72 @@ void medit_parse(struct descriptor_data *d, char *arg)
|
|||
write_to_output(d, "Oops...\r\n");
|
||||
return;
|
||||
|
||||
case MEDIT_SKILL_MENU:
|
||||
switch (*arg) {
|
||||
case 'q':
|
||||
case 'Q':
|
||||
medit_disp_menu(d);
|
||||
return;
|
||||
case 'a':
|
||||
case 'A':
|
||||
write_to_output(d, "Enter skill name to add or modify: ");
|
||||
OLC_MODE(d) = MEDIT_SKILL_EDIT;
|
||||
return;
|
||||
case 'd':
|
||||
case 'D':
|
||||
write_to_output(d, "Enter skill name to delete: ");
|
||||
OLC_MODE(d) = MEDIT_SKILL_EDIT;
|
||||
OLC_VAL(d) = 1; /* delete mode */
|
||||
return;
|
||||
default:
|
||||
medit_disp_skill_menu(d);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case MEDIT_SKILL_EDIT: {
|
||||
char skillname[MAX_INPUT_LENGTH];
|
||||
int snum;
|
||||
|
||||
skip_spaces(&arg);
|
||||
strlcpy(skillname, arg, sizeof(skillname));
|
||||
snum = find_skill_num(skillname);
|
||||
|
||||
if (snum <= 0 || snum >= MAX_SKILLS) {
|
||||
write_to_output(d, "Invalid skill.\r\n");
|
||||
medit_disp_skill_menu(d);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Delete mode */
|
||||
if (OLC_VAL(d) == 1) {
|
||||
OLC_MOB(d)->mob_specials.skills[snum] = 0;
|
||||
write_to_output(d, "Removed %s.\r\n", spell_info[snum].name);
|
||||
OLC_VAL(d) = 0;
|
||||
medit_disp_skill_menu(d);
|
||||
return;
|
||||
}
|
||||
|
||||
write_to_output(d, "Enter skill value (0-100): ");
|
||||
OLC_VAL(d) = snum;
|
||||
OLC_MODE(d) = MEDIT_SKILL_EDIT + 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case MEDIT_SKILL_EDIT + 1: {
|
||||
int val = atoi(arg);
|
||||
int snum = OLC_VAL(d);
|
||||
|
||||
val = MAX(0, MIN(100, val));
|
||||
OLC_MOB(d)->mob_specials.skills[snum] = (byte)val;
|
||||
|
||||
write_to_output(d, "%s set to %d%%.\r\n", spell_info[snum].name, val);
|
||||
medit_disp_skill_menu(d);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case OLC_SCRIPT_EDIT:
|
||||
if (dg_script_edit_parse(d, arg)) return;
|
||||
break;
|
||||
|
|
|
|||
50
src/oasis.h
50
src/oasis.h
|
|
@ -261,32 +261,34 @@ extern const char *nrm, *grn, *cyn, *yel;
|
|||
#define MEDIT_AFF_FLAGS 6
|
||||
#define MEDIT_CONFIRM_SAVESTRING 7
|
||||
#define MEDIT_STATS_MENU 8
|
||||
#define MEDIT_SKILL_MENU 9
|
||||
#define MEDIT_SKILL_EDIT 10
|
||||
|
||||
/* Numerical responses. */
|
||||
#define MEDIT_NUMERICAL_RESPONSE 10
|
||||
#define MEDIT_SEX 11
|
||||
#define MEDIT_NUM_HP_DICE 12
|
||||
#define MEDIT_SIZE_HP_DICE 13
|
||||
#define MEDIT_ADD_HP 14
|
||||
#define MEDIT_POS 15
|
||||
#define MEDIT_DEFAULT_POS 16
|
||||
#define MEDIT_ATTACK 17
|
||||
#define MEDIT_LEVEL 18
|
||||
#define MEDIT_ALIGNMENT 19
|
||||
#define MEDIT_DELETE 20
|
||||
#define MEDIT_COPY 21
|
||||
#define MEDIT_STR 22
|
||||
#define MEDIT_INT 23
|
||||
#define MEDIT_WIS 24
|
||||
#define MEDIT_DEX 25
|
||||
#define MEDIT_CON 26
|
||||
#define MEDIT_CHA 27
|
||||
#define MEDIT_SAVE_STR 28
|
||||
#define MEDIT_SAVE_DEX 29
|
||||
#define MEDIT_SAVE_CON 30
|
||||
#define MEDIT_SAVE_INT 31
|
||||
#define MEDIT_SAVE_WIS 32
|
||||
#define MEDIT_SAVE_CHA 33
|
||||
#define MEDIT_NUMERICAL_RESPONSE 11
|
||||
#define MEDIT_SEX 12
|
||||
#define MEDIT_NUM_HP_DICE 13
|
||||
#define MEDIT_SIZE_HP_DICE 14
|
||||
#define MEDIT_ADD_HP 15
|
||||
#define MEDIT_POS 16
|
||||
#define MEDIT_DEFAULT_POS 17
|
||||
#define MEDIT_ATTACK 18
|
||||
#define MEDIT_LEVEL 19
|
||||
#define MEDIT_ALIGNMENT 20
|
||||
#define MEDIT_DELETE 21
|
||||
#define MEDIT_COPY 22
|
||||
#define MEDIT_STR 23
|
||||
#define MEDIT_INT 24
|
||||
#define MEDIT_WIS 25
|
||||
#define MEDIT_DEX 26
|
||||
#define MEDIT_CON 27
|
||||
#define MEDIT_CHA 28
|
||||
#define MEDIT_SAVE_STR 29
|
||||
#define MEDIT_SAVE_DEX 30
|
||||
#define MEDIT_SAVE_CON 31
|
||||
#define MEDIT_SAVE_INT 32
|
||||
#define MEDIT_SAVE_WIS 33
|
||||
#define MEDIT_SAVE_CHA 34
|
||||
|
||||
/* Submodes of SEDIT connectedness. */
|
||||
#define SEDIT_MAIN_MENU 0
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ static void auto_equip(struct char_data *ch, struct obj_data *obj, int location)
|
|||
static void Crash_restore_weight(struct obj_data *obj);
|
||||
static int Crash_load_objs(struct char_data *ch);
|
||||
static int handle_obj(struct obj_data *obj, struct char_data *ch, int locate, struct obj_data **cont_rows);
|
||||
static int objsave_write_rentcode(FILE *fl, int rentcode, int cost_per_day, struct char_data *ch);
|
||||
|
||||
/* Writes one object record to FILE. Old name: Obj_to_store().
|
||||
* Updated to save all NUM_OBJ_VAL_POSITIONS values instead of only 4. */
|
||||
|
|
@ -526,24 +525,6 @@ void Crash_rentsave(struct char_data *ch, int cost)
|
|||
Crash_crashsave(ch);
|
||||
}
|
||||
|
||||
static int objsave_write_rentcode(FILE *fl, int rentcode, int cost_per_day, struct char_data *ch)
|
||||
{
|
||||
if (fprintf(fl, "%d %ld %d %d %d %d\r\n",
|
||||
rentcode,
|
||||
(long) time(0),
|
||||
cost_per_day,
|
||||
GET_GOLD(ch),
|
||||
GET_BANK_GOLD(ch),
|
||||
0)
|
||||
< 1)
|
||||
{
|
||||
perror("Syserr: Writing rent code");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
void Crash_save_all(void)
|
||||
{
|
||||
struct descriptor_data *d;
|
||||
|
|
|
|||
|
|
@ -248,7 +248,10 @@ int load_char(const char *name, struct char_data *ch)
|
|||
/* Character initializations. Necessary to keep some things straight. */
|
||||
ch->affected = NULL;
|
||||
for (i = 1; i <= MAX_SKILLS; i++)
|
||||
GET_SKILL(ch, i) = 0;
|
||||
if (IS_NPC(ch))
|
||||
ch->mob_specials.skills[i] = 0;
|
||||
else
|
||||
ch->player_specials->saved.skills[i] = 0;
|
||||
GET_SEX(ch) = PFDEF_SEX;
|
||||
GET_CLASS(ch) = PFDEF_CLASS;
|
||||
GET_LEVEL(ch) = PFDEF_LEVEL;
|
||||
|
|
@ -479,7 +482,10 @@ int load_char(const char *name, struct char_data *ch)
|
|||
/* initialization for imms */
|
||||
if (GET_LEVEL(ch) >= LVL_IMMORT) {
|
||||
for (i = 1; i <= MAX_SKILLS; i++)
|
||||
GET_SKILL(ch, i) = 100;
|
||||
if (IS_NPC(ch))
|
||||
ch->mob_specials.skills[i] = 100;
|
||||
else
|
||||
ch->player_specials->saved.skills[i] = 100;
|
||||
GET_COND(ch, HUNGER) = -1;
|
||||
GET_COND(ch, THIRST) = -1;
|
||||
GET_COND(ch, DRUNK) = -1;
|
||||
|
|
@ -868,8 +874,13 @@ static void load_skills(FILE *fl, struct char_data *ch)
|
|||
do {
|
||||
get_line(fl, line);
|
||||
sscanf(line, "%d %d", &num, &num2);
|
||||
if (num != 0)
|
||||
GET_SKILL(ch, num) = num2;
|
||||
|
||||
if (num != 0) {
|
||||
if (IS_NPC(ch))
|
||||
ch->mob_specials.skills[num] = num2;
|
||||
else
|
||||
ch->player_specials->saved.skills[num] = num2;
|
||||
}
|
||||
} while (num != 0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1014,6 +1014,7 @@ struct mob_special_data
|
|||
memory_rec *memory; /**< List of PCs to remember */
|
||||
byte attack_type; /**< The primary attack type (bite, sting, hit, etc.) */
|
||||
byte default_pos; /**< Default position (standing, sleeping, etc.) */
|
||||
byte skills[MAX_SKILLS]; /* NPC-specific skill proficiency (0-100) */
|
||||
};
|
||||
|
||||
/** An affect structure. */
|
||||
|
|
|
|||
15
src/utils.h
15
src/utils.h
|
|
@ -659,10 +659,17 @@ do \
|
|||
/** The type of quest ch is currently participating in. */
|
||||
#define GET_QUEST_TYPE(ch) (real_quest(GET_QUEST((ch))) != NOTHING ? aquest_table[real_quest(GET_QUEST((ch)))].type : AQ_UNDEFINED )
|
||||
|
||||
/** The current skill level of ch for skill i. */
|
||||
#define GET_SKILL(ch, i) CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.skills[i]))
|
||||
/** Copy the current skill level i of ch to pct. */
|
||||
#define SET_SKILL(ch, i, pct) do { CHECK_PLAYER_SPECIAL((ch), (ch)->player_specials->saved.skills[i]) = pct; } while(0)
|
||||
/* Unified access macros for PC and NPC skills */
|
||||
#define GET_SKILL(ch, i) \
|
||||
(IS_NPC(ch) ? ((ch)->mob_specials.skills[(i)]) : ((ch)->player_specials->saved.skills[(i)]))
|
||||
|
||||
#define SET_SKILL(ch, i, pct) do { \
|
||||
if (IS_NPC(ch)) \
|
||||
(ch)->mob_specials.skills[(i)] = (pct); \
|
||||
else { \
|
||||
CHECK_PLAYER_SPECIAL((ch), (ch)->player_specials->saved.skills[(i)]) = (pct); \
|
||||
} \
|
||||
} while (0)
|
||||
/** Per-skill next gain time (epoch seconds). Index with a valid skill number. **/
|
||||
#define GET_SKILL_NEXT_GAIN(ch, i) \
|
||||
(CHECK_PLAYER_SPECIAL((ch), (ch)->player_specials->saved.next_skill_gain[(i)]))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue