Welcome to the Builder Academy

Question Hometown Code for TBAmud 2025 -

More
Today 13:51 #11078 by wlessard1
I stumbled and eventually built a hometown code for tba2023. It was a long hard slog for me. I worked with Grok Bot to convert it to stock 2025 Code.
Hometowns are something I have seen since the late 90's on a mud and seen in various versions, most notably Envy/UltraEnvy and always wondered why Circle/TBA never really had it.

Here you will find a few things. The code changes, including the new files you need to add, both in lib as /lib/town and a few other things. I went with a default hometown to start but later on there is a Travel Agent you can buy a new hometown from through spec_proc and spec_assign. Midgaard is obviously the first Hometown. I am sure someone if they want can incorporate it into the character creation system.

Here is the basic snippet. Hope you like it.
Code:
HOMETOWN SNIPPET for tbaMUD 2025 - edits to stock files          Bramage ========================================================================== HOW TO READ THIS FILE   Each file has a  ===== src/file =====  header, then numbered steps in   the order to do them.  Each step says roughly WHERE (function name), then:     Find:              the stock lines to search for, between ---- lines     Add these lines BELOW it: / Add these lines ABOVE it: / CHANGE it to:                        the new code, between ++++ lines   Copy only what is BETWEEN the ---- or ++++ lines.  Tabs are real tabs,   as in stock.  Every new line carries or sits under a "Bramage" comment.   Search for a short piece of the Find text if your copy is not stock. ===== src/structs.h ===== Step 1 of 1.  struct player_special_data_saved - the very end of the struct, just before its closing }; Find: ----   time_t   lastnews;            /**< Last time player read news */ }; ---- CHANGE it to: ++++   time_t   lastnews;            /**< Last time player read news */   /* Bramage: HOMETOWN.  Index into town_table[] (town.c); 0 = the first    * town in lib/town/town.lst (Midgaard).  Saved in the pfile by NAME as    * "Htwn:" so reordering town.lst never moves anyone. */   int hometown; }; ++++ ===== src/utils.h ===== Step 1 of 1.  The GET_LOADROOM() macro, with the other player_specials macros. Find: ---- #define GET_LOADROOM(ch) CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.load_room)) ---- Add these lines BELOW it: ++++ /** Bramage: index into town_table[] (town.c).  Use valid_hometown(ch) to read it safely. */ #define GET_HOMETOWN(ch) CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->saved.hometown)) ++++ ===== src/db.h ===== Step 1 of 3.  The Mac (#if defined(CIRCLE_MACINTOSH)) LIB_ block near the top - the lines with colons. Find: ---- #define LIB_HOUSE ":house:" ---- Add these lines BELOW it: ++++ #define LIB_TOWN ":town:"    /* Bramage: hometown files (town.c) */ ++++ Step 2 of 3.  The normal LIB_ block right under it - the lines with slashes. Find: ---- #define LIB_PLRFILES    "plrfiles/" ---- Add these lines BELOW it: ++++ #define LIB_TOWN "town/"     /* Bramage: hometown files (town.c) */ ++++ Step 3 of 3.  The list of data files (CONFIG_FILE, PLAYER_FILE, ... TIME_FILE). Find: ---- #define TIME_FILE LIB_ETC"time"    /* for calendar system */ ---- Add these lines BELOW it: ++++ #define TOWN_LIST_FILE LIB_TOWN"town.lst" /* Bramage: hometown list, first = default */ ++++ ===== src/db.c ===== Step 1 of 3.  At the top of the file, with the other #includes. Find: ---- #include <sys/stat.h> ---- Add these lines BELOW it: ++++ #include "town.h"   /* Bramage: hometowns */ ++++ Step 2 of 3.  boot_db() - right after boot_world(), before the help entries load. Find: ----   boot_world();   log("Loading help entries."); ---- CHANGE it to: ++++   boot_world();   /* Bramage: hometowns (lib/town/).  The room vnums are looked up when    * used, so this only has to come before players log in. */   log("Loading hometown files.");   load_town_files();   log("Loading help entries."); ++++ Step 3 of 3.  init_char() - just after the player_special structure is created. Find: ----   /* If this is our first player make him IMPL. */   if (top_of_p_table == 0) { ---- Add these lines ABOVE it: ++++   /* Bramage: no hometown menu at creation - everyone starts in the first    * town in lib/town/town.lst (Midgaard).  The Travel Agent changes it. */   GET_HOMETOWN(ch) = 0; ++++ ===== src/players.c ===== Step 1 of 4.  At the top of the file, with the other #includes. Find: ---- #include "quest.h" ---- Add these lines BELOW it: ++++ #include "town.h"   /* Bramage: hometowns */ ++++ Step 2 of 4.  load_char() - the block that sets the PFDEF_ defaults. Find: ----     GET_LOADROOM(ch) = PFDEF_LOADROOM; ---- Add these lines BELOW it: ++++     GET_HOMETOWN(ch) = 0;   /* Bramage: no Htwn line = first town (Midgaard) */ ++++ Step 3 of 4.  load_char() - the tag switch, case 'H'. Find: ---- else if (!strcmp(tag, "Hite")) GET_HEIGHT(ch) = atoi(line); ---- Add these lines BELOW it: ++++         else if (!strcmp(tag, "Htwn")) {           /* Bramage: hometown saved by name; unknown name = first town. */           int ht = town_by_name(line);           GET_HOMETOWN(ch) = (ht < 0) ? 0 : ht;         } ++++ Step 4 of 4.  save_char() - where the Room: line is written. Find: ----   if (GET_LOADROOM(ch)    != PFDEF_LOADROOM) fprintf(fl, "Room: %d\n", GET_LOADROOM(ch)); ---- Add these lines BELOW it: ++++   /* Bramage: hometown by name, only when it isn't the default first town. */   if (valid_hometown(ch) != 0) fprintf(fl, "Htwn: %s\n", town_table[valid_hometown(ch)].name); ++++ ===== src/interpreter.c ===== Step 1 of 2.  At the top of the file, with the other #includes. Find: ---- #include "mud_event.h" ---- Add these lines BELOW it: ++++ #include "town.h"   /* Bramage: hometowns */ ++++ Step 2 of 2.  enter_player_game() - where a char with no load room gets a start room. Find: ----     if (GET_LEVEL(d->character) >= LVL_IMMORT)       load_room = r_immort_start_room;     else       load_room = r_mortal_start_room; ---- CHANGE it to: ++++     if (GET_LEVEL(d->character) >= LVL_IMMORT)       load_room = r_immort_start_room;     else /* Bramage: mortals (and brand-new chars) start at their HOMETOWN           * Start room.  Immortal/frozen start rooms stay global (cedit). */       load_room = hometown_room(d->character, TOWN_START); ++++ ===== src/fight.c ===== Step 1 of 2.  At the top of the file, with the other #includes. Find: ---- #include "quest.h" ---- Add these lines BELOW it: ++++ #include "town.h"   /* Bramage: hometowns */ ++++ Step 2 of 2.  raw_kill() - between make_corpse() and extract_char(). Find: ----   make_corpse(ch);   extract_char(ch); ---- CHANGE it to: ++++   make_corpse(ch);   /* Bramage: a dead player comes back at their HOMETOWN Death room    * (town.c).  extract_char() saves the pfile, and the menu's "enter game"    * uses this load room once, then clears it.  A player with a sticky    * load room (PLR_LOADROOM, set by an imm) keeps that instead. */   if (!IS_NPC(ch) && !PLR_FLAGGED(ch, PLR_LOADROOM) && GET_LEVEL(ch) < LVL_IMMORT)     GET_LOADROOM(ch) = GET_ROOM_VNUM(hometown_room(ch, TOWN_DEATH));   extract_char(ch); ++++ ===== src/spells.c ===== Step 1 of 2.  At the top of the file, with the other #includes. Find: ---- #include "fight.h" ---- Add these lines BELOW it: ++++ #include "town.h"   /* Bramage: hometowns */ ++++ Step 2 of 2.  ASPELL(spell_recall) - where the victim is moved. Find: ----   char_to_room(victim, r_mortal_start_room); ---- CHANGE it to: ++++   /* Bramage: recall goes to the victim's HOMETOWN Recall room (town.c). */   char_to_room(victim, hometown_room(victim, TOWN_RECALL)); ++++ ===== src/act.item.c ===== Step 1 of 2.  At the top of the file, with the other #includes. Find: ---- #include "quest.h" ---- Add these lines BELOW it: ++++ #include "town.h"   /* Bramage: hometowns */ ++++ Step 2 of 2.  ACMD(do_drop) - case SCMD_DONATE, right after the donation room switch. Find: ----     case 4: RDR = real_room(CONFIG_DON_ROOM_3); break;     }     if (RDR == NOWHERE) { ---- CHANGE it to: ++++     case 4: RDR = real_room(CONFIG_DON_ROOM_3); break;     }     /* Bramage: a real donation goes to the donor's HOMETOWN Donation room      * (town.c).  The stock junk chance (case 0) above is kept.  The cedit      * donation rooms are only used if the town room is missing. */     if (mode == SCMD_DONATE && !IS_NPC(ch) && real_room(hometown_vnum(ch, TOWN_DONATION)) != NOWHERE)       RDR = real_room(hometown_vnum(ch, TOWN_DONATION));     if (RDR == NOWHERE) { ++++ ===== src/limits.c ===== Step 1 of 2.  At the top of the file, with the other #includes. Find: ---- #include "mud_event.h" ---- Add these lines BELOW it: ++++ #include "town.h"   /* Bramage: hometowns */ ++++ Step 2 of 2.  check_idling() - the very top of the function body. Find: ---- static void check_idling(struct char_data *ch) { ---- Add these lines BELOW it: ++++   /* Bramage: a connected player idling in their hometown's Rest room is    * never pulled into the void or idle-rented.  If they go linkdead the    * normal rules apply, so a dropped connection can't leave a ghost. */   if (ch->desc && IN_ROOM(ch) != NOWHERE &&       hometown_vnum(ch, TOWN_REST) != NOWHERE &&       GET_ROOM_VNUM(IN_ROOM(ch)) == hometown_vnum(ch, TOWN_REST))     return; ++++ ===== src/act.informative.c ===== Step 1 of 2.  At the top of the file, with the other #includes. Find: ---- #include "quest.h" ---- Add these lines BELOW it: ++++ #include "town.h"   /* Bramage: hometowns */ ++++ Step 2 of 2.  ACMD(do_score) - after the exp / gold / questpoints line. Find: ----   send_to_char(ch, "You have %d exp, %d gold coins, and %d questpoints.\r\n",       GET_EXP(ch), GET_GOLD(ch), GET_QUESTPOINTS(ch)); ---- Add these lines BELOW it: ++++   /* Bramage: hometown (town.c). */   send_to_char(ch, "Your hometown is %s.\r\n", town_table[valid_hometown(ch)].name); ++++ ===== src/act.wizard.c ===== Step 1 of 4.  At the top of the file, with the other #includes. Find: ---- #include "ban.h" #include "screen.h" ---- Add these lines BELOW it: ++++ #include "town.h"   /* Bramage: hometowns */ ++++ Step 2 of 4.  do_stat_character() - after the Created / Last Logon line (PC only part). Find: ----     send_to_char(ch, "Created: [%s], Last Logon: [%s]\r\n", buf1, buf2); ---- Add these lines BELOW it: ++++     /* Bramage: hometown (town.c). */     send_to_char(ch, "Hometown: [%s]\r\n", town_table[valid_hometown(k)].name); ++++ Step 3 of 4.  set_fields[] in do_set's table - add a new LAST entry, just above the "\n" line. If your list is longer than stock, use the next free number here AND in the case below (stock's last entry is questhistory = 57, so ours is 58). Find: ----    { "questhistory",    LVL_GOD,        PC,   NUMBER }, ---- Add these lines BELOW it: ++++    { "hometown",        LVL_GOD,        PC,     MISC },  /* 58 Bramage */ ++++ Step 4 of 4.  perform_set() - the switch (mode); add a case just above default:. Find: ----     default:       send_to_char(ch, "Can't set that!\r\n"); ---- Add these lines ABOVE it: ++++     case 58: /* Bramage: hometown, by town name (town.c) */       if ((i = town_by_name(val_arg)) < 0) {         send_to_char(ch, "No such hometown.  Towns:");         for (i = 0; i < num_towns; i++)           send_to_char(ch, " %s%s", town_table[i].name, i < num_towns - 1 ? "," : "");         send_to_char(ch, "\r\n");         return (0);       }       GET_HOMETOWN(vict) = i;       send_to_char(ch, "%s's hometown is now %s.\r\n", GET_NAME(vict), town_table[i].name);       return (1); ++++ ===== src/spec_procs.h ===== Step 1 of 1.  The SPECIAL() prototypes for spec_procs.c. Find: ---- SPECIAL(bank); ---- Add these lines BELOW it: ++++ SPECIAL(travel_agent); /* Bramage: hometown changer, town.c */ ++++ ===== src/spec_assign.c ===== Step 1 of 2.  assign_mobiles() - at the end, after the receptionists. Change 3014 to whatever mob is your travel agent (see README). Find: ----   ASSIGNMOB(27730, receptionist); } ---- CHANGE it to: ++++   ASSIGNMOB(27730, receptionist);   /* Bramage: the Midgaard TRAVEL AGENT (town.c) - "list" shows the    * hometowns, "buy <town> confirm" changes yours for gold.  Never put    * travel_agent on a shopkeeper; shops answer "list" and "buy" too. */   ASSIGNMOB(3014, travel_agent); } ++++ Step 2 of 2.  spec_func_list[] - so stat shows the mob's SpecProc as "Travel Agent". Find: ----   {"Shopkeeper",     shop_keeper }, ---- Add these lines BELOW it: ++++   {"Travel Agent",   travel_agent }, /* Bramage: hometown changer, town.c */ ++++ ===== END ===== That is all 31 edits in 14 files.  Now rebuild (README.txt, step 4).


Here is the town file town list and template for new towns.
Code:
* ========================================================================= *  midgaard.town  -  the default hometown.  Keep it FIRST in town.lst. *  Bramage: see template.town for what each line means. *  Rooms are stock tbaMUD Midgaard (zone 30). * ========================================================================= Name      Midgaard~ * 3001 = The Temple Of Midgaard Start     3001 Recall    3001 Death     3001 * 3063 = The Midgaard Donation Room Donation  3063 * 3008 = The Reception Rest      3008 End
Town template
Code:
* ========================================================================= *  template.town  -  copy me to make a new hometown  (NOT in town.lst) * ========================================================================= *  Bramage: HOW TO READ AND EDIT A TOWN FILE * *  - A line starting with * is a comment.  Blank lines are skipped. *  - Every other line is a KEYWORD then its value.  Name / Warning may end *    with ~ like other tbaMUD files (optional). *  - Edit, save, reboot.  No compile needed.  Typos are logged as *    "SYSERR: town file town/xxx.town, line NN" and that line is skipped - *    the MUD still boots. * *  KEYWORDS *  Name      the town's name.  Players type it at the Travel Agent, and *            the pfile saves it ("Htwn: New Thalos") - so DON'T rename a *            town once players live there, or they fall back to the first *            town (Midgaard). *  Start     room vnum new/returning players appear in (no load room). *  Recall    room the recall spell / word of recall sends them to. *  Death     room a dead player comes back to. *  Donation  room the donate command sends items to. *  Rest      idle-safe room: a connected player idling here is never *            pulled into the void or idle-rented. *            (Any room you leave out copies the Start room.) *  Warning   optional.  Shown at the Travel Agent in red. *  Price     optional.  Gold to move here.  Leave it out to use *            HOMETOWN_PRICE in src/town.h (10000). *  End       end of the file (a $ line works too). * *  Temples, inns, shops and trainers are zone content - they don't go here. * *  Example below uses stock New Thalos (zone 54) room numbers - CHECK them *  in your world before you add this file to town.lst. * ========================================================================= Name      New Thalos~ * 5406 = The Center Of Market Square,  5401 = The Reception Area Start     5406 Recall    5406 Death     5406 Donation  5406 Rest      5401 * Warning   Not recommended for new or low-level characters.~ * Price     10000 End
and town list
Code:
* ========================================================================= *  town.lst  -  the hometown files the MUD loads at boot  (src/town.c) * ========================================================================= *  Bramage: *   - One .town file name per line.  Lines starting with * are comments. *     The list ends with a line holding just $. *   - The FIRST town is the default hometown.  Every new character starts *     there (no menu at creation), and anyone whose saved town is unknown *     falls back to it.  Keep midgaard.town first. *   - Order does NOT matter otherwise - pfiles save the town by NAME. *   - To add a town: copy template.town to newtown.town, edit it, add its *     name above the $, reboot.  No compile. * ========================================================================= midgaard.town $

As always, I do not guarantee this will work with any customization already in tba2025 by coders. It compiles and boots. 

Hope you folks like it.

Just a guy coding a mud at home for no reason but the challenge.

Please Log in or Create an account to join the conversation.

Time to create page: 0.263 seconds