Reroll update

This commit is contained in:
kinther 2025-12-30 08:22:48 -08:00
parent 4f5ee09ee4
commit b186c7e87c
9 changed files with 156 additions and 2 deletions

View file

@ -59,6 +59,7 @@ Changes in v1.1.0-alpha:
* PC's and NPC's can now have an age set between 18-65
* "audit ac" command for immortals (formerly "acaudit"), allowing for further audit commands in the future
* Minor score output change to only show quest status while on a quest, PC/NPC name, sdesc, and current ldesc
* Added ability to reroll initial stats if they are not to player's liking, and undo reroll if needed
Features to be implemented in the next few releases:

View file

@ -7962,7 +7962,15 @@ From: justo
#2
REROLL
Usage: reroll <player>
Usage: reroll
reroll undo
Reroll lets you roll a new set of stats once. Your original stats are saved
for 2 hours; during that window you may use 'reroll undo' to restore them.
After the review period or after using reroll undo, your stats are permanent
and you cannot reroll again.
Immortals: reroll <player> rerolls that player's stats.
REROLL gives a player new stats (i.e., Str, Int, Wis, Dex, Con, and Cha)

View file

@ -258,6 +258,7 @@ ACMD(do_hide);
ACMD(do_listen);
ACMD(do_not_here);
ACMD(do_change);
ACMD(do_reroll);
ACMD(do_report);
ACMD(do_save);
ACMD(do_skills);

View file

@ -66,6 +66,14 @@ static void change_trim_trailing_spaces(char *text)
}
}
#define REROLL_REVIEW_SECONDS (2 * SECS_PER_REAL_HOUR)
static void reroll_clear_saved(struct char_data *ch)
{
GET_REROLL_EXPIRES(ch) = 0;
memset(&GET_REROLL_OLD_ABILS(ch), 0, sizeof(struct char_ability_data));
}
ACMD(do_quit)
{
char first[MAX_INPUT_LENGTH];
@ -275,6 +283,105 @@ ACMD(do_change)
send_to_char(ch, "Long description updated.\r\n");
}
ACMD(do_reroll)
{
char arg[MAX_INPUT_LENGTH];
struct char_data *vict;
time_t now;
time_t remaining;
bool expired = FALSE;
one_argument(argument, arg);
if (IS_NPC(ch)) {
send_to_char(ch, "You can't reroll stats.\r\n");
return;
}
now = time(0);
if (GET_REROLL_EXPIRES(ch) > 0 && now >= GET_REROLL_EXPIRES(ch)) {
reroll_clear_saved(ch);
save_char(ch);
expired = TRUE;
}
if (*arg && is_abbrev(arg, "undo")) {
if (!GET_REROLL_USED(ch)) {
send_to_char(ch, "You haven't rerolled yet.\r\n");
return;
}
if (GET_REROLL_EXPIRES(ch) <= 0 || expired) {
send_to_char(ch, "You no longer have a reroll pending; your stats are permanent.\r\n");
return;
}
ch->real_abils = GET_REROLL_OLD_ABILS(ch);
affect_total(ch);
reroll_clear_saved(ch);
save_char(ch);
send_to_char(ch, "Your original stats have been restored. You cannot reroll again.\r\n");
send_to_char(ch, "Stats: Str %d, Int %d, Wis %d, Dex %d, Con %d, Cha %d\r\n",
GET_STR(ch), GET_INT(ch), GET_WIS(ch),
GET_DEX(ch), GET_CON(ch), GET_CHA(ch));
return;
}
if (*arg && GET_LEVEL(ch) >= LVL_GRGOD) {
if (!(vict = get_char_vis(ch, arg, NULL, FIND_CHAR_WORLD)))
send_to_char(ch, "There is no such player.\r\n");
else if (IS_NPC(vict))
send_to_char(ch, "You can't do that to a mob!\r\n");
else {
roll_real_abils(vict);
affect_total(vict);
send_to_char(ch, "Rerolled...\r\n");
log("(GC) %s has rerolled %s.", GET_NAME(ch), GET_NAME(vict));
send_to_char(ch, "New stats: Str %d, Int %d, Wis %d, Dex %d, Con %d, Cha %d\r\n",
GET_STR(vict), GET_INT(vict), GET_WIS(vict),
GET_DEX(vict), GET_CON(vict), GET_CHA(vict));
save_char(vict);
}
return;
}
if (*arg) {
send_to_char(ch, "Usage: reroll | reroll undo\r\n");
return;
}
if (GET_REROLL_USED(ch)) {
if (GET_REROLL_EXPIRES(ch) > 0 && now < GET_REROLL_EXPIRES(ch)) {
remaining = GET_REROLL_EXPIRES(ch) - now;
int hours = remaining / SECS_PER_REAL_HOUR;
int mins = (remaining % SECS_PER_REAL_HOUR) / SECS_PER_REAL_MIN;
if (hours > 0)
send_to_char(ch, "You have already rerolled. You can 'reroll undo' within %d hour%s %d minute%s.\r\n",
hours, hours == 1 ? "" : "s", mins, mins == 1 ? "" : "s");
else
send_to_char(ch, "You have already rerolled. You can 'reroll undo' within %d minute%s.\r\n",
mins, mins == 1 ? "" : "s");
} else {
send_to_char(ch, "You have already rerolled and cannot reroll again.\r\n");
}
return;
}
GET_REROLL_OLD_ABILS(ch) = ch->real_abils;
roll_real_abils(ch);
affect_total(ch);
GET_REROLL_USED(ch) = TRUE;
GET_REROLL_EXPIRES(ch) = now + REROLL_REVIEW_SECONDS;
save_char(ch);
send_to_char(ch, "Your stats have been rerolled. You have 2 hours to review them.\r\n");
send_to_char(ch, "New stats: Str %d, Int %d, Wis %d, Dex %d, Con %d, Cha %d\r\n",
GET_STR(ch), GET_INT(ch), GET_WIS(ch),
GET_DEX(ch), GET_CON(ch), GET_CHA(ch));
send_to_char(ch, "Use 'reroll undo' to restore your original stats before the timer expires.\r\n");
}
/* Generic function for commands which are normally overridden by special
* procedures - i.e., shop commands, mail commands, etc. */
ACMD(do_not_here)

