I wrote this guide to help people add a rather simple floating item. 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.
To use a floating item, the player must release (keyword). It will only work on an item that is set to be a FLOATING wear item.
*** In act.item.c in wear_bitvectors, add it to the end of the list. ***
*** Note: Don't forget to add a comma after the last one! (And don't put one after your new addition...) ***
int wear_bitvectors[] = {
ITEM_WEAR_TAKE, ITEM_WEAR_FINGER, ITEM_WEAR_FINGER, ITEM_WEAR_NECK,
ITEM_WEAR_NECK, ITEM_WEAR_BODY, ITEM_WEAR_HEAD, ITEM_WEAR_LEGS,
ITEM_WEAR_FEET, ITEM_WEAR_HANDS, ITEM_WEAR_ARMS, ITEM_WEAR_SHIELD,
ITEM_WEAR_ABOUT, ITEM_WEAR_WAIST, ITEM_WEAR_WRIST, ITEM_WEAR_WRIST,
- ITEM_WEAR_WIELD, ITEM_WEAR_TAKE, ITEM_WEAR_ANKLE, ITEM_WEAR_ANKLE
+ ITEM_WEAR_WIELD, ITEM_WEAR_TAKE, ITEM_WEAR_ANKLE, ITEM_WEAR_ANKLE,
+ ITEM_WEAR_FLOATING
};
*** In const char *already_wearing, add it to the bottom. Don't forget to pay attention to the commas! ***
"You're already wearing something around both of your wrists.\r\n",
"You're already wielding a weapon.\r\n",
- "You're already holding something.\r\n"
+ "You're already holding something.\r\n",
+ "You're already using something as a floaty.\r\n"
};
*** In *keywords, add it to the bottom. There must be a comma at the end of the last line! ***
"hands",
"arms",
"shield",
"about",
"waist",
"wrist",
"!RESERVED!",
"!RESERVED!",
"!RESERVED!",
"ankle",
"!RESERVED!",
+ "floating",
};
*** After do_wear, add a similar command. ***
ACMD(do_release)
{
char arg[MAX_INPUT_LENGTH];
struct obj_data *obj;
one_argument(argument, arg);
if (!*arg)
send_to_char(ch, "Release what?\r\n");
else if (!(obj = get_obj_in_list_vis(ch, arg, NULL, ch->carrying)))
send_to_char(ch, "You don't seem to have %s %s.\r\n", AN(arg), arg);
else {
if (!CAN_WEAR(obj, ITEM_WEAR_FLOATING))
send_to_char(ch, "You can't release that as a floaty.\r\n");
else
perform_wear(ch, obj, WEAR_FLOATING);
}
}
*** In constants.c in *wear_where, add it to the bottom of the list. ***
*** Note: Mind the comma! ***
"<worn on waist> ",
"<worn around wrist> ",
"<worn around wrist> ",
"<wielded> ",
"<held> ",
"<worn around ankle> ",
- "<worn around ankle> "
+ "<worn around ankle> ",
+ "<floating nearby> "
*** In *equipment_types, add it to the bottom of the list. ***
"Worn around left wrist",
"Wielded",
"Held",
"Worn on ankles",
"Worn on ankles",
+ "Floating nearby",
*** In *wear_bits, add it to the bottom of the list. ***
"WAIST",
"WRIST",
"WIELD",
"HOLD",
"ANKLE",
+ "FLOATING",
"\n"
};
*** In objsave.c, add it to the bottom of the list in the big list of checks. ***
case WEAR_HOLD:
if (CAN_WEAR(obj, ITEM_WEAR_HOLD))
break;
if (IS_WARRIOR(ch) && CAN_WEAR(obj, ITEM_WEAR_WIELD) && GET_OBJ_TYPE(obj) == ITEM_WEAPON)
break;
location = LOC_INVENTORY;
break;
case WEAR_ANKLE_R:
case WEAR_ANKLE_L:
if (!CAN_WEAR(obj, ITEM_WEAR_ANKLE))
location = LOC_INVENTORY;
break;
+ case WEAR_FLOATING:
+ if (!CAN_WEAR(obj, ITEM_WEAR_FLOATING))
+ location = LOC_INVENTORY;
+ break;
default:
location = LOC_INVENTORY;
}
*** In act.wizard.c in zarmor, add it to the list at the bottom. ***
*** There should not be a comma at the end of this list. ***
{ITEM_WEAR_WAIST, 10, "Belt"},
{ITEM_WEAR_WRIST, 10, "Wristwear"},
{ITEM_WEAR_HOLD, 10, "Held item"},
- {ITEM_WEAR_ANKLE, 10, "Anklewear"}
+ {ITEM_WEAR_ANKLE, 10, "Anklewear"},
+ {ITEM_WEAR_FLOATING, 10, "Floating"}
*** In structs.h in the #defines for all the wear spots, add it to the bottom. ***
*** Be sure to increment the total afterward! ***
#define WEAR_WRIST_L 15 /**< Equipment Location Left Wrist */
#define WEAR_WIELD 16 /**< Equipment Location Weapon */
#define WEAR_HOLD 17 /**< Equipment Location held in offhand */
#define WEAR_ANKLE_R 18 /**< Equipment Location for right ankle */
#define WEAR_ANKLE_L 19 /**< Equipment Location for left ankle */
+ #define WEAR_FLOATING 20 /**< Equipment Location for floaty */
- #define NUM_WEARS 20
+ #define NUM_WEARS 21
*** In the item wear defines, add it to the bottom. ***
*** Again, note the increment in NUM_ITEM_WEARS. ***
#define ITEM_WEAR_WRIST 12
#define ITEM_WEAR_WIELD 13
#define ITEM_WEAR_HOLD 14
#define ITEM_WEAR_ANKLE 15
+ #define ITEM_WEAR_FLOATING 16
- #define NUM_ITEM_WEARS 16
+ #define NUM_ITEM_WEARS 17
*** Finish up the code by adding in the necessities for do_release...***
*** In act.h, right at the top, add after do_wield. ***
ACMD(do_wield);
ACMD(do_release);
*** Finally, in interpreter.c, add it in the alphabetical listing. ***
{ "recite" , "reci" , POS_RESTING , do_use , 0, SCMD_RECITE },
{ "receive" , "rece" , POS_STANDING, do_not_here , 1, 0 },
+ { "release" , "rel" , POS_RESTING , do_release , 0, 0 },
{ "remove" , "rem" , POS_RESTING , do_remove , 0, 0 },
{ "remort" , "remo" , POS_STANDING, do_remort , 1, 0 },
Not hard at all. Please feel free to comment with suggestions for additions, or point out if I've missed anything. :)
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.
*** 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. :)
I wrote this guide to help people add in more sector types to their OLC, which as you can see is pretty simple. Just don't forget to change the number flags any time you add one. This code is written, tested, and works on stock tbaMUD. It may or may not work if your game is heavily modified or from an older version of CWG.
*** In constants.c scroll down to where it lists the basic sector types.
*** (Inside, City, Field, Forest, etc.) and add to the bottom of the list.
const char *sector_types[] = {
"Inside",
"City",
"Field",
"Forest",
"Hills",
"Mountains",
"Water (Swim)",
"Water (No Swim)",
"In Flight",
"Underwater",
+ "Desert",
"\n",
};
*** Further down in constants.c (under int movement_loss) you'll want to define how much
*** movement is lost per step with your new terrain type.
*** Note: Make sure the last line doesn't have the comma after the number, but all the previous ones do.
int movement_loss[] =
{
1, /* Inside */
1, /* City */
2, /* Field */
3, /* Forest */
4, /* Hills */
6, /* Mountains */
4, /* Swimming */
1, /* Unswimable */
1, /* Flying */
- 5 /* Underwater */
+ 5, /* Underwater */
+ 3 /* Desert */
};
*** In structs.h scroll down to where the list is again, for basic sector types.
/* Sector types: used in room_data.sector_type */
#define SECT_INSIDE 0 /**< Indoors, connected to SECT macro. */
#define SECT_CITY 1 /**< In a city */
#define SECT_FIELD 2 /**< In a field */
#define SECT_FOREST 3 /**< In a forest */
#define SECT_HILLS 4 /**< In the hills */
#define SECT_MOUNTAIN 5 /**< On a mountain */
#define SECT_WATER_SWIM 6 /**< Swimmable water */
#define SECT_WATER_NOSWIM 7 /**< Water - need a boat */
#define SECT_FLYING 8 /**< Flying */
#define SECT_UNDERWATER 9 /**< Underwater */
+ #define SECT_DESERT 10 /**< Desert */
*** Be sure to bump up NUM_SPELLS by 1
+ #define NUM_ROOM_SECTORS 11
*** In asciimap.c scroll down to the first instance of sector types.
*** At the next -1 at the bottom fill in your new sector type.
static struct map_info_type map_info[] =
{
{ SECT_INSIDE, "@c[@n.@c]@n" }, /* 0 */
{ SECT_CITY, "@c[@wC@c]@n" },
{ SECT_FIELD, "@c[@g,@c]@n" },
{ SECT_FOREST, "@c[@gY@c]@n" },
{ SECT_HILLS, "@c[@Mm@c]@n" },
{ SECT_MOUNTAIN, "@c[@rM@c]@n" }, /* 5 */
{ SECT_WATER_SWIM, "@c[@c~@c]@n" },
{ SECT_WATER_NOSWIM, "@c[@b=@c]@n" },
{ SECT_FLYING, "@c[@C^@c]@n" },
{ SECT_UNDERWATER, "@c[@bU@c]@n" },
- { -1, "" }, /* 10 */
+ { SECT_DESERT, "@c[@Y-@c]@n" }, /* 10 */
*** Scroll down a bit more to the next set and do the same.
*** Since we used @Y- for the symbol above, use it again here.
static struct map_info_type world_map_info[] =
{
{ SECT_INSIDE, "@n." }, /* 0 */
{ SECT_CITY, "@wC" },
{ SECT_FIELD, "@g," },
{ SECT_FOREST, "@gY" },
{ SECT_HILLS, "@Mm" },
{ SECT_MOUNTAIN, "@rM" }, /* 5 */
{ SECT_WATER_SWIM, "@c~" },
{ SECT_WATER_NOSWIM, "@b=" },
{ SECT_FLYING, "@C^" },
{ SECT_UNDERWATER, "@bU" },
- { -1, "" }, /* 10 */
+ { SECT_DESERT, "@y-" }, /* 10 */
*** Finally, jump down even more to where they're listed again like this, and add your new sector.
count += sprintf(buf + count, "@n%s Swim\\\\", map_info[SECT_WATER_SWIM].disp);
count += sprintf(buf + count, "@n%s Boat\\\\", map_info[SECT_WATER_NOSWIM].disp);
count += sprintf(buf + count, "@n%s Flying\\\\", map_info[SECT_FLYING].disp);
count += sprintf(buf + count, "@n%s Underwater\\\\", map_info[SECT_UNDERWATER].disp);
+ count += sprintf(buf + count, "@n%s Desert\\\\", map_info[SECT_DESERT].disp);
I wrote this guide to help people add in basic area spells. It is not meant to be a guide for advanced spells or any other type of spell. It is written, tested, and works on stock tbaMUD. It may or may not work if your game is heavily modified or from an older version of CWG.
*** In spells.h scroll down to the bottom of the spell list and define a
*** new one. Make sure it is +1 from the previous spell.
#define SPELL_WATERWALK 51 /* Reserved Skill[] DO NOT CHANGE */
#define SPELL_METEOR 52 /* Meteor of DOOM! */
+ #define SPELL_TREMOR 53 /* A miniature Earthquake */
*** In spells.h, right under that, there should be #define NUM_SPELLS. Make
*** sure you add one to that since you have defined a new one.
+ #define NUM_SPELLS 53
*** In magic.c search Area Spells (commented out). You should see Earthquake,
*** which is a great example for an area spell. Tremor, the new spell, acts like
*** Earthquake but only weaker.
/* Area spells */
case SPELL_EARTHQUAKE:
dam = dice(2, 8) + level;
break;
+ case SPELL_TREMOR:
+ dam = dice(1, 4) + level;
+ break;
**( In magic.c still, search for another instance of Earthquake. It will look
*** something like below. Add in another case for the new area spell.
switch (spellnum) {
case SPELL_EARTHQUAKE:
to_char = "You gesture and the earth begins to shake all around you!";
to_room ="$n gracefully gestures and the earth begins to shake violently!";
break;
+ case SPELL_TREMOR:
+ to_char = "You gesture and cause a tremor to shake the ground beneath you!";
+ to_room = "$n gracefully gestures, causing a tremor to shake the ground beneath you!";
+ break;
}
*** In spell_parser.c search for Earthquake since it is an area spell.
*** It will be listed many lines below mag_assign_spells.
*** 40, 25, 3 in Earthquake stands for minimum mana cost of 25, maximum mana cost
*** of 40. Every level the mana cost decreases by 3 but it will never go
*** below 25. So in Tremor the new spell, I lowered the cost because it is weaker.
spello(SPELL_EARTHQUAKE, "earthquake", 40, 25, 3, POS_FIGHTING,
TAR_IGNORE, TRUE, MAG_AREAS,
NULL);
+ spello(SPELL_TREMOR, "tremor", 30, 15, 2, POS_FIGHTING,
+ TAR_IGNORE, TRUE, MAG_AREAS,
+ NULL);
*** In class.c search for init_spell_levels and add in your new
*** spell into that list. CLASS_CLERIC can be any of the classes that
*** are built into your game. Level "8" is the level of which the Cleric
*** will learn Tremor.
spell_level(SPELL_WORD_OF_RECALL, CLASS_CLERIC, 12);
spell_level(SPELL_EARTHQUAKE, CLASS_CLERIC, 12);
+ spell_level(SPELL_TREMOR, CLASS_CLERIC, 8);
spell_level(SPELL_DISPEL_EVIL, CLASS_CLERIC, 14);
*** Back out of the src directory, and enter the lib director, then
*** misc. Open the file messages, search for the damaging spells, and add
*** in the messages for your new spell. Be sure the number above the messages
*** match the spell number from spells.h.
*** Note: Don't forget the "M" on the line just above the spell number!!!
+ * Tremor
+ M
+ 53
+ A small crack opens beneath $N's feet and swallows $M whole!
+ A small crack opens beneath your feet and swallows you whole!
+ A small crack opens beneath $N's feet and swallows $M whole!
+ $N desperately tries to keep $S balance as the earth tremors beneath $S feet!
+ You desperately try to keep your balance as the earth tremors beneath your feet!
+ $N desperately tries to keep $S balance as the earth tremors beneath $S feet!
+ $N falls down and hurts $Mself!
+ You fall down and hurt yourself!
+ $N falls down and hurts $Mself!
+ $N holds $S ground as you send a tremor $S way.
+ You hold your ground as the tremor shakes the place.
+ $N holds $S ground as a tremor shakes the place.
I was looking to add in fishing on the new AstoriaTBA port, to help bide some time with the conversion, so I Googled for some snippets.
I came up with an old snippet, which I've seen done on some other MUDs, and figured why not. The snippet I found and modified here.
I wrote this guide to help people add in basic fishing for players. It is not meant to be a guide for advanced fishing and I am not claiming the original idea for it, nor even the code. It is written, tested, and works on stock tbaMUD. It may or may not work if your game is heavily modified or from an older version of CWG.
send_to_chars were backwards.
Example: send_to_char("You need to be holding a fishing pole first.\r\n", ch);
should be:
send_to_char(ch, "You need to be holding a fishing pole first.\r\n");
number should be rand_number
Example: bite = number(1, 10);
should be:
bite = rand_number(1, 10);
Changed sprintf to send_to_char
Example: sprintf(buf, "You reel in %s! Nice catch!\r\n", fish->short_description);
should be:
send_to_char(ch, "You reel in %s! Nice catch!\r\n", fish->short_description);
Added in some things to interpreter.c and act.h as well
So here it is, revised, with all of the fixes. (Much thanks go to Fizban for helping squash several of the errors. His scripting website is here if anyone has any script related questions.)
*** In structs.h, with all your player flags, add this to the bottom.
#define PLR_CRYO 15 /**< Player is cryo-saved (purge prog) */
#define PLR_NOTDEADYET 16 /**< (R) Player being extracted */
+ #define PLR_FISHING 17 /**< Player has a line in the water */
+ #define PLR_FISH_ON 18 /**< Player has a fish on their line */
*** In structs.h, with your item types, add this to the bottom.
#define ITEM_FOUNTAIN 23 /**< Item is a fountain */
+ #define ITEM_POLE 24 /**< Item is a fishing pole */
*** Be sure to increase #define NUM_ITEM_TYPES by one.
+ #define NUM_ITEM_TYPES 25
*** In structs.h, with your flags, add this to the bottom. Be sure to
*** increase NUM_ROOM_FLAGS by one.
#define ROOM_BFS_MARK 15 /**< (R) breath-first srch mrk */
#define ROOM_WORLDMAP 16 /**< World-map style maps here */
+ #define ROOM_SALTWATER_FISH 17 /**< Fish are saltwater */
+ #define ROOM_FRESHWATER_FISH 18 /**< Fish are freshwater */
*** In constants.c, add to const char *room_bits[] at bottom,
*** before "\n".
"WORLDMAP",
+ "SALTWATER_FISH",
+ "FRESHWATER_FISH",
"\n"
*** In constants.c, add to const char *player_bits[] at bottom,
*** before "\n"
"UNUSED5",
+ "FISHING",
+ "FISH_ON",
"\n"
*** In constants.c, add to const char *item_types[] at bottom,
*** before "\n"
"FOUNTAIN",
+ "FISHING POLE",
"\n"
*** In act.item.c add at the bottom.
ACMD(do_castout)
{
struct obj_data *pole;
int fail;
if (PLR_FLAGGED(ch, PLR_FISHING)) {
send_to_char(ch, "You are already fishing!\r\n");
return;
}
if (!(pole = GET_EQ(ch, WEAR_HOLD)) ||
(GET_OBJ_TYPE(pole) != ITEM_POLE)) {
send_to_char(ch, "You need to be holding a fishing pole first.\r\n");
return;
}
if (!ROOM_FLAGGED(ch->in_room, ROOM_SALTWATER_FISH) &&
!ROOM_FLAGGED(ch->in_room, ROOM_FRESHWATER_FISH)) {
send_to_char(ch, "This is not a good place to fish, you'll want to find a "
"better spot.\r\n");
return;
}
fail = rand_number(1, 10);
if (fail <= 3) {
send_to_char(ch, "You pull your arm back and try to cast out your line, but "
"it gets all tangled up.\r\nTry again.\r\n");
act("$n pulls $s arm back, trying to cast $s fishing line out into the "
"water,\r\nbut ends up just a bit tangled.\r\n",
FALSE, ch, 0, 0, TO_ROOM);
return;
}
/* Ok, now they've gone through the checks, now set them fishing */
SET_BIT_AR(PLR_FLAGS(ch), PLR_FISHING);
send_to_char(ch, "You cast your line out into the water, hoping for a bite.\r\n");
act("$n casts $s line out into the water, hoping to catch some food.\r\n",
FALSE, ch, 0, 0, TO_ROOM);
return;
}
ACMD(do_reelin)
{
int success, f_num, fish_num;
struct obj_data *fish;
if (!PLR_FLAGGED(ch, PLR_FISHING)) {
send_to_char(ch, "You aren't even fishing!\r\n");
return;
}
if (!PLR_FLAGGED(ch, PLR_FISH_ON)) {
send_to_char(ch, "You reel in your line, but alas... nothing on the end.\r\n"
"Better luck next time.\r\n");
REMOVE_BIT_AR(PLR_FLAGS(ch), PLR_FISHING);
act("$n reels $s line in, but with nothing on the end.\r\n",
FALSE, ch, 0, 0, TO_ROOM);
return;
}
/* Ok, they are fishing and have a fish on */
success = rand_number(1, 10);
REMOVE_BIT_AR(PLR_FLAGS(ch), PLR_FISHING);
REMOVE_BIT_AR(PLR_FLAGS(ch), PLR_FISH_ON);
if (success <= 6) {
send_to_char(ch, "You reel in your line, putting up a good fight, but you "
"lose him!\r\nTry again?\r\n");
act("$n reels $s line in, fighting with whatever is on the end, but loses "
"the catch.\r\n", FALSE, ch, 0, 0, TO_ROOM);
return;
}
/* We used object vnums 10030-10050 for our fish that people could
* catch. The below numbers reflect that use. If you wish to change
* the vnums of the fish, just change the numbers below. You can
* see that we seperated the type of fish by freshwater and salt
* water.
*/
if (ROOM_FLAGGED(ch->in_room, ROOM_SALTWATER_FISH)) {
fish_num = rand_number(10030, 10039);
f_num = real_object(fish_num);
fish = read_object(f_num, REAL);
send_to_char(ch, "You reel in %s! Nice catch!\r\n",fish->short_description);
act("Wow! $n reels in a helluva catch! Looks like $p!\r\n",
FALSE, ch, fish, 0, TO_ROOM);
obj_to_char(fish, ch);
return;
} else
if (ROOM_FLAGGED(ch->in_room, ROOM_FRESHWATER_FISH)) {
fish_num = rand_number(10040, 10050);
f_num = real_object(fish_num);
fish = read_object(f_num, REAL);
send_to_char(ch, "You reel in %s! Nice catch!\r\n", fish->short_description);
act("Wow! $n reels in a helluva catch! Looks like a $p!\r\n",
FALSE, ch, fish, 0, TO_ROOM);
obj_to_char(fish, ch);
return;
} else
send_to_char(ch, "You should never see this message, please report it.\r\n");
return;
}
*** Now, in comm.c add to your voids at the top of the file.
void check_fishing();
*** In comm.c in, before PULSE_DG_SCRIPT, add:
if (!(pulse % (40 * PASSES_PER_SEC)))
check_fishing();
*** In weather.c at the bottom, add:
void check_fishing() {
struct descriptor_data *d;
int bite;
for (d = descriptor_list; d; d = d->next) {
if (d->connected) continue;
if (PLR_FLAGGED(d->character, PLR_FISHING) &&
(!ROOM_FLAGGED(d->character->in_room, ROOM_SALTWATER_FISH) &&
!ROOM_FLAGGED(d->character->in_room, ROOM_FRESHWATER_FISH)))
REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_FISHING);
if (PLR_FLAGGED(d->character, PLR_FISHING) &&
!PLR_FLAGGED(d->character, PLR_FISH_ON)) {
bite = rand_number(1, 10);
if (bite >= 7 && bite <= 8) {
send_to_char(d->character, "Time goes by... not even a nibble.\r\n");
} else if (bite >= 6) {
send_to_char(d->character, "You feel a slight jiggle on your line.\r\n");
} else if (bite >= 4) {
send_to_char(d->character, "You feel a very solid pull on your line!\r\n");
SET_BIT_AR(PLR_FLAGS(d->character), PLR_FISH_ON);
} else if (bite >= 2) {
send_to_char(d->character, "Your line suddenly jumps to life, FISH ON!!!\r\n");
SET_BIT_AR(PLR_FLAGS(d->character), PLR_FISH_ON);
}
}
}
}
*** In act.movement.c, in do_simple_move add the below snippet just
*** above char_from_room:
if ((ROOM_FLAGGED(ch->in_room, ROOM_SALTWATER_FISH) ||
ROOM_FLAGGED(ch->in_room, ROOM_FRESHWATER_FISH)) &&
(PLR_FLAGGED(ch, PLR_FISHING) || PLR_FLAGGED(ch, PLR_FISH_ON))) {
REMOVE_BIT_AR(PLR_FLAGS(ch), PLR_FISHING);
REMOVE_BIT_AR(PLR_FLAGS(ch), PLR_FISH_ON);
send_to_char(ch, "\r\nYou pack up your fishing gear and move on.\r\n\r\n");
}
*** In fight.c in void damage, just under the Sanctuary check, add:
/* Cut damage in half if victim has sanct, to a minimum 1 */
if (AFF_FLAGGED(victim, AFF_SANCTUARY) && dam >= 2)
dam /= 2;
/* Player Fishing */
+ if (PLR_FLAGGED(victim, PLR_FISHING) && dam >= 4)
+ dam = ((float) dam * 1.5);
*** New: In interpreter.c under "cast" add:
{ "cast" , "c" , POS_SITTING , do_cast , 1, 0 },
+ { "castout" , "castout" , POS_SITTING , do_castout , 0, 0 },
*** New! In interpreter.c under "receive" add:
{ "receive" , "rece" , POS_STANDING, do_not_here , 1, 0 },
+ { "reelin" , "reelin" , POS_SITTING , do_reelin , 0, 0 },
*** New! In act.h add this below the other ACMD's of functions without subcommands:
ACMD(do_rescue);
/* Fishing */
+ ACMD(do_castout);
+ ACMD(do_reelin);
FISHING CASTOUT REELIN
Usage: castout
reelin
To fish, you must be near water, in a room specified as such. Also, you
must be holding a fishing pole. If you move from your original place of
fishing, you automatically pack up your gear and move on.
Anyone can fish, all you need is a fishing pole and patience.
Note: If you are fishing and get attacked, your fighting skills are
severely impeded, and you will take more than your average
damage until you reel your line in.
Happy fishing everyone!
I wrote this guide to help people add in basic damaging spells. It is not meant to be a guide for advanced spells or any other type of spell. It is written, tested, and works on stock tbaMUD. It may or may not work if your game is heavily modified or from an older version of CWG.
*** In spells.h scroll down to the bottom of the spell list and define a
*** new one. Make sure it is +1 from the previous spell.
#define SPELL_INFRAVISION 50 /* Reserved Skill[] DO NOT CHANGE */
#define SPELL_WATERWALK 51 /* Reserved Skill[] DO NOT CHANGE */
+ #define SPELL_METEOR 52 /* Meteor of DOOM! */
*** In spells.h, right under that, there should be #define NUM_SPELLS. Make
*** sure you add one to that since you have defined a new one.
+ #define NUM_SPELLS 52
*** In magic.c search mag_damage and scroll past the spellnum.
*** The spells here should be damaging spells like Fireball, Magic Missile,
*** and Chill Touch. Add in the new spell beneath it.
*** Note: If the spell affects the character casting in any way it must be
*** added to man_damage (with spells like Armor and Blindness) but in this
*** example the spell does not.
case SPELL_FIREBALL:
if (IS_MAGIC_USER(ch))
dam = dice(11, 8) + 11;
else
dam = dice(11, 6) + 11;
break;
+ case SPELL_METEOR:
+ dam = dice(25, 15) + 15;
+ break;
*** In spell_parser.c search for another damaging spell. I used Fireball as
*** my template. These spells should be listed a few lines below
*** mag_assign_spells.
spello(SPELL_FIREBALL, "fireball", 40, 30, 2, POS_FIGHTING,
TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE,
NULL);
+ spello(SPELL_METEOR, "meteor", 40, 30, 2, POS_FIGHTING,
+ TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE,
+ NULL);
*** In class.c search for init_spell_levels and add in your new
*** spell into that list. CLASS_MAGIC_USER can be any of the classes that
*** are built into your game, but since Mages are the unpredictable spell
*** casters I chose to assign it to them. "30" is the level of which the Mage
*** will learn that spell.
spell_level(SPELL_FIREBALL, CLASS_MAGIC_USER, 15);
+ spell_level(SPELL_METEOR, CLASS_MAGIC_USER, 30);
spell_level(SPELL_CHARM, CLASS_MAGIC_USER, 16);
*** Back out of the src directory, and enter the lib director, then
*** misc. Open the file messages, search for the damaging spells, and add
*** in the messages for your new spell. Be sure the number above the messages
*** match the spell number from spells.h.
*** Note: Don't forget the "M" on the line just above the spell number!!!
+ * Meteor
+ M
+ 52
+ Your meteor hits $N with full force, causing an immediate death!
+ A meteor summoned by $n hits you with full force. What a way to go...
+ $N summons a meteor on $n's head, causing instant death. Booyah!
+ The meteor you summoned seems to have...disintegrated.
+ The meteor $n summoned seems to have disintegrated. Whew!
+ The meteor $n summoned upon $N's head seems to have disintegrated. Oops!
+ You summon a meteor from the sky and reign it down upon the doomed head of $N!
+ $n has summoned a flaming meteor down upon your head. Ping!
+ $N has summoned a flaming meteor from the sky upon the doomed head of $N!
+ Hah, the Gods -made- the meteors!
+ Laugh, $n has tried summoning a meteor to hit you!
+ $N gracefully disintegrates the meteor that $n has tried to summon.