I do hope that you find this workable and useful. I also hope I posted this properly.
Thanks to those who helped give me hints and suggestions despite my thick skull and being blind to them
for a few posts.
If this helps someone else, I am glad I gave back some for all the snippets and code I have used and gotten help for over the years.
Code:
Here is my take on remorting.
This code is for a single class remorting.
I was inspired by the MUD Nukefire which I play a lot.
While my mud is offline and just for my amusment alone, I feel passing on my take on
remorts would be at least interesting and maybe might generate some laughter at least.
First you want to make 2 files.
remort.c
remort.h not 100% I needed this one but. Also I include the banner, I hope I got that right.
Remort.h
/**
* @file remort.h
* This contains the headers and other functions possibly needed for remorting
* I will improve the header for the whole file later to make sure I cover licensing.
* Part of the core tbaMUD source code distribution, which is a derivative
* of, and continuation of, CircleMUD.
*
* All rights reserved. See license for complete information.
* Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University
* CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991
*/
#ifndef _REMORT_H_
#define _REMORT_H_
/* Constants for remort classes
#define CLASS_MAGIC_USER 0
#define CLASS_CLERIC 1
#define CLASS_THIEF 2
#define CLASS_WARRIOR 3
#define CLASS_BARD 4 */
/* Function prototypes */
void do_remort(struct char_data *ch, char *argument, int cmd, int subcmd);
void do_remort_start(struct char_data *ch);
/*void assign_remort_skills(struct char_data *ch, int remort_level);*/
#endif /* _REMORT_H_ */
Remort.c I added a bunch of debug lines to check and make sure things were doing what
I wanted properly. My mud has 51 levels of mortal.
#include "conf.h"
#include "sysdep.h"
#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "interpreter.h"
#include "handler.h"
#include "db.h"
#include "remort.h"
#include "spells.h"
extern const char *class_menu;
int parse_class(char arg);
void do_remort_start(struct char_data *ch);
ACMD(do_remort) {
char arg[MAX_STRING_LENGTH];
char buf[MAX_INPUT_LENGTH];
if(GET_LEVEL(ch) < 51 || GET_LEVEL(ch) > 51){
send_to_char(ch, "You cannot remort at this time!");
return;
}
one_argument(argument, arg);
if(GET_REMORT_LEVEL(ch) < 20) {
switch(*arg)
{
case 'n':
case 'N':
send_to_char(ch, "\r\nYour not going to remort at this time?");
send_to_char(ch, "\r\nThe immortals have allowed you to stay at your level");
break;
case 'y':
case 'Y':
send_to_char(ch, "\r\nCongrulations!");
send_to_char(ch, "\r\nYou have decided to remort!");
send_to_char(ch, "\r\nYou are now leaving you old body, to start a new!");
send_to_char(ch, "\r\nA new journey has begun for you!\r\n");
GET_LEVEL(ch) = 1;
log("DEBUG: Setting remort level for %s to %d", GET_NAME(ch), GET_REMORT_LEVEL(ch) + 1);
GET_REMORT_LEVEL(ch) = GET_REMORT_LEVEL(ch) + 1;
if (GET_REMORT_LEVEL(ch) == 1)
ch->points.max_hit = 100 + (GET_REMORT_LEVEL(ch) * 50);
ch->points.max_mana = 100 + (GET_REMORT_LEVEL(ch) * 50);
ch->points.max_move = 100 + (GET_REMORT_LEVEL(ch) * 50);
ch->points.hit = 100;
ch->points.mana = 100;
ch->points.move = 100;
ch->points.exp = 1;
do_remort_start(ch);
log("DEBUG: Saving character %s after remort", GET_NAME(ch));
save_char(ch);
sprintf(buf, "%s has remorted to level 1.", GET_NAME(ch));
/* mudlog(buf, NRM, MAX(LVL_IMMORT, GET_INVIS_LEV(ch)), TRUE); TEMP REMOVAL */
break;
default:
send_to_char(ch, "\r\n(type: \"remort y\" if u DO OR \"remort n\" if you DON'T!");
send_to_char(ch, "\r\nAre you sure you want to remort: ");
return;
}
} else {
send_to_char(ch, "\r\nYou can't remort anymore!");
send_to_char(ch, "\r\nContact Management if you need help!");
}
}
void do_remort_start(struct char_data *ch) {
/* Debug: Confirm do_remort_start is called */
log("DEBUG: do_remort_start called for %s (class: %d, remort level: %d)", GET_NAME(ch), GET_CLASS(ch), GET_REMORT_LEVEL(ch));
/* Increment remort level
GET_REMORT_LEVEL(ch)++; */
/* Initialize based on do_start */
set_title(ch, NULL);
GET_LEVEL(ch) = 1;
GET_EXP(ch) = 1;
/* Set stats (minimal, to be adjusted in class.c or elsewhere) */
GET_MAX_HIT(ch) = 100 + (GET_REMORT_LEVEL(ch) * 50);
GET_MAX_MANA(ch) = 100 + (GET_REMORT_LEVEL(ch) * 50);
GET_MAX_MOVE(ch) = 100 + (GET_REMORT_LEVEL(ch) * 50);
GET_HIT(ch) = GET_MAX_HIT(ch);
GET_MANA(ch) = GET_MAX_MANA(ch);
GET_MOVE(ch) = GET_MAX_MOVE(ch);
/* Assign class-specific skills and bonuses */
switch (GET_CLASS(ch)) {
case CLASS_CLERIC:
log("DEBUG: No skills or bonuses assigned for %s (Cleric, remort level: %d)", GET_NAME(ch), GET_REMORT_LEVEL(ch));
break;
case CLASS_MAGIC_USER:
log("DEBUG: No skills or bonuses assigned for %s (Magic User, remort level: %d)", GET_NAME(ch), GET_REMORT_LEVEL(ch));
break;
case CLASS_THIEF:
log("DEBUG: No skills or bonuses assigned for %s (Thief, remort level: %d)", GET_NAME(ch), GET_REMORT_LEVEL(ch));
break;
case CLASS_WARRIOR:
if (GET_REMORT_LEVEL(ch) == 1) {
/* Skills */
if (GET_SKILL(ch, SKILL_SNEAK) == 0) {
SET_SKILL(ch, SKILL_SNEAK, 10); /* Remort level 1 skill */
log("DEBUG: Assigned SNEAK to %s (Warrior): SNEAK=%d", GET_NAME(ch), GET_SKILL(ch, SKILL_SNEAK));
} else {
log("DEBUG: Preserved SNEAK at %d for %s (Warrior)", GET_SKILL(ch, SKILL_SNEAK), GET_NAME(ch));
}
/* Bonuses */
GET_AC(ch) += -10; /* Improved AC (lower is better in tbaMUD) */
GET_HITROLL(ch) += 1; /* +1 hit roll */
GET_DAMROLL(ch) += 1; /* +1 damage roll */
log("DEBUG: Warrior remort 1 bonuses for %s: AC=%d, HITROLL=%d, DAMROLL=%d", GET_NAME(ch), GET_AC(ch), GET_HITROLL(ch), GET_DAMROLL(ch));
} else if (GET_REMORT_LEVEL(ch) == 2) {
/* Skills */
if (GET_SKILL(ch, SPELL_IDENTIFY) == 0) {
SET_SKILL(ch, SPELL_IDENTIFY, 10); /* Remort level 2 skill */
log("DEBUG: Assigned SPELL_IDENTIFY to %s (Warrior): IDENTIFY=%d", GET_NAME(ch), GET_SKILL(ch, SPELL_IDENTIFY));
} else {
log("DEBUG: Preserved SPELL_IDENTIFY at %d for %s (Warrior)", GET_SKILL(ch, SPELL_IDENTIFY), GET_NAME(ch));
}
/* Bonuses */
GET_AC(ch) += -15; /* Further AC improvement */
GET_HITROLL(ch) += 2; /* +2 hit roll */
GET_DAMROLL(ch) += 2; /* +2 damage roll */
log("DEBUG: Warrior remort 2 bonuses for %s: AC=%d, HITROLL=%d, DAMROLL=%d", GET_NAME(ch), GET_AC(ch), GET_HITROLL(ch), GET_DAMROLL(ch));
} else if (GET_REMORT_LEVEL(ch) == 3) {
/* Skills */
if (GET_SKILL(ch, SKILL_KICK) == 0) {
SET_SKILL(ch, SKILL_KICK, 10); /* Remort level 3 skill */
log("DEBUG: Assigned KICK to %s (Warrior): KICK=%d", GET_NAME(ch), GET_SKILL(ch, SKILL_KICK));
} else {
log("DEBUG: Preserved KICK at %d for %s (Warrior)", GET_SKILL(ch, SKILL_KICK), GET_NAME(ch));
}
/* Bonuses */
GET_AC(ch) += -20; /* Further AC improvement */
GET_HITROLL(ch) += 3; /* +3 hit roll */
GET_DAMROLL(ch) += 3; /* +3 damage roll */
log("DEBUG: Warrior remort 3 bonuses for %s: AC=%d, HITROLL=%d, DAMROLL=%d", GET_NAME(ch), GET_AC(ch), GET_HITROLL(ch), GET_DAMROLL(ch));
}
break;
case CLASS_BARD:
log("DEBUG: No skills or bonuses assigned for %s (Bard, remort level: %d)", GET_NAME(ch), GET_REMORT_LEVEL(ch));
break;
default:
log("DEBUG: No skills or bonuses assigned for %s (unknown class: %d)", GET_NAME(ch), GET_CLASS(ch));
break;
}
/* Set conditions (drunk can be 0, no hunger/thirst I don't like hunger and thirst, adjust as you see fit) */
GET_COND(ch, THIRST) = -1;
GET_COND(ch, HUNGER) = -1;
GET_COND(ch, DRUNK) = 0;
/* Save character */
save_char(ch);
}
PFDEFAULTS.H
Around line 20 in stock tbamud add this.
#define PFDEF_REMORT_LEVEL 0
In Players.c
Around line 258 in load_char
GET_REMORT_LEVEL(ch) = PFDEF_REMORT_LEVEL;
around line 440 in load_char
else if(!strcmp(tag, "Rmlv")) GET_REMORT_LEVEL(ch) = atoi(line);
Around line 588 this is in function void save_char
if (GET_REMORT_LEVEL(ch) != PFDEF_REMORT_LEVEL) fprintf(fl, "Rmlv: %d\n", GET_REMORT_LEVEL(ch));
Also in save_char around line 734
/* Update Remort Level in player index */
if (player_table[id].rmvl != GET_REMORT_LEVEL(ch)) {
save_index = TRUE;
player_table[id].rmvl = GET_REMORT_LEVEL(ch);
spec_procs.c
I fought the code for so long to get this right I am putting in the whole
Void List_skills function
void list_skills(struct char_data *ch)
{
const char *overflow = "\r\n**OVERFLOW**\r\n";
int i, sortpos, ret;
size_t len = 0;
char buf2[MAX_STRING_LENGTH];
len = snprintf(buf2, sizeof(buf2), "You have %d practice session%s remaining.\r\n"
"You know of the following %ss:\r\n", GET_PRACTICES(ch),
GET_PRACTICES(ch) == 1 ? "" : "s", SPLSKL(ch));
for (sortpos = 1; sortpos <= MAX_SKILLS; sortpos++) {
i = spell_sort_info[sortpos];
if (strcmp(spell_info[i].name, unused_spellname) != 0 &&
((GET_LEVEL(ch) >= spell_info[i].min_level[(int) GET_CLASS(ch)]) ||
(GET_REMORT_LEVEL(ch) > 0 && GET_SKILL(ch, i) > 0))) {
ret = snprintf(buf2 + len, sizeof(buf2) - len, "%-20s %s\r\n", spell_info[i].name, how_good(GET_SKILL(ch, i)));
if (ret < 0 || len + ret >= sizeof(buf2))
break;
len += ret;
}
}
if (len >= sizeof(buf2))
strcpy(buf2 + sizeof(buf2) - strlen(overflow) - 1, overflow); /* strcpy: OK */
page_string(ch->desc, buf2, TRUE);
}
act.informative.c I set my current remort to allow for 20 remort levels.
In ACMD Do_who Just above "if (GET_INVIS_LEV(tch))
if (GET_REMORT_LEVEL(tch) == 1)
strcat(buf, " (teir)");
if (GET_REMORT_LEVEL(tch) == 2)
strcat(buf, " (hero)");
if (GET_REMORT_LEVEL(tch) == 3)
strcat(buf, " (avatar)");
if (GET_REMORT_LEVEL(tch) == 4)
strcat(buf, " (high mortal)");
act.wizard.c You might not have this so skip.
Function do_stat_mortal
send_to_char(ch, "Name: %s, Level: %2d %s %s Remort Level: %d\r\n",
GET_NAME(ch), GET_LEVEL(ch), buf1, buf2, GET_REMORT_LEVEL(ch));
further down in do_advance
} else if (oldlevel < LVL_IMMORT && newlevel >= LVL_IMMORT && GET_REMORT_LEVEL(victim) == 0) {
Next in class.c
In function do_start
First two lines are for location
GET_LEVEL(ch) = 1;
GET_EXP(ch) = 10801;
GET_REMORT_LEVEL(ch) = 0; /* remort snippet bramage */
in Do_advance I put what I wanted for stat progression
switch (GET_CLASS(ch)) {
case CLASS_MAGIC_USER:
add_hp += rand_number(10, 20) + (int)(GET_REMORT_LEVEL(ch) * 50);
add_mana = rand_number(GET_LEVEL(ch), (int)(5 * GET_LEVEL(ch))) + (int)(GET_REMORT_LEVEL(ch) * 50);
add_move = rand_number(10, 20);
break;
case CLASS_CLERIC:
add_hp += rand_number(10, 20) + (int)(GET_REMORT_LEVEL(ch) * 50);
add_mana = rand_number(GET_LEVEL(ch), (int)(5 * GET_LEVEL(ch))) + (int)(GET_REMORT_LEVEL(ch) * 50);
add_move = rand_number(10, 20);
break;
case CLASS_THIEF:
add_hp += rand_number(10, 20) + (int)(GET_REMORT_LEVEL(ch) * 50);
add_mana = 5;
add_move = rand_number(10, 20);
break;
case CLASS_WARRIOR:
add_hp += rand_number(10, 20) + (int)(GET_REMORT_LEVEL(ch) * 50);
add_mana = 5;
add_move = rand_number(10, 20);
break;
case CLASS_BARD:
add_hp += rand_number(10, 20) + (int)(GET_REMORT_LEVEL(ch) * 50);
add_mana = rand_number(GET_LEVEL(ch), (int)(5 * GET_LEVEL(ch))) + (int)(GET_REMORT_LEVEL(ch) * 25);
add_move = rand_number(10, 20);
break;
}
Next in iterpreter.c
Set remort for max level mortal.
{ "remort" , "remort" , POS_STANDING , do_remort , 51, 0 }, /* Remort Snippet Bramage */
in Do_score
I removed do_score a while back into its own file
But this is the change.
Make sure where ever your do_score is you also have
#include "remort.h"
in the actual function
send_to_char(ch, "Level: %d Remort Level: %d\r\n", GET_LEVEL(ch), GET_REMORT_LEVEL(ch));
In act.h around line 337
ACMD(do_remort); /* Remort snippet bramage */
In structs.h
in player_special_data_saved
int remort_level; /**< Remort Level snippet Bramage */
now the last one...
in utils.h around line 577
#define GET_REMORT_LEVEL(ch) CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.remort_level))
This should be it, I do not take any responsibilty for code issues. This works just about perfectly
on my mud. I do not have a player load as I am the only player so I do not know how it fairs
This works. It gives skills/spells to players and even bonuses to different abilities.
I am testing what I can give a player and what I cant
I only filled the Warrior remort levels for now because I am still testing how far I can go with it
and it still works. I haven't broken it yet.
I also make no claims on how this would work in a multiclass situation.
I hope I have made sure I have all the pieces I used in here for you if you choose to use it.