I wrote this guide to help people add in another basic stat, like Str, Dex, Cha, etc. This code is written, tested, and works on stock tbaMUD 3.61. It may or may not work if your game is heavily modified or from an older version of CWG.
In most cases Luck (LCK) is added after Charisma (CHA). Following these directions to the letter will cause your player files to "break" so if you want to avoid that you may want to re-arrange where some things go.
Code:
// In class.c find the void roll_real_abils and change some numbers so that a new table is created. ***
/* Roll the 6 stats for a character... each stat is made of the sum of the best
* 3 out of 4 rolls of a 6-sided die. Each class then decides which priority
* will be given for the best to worst stats. */
void roll_real_abils(struct char_data *ch)
{
int i, j, k, temp;
- ubyte table[6]
+ ubyte table[7]
ubyte rolls[4];
- for (i = 0; i < 6; i++)
+ for (i = 0; i < 7; i++)
table[i] = 0;
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < 7; i++) {
for (j = 0; j < 4; j++)
- rolls[j] = rand_number(1, 6);
+ rolls[j] = rand_number(1, 7);
temp = rolls[0] + rolls[1] + rolls[2] + rolls[3] -
MIN(rolls[0], MIN(rolls[1], MIN(rolls[2], rolls[3])));
- for (k = 0; k < 6; k++)
+ for (k = 0; k < 7; k++)
if (table[k] < temp) {
temp ^= table[k];
// Scroll down a little, and find the rea_abils sets. ***
ch->real_abils.wis = table[0];
ch->real_abils.intel = table[1];
ch->real_abils.str = table[2];
ch->real_abils.dex = table[3];
ch->real_abils.con = table[4];
ch->real_abils.cha = table[5];
+ ch->real_abils.lck = table[6];
// In act.wizard.c, find the first instance of GET_CON, or the part that looks similar to the following. ***
send_to_char(ch, "Str: [%s%d/%d%s] Int: [%s%d%s] Wis: [%s%d%s] "
- "Dex: [%s%d%s] Con: [%s%d%s] Cha: [%s%d%s]\r\n",
+ "Dex: [%s%d%s] Con: [%s%d%s] Cha: [%s%d%s] Lck: [%s%d%s]\r\n",
CCCYN(ch, C_NRM), GET_STR(k), GET_ADD(k), CCNRM(ch, C_NRM),
CCCYN(ch, C_NRM), GET_INT(k), CCNRM(ch, C_NRM),
CCCYN(ch, C_NRM), GET_WIS(k), CCNRM(ch, C_NRM),
CCCYN(ch, C_NRM), GET_DEX(k), CCNRM(ch, C_NRM),
CCCYN(ch, C_NRM), GET_CON(k), CCNRM(ch, C_NRM),
- CCCYN(ch, C_NRM), GET_CHA(k), CCNRM(ch, C_NRM));
+ CCCYN(ch, C_NRM), GET_CHA(k), CCNRM(ch, C_NRM),
+ CCCYN(ch, C_NRM), GET_LCK(k), CCNRM(ch, C_NRM));
// Further down, find the section that looks similar and change, after real_abils.cha. ***
if (!IS_NPC(vict) && GET_LEVEL(ch) >= LVL_GRGOD) {
if (GET_LEVEL(vict) >= LVL_IMMORT)
for (i = 1; i <= MAX_SKILLS; i++)
SET_SKILL(vict, i, 100);
if (GET_LEVEL(vict) >= LVL_GRGOD) {
vict->real_abils.str_add = 100;
vict->real_abils.intel = 25;
vict->real_abils.wis = 25;
vict->real_abils.dex = 25;
vict->real_abils.str = 18;
vict->real_abils.con = 25;
vict->real_abils.cha = 25;
+ vict->real_abils.lck = 25;
// In do_wizutil, add it into SCMD_REROLL. ***
case SCMD_REROLL:
send_to_char(ch, "Rerolled...\r\n");
roll_real_abils(vict);
log("(GC) %s has rerolled %s.", GET_NAME(ch), GET_NAME(vict));
send_to_char(ch, "New stats: Str %d/%d, Int %d, Wis %d, Dex %d, Con %d, Cha %d, Lck %d\r\n",
GET_STR(vict), GET_ADD(vict), GET_INT(vict), GET_WIS(vict),
- GET_DEX(vict), GET_CON(vict), GET_CHA(vict));
+ GET_DEX(vict), GET_CON(vict), GET_CHA(vict), GET_LCK(vict));
break;
// In set_fields, add it to the large list at the bottom. Don't forget the comma at the end. ***
{ "weight", LVL_BUILDER, BOTH, NUMBER },
{ "wis", LVL_BUILDER, BOTH, NUMBER }, /* 55 */
{ "questpoints", LVL_GOD, PC, NUMBER },
{ "questhistory", LVL_GOD, PC, NUMBER },
+ { "lck", LVL_BUILDER, BOTH, NUMBER },
{ "\n", 0, BOTH, MISC }
};
// Shortly after that, add it to the bottom of the values list. It should be the next number available. ***
case 56: /* questpoints */
GET_QUESTPOINTS(vict) = RANGE(0, 100000000);
break;
case 57: /* questhistory */
qvnum = atoi(val_arg);
if (real_quest(qvnum) == NOTHING) {
send_to_char(ch, "That quest doesn't exist.\r\n");
return FALSE;
} else {
if (is_complete(vict, qvnum)) {
remove_completed_quest(vict, qvnum);
send_to_char(ch, "Quest %d removed from history for player %s.\r\n",
qvnum, GET_NAME(vict));
} else {
add_completed_quest(vict, qvnum);
send_to_char(ch, "Quest %d added to history for player %s.\r\n",
qvnum, GET_NAME(vict));
}
break;
}
+ case 58: /* lck */
+ if (IS_NPC(vict) || GET_LEVEL(vict) >= LVL_GRGOD)
+ RANGE(3, 25);
+ else
+ RANGE(3, 18);
+ vict->real_abils.lck = value;
+ affect_total(vict);
+ break;
default:
send_to_char(ch, "Can't set that!\r\n");
return (0);
}
// Finally, in zaffs[] where they have the applies, add it in after CHA ***
{APPLY_WIS, -5, 3, "wisdom"},
{APPLY_CON, -5, 3, "constitution"},
{APPLY_CHA, -5, 3, "charisma"},
+ {APPLY_LCK, -5, 3, "luck"},
{APPLY_CLASS, 0, 0, "class"},
{APPLY_LEVEL, 0, 0, "level"},
{APPLY_AGE, -10, 10, "age"},
// In utils.h find the #defines and add it to the bottom, after CHA. ***
#define GET_STR(ch) ((ch)->aff_abils.str)
#define GET_ADD(ch) ((ch)->aff_abils.str_add)
#define GET_DEX(ch) ((ch)->aff_abils.dex)
#define GET_INT(ch) ((ch)->aff_abils.intel)
#define GET_WIS(ch) ((ch)->aff_abils.wis)
#define GET_CON(ch) ((ch)->aff_abils.con)
#define GET_CHA(ch) ((ch)->aff_abils.cha)
+ #define GET_LCK(ch) ((ch)->aff_abils.lck)
// In handler.c make sure it's in the applies at the bottom, after CHA. ***
case APPLY_CON:
GET_CON(ch) += mod;
break;
case APPLY_CHA:
GET_CHA(ch) += mod;
break;
+ case APPLY_LCK:
+ GET_LCK(ch) += mod;
+ break;
// Make sure it has the MIN and MAX as well, a little further down, after CHA. ***
GET_DEX(ch) = MAX(0, MIN(GET_DEX(ch), i));
GET_INT(ch) = MAX(0, MIN(GET_INT(ch), i));
GET_WIS(ch) = MAX(0, MIN(GET_WIS(ch), i));
GET_CON(ch) = MAX(0, MIN(GET_CON(ch), i));
GET_CHA(ch) = MAX(0, MIN(GET_CHA(ch), i));
+ GET_LCK(ch) = MAX(0, MIN(GET_LCK(ch), i));
GET_STR(ch) = MAX(0, GET_STR(ch));
// In players.c in character initializations, add it after CHA. ***
ch->real_abils.dex = PFDEF_DEX;
ch->real_abils.intel = PFDEF_INT;
ch->real_abils.wis = PFDEF_WIS;
ch->real_abils.con = PFDEF_CON;
ch->real_abils.cha = PFDEF_CHA;
+ ch->real_abils.lck = PFDEF_LCK;
GET_HIT(ch) = PFDEF_HIT;
GET_MAX_HIT(ch) = PFDEF_MAXHIT;
// A little further down there are all the cases. Add it where it makes sense alphabetically. ***
case 'L':
if (!strcmp(tag, "Last")) ch->player.time.logon = atol(line);
else if (!strcmp(tag, "Lern")) GET_PRACTICES(ch) = atoi(line);
else if (!strcmp(tag, "Levl")) GET_LEVEL(ch) = atoi(line);
else if (!strcmp(tag, "Lmot")) GET_LAST_MOTD(ch) = atoi(line);
else if (!strcmp(tag, "Lnew")) GET_LAST_NEWS(ch) = atoi(line);
+ else if (!strcmp(tag, "Lck ")) ch->real_abils.lck = atoi(line);
break;
// Even further down, look for GET_CHA with the fprint and add it right after. ***
if (GET_CON(ch) != PFDEF_CON) fprintf(fl, "Con : %d\n", GET_CON(ch));
if (GET_CHA(ch) != PFDEF_CHA) fprintf(fl, "Cha : %d\n", GET_CHA(ch));
+ if (GET_LCK(ch) != PFDEF_LCK) fprintf(fl, "Lck : %d\n", GET_LCK(ch));
if (GET_AC(ch) != PFDEF_AC) fprintf(fl, "Ac : %d\n", GET_AC(ch));
if (GET_GOLD(ch) != PFDEF_GOLD) fprintf(fl, "Gold: %d\n", GET_GOLD(ch));
// In db.c in parse_simple_mob, add it after real_abils.cha. ***
mob_proto[i].real_abils.con = 11;
mob_proto[i].real_abils.cha = 11;
+ mob_proto[i].real_abils.lck = 11;
if (!get_line(mob_f, line)) {
log("SYSERR: Format error in mob #%d, file ended after S flag!", nr);
exit(1);
// Further down, where it defines the ranges, add it after CHA. ***
CASE("Con") {
RANGE(3, 25);
mob_proto[i].real_abils.con = num_arg;
}
CASE("Cha") {
RANGE(3, 25);
mob_proto[i].real_abils.cha = num_arg;
}
+ CASE("Lck") {
+ RANGE(3, 25);
+ mob_proto[i].real_abils.lck = num_arg;
+ }
CASE("SavingPara") {
RANGE(0, 100);
mob_proto[i].char_specials.saved.apply_saving_throw[SAVING_PARA] = num_arg;
}
Even further down, add it again after real_abils.cha. ***
for (i = 0; i < 5; i++)
GET_SAVE(ch, i) = 0;
ch->real_abils.intel = 25;
ch->real_abils.wis = 25;
ch->real_abils.dex = 25;
ch->real_abils.str = 25;
ch->real_abils.str_add = 100;
ch->real_abils.con = 25;
ch->real_abils.cha = 25;
+ ch->real_abils.lck = 25;
for (i = 0; i < 3; i++)
GET_COND(ch, i) = (GET_LEVEL(ch) == LVL_IMPL ? -1 : 24);
// In medit.c, in init_mob, add after real_abils.cha = 11; ***
GET_WEIGHT(mob) = 200;
GET_HEIGHT(mob) = 198;
mob->real_abils.str = mob->real_abils.intel = mob->real_abils.wis = 11;
mob->real_abils.dex = mob->real_abils.con = mob->real_abils.cha = 11;
+ mob->real_abils.lck = 11;
mob->aff_abils = mob->real_abils;
GET_SAVE(mob, SAVING_PARA) = 0;
GET_SAVE(mob, SAVING_ROD) = 0;
// In CONFIG_MEDIT_ADVANCED, make the following changes. ***
if (CONFIG_MEDIT_ADVANCED) {
/* Bottom section - non-standard stats, togglable in cedit */
write_to_output(d,
"(%sF%s) Str: %s[%s%2d/%3d%s]%s Saving Throws\r\n"
"(%sG%s) Int: %s[%s%3d%s]%s (%sL%s) Paralysis %s[%s%3d%s]%s\r\n"
"(%sH%s) Wis: %s[%s%3d%s]%s (%sM%s) Rods/Staves %s[%s%3d%s]%s\r\n"
"(%sI%s) Dex: %s[%s%3d%s]%s (%sN%s) Petrification %s[%s%3d%s]%s\r\n"
"(%sJ%s) Con: %s[%s%3d%s]%s (%sO%s) Breath %s[%s%3d%s]%s\r\n"
- "(%sK%s) Cha: %s[%s%3d%s]%s (%sP%s) Spells %s[%s%3d%s]%s\r\n\r\n",
+ "(%sK%s) Cha: %s[%s%3d%s]%s (%sP%s) Spells %s[%s%3d%s]%s\r\n"
+ "(%sT%s) Lck: %s[%s%3d%s]%s\r\n",
cyn, nrm, cyn, yel, GET_STR(mob), GET_ADD(mob), cyn, nrm,
cyn, nrm, cyn, yel, GET_INT(mob), cyn, nrm, cyn, nrm, cyn, yel, GET_SAVE(mob, SAVING_PARA), cyn, nrm,
cyn, nrm, cyn, yel, GET_WIS(mob), cyn, nrm, cyn, nrm, cyn, yel, GET_SAVE(mob, SAVING_ROD), cyn, nrm,
cyn, nrm, cyn, yel, GET_DEX(mob), cyn, nrm, cyn, nrm, cyn, yel, GET_SAVE(mob, SAVING_PETRI), cyn, nrm,
cyn, nrm, cyn, yel, GET_CON(mob), cyn, nrm, cyn, nrm, cyn, yel, GET_SAVE(mob, SAVING_BREATH), cyn, nrm,
- cyn, nrm, cyn, yel, GET_CHA(mob), cyn, nrm, cyn, nrm, cyn, yel, GET_SAVE(mob, SAVING_SPELL), cyn, nrm
+ cyn, nrm, cyn, yel, GET_CHA(mob), cyn, nrm, cyn, nrm, cyn, yel, GET_SAVE(mob, SAVING_SPELL), cyn, nrm,
+ cyn, nrm, cyn, yel, GET_LCK(mob), cyn, nrm
);
}
// Further down, in the cases, add in a new one for T. ***
case 'k':
case 'K':
if (!CONFIG_MEDIT_ADVANCED) {
write_to_output(d, "Invalid Choice!\r\nEnter Choice : ");
return;
}
OLC_MODE(d) = MEDIT_CHA;
i++;
break;
+ case 't':
+ case 'T':
+ if (!CONFIG_MEDIT_ADVANCED) {
+ write_to_output(d, "Invalid Choice!\r\nEnter Choice : ");
+ return;
+ }
+ OLC_MODE(d) = MEDIT_LCK;
+ i++;
+ break;
case 'l':
case 'L':
if (!CONFIG_MEDIT_ADVANCED) {
write_to_output(d, "Invalid Choice!\r\nEnter Choice : ");
return;
}
OLC_MODE(d) = MEDIT_PARA;
i++;
break;
// A little down from that, find MEDIT_CHA and add below. ***
case MEDIT_CHA:
GET_CHA(OLC_MOB(d)) = LIMIT(i, 11, 25);
OLC_VAL(d) = TRUE;
medit_disp_stats_menu(d);
return;
+ case MEDIT_LCK:
+ GET_LCK(OLC_MOB(d)) = LIMIT(i, 11, 25);
+ OLC_VAL(d) = TRUE;
+ medit_disp_stats_menu(d);
+ return;
// Near the very bottom, add it as well. ***
GET_DEX(OLC_MOB(d)) = LIMIT((mob_lev*2)/3, 11, 18);
GET_CON(OLC_MOB(d)) = LIMIT((mob_lev*2)/3, 11, 18);
GET_CHA(OLC_MOB(d)) = LIMIT((mob_lev*2)/3, 11, 18);
+ GET_LCK(OLC_MOB(d)) = LIMIT((mob_lev*2)/3, 11, 18);
// In genmob.c in write_mobile_espec, add it after CHA. ***
if (GET_WIS(mob) != 11)
fprintf(fd, "Wis: %d\n", GET_WIS(mob));
if (GET_CON(mob) != 11)
fprintf(fd, "Con: %d\n", GET_CON(mob));
if (GET_CHA(mob) != 11)
fprintf(fd, "Cha: %d\n", GET_CHA(mob));
+ if (GET_LCK(mob) != 11)
+ fprintf(fd, "Lck: %d\n", GET_LCK(mob));
if (GET_CLASS(mob) != 1)
fprintf(fd, "Class: %d\n", GET_CLASS(mob));
// In oasis.h add it into the #defines. I added it right below MEDIT_CHA. ***
// Note: Make sure your numbers are in proper order! ***
#define MEDIT_DEX 32
#define MEDIT_CON 33
#define MEDIT_CHA 34
+ #define MEDIT_LCK 35
// In pfdefaults.h, make sure it's defined after PFDEF_CHA. ***
#define PFDEF_WIS 0
#define PFDEF_CON 0
+ #define PFDEF_CHA 0
#define PFDEF_LCK 0
#define PFDEF_HIT 0
#define PFDEF_MAXHIT 0
// In structs.h, add it after CHA and reorder the numbers. ***
// Note: You can change this if you don't want to reorder player files. ***
#define APPLY_WIS 4 /**< Apply to wisdom */
#define APPLY_CON 5 /**< Apply to constitution */
#define APPLY_CHA 6 /**< Apply to charisma */
+ #define APPLY_LCK 7 /**< Apply to luck */
#define APPLY_CLASS 8 /**< Reserved */
#define APPLY_LEVEL 9 /*
// In char_ability_data, after cha. ***
struct char_ability_data
{
sbyte str; /**< Strength. */
sbyte str_add; /**< Strength multiplier if str = 18. Usually from 0 to 100 */
sbyte intel; /**< Intelligence */
sbyte wis; /**< Wisdom */
sbyte dex; /**< Dexterity */
sbyte con; /**< Constitution */
sbyte cha; /**< Charisma */
+ sbyte lck; /**< Luck */
};
// In constants.c in apply_types, add it after CHA. ***
"INT",
"WIS",
"CON",
"CHA",
+ "LCK",
"CLASS",
"LEVEL",
"AGE",
// In utils/plrtoascii.c in char_ability_data_plrtoascii, add it after cha. ***
sbyte wis;
sbyte dex;
sbyte con;
sbyte cha;
+ sbyte lck;
};
// A little further down, add it to the char ability data, or cad. ***
if (cad->con != PFDEF_CON)
fprintf(outfile, "Con : %d\n", cad->con);
if (cad->cha != PFDEF_CHA)
fprintf(outfile, "Cha : %d\n", cad->cha);
+ if (cad->lck != PFDEF_LCK)
+ fprintf(outfile, "Lck : %d\n", cad->lck);
/* char_point_data */
cpd = &(player.points);
Hopefully this goes smoothly for anybody looking to use this guide. Please don't hesitate to post comments or questions. I'll try my best to answer them.