View file

@ -264,7 +264,7 @@ cpp_extern const struct command_info cmd_info[] = {
{ "recent" , "recent" , POS_DEAD , do_recent , LVL_IMMORT, 0 },
{ "remove" , "rem" , POS_RESTING , do_remove , 0, 0 },
{ "report" , "repo" , POS_RESTING , do_report , 0, 0 },
{ "reroll" , "rero" , POS_DEAD , do_wizutil , LVL_GRGOD, SCMD_REROLL },
{ "reroll" , "rero" , POS_DEAD , do_reroll , 0, 0 },
{ "rescue" , "resc" , POS_FIGHTING, do_rescue , 1, 0 },
{ "restore" , "resto" , POS_DEAD , do_restore , LVL_GOD, 0 },
{ "return" , "retu" , POS_DEAD , do_return , 0, 0 },

View file

@ -58,5 +58,7 @@
#define PFDEF_CURRQUEST NOTHING
#define PFDEF_LASTMOTD 0
#define PFDEF_LASTNEWS 0
#define PFDEF_REROLL_USED 0
#define PFDEF_REROLL_EXPIRES 0
#endif /* _PFDEFAULTS_H_ */

View file

@ -315,6 +315,9 @@ int load_char(const char *name, struct char_data *ch)
GET_NUM_QUESTS(ch) = PFDEF_COMPQUESTS;
GET_LAST_MOTD(ch) = PFDEF_LASTMOTD;
GET_LAST_NEWS(ch) = PFDEF_LASTNEWS;
GET_REROLL_USED(ch) = PFDEF_REROLL_USED;
GET_REROLL_EXPIRES(ch) = PFDEF_REROLL_EXPIRES;
memset(&GET_REROLL_OLD_ABILS(ch), 0, sizeof(struct char_ability_data));
if (GET_ACCOUNT(ch)) {
free(GET_ACCOUNT(ch));
GET_ACCOUNT(ch) = NULL;
@ -454,6 +457,20 @@ int load_char(const char *name, struct char_data *ch)
case 'R':
if (!strcmp(tag, "Room")) GET_LOADROOM(ch) = atoi(line);
else if (!strcmp(tag, "RrUs")) GET_REROLL_USED(ch) = atoi(line);
else if (!strcmp(tag, "RrTm")) GET_REROLL_EXPIRES(ch) = (time_t)atol(line);
else if (!strcmp(tag, "RrAb")) {
int rstr, rint, rwis, rdex, rcon, rcha;
if (sscanf(line, "%d %d %d %d %d %d", &rstr, &rint, &rwis, &rdex, &rcon, &rcha) == 6) {
GET_REROLL_OLD_ABILS(ch).str = rstr;
GET_REROLL_OLD_ABILS(ch).intel = rint;
GET_REROLL_OLD_ABILS(ch).wis = rwis;
GET_REROLL_OLD_ABILS(ch).dex = rdex;
GET_REROLL_OLD_ABILS(ch).con = rcon;
GET_REROLL_OLD_ABILS(ch).cha = rcha;
}
}
break;
case 'S':
@ -663,6 +680,18 @@ void save_char(struct char_data * ch)
fprintf(fl, "Lmot: %d\n", (int)GET_LAST_MOTD(ch));
if (GET_LAST_NEWS(ch) != PFDEF_LASTNEWS)
fprintf(fl, "Lnew: %d\n", (int)GET_LAST_NEWS(ch));
if (GET_REROLL_USED(ch) != PFDEF_REROLL_USED)
fprintf(fl, "RrUs: %d\n", (int)GET_REROLL_USED(ch));
if (GET_REROLL_EXPIRES(ch) != PFDEF_REROLL_EXPIRES) {
fprintf(fl, "RrTm: %ld\n", (long)GET_REROLL_EXPIRES(ch));
fprintf(fl, "RrAb: %d %d %d %d %d %d\n",
GET_REROLL_OLD_ABILS(ch).str,
GET_REROLL_OLD_ABILS(ch).intel,
GET_REROLL_OLD_ABILS(ch).wis,
GET_REROLL_OLD_ABILS(ch).dex,
GET_REROLL_OLD_ABILS(ch).con,
GET_REROLL_OLD_ABILS(ch).cha);
}
if (GET_HOST(ch)) fprintf(fl, "Host: %s\n", GET_HOST(ch));
if (GET_HEIGHT(ch) != PFDEF_HEIGHT) fprintf(fl, "Hite: %d\n", GET_HEIGHT(ch));

View file

@ -1052,6 +1052,9 @@ struct player_special_data_saved
int quest_counter; /**< Count of targets left to get */
time_t lastmotd; /**< Last time player read motd */
time_t lastnews; /**< Last time player read news */
bool reroll_used; /**< Has the PC used their one-time reroll */
time_t reroll_expires; /**< When the reroll review period ends */
struct char_ability_data reroll_old_abils; /**< Original stats before reroll */
time_t next_skill_gain[MAX_SKILLS+1]; /* indexed by skill/spell number */
};

View file

@ -678,6 +678,9 @@ do \
#define GET_SCAN_RESULTS(ch) CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->scan_results))
#define GET_LAST_MOTD(ch) CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.lastmotd))
#define GET_LAST_NEWS(ch) CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.lastnews))
#define GET_REROLL_USED(ch) CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.reroll_used))
#define GET_REROLL_EXPIRES(ch) CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.reroll_expires))
#define GET_REROLL_OLD_ABILS(ch) CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.reroll_old_abils))
/** Get channel history i for ch. */
#define GET_HISTORY(ch, i) CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.comm_hist[i]))
/** Return the page length (height) for ch. */