From 8eb30084b0a54f624ededf31fa8477a0825ed0b2 Mon Sep 17 00:00:00 2001 From: kinther Date: Sat, 27 Dec 2025 15:28:42 -0800 Subject: [PATCH 01/40] Clean up legacy practice code --- doc/building.txt | 10 +- doc/coding.txt | 4 +- lib/misc/messages | 3 +- lib/text/help/help.hlp | 88 ++---- lib/text/info | 7 +- lib/world/trg/30.trg | 596 --------------------------------------- lib/world/trg/index | 1 - lib/world/trg/index.mini | 1 - src/class.c | 46 +-- src/class.h | 1 - src/pfdefaults.h | 1 - src/protocol.c | 9 +- src/protocol.h | 9 +- src/spec_procs.c | 20 +- src/spells.h | 2 +- src/util/plrtoascii.c | 6 +- 16 files changed, 59 insertions(+), 745 deletions(-) delete mode 100644 lib/world/trg/30.trg diff --git a/doc/building.txt b/doc/building.txt index 3a1b5a2..13001c7 100644 --- a/doc/building.txt +++ b/doc/building.txt @@ -226,7 +226,7 @@ sell objects to players. A single zone typically contains up to than 100 rooms, 100 monster definitions and 100 object definitions, but a large region can be subdivided into several -zones at the author’s discretion. For example, the City of Midgaard is divided +zones at the author’s discretion. For example, a large city can be divided into two zones, one for the main city and one for the southern residential area. In addition to this, with the new zone system describing top and bottom rooms of a zone, zones can contain very few rooms and indeed can overlap with other @@ -242,7 +242,7 @@ independent, so there can be both a room number 3001 and an object number refers to each entity by its Vnum and never by name. Vnums are normally not seen by players. Each zone itself also has a Vnum. A common convention is to number the zone with the Vnums of its component rooms, divided by 100. For -example, Midgaard is zone 30, consisting of rooms 3000 to 3099. Mobile and +example, the main city is zone 30, consisting of rooms 3000 to 3099. Mobile and object numbering follows the same convention. The author of the zone can define aspects of each room such as the terrain type, @@ -1311,7 +1311,7 @@ terminated by the literal letter S. Virtual Number An arbitrary number used to identify the zone. Zone numbers are traditionally the room numbers of the zone divided by 100; for example, -Midgaard, which consists of rooms 3000 through 3099, is zone 30. +The main city, which consists of rooms 3000 through 3099, is zone 30. Zone Name A label given to the zone so that it can be identified in system logs. @@ -1444,7 +1444,7 @@ Zone File Example A sample zone file annotated with comments follows. #30 * This is zone number 30 -Northern Midgaard Main City~ * The name of the zone +Northern Main City~ * The name of the zone 3099 15 2 * Top of zone is room #3099; it resets every 15 minutes. * * Resets regardless of people. * @@ -1823,7 +1823,7 @@ interactions you want it to perform. See the help files in game for details. 8.2 Trigger File Example #100 -Obj Command 100 - portal to Midgaard~ +Obj Command 100 - portal to the capital~ 1 c 7 en~ if %cmd.mudcommand% == enter && %arg% /= portal diff --git a/doc/coding.txt b/doc/coding.txt index ccb3eda..6f4613b 100644 --- a/doc/coding.txt +++ b/doc/coding.txt @@ -1559,7 +1559,7 @@ foreground colors. Basic special procedures have largely been replaced by trigedit. Thus shifting the workload from the coder to the builder to add life and creativity into their zones. While it is easier, and less time consuming, to make triggers than special -procedures they are still used for such functions as banks and guildmasters. +procedures they are still used for such functions as banks. Using special procedures, your virtual world is not just a bunch of monsters, objects and rooms, reduced to a number of statistics. Just like good descriptions @@ -1570,7 +1570,7 @@ Several special procedures are provided with stock tbaMUD which you can use to create your own and get used to the mechanics of special procedures. These special procedures can be found in castle.c and spec_procs.c. They range from very simple procedures, like puff (pulsed special procedure) or bank (command-driven special -procedure), to very complex procedures like the guild master. +procedure), to very complex procedures. In this chapter, FALSE refers to the value 0 and TRUE to any non-zero value. diff --git a/lib/misc/messages b/lib/misc/messages index dacd493..1f4a4bb 100644 --- a/lib/misc/messages +++ b/lib/misc/messages @@ -308,7 +308,7 @@ You receive a punch in your kidneys which ends your worldly misery -- R.I.P.! $n punches $N in the kidneys causing immediate death! You wildly punch at the air, missing $N. $n misses a wild punch at you. -$n practices shadow-boxing while $N takes a break. +$n shadow-boxes while $N takes a break. # # # @@ -861,4 +861,3 @@ $N is hit by $n's lightning breath. $N is immortal and immune to lightning breath. $n tries to breath lightning upon you. $n tries to breath lightning upon $N. - diff --git a/lib/text/help/help.hlp b/lib/text/help/help.hlp index 80f2657..c1a9f5b 100644 --- a/lib/text/help/help.hlp +++ b/lib/text/help/help.hlp @@ -930,9 +930,8 @@ Backstab is a way to sneak up on a person and attempt to place your dagger in his back, at exactly the point where it does most damage. A successful backstab gives a damage multiplier, depending on your level: -The chance of successfully backstabbing a person depends on how well you -have practiced backstab at your guild. You can always backstab sleeping -people. +The chance of successfully backstabbing a person depends on your backstab +skill. You can always backstab sleeping people. #0 BALANCE BALANCING @@ -1007,7 +1006,7 @@ BASH Fighters only. -The success of a bash depends upon how many times you have practiced. To bash +The success of a bash depends on your bash skill. To bash someone is to attempt to 'knock' that person over. If you succeed, you will inflict minor damage, and cause the victim to fall on its rear. The victim will be unable to issue any commands for 2 rounds of violence. If you miss @@ -1684,7 +1683,6 @@ next_in_room - The next mob/player in the room as a variable (id) nice to use for loops, or an empty return @RTSTAT 23@n pos() - %actor.pos% returns position. Subfield modifies. Sleeping, resting, sitting, fighting, standing. @RTSTAT 1399, 20997@n -prac() - The actor's number of practices. Subfield adjusts. pref() - Checks if actor has PRF flag enabled. @RTSTAT 1210@n quest - Returns the current quest (or 0 if there's no current quest). questdone(#) - Returns TRUE (1) if the quest vnum (#) has been completed. @@ -1697,8 +1695,6 @@ saving_breath() - The actors saving throw for breath weapons. Subfield adjusts. saving_spell() - The actors saving throw for spells. Subfield adjusts. sex - The actor's sex, as a string: MALE, FEMALE, or NEUTRAL. skill() - The percentage of learnedness in the skill subfield. -skillset("" #) - Set the actors practiced level any skill or spell (1-100). - %actor.skillset("magic missile" 95)%. thirst() - The actor's thirst. Subfield sets, -1 is off. title() - The actor's title. Subfield sets. Not used for mobs. varexists() - Returns 1 if global variable in subfield exists, 0 if not. @@ -1749,7 +1745,7 @@ Checking load info for the beastly fido... [ 3012] Main Street (15 Max.) > checkload t 100 -Checking load info for the object trigger 'Portal to Midgaard - 100': +Checking load info for the object trigger 'Portal to the Capital - 100': (obj) [ 100] the portal See also: LINKS, RLIST, OLIST, MLIST, SLIST @@ -1845,11 +1841,11 @@ Clerics have an ancient belief in not carrying sharp weapons. Hence, they can only wield bludgeoning weapons. This class gives you the wisdom of peace, blessing and healing, though it is possible to learn more violent spells. -You can improve your spells by using the practice command. +You can improve your spells by using them. See @RHELP SPELLS@n for a list of spells available. -See also: PRACTICE, SPELLS +See also: SPELLS #0 CLSOLC @@ -4033,7 +4029,7 @@ INFORMATION The following commands deal with information - for more info, @RHELP KEYWORD@n RULES POLICY - The rules of the game. -SCORE AFFECTS COINS TOGGLE PRACTICE - Info about yourself and your settings. +SCORE AFFECTS COINS TOGGLE - Info about yourself and your settings. HELP INFO NEWS MOTD IMOTD - Info about the game, recent changes. WHO WHERE CONSIDER FLAGS TITLE - Info on other players. TIME DATE - Info on time. @@ -4773,11 +4769,11 @@ MAGIC-USER WIZARD MAGE This is the class of powerful and violent magic, but the magic user do not control the nature, and can therefore not bless and such. -You can improve your spells by using the practice command. +You can improve your spells by using them. See @RHELP SPELLS@n for a list of spells available. -See also: PRACTICE, SPELLS +See also: SPELLS #0 MAKEUID UID UNIQUE @@ -5451,7 +5447,7 @@ Usage: murder [target] Kill command to hit another player. To avoid accidental flagging (i.e. trying to type kiss Nia but accidentally typing kill Nia). -See also: FLAGS +See also: SKILLS #0 MUTE SQUELCH @@ -5461,7 +5457,7 @@ Usage: mute MUTE is used to prevent a player from using global communication channels. It is a toggle that can be turned on and off by the same command. -See also: FLAGS +See also: SKILLS #2 MV MOVEPOINTS MOVE-POINTS MOVEMENTPOINTS MOVEMENT-POINTS @@ -6728,22 +6724,6 @@ game and will have to be redone. This is typical of people who are power hungry and are building for themselves and not for others. That is not a sign of a good builder (see @RHELP BUILDER@n). -#2 -PRACTICE PRACTISE TRAINING GUILDS GUILDMASTERS PRACTICING EXPERIENCES - -Usage: practice [skill or spell name] - -Practice is the way you improve your spells and skills. You can only do -so in a guild, where a guildmaster can help you train. You learn new skills -as you gain levels. A guildmaster can be found throughout the realms and will -charge you for your training. - -If you type practice anywhere other than with a guildmaster, you will get a -list of all of the spells and skills you know and your level of proficiency at -each. - -See also: SPELLS, SKILLS, LEVELS -#0 PRAISE REVIEWS RATINGS Review Submitted By: Detta @@ -7186,7 +7166,7 @@ large dragon steak. These are normally acquired from the large green dragons up on Wyrm Mountain. My normal source got eaten last week, and I have a large order to fill. I need these within 24 hours -Thanks, Bob the Butcher, Midgaard +Thanks, Bob the Butcher, the capital The questmaster sighs. The questmaster says "A tricky quest, but it'll cost you 5qp to back out now" #2 @@ -7929,7 +7909,7 @@ ever seen. I have never seen anyone put so much work into a zone. Kudos to Justo I am saving this because I would like everyone to use Justo's work as an outstanding example of how a builder should develop and plan a full zone. - * * * * Midgaard Mail System * * * * + * * * * City Mail System * * * * Date: Sun Oct 13 10:33:59 2002 To: rumble From: justo @@ -8531,7 +8511,6 @@ olc GrGod PC MISC password GrGod PC MISC poofin Imm PC MISC poofout Imm PC MISC -practices God PC NUMBER quest God PC BINARY questhistory God PC NUMBER questpoints God PC NUMBER @@ -8952,7 +8931,7 @@ SPECIALS SPEC-PROC SPECIAL-PROCEDURES SPECPROC SPEC_PROC mobs, and objects. They are written by coders and are normally not created by builders. If you have something you wish to assign a special procedure to talk it over with a coder. The most common special procedures include: -Postmasters, banks, guildmasters, pet shops, and boards. If your zone requires +Postmasters, banks, pet shops, and boards. If your zone requires any of the above mudmail your coder after your zone is complete. Most of the things possible through special procedures can now be done through trigedit. @@ -8961,12 +8940,6 @@ To create a postmaster make a mob, set one of the keywords as "postmaster," set the NPC flag SPEC, and load it to the room via zedit. Then have your coder add to spec_assign.c:110: ASSIGNMOB(#, postmaster); NOTE: # = the mob/obj vnum. -To create a guildmaster make a mob, set one of the keywords as "guildmaster," -set the NPC flag SPEC, and load it to the room via zedit. Then have your coder -add to spec_assign.c:69: ASSIGNMOB(#, guild); A player can practice at any -guildmaster, it is the guildguards that usually limit who can access what -guildmaster. @RTSTAT 133@n - To create a bank make an object, set it to type OTHER, add keyword "bank" and load it to the room via zedit. Then have your coder add to spec_assign.c: 138: ASSIGNOBJ(#, bank); @@ -8981,7 +8954,7 @@ In all cases special procedures need to be added in by a coder. Once your zone is complete mudmail your coder for the additions you want including type and mob or object vnum. -See also: POSTMASTER, PETSHOPS, BANKS, GUILDMASTER, BOARDS +See also: POSTMASTER, PETSHOPS, BANKS, BOARDS #2 SPELLS @@ -9224,9 +9197,8 @@ Thief Only. Usage: steal [target] -Use steal to steal coins or items from people. The chance of not getting -caught depends on how well you have practiced steal, and if the person -is asleep. +Use steal to steal coins or items from people. The chance of not getting +caught depends on your steal skill and whether the person is asleep. Examples: @@ -9281,11 +9253,11 @@ This is a listing of stock areas. 186 Newbie Zone -- Maynard of StrangeMUD 25 The High Tower of Magic -- Skylar of SillyMUD* 26 The High Tower Of Magic -- Skylar of SillyMUD* -30 Northern Midgaard Main City -- DikuMUD -31 Southern Part of Midgaard -- DikuMUD +30 Northern Main City -- DikuMUD +31 Southern Main City -- DikuMUD 33 The Three Of Swords -- C.A.W. 35 Miden'Nir -- Copper II, modified by VampLestat of MercMUD* -36 The Chessboard of Midgaard -- Exxon of SillyMUD +36 The Chessboard of the City -- Exxon of SillyMUD 40 Mines of Moria -- Redferne of DikuMUD* 41 Mines of Moria -- Redferne of DikuMUD* 50 The Great Eastern Desert -- Rorschach @@ -10059,7 +10031,7 @@ The teleporter is used to transfer players between zones. Accessible zones are listed under HELP ZONES by being CAPITALIZED. For example to teleport to: 74 Newbie GRAVEyard -- Jojen 3- 5 type: teleport grave - The teleporter may also be used to recall back to Midgaard at any time. + The teleporter may also be used to recall back to the capital at any time. Uncapitalized zones are linked through a capitalized zone. @@ -10254,13 +10226,13 @@ Thieves are known to have very special qualities, that no other class offers. Their specialty tends to be in the darker, sneakier art. Many of these qualities can come in handy in many situations, such as picking locks. -You can improve you skills by using the practice command. +You can improve your skills by using them. Skills available to thieves: sneak, hide, steal, backstab, pick lock, track See the help on each skill for more information. -See also: PRACTICE, FLAGS +See also: FLAGS #0 TILDES ~ @@ -12444,11 +12416,11 @@ them better at hand-to-hand-combat, as they possess skills of violence and fighting unequaled by the members of any other class. However, they lack the ability to use magic of any sort. -You can improve your skills by using the practice command. +You can improve your skills by using them. Skills available to warriors: kick, rescue, track, bash -See also: PRACTICE +See also: FLAGS #0 WATERWALK WATWALK @@ -13314,12 +13286,12 @@ rumble@*tbamud.com 26 High Tower Of Magic II -- Skylar 1-30 27 MEMLIN Caves -- Detta 17-25 28 MUDSCHOOL -- Welcor 1- 3 - 30 Northern MIDGAARD -- DikuMUD 1-33 - 31 Southern MIDGAARD -- DikuMUD 1-33 - 32 MIDGAARD -- DikuMUD 1-33 + 30 Northern MAIN CITY -- DikuMUD 1-33 + 31 Southern MAIN CITY -- DikuMUD 1-33 + 32 MAIN CITY -- DikuMUD 1-33 33 Three Of Swords -- C.A.W. 5-30 35 Miden'Nir -- Copper II 4-10 - 36 Chessboard of Midgaard -- Exxon 6-30 + 36 Chessboard of the City -- Exxon 6-30 37 CAPITAL Sewer System -- Welcor 3- 7 38 CAPITAL Sewer System II -- Welcor 7-14 39 HAVEN -- Nivan 3-14 @@ -13388,7 +13360,7 @@ rumble@*tbamud.com 239 South PASS -- Crysanthia 16-21 240 Dun MAURA -- Rumble 7-10 241 Starship ENTERPRISE -- Crazyman 26-30 - 242 NEW Midgaard -- Crazyman 3- 7 + 242 NEW Main City -- Crazyman 3- 7 243 Snowy VALLEY -- Crazyman 7-10 244 Cooland PRISON -- Crazyman 30 245 The NETHER -- Kaan 20 diff --git a/lib/text/info b/lib/text/info index 661518c..23dab0a 100644 --- a/lib/text/info +++ b/lib/text/info @@ -3,7 +3,7 @@ [Note: Further information can be gained on the capitalized words by using the HELP-command] -Classes, skills, and guilds: +Classes and skills: When you enter the game the first time, you are asked to select a class; either THIEF, WARRIOR, CLERIC, or MAGIC user. Characters belonging to each of these @@ -16,10 +16,7 @@ keys, creating food supplies out of nothing, and destroying an enemy in several different ways. It is not advisable for a new player to offend the members of such a group! -In order to learn the tricks of your specific trade, you need to find your -GUILD, which may take a little exploring. However, you can usually find a -guild in any reasonably populated city. Once you've found it, you need to -look up your guildmaster and PRACTICE. +You improve your skills by using them in play. Equipment: diff --git a/lib/world/trg/30.trg b/lib/world/trg/30.trg deleted file mode 100644 index 9d7d2a9..0000000 --- a/lib/world/trg/30.trg +++ /dev/null @@ -1,596 +0,0 @@ -#3000 -Mage Guildguard - 3024~ -0 q 100 -~ -* Check the direction the player must go to enter the guild. -if %direction% == south - * Stop them if they are not the appropriate class. - if %actor.class% != Magic User - return 0 - %send% %actor% The guard humiliates you, and blocks your way. - %echoaround% %actor% The guard humiliates %actor.name%, and blocks %actor.hisher% way. - end -end -~ -#3001 -Cleric Guildguard - 3025~ -0 q 100 -~ -* Check the direction the player must go to enter the guild. -if %direction% == north - * Stop them if they are not the appropriate class. - if %actor.class% != Cleric - return 0 - %send% %actor% The guard humiliates you, and blocks your way. - %echoaround% %actor% The guard humiliates %actor.name%, and blocks %actor.hisher% way. - end -end -~ -#3002 -Thief Guildguard - 3026~ -0 q 100 -~ -* Check the direction the player must go to enter the guild. -if %direction% == east - * Stop them if they are not the appropriate class. - if %actor.class% != Thief - return 0 - %send% %actor% The guard humiliates you, and blocks your way. - %echoaround% %actor% The guard humiliates %actor.name%, and blocks %actor.hisher% way. - end -end -~ -#3003 -Warrior Guildguard - 3027~ -0 q 100 -~ -* Check the direction the player must go to enter the guild. -if %direction% == east - * Stop them if they are not the appropriate class. - if %actor.class% != Warrior - return 0 - %send% %actor% The guard humiliates you, and blocks your way. - %echoaround% %actor% The guard humiliates %actor.name%, and blocks %actor.hisher% way. - end -end -~ -#3004 -Dump - 3030~ -2 h 100 -~ -%send% %actor% You are awarded for outstanding performance. -%echoaround% %actor% %actor.name% has been awarded for being a good citizen. -eval value %object.cost% / 10 -if %value% > 50 - set value 50 -elseif %value% < 1 - set value 1 -end -if %actor.level% < 3 - nop %actor.exp(%value%)% -else - nop %actor.coins(%value%)% -end -%purge% %object% -~ -#3005 -Stock Thief~ -0 b 10 -~ -set actor %random.char% -if %actor% - if %actor.is_pc% && %actor.coins% - %send% %actor% You discover that %self.name% has %self.hisher% hands in your wallet. - %echoaround% %actor% %self.name% tries to steal coins from %actor.name%. - eval coins %actor.coins% * %random.10% / 100 - nop %actor.coins(-%coins%)% - nop %self.coins(%coins%)% - end -end -~ -#3006 -Stock Snake~ -0 k 10 -~ -%send% %actor% %self.name% bites you! -%echoaround% %actor% %self.name% bites %actor.name%. -dg_cast 'poison' %actor% -~ -#3007 -Stock Magic User~ -0 k 10 -~ -switch %actor.level% - case 1 - case 2 - case 3 - break - case 4 - dg_cast 'magic missile' %actor% - break - case 5 - dg_cast 'chill touch' %actor% - break - case 6 - dg_cast 'burning hands' %actor% - break - case 7 - case 8 - dg_cast 'shocking grasp' %actor% - break - case 9 - case 10 - case 11 - dg_cast 'lightning bolt' %actor% - break - case 12 - dg_cast 'color spray' %actor% - break - case 13 - dg_cast 'energy drain' %actor% - break - case 14 - dg_cast 'curse' %actor% - break - case 15 - dg_cast 'poison' %actor% - break - case 16 - if %actor.align% > 0 - dg_cast 'dispel good' %actor% - else - dg_cast 'dispel evil' %actor% - end - break - case 17 - case 18 - dg_cast 'call lightning' %actor% - break - case 19 - case 20 - case 21 - case 22 - dg_cast 'harm' %actor% - break - default - dg_cast 'fireball' %actor% - break -done -~ -#3008 -Near Death Trap~ -2 g 100 -~ -* By Rumble of The Builder Academy tbamud.com 9091 -* Near Death Trap stuns actor -set stunned %actor.hitp% -%damage% %actor% %stunned% -%send% %actor% You are on the brink of life and death. -%send% %actor% The Gods must favor you this day. -~ -#3009 -Stock Cityguard - 3059, 60, 67~ -0 b 50 -~ -if !%self.fighting% - set actor %random.char% - if %actor% - if %actor.is_killer% - emote screams 'HEY!!! You're one of those PLAYER KILLERS!!!!!!' - kill %actor.name% - elseif %actor.is_thief% - emote screams 'HEY!!! You're one of those PLAYER THIEVES!!!!!!' - kill %actor.name% - elseif %actor.cha% < 6 - %send% %actor% %self.name% spits in your face. - %echoaround% %actor% %self.name% spits in %actor.name%'s face. - end - if %actor.fighting% - eval victim %actor.fighting% - if %actor.align% < %victim.align% && %victim.align% >= 0 - emote screams 'PROTECT THE INNOCENT! BANZAI! CHARGE! ARARARAGGGHH!' - kill %actor.name% - end - end - end -end -~ -#3010 -Stock Fido - 3062, 3066~ -0 b 100 -~ -set inroom %self.room% -set item %inroom.contents% -while %item% - * Target the next item in room. In case it is devoured. - set next_item %item.next_in_list% - * Check for a corpse. Corpse on TBA is vnum 65535. Stock is -1. - if %item.vnum(65535)% - emote savagely devours a corpse. - %purge% %item% - halt - end - set item %next_item% - * Loop back -done -~ -#3011 -Stock Janitor - 3061, 3068~ -0 b 100 -~ -eval inroom %self.room% -eval item %inroom.contents% -while %item% - * Target the next item in room. In case it is picked up. - set next_item %item.next_in_list% -* TODO: if %item.wearflag(take)% - * Check for fountains and expensive items. - if %item.type% != FOUNTAIN && %item.cost% <= 15 - take %item.name% - end - set item %next_item% - * Loop back -done -~ -#3012 -Newbie Tour Guide~ -0 e 0 -has entered the game.~ -%echo% This trigger commandlist is not complete! -~ -#3013 -Newbie Tour Guide Loader~ -0 e 0 -has entered the game.~ -* By Rumble of The Builder Academy tbamud.com 9091 -* Num Arg 0 means the argument has to match exactly. So trig will only fire off: -* "has entered game." and not "has" or "entered" etc. (that would be num arg 1). -* Figure out what vnum the mob is in so we can use zoneecho. -eval inroom %self.room% -%zoneecho% %inroom.vnum% %self.name% shouts, 'Welcome, %actor.name%!' -~ -#3014 -Teleporter~ -1 c 3 -teleport~ -* By Rumble and Jamie Nelson of The Builder Academy tbamud.com 9091 -%send% %actor% You attempt to manipulate space and time. -%echoaround% %actor% %actor.name% attempts to manipulate space and time. -wait 1 sec -set sanctus 100 -set jade 400 -set newbie 500 -set sea 600 -set camelot 775 -set nuclear 1800 -set spider 1999 -set arena 2000 -set tower 2200 -set memlin 2798 -set mudschool 2800 -set midgaard 3001 -set capital 3702 -set haven 3998 -set chasm 4200 -set arctic 4396 -set Orc 4401 -set monastery 4512 -set ant 4600 -set zodiac 5701 -set grave 7401 -set zamba 7500 -set gidean 7801 -set glumcoins 8301 -set duke 8660 -set oasis 9000 -set domiae 9603 -set northern 10004 -set south 10101 -set dbz 10301 -set orchan 10401 -set elcardo 10604 -set iuel 10701 -set omega 11501 -set torres 11701 -set dollhouse 11899 -set hannah 12500 -set maze 13001 -set wyvern 14000 -set caves 16999 -set cardinal 17501 -set circus 18700 -set western 20001 -set sapphire 20101 -set kitchen 22001 -set terringham 23200 -set dragon 23300 -set school 23400 -set mines 23500 -set aldin 23601 -set crystal 23875 -set pass 23901 -set maura 24000 -set enterprise 24100 -set new 24200 -set valley 24300 -set prison 24457 -set nether 24500 -set yard 24700 -set elven 24801 -set jedi 24901 -set dragonspyre 25000 -set ape 25100 -set vampyre 25200 -set windmill 25300 -set village 25400 -set shipwreck 25516 -set keep 25645 -set jareth 25705 -set light 25800 -set mansion 25907 -set grasslands 26000 -set igor's 26100 -set forest 26201 -set farmlands 26300 -set banshide 26400 -set beach 26500 -set ankou 26600 -set vice 26728 -set desert 26900 -set wasteland 27001 -set sundhaven 27119 -set station 27300 -set smurfville 27400 -set sparta 27501 -set shire 27700 -set oceania 27800 -set notre 27900 -set motherboard 28000 -set khanjar 28100 -set kerjim 28200 -set haunted 28300 -set ghenna 28400 -set hell 28601 -set goblin 28700 -set galaxy 28801 -set werith's 28900 -set lizard 29000 -set black 29100 -set kerofk 29202 -set trade 29400 -set jungle 29500 -set froboz 29600 -set desire 29801 -set cathedral 29900 -set ancalador 30000 -set campus 30100 -set bull 30401 -set chessboard 30537 -set tree 30600 -set castle 30700 -set baron 30800 -set westlawn 30900 -set graye 31003 -set teeth 31100 -set leper 31200 -set altar 31400 -set mcgintey 31500 -set wharf 31700 -set dock 31801 -set yllnthad 31900 -set bay 32200 -set pale 32300 -set army 32400 -set revelry 32500 -set perimeter 32600 -set asylum 34501 -set ultima 55685 -set tarot 21101 -if !%arg% - *they didnt type a location - set fail 1 -else - *take the first word they type after the teleport command - *compare it to a variable above - eval loc %%%arg.car%%% - if !%loc% - *they typed an invalid location - set fail 1 - end -end -if %fail% - %send% %actor% You fail. - %echoaround% %actor% %actor.name% fails. - halt -end -%echoaround% %actor% %actor.name% seems successful as %actor.heshe% steps into another realm. -%teleport% %actor% %loc% -%force% %actor% look -%echoaround% %actor% %actor.name% steps out of space and time. -~ -#3015 -Teleporter Recall and Return~ -1 c 7 -re~ -* By Rumble of The Builder Academy tbamud.com 9091 -if %cmd% == recall - eval teleporter_return_room %actor.room.vnum% - remote teleporter_return_room %actor.id% - %send% %actor% You recall to safety. - %echoaround% %actor% %actor.name% recalls. - %teleport% %actor% 3001 - %force% %actor% look - %echoaround% %actor% %actor.name% appears in the room. -elseif %cmd% == return - %send% %actor% You return to your previous location. - %echoaround% %actor% %actor.name% teleports out of the room. - %teleport% %actor% %actor.teleporter_return_room% - %force% %actor% look - %echoaround% %actor% %actor.name% appears in the room. -else - return 0 -end -~ -#3016 -Kind Soul Gives Newbie Equipment~ -0 g 100 -~ -* By Rumble of The Builder Academy tbamud.com 9091 -* If a player is < level 5 and naked it fully equips them. If < 5 and missing -* some equipment it will equip one spot. -if %actor.is_pc% && %actor.level% < 5 - wait 2 sec - if !%actor.eq(*)% - say get some clothes on! Here, I will help. - %load% obj 3037 %actor% light - %load% obj 3083 %actor% rfinger - %load% obj 3083 %actor% lfinger - %load% obj 3082 %actor% neck1 - %load% obj 3082 %actor% neck2 - %load% obj 3040 %actor% body - %load% obj 3076 %actor% head - %load% obj 3080 %actor% legs - %load% obj 3084 %actor% feet - %load% obj 3071 %actor% hands - %load% obj 3086 %actor% arms - %load% obj 3042 %actor% shield - %load% obj 3087 %actor% about - %load% obj 3088 %actor% waist - %load% obj 3089 %actor% rwrist - %load% obj 3089 %actor% lwrist - %load% obj 3021 %actor% wield - %load% obj 3055 %actor% hold - halt - end - if !%actor.eq(light)% - say you really shouldn't be wandering these parts without a light source %actor.name%. - shake - %load% obj 3037 - give candle %actor.name% - halt - end - if !%actor.eq(rfinger)% || !%actor.eq(lfinger)% - say did you lose one of your rings? - sigh - %load% obj 3083 - give ring %actor.name% - halt - end - if !%actor.eq(neck1)% || !%actor.eq(neck2)% - say you lose everything don't you? - roll - %load% obj 3082 - give neck %actor.name% - halt - end - if !%actor.eq(body)% - say you won't get far without some body armor %actor.name%. - %load% obj 3040 - give plate %actor.name% - halt - end - if !%actor.eq(head)% - say protect that noggin of yours, %actor.name%. - %load% obj 3076 - give cap %actor.name% - halt - end - if !%actor.eq(legs)% - say why do you always lose your pants %actor.name%? - %load% obj 3080 - give leggings %actor.name% - halt - end - if !%actor.eq(feet)% - say you can't go around barefoot %actor.name%. - %load% obj 3084 - give boots %actor.name% - halt - end - if !%actor.eq(hands)% - say need some gloves %actor.name%? - %load% obj 3071 - give gloves %actor.name% - halt - end - if !%actor.eq(arms)% - say you must be freezing %actor.name%. - %load% obj 3086 - give sleeve %actor.name% - halt - end - if !%actor.eq(shield)% - say you need one of these to protect yourself %actor.name%. - %load% obj 3042 - give shield %actor.name% - halt - end - if !%actor.eq(about)% - say you are going to catch a cold %actor.name%. - %load% obj 3087 - give cape %actor.name% - halt - end - if !%actor.eq(waist)% - say better use this to hold your pants up %actor.name%. - %load% obj 3088 - give belt %actor.name% - halt - end - if !%actor.eq(rwrist)% || !%actor.eq(lwrist)% - say misplace something? - smile - %load% obj 3089 - give wristguard %actor.name% - halt - end - if !%actor.eq(wield)% - say without a weapon you will be Fido food %actor.name%. - %load% obj 3021 - give sword %actor.name% - halt - end -end -~ -#3017 -Mortal Greet~ -2 s 100 -~ -* By Rumble of The Builder Academy tbamud.com 9091 -* TBA mortal greet and equip. New players start at level 0. -wait 1 sec -if %actor.level% == 0 - if !%actor.eq(*)% - %load% obj 3037 %actor% light - %load% obj 3083 %actor% rfinger - %load% obj 3083 %actor% lfinger - %load% obj 3082 %actor% neck1 - %load% obj 3082 %actor% neck2 - %load% obj 3040 %actor% body - %load% obj 3076 %actor% head - %load% obj 3080 %actor% legs - %load% obj 3084 %actor% feet - %load% obj 3071 %actor% hands - %load% obj 3086 %actor% arms - %load% obj 3042 %actor% shield - %load% obj 3087 %actor% about - %load% obj 3088 %actor% waist - %load% obj 3089 %actor% rwrist - %load% obj 3089 %actor% lwrist - %load% obj 3021 %actor% wield - %load% obj 3055 %actor% hold - end - if !%actor.has_item(3006)% - %load% obj 3006 %actor% inv - end -end -wait 3 sec -%zoneecho% 3001 A booming voice announces, 'Welcome %actor.name% to the realm!' -~ -#3099 -Test~ -2 b 1 -~ -%zoneecho% 3001 You hear a loud --=BOOM=--, -~ -$~ diff --git a/lib/world/trg/index b/lib/world/trg/index index 30dfe62..695b3a8 100644 --- a/lib/world/trg/index +++ b/lib/world/trg/index @@ -1,5 +1,4 @@ 0.trg 1.trg 2.trg -30.trg $ diff --git a/lib/world/trg/index.mini b/lib/world/trg/index.mini index 81a6b8c..857f13a 100644 --- a/lib/world/trg/index.mini +++ b/lib/world/trg/index.mini @@ -1,2 +1 @@ -30.trg $ diff --git a/src/class.c b/src/class.c index a81c1cf..69da305 100644 --- a/src/class.c +++ b/src/class.c @@ -95,52 +95,18 @@ bitvector_t find_class_bitvector(const char *arg) return (ret); } -/* These are definitions which control the guildmasters for each class. - * The first field (top line) controls the highest percentage skill level a - * character of the class is allowed to attain in any skill. (After this - * level, attempts to practice will say "You are already learned in this area." - * - * The second line controls the maximum percent gain in learnedness a character - * is allowed per practice -- in other words, if the random die throw comes out - * higher than this number, the gain will only be this number instead. - * - * The third line controls the minimu percent gain in learnedness a character - * is allowed per practice -- in other words, if the random die throw comes - * out below this number, the gain will be set up to this number. - * - * The fourth line simply sets whether the character knows 'spells' or 'skills'. - * This does not affect anything except the message given to the character when - * trying to practice (i.e. "You know of the following spells" vs. "You know of - * the following skills" */ - -#define SPELL 0 -#define SKILL 1 - -/* #define LEARNED_LEVEL 0 % known which is considered "learned" */ -/* #define MAX_PER_PRAC 1 max percent gain in skill per practice */ -/* #define MIN_PER_PRAC 2 min percent gain in skill per practice */ -/* #define PRAC_TYPE 3 should it say 'spell' or 'skill'? */ - -int prac_params[4][NUM_CLASSES] = { - /* SOR CLE THE FIG BAR RAN BARD DRU */ - { 95, 95, 85, 80, 75, 85, 85, 95 }, /* learned level */ - { 100, 100, 12, 12, 11, 12, 13, 90 }, /* max per practice */ - { 25, 25, 0, 0, 0, 0, 25, 25 }, /* min per practice */ - { SPELL, SPELL, SKILL, SKILL, SKILL, SKILL, SKILL, SKILL }, /* prac name */ -}; - -/* The appropriate rooms for each guildmaster/guildguard; controls which types - * of people the various guildguards let through. i.e., the first line shows +/* The appropriate rooms for each class gatekeeper; controls which types + * of people the various guards let through. i.e., the first line shows * that from room 3017, only SORCERORS are allowed to go south. Don't forget - * to visit spec_assign.c if you create any new mobiles that should be a guild + * to visit spec_assign.c if you create any new mobiles that should be a * master or guard so they can act appropriately. If you "recycle" the - * existing mobs that are used in other guilds for your new guild, then you - * don't have to change that file, only here. Guildguards are now implemented + * existing mobs that are used in other areas for your new one, then you + * don't have to change that file, only here. Guards are now implemented * via triggers. This code remains as an example. */ /* TO-DO: Is this necessary anymore now that there are no official guild rooms? */ struct guild_info_type guild_info[] = { -/* Midgaard */ +/* Main City */ { CLASS_SORCEROR, 3017, SOUTH }, { CLASS_CLERIC, 3004, NORTH }, { CLASS_ROGUE, 3027, EAST }, diff --git a/src/class.h b/src/class.h index f409bb5..0502604 100644 --- a/src/class.h +++ b/src/class.h @@ -29,7 +29,6 @@ void grant_class_skills(struct char_data *ch, bool reset); extern const char *class_abbrevs[]; extern const char *pc_class_types[]; extern const char *class_menu; -extern int prac_params[][NUM_CLASSES]; extern struct guild_info_type guild_info[]; #endif /* _CLASS_H_*/ diff --git a/src/pfdefaults.h b/src/pfdefaults.h index 2d51229..afd4ba9 100644 --- a/src/pfdefaults.h +++ b/src/pfdefaults.h @@ -29,7 +29,6 @@ #define PFDEF_CONDITION 0 #define PFDEF_BADPWS 0 #define PFDEF_PREFFLAGS 0 -#define PFDEF_PRACTICES 0 #define PFDEF_COINS 0 #define PFDEF_BANK_COINS 0 #define PFDEF_EXP 0 diff --git a/src/protocol.c b/src/protocol.c index dadaea1..e9ad34c 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -142,11 +142,10 @@ static variable_name_t VariableNameTable[eMSDP_MAX+1] = { eMSDP_LEVEL, "LEVEL", NUMBER_READ_ONLY }, { eMSDP_RACE, "RACE", STRING_READ_ONLY }, { eMSDP_CLASS, "CLASS", STRING_READ_ONLY }, - { eMSDP_MANA, "MANA", NUMBER_READ_ONLY }, - { eMSDP_MANA_MAX, "MANA_MAX", NUMBER_READ_ONLY }, - { eMSDP_WIMPY, "WIMPY", NUMBER_READ_ONLY }, - { eMSDP_PRACTICE, "PRACTICE", NUMBER_READ_ONLY }, - { eMSDP_MONEY, "MONEY", NUMBER_READ_ONLY }, + { eMSDP_MANA, "MANA", NUMBER_READ_ONLY }, + { eMSDP_MANA_MAX, "MANA_MAX", NUMBER_READ_ONLY }, + { eMSDP_WIMPY, "WIMPY", NUMBER_READ_ONLY }, + { eMSDP_MONEY, "MONEY", NUMBER_READ_ONLY }, { eMSDP_MOVEMENT, "MOVEMENT", NUMBER_READ_ONLY }, { eMSDP_MOVEMENT_MAX, "MOVEMENT_MAX", NUMBER_READ_ONLY }, { eMSDP_AC, "AC", NUMBER_READ_ONLY }, diff --git a/src/protocol.h b/src/protocol.h index a647a7c..c209fc2 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -106,11 +106,10 @@ typedef enum eMSDP_LEVEL, eMSDP_RACE, eMSDP_CLASS, - eMSDP_MANA, - eMSDP_MANA_MAX, - eMSDP_WIMPY, - eMSDP_PRACTICE, - eMSDP_MONEY, + eMSDP_MANA, + eMSDP_MANA_MAX, + eMSDP_WIMPY, + eMSDP_MONEY, eMSDP_MOVEMENT, eMSDP_MOVEMENT_MAX, eMSDP_AC, diff --git a/src/spec_procs.c b/src/spec_procs.c index e700808..5b29ad1 100644 --- a/src/spec_procs.c +++ b/src/spec_procs.c @@ -81,22 +81,6 @@ static const char *how_good(int percent) return " (superb)"; } -static const char *prac_types[] = { - "spell", - "skill" -}; - -/* TO-DO: Dig deeper and figure out if the min/max practice defines can be removed */ -#define LEARNED_LEVEL 0 /* % known which is considered "learned" */ -#define MAX_PER_PRAC 1 /* max percent gain in skill per practice */ -#define MIN_PER_PRAC 2 /* min percent gain in skill per practice */ -#define PRAC_TYPE 3 /* should it say 'spell' or 'skill'? */ - -#define LEARNED(ch) (prac_params[LEARNED_LEVEL][(int)GET_CLASS(ch)]) -#define MINGAIN(ch) (prac_params[MIN_PER_PRAC][(int)GET_CLASS(ch)]) -#define MAXGAIN(ch) (prac_params[MAX_PER_PRAC][(int)GET_CLASS(ch)]) -#define SPLSKL(ch) (prac_types[prac_params[PRAC_TYPE][(int)GET_CLASS(ch)]]) - void list_skills(struct char_data *ch) { const char *overflow = "\r\n**OVERFLOW**\r\n"; @@ -104,7 +88,7 @@ void list_skills(struct char_data *ch) size_t len = 0; char buf2[MAX_STRING_LENGTH]; - len = snprintf(buf2, sizeof(buf2), "You know of the following %ss:\r\n", SPLSKL(ch)); + len = snprintf(buf2, sizeof(buf2), "You know of the following skills:\r\n"); if (IS_NPC(ch)) { /* NPCs: show only the skills actually assigned to them */ @@ -229,7 +213,7 @@ SPECIAL(mayor) break; case 'E': - act("$n says 'I hereby declare Midgaard closed!'", FALSE, ch, 0, 0, TO_ROOM); + act("$n says 'I hereby declare the city closed!'", FALSE, ch, 0, 0, TO_ROOM); break; case 'O': diff --git a/src/spells.h b/src/spells.h index 67a9d4d..3405aa0 100644 --- a/src/spells.h +++ b/src/spells.h @@ -136,7 +136,7 @@ /* New skills may be added here up to MAX_SKILLS (200) */ -/* NON-PLAYER AND OBJECT SPELLS AND SKILLS: The practice levels for the spells +/* NON-PLAYER AND OBJECT SPELLS AND SKILLS: The skill levels for the spells * and skills below are _not_ recorded in the players file; therefore, the * intended use is for spells and skills associated with objects (such as * SPELL_IDENTIFY used with scrolls of identify) or non-players (such as NPC diff --git a/src/util/plrtoascii.c b/src/util/plrtoascii.c index 3c03739..8888a2f 100755 --- a/src/util/plrtoascii.c +++ b/src/util/plrtoascii.c @@ -70,7 +70,7 @@ struct char_special_data_saved_plrtoascii { struct player_special_data_saved_plrtoascii { byte skills[MAX_SKILLS+1]; /* array of skills plus skill 0 */ - byte PADDING0; /* used to be spells_to_learn */ + byte legacy0; /* legacy unused byte */ bool talks[MAX_TONGUE]; /* PC s Tongues 0 for NPC */ int wimp_level; /* Below this # of hit points, flee! */ byte freeze_level; /* Level of god who froze char, if any */ @@ -89,7 +89,7 @@ struct player_special_data_saved_plrtoascii { ubyte spare3; ubyte spare4; ubyte page_length; - int spells_to_learn; /* How many can you learn yet this level*/ + int spare5; int olc_zone; int spare8; int spare9; @@ -263,8 +263,6 @@ void convert(char *filename) if (psds->conditions[2] && player.level < LVL_IMMORT && psds->conditions[DRUNK] != PFDEF_DRUNK) fprintf(outfile, "Drnk: %d\n", (int)psds->conditions[2]); - if (psds->spells_to_learn != PFDEF_PRACTICES) - fprintf(outfile, "Lern: %d\n", (int)psds->spells_to_learn); /* char_ability_data */ cad = &(player.abilities); From 1efb08dafd9aa03d479d6df7507bcb6e6dbbce1e Mon Sep 17 00:00:00 2001 From: kinther Date: Sun, 28 Dec 2025 15:11:37 -0800 Subject: [PATCH 02/40] Cap skill levels, fix imm combat, remove plr_killer and plr_thief flags --- README.md | 25 ++- lib/world/trg/0.trg | 6 + lib/world/trg/index | 1 + src/act.informative.c | 11 -- src/act.offensive.c | 11 +- src/act.wizard.c | 28 ++- src/cedit.c | 11 -- src/class.c | 399 ++++++++++++++++++++++++------------------ src/class.h | 2 + src/config.c | 7 - src/config.h | 1 - src/constants.c | 4 +- src/db.c | 7 +- src/dg_variables.c | 24 --- src/fight.c | 112 ++++++++---- src/fight.h | 1 - src/limits.c | 12 +- src/magic.c | 13 +- src/spec_procs.c | 12 -- src/spells.c | 24 --- src/structs.h | 5 +- src/utils.h | 1 - 22 files changed, 366 insertions(+), 351 deletions(-) diff --git a/README.md b/README.md index 682532d..d613d35 100644 --- a/README.md +++ b/README.md @@ -46,16 +46,31 @@ Features in Miranthas MUD Alpha release: Features to be implemented in the next few releases: -* Race/species selection -* Subclass selection +* Race/species selection and stat ranges (elves have higher dex, dwarves have higher str, etc) +* Subclass selection to personalize character further +* Prioritized stats during character generation +* Combat is slowed down so it isn't over in < 15 seconds (unless you're far outmatched) +* Mounts added to help with long trips +* Wagons added to help with caravans +* Plantlife introduced +* Updated lockpicking skill +* Trap as a skill - one focused on city and one focused on desert +* Poisons and antidotes +* New alcohol and drugs/stimulants +* Skimmers/ships to traverse difficult terrain +* New elemental classes +* Introduction of gathering mana/magic for sorceror class +* Highly modified magic system +* Components for some magical spells +* Reading/writing limited to specific castes of society +* Haggling and bartering system * New calendar and moon cycles * Heat based on time of day increases/decreases, changing hunger/thirst levels -* Sandstorms -* Shaded rooms +* Sandstorms limiting visibility +* Shaded rooms providing bonuses to regeneration * Criminal system for cities and jails * Basic Psionics * Basic crafting system -* Continued skill and spell improvements * Apartment rentals for storing your loot * Enhanced quest system * Dialogue trees with NPC's diff --git a/lib/world/trg/0.trg b/lib/world/trg/0.trg index 185c943..ffda257 100644 --- a/lib/world/trg/0.trg +++ b/lib/world/trg/0.trg @@ -1 +1,7 @@ +#1 +Test~ +0 q 1 +~ +* No Script +~ $~ diff --git a/lib/world/trg/index b/lib/world/trg/index index 695b3a8..95df992 100644 --- a/lib/world/trg/index +++ b/lib/world/trg/index @@ -1,4 +1,5 @@ 0.trg 1.trg 2.trg + $ diff --git a/src/act.informative.c b/src/act.informative.c index 33dc482..04c2183 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -1589,8 +1589,6 @@ ACMD(do_who) continue; if (!CAN_SEE(ch, tch) || GET_LEVEL(tch) < low || GET_LEVEL(tch) > high) continue; - if (outlaws && !PLR_FLAGGED(tch, PLR_KILLER) && !PLR_FLAGGED(tch, PLR_THIEF)) - continue; if (questwho && !PRF_FLAGGED(tch, PRF_QUEST)) continue; if (localwho && world[IN_ROOM(ch)].zone != world[IN_ROOM(tch)].zone) @@ -1635,8 +1633,6 @@ ACMD(do_who) continue; if (!CAN_SEE(ch, tch) || GET_LEVEL(tch) < low || GET_LEVEL(tch) > high) continue; - if (outlaws && !PLR_FLAGGED(tch, PLR_KILLER) && !PLR_FLAGGED(tch, PLR_THIEF)) - continue; if (questwho && !PRF_FLAGGED(tch, PRF_QUEST)) continue; if (localwho && world[IN_ROOM(ch)].zone != world[IN_ROOM(tch)].zone) @@ -1709,10 +1705,6 @@ ACMD(do_who) send_to_char(ch, " (noshout)"); if (PRF_FLAGGED(tch, PRF_QUEST)) send_to_char(ch, " (quest)"); - if (PLR_FLAGGED(tch, PLR_THIEF)) - send_to_char(ch, " (THIEF)"); - if (PLR_FLAGGED(tch, PLR_KILLER)) - send_to_char(ch, " (KILLER)"); send_to_char(ch, "\r\n"); } } @@ -1820,9 +1812,6 @@ ACMD(do_users) continue; if (!CAN_SEE(ch, tch) || GET_LEVEL(tch) < low || GET_LEVEL(tch) > high) continue; - if (outlaws && !PLR_FLAGGED(tch, PLR_KILLER) && - !PLR_FLAGGED(tch, PLR_THIEF)) - continue; if (showclass && !(showclass & (1 << GET_CLASS(tch)))) continue; if (GET_INVIS_LEV(tch) > GET_LEVEL(ch)) diff --git a/src/act.offensive.c b/src/act.offensive.c index 3d59499..61bdf03 100644 --- a/src/act.offensive.c +++ b/src/act.offensive.c @@ -54,8 +54,6 @@ ACMD(do_assist) else if (!CAN_SEE(ch, opponent)) act("You can't see who is fighting $M!", FALSE, ch, 0, helpee, TO_CHAR); /* prevent accidental pkill */ - else if (!CONFIG_PK_ALLOWED && !IS_NPC(opponent)) - send_to_char(ch, "You cannot kill other players.\r\n"); else { send_to_char(ch, "You join the fight!\r\n"); act("$N assists you!", 0, helpee, 0, ch, TO_CHAR); @@ -82,9 +80,6 @@ ACMD(do_hit) } else if (AFF_FLAGGED(ch, AFF_CHARM) && (ch->master == vict)) act("$N is just such a good friend, you simply can't hit $M.", FALSE, ch, 0, vict, TO_CHAR); else { - if (!CONFIG_PK_ALLOWED && !IS_NPC(vict) && !IS_NPC(ch)) - check_killer(ch, vict); - if ((GET_POS(ch) == POS_STANDING) && (vict != FIGHTING(ch))) { if (GET_DEX(ch) > GET_DEX(vict) || (GET_DEX(ch) == GET_DEX(vict) && rand_number(1, 2) == 1)) /* if faster */ hit(ch, vict, TYPE_UNDEFINED); /* first */ @@ -150,7 +145,7 @@ ACMD(do_backstab) return; } /* Only piercing weapons allowed */ - if (GET_OBJ_VAL(weap, 3) != TYPE_PIERCE - TYPE_HIT) { + if (GET_OBJ_VAL(weap, 2) != TYPE_PIERCE - TYPE_HIT) { send_to_char(ch, "Only piercing weapons can be used for backstabbing.\r\n"); return; } @@ -187,14 +182,14 @@ ACMD(do_backstab) /* Keeping this logic really simple so it can be adjusted later if need be */ if (crit_success) { /* Simple crit = 2x damage */ - int base = dice(GET_OBJ_VAL(weap, 1), GET_OBJ_VAL(weap, 2)); + int base = dice(GET_OBJ_VAL(weap, 0), GET_OBJ_VAL(weap, 1)); int dmg = base + GET_ABILITY_MOD(GET_DEX(ch)); if (dmg < 1) dmg = 1; dmg *= 2; damage(ch, vict, dmg, SKILL_BACKSTAB); } else { /* Hit but not crit = 1.5x damage */ - int base = dice(GET_OBJ_VAL(weap, 1), GET_OBJ_VAL(weap, 2)); + int base = dice(GET_OBJ_VAL(weap, 0), GET_OBJ_VAL(weap, 1)); int dmg = base + GET_ABILITY_MOD(GET_DEX(ch)); if (dmg < 1) dmg = 1; dmg *= 1.5; diff --git a/src/act.wizard.c b/src/act.wizard.c index 794c3fa..f3943a0 100644 --- a/src/act.wizard.c +++ b/src/act.wizard.c @@ -3302,16 +3302,8 @@ ACMD(do_wizutil) GET_DEX(vict), GET_CON(vict), GET_CHA(vict)); break; case SCMD_PARDON: - if (!PLR_FLAGGED(vict, PLR_THIEF) && !PLR_FLAGGED(vict, PLR_KILLER)) { - send_to_char(ch, "Your victim is not flagged.\r\n"); - return; - } - REMOVE_BIT_AR(PLR_FLAGS(vict), PLR_THIEF); - REMOVE_BIT_AR(PLR_FLAGS(vict), PLR_KILLER); - send_to_char(ch, "Pardoned.\r\n"); - send_to_char(vict, "You have been pardoned by the Gods!\r\n"); - mudlog(BRF, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE, "(GC) %s pardoned by %s", GET_NAME(vict), GET_NAME(ch)); - break; + send_to_char(ch, "Criminal flags are currently disabled.\r\n"); + return; case SCMD_MUTE: result = PLR_TOG_CHK(vict, PLR_NOSHOUT); mudlog(BRF, MAX(LVL_GOD, GET_INVIS_LEV(ch)), TRUE, "(GC) Mute %s for %s by %s.", @@ -3783,7 +3775,7 @@ static struct set_struct { { "int", LVL_BUILDER, BOTH, NUMBER }, { "invis", LVL_GOD, PC, NUMBER }, { "invstart", LVL_BUILDER, PC, BINARY }, - { "killer", LVL_GOD, PC, BINARY }, + { "unused0", LVL_GOD, PC, BINARY }, { "level", LVL_GRGOD, BOTH, NUMBER }, /* 25 */ { "loadroom", LVL_BUILDER, PC, MISC }, { "mana", LVL_BUILDER, BOTH, NUMBER }, @@ -3808,7 +3800,7 @@ static struct set_struct { { "siteok", LVL_GOD, PC, BINARY }, { "skill", LVL_GOD, BOTH, NUMBER }, { "str", LVL_BUILDER, BOTH, NUMBER }, - { "thief", LVL_GOD, PC, BINARY }, + { "unused1", LVL_GOD, PC, BINARY }, { "thirst", LVL_BUILDER, BOTH, MISC }, /* 50 */ { "variable", LVL_GRGOD, PC, MISC }, { "weight", LVL_BUILDER, BOTH, NUMBER }, @@ -4024,9 +4016,9 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c case 21: /* invistart */ SET_OR_REMOVE(PLR_FLAGS(vict), PLR_INVSTART); break; - case 22: /* killer */ - SET_OR_REMOVE(PLR_FLAGS(vict), PLR_KILLER); - break; + case 22: /* unused0 (removed killer flag) */ + send_to_char(ch, "That flag is no longer in use.\r\n"); + return (0); case 23: /* level */ if ((!IS_NPC(vict) && value > GET_LEVEL(ch)) || value > LVL_IMPL) { send_to_char(ch, "You can't do that.\r\n"); @@ -4273,9 +4265,9 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c vict->real_abils.str = value; affect_total(vict); break; - case 47: /* thief */ - SET_OR_REMOVE(PLR_FLAGS(vict), PLR_THIEF); - break; + case 47: /* unused1 (removed thief flag) */ + send_to_char(ch, "That flag is no longer in use.\r\n"); + return (0); case 48: /* thirst */ if (!str_cmp(val_arg, "off")) { GET_COND(vict, THIRST) = -1; diff --git a/src/cedit.c b/src/cedit.c index 8feba55..af0bb5c 100644 --- a/src/cedit.c +++ b/src/cedit.c @@ -79,7 +79,6 @@ static void cedit_setup(struct descriptor_data *d) /* Copy the current configuration from the config_info to this one and copy * the game play options from the configuration info struct. */ - OLC_CONFIG(d)->play.pk_allowed = CONFIG_PK_ALLOWED; OLC_CONFIG(d)->play.pt_allowed = CONFIG_PT_ALLOWED; OLC_CONFIG(d)->play.level_can_shout = CONFIG_LEVEL_CAN_SHOUT; OLC_CONFIG(d)->play.tunnel_size = CONFIG_TUNNEL_SIZE; @@ -177,7 +176,6 @@ static void cedit_save_internally(struct descriptor_data *d) /* see if we need to reassign spec procs on rooms */ int reassign = (CONFIG_DTS_ARE_DUMPS != OLC_CONFIG(d)->play.dts_are_dumps); /* Copy the data back from the descriptor to the config_info structure. */ - CONFIG_PK_ALLOWED = OLC_CONFIG(d)->play.pk_allowed; CONFIG_PT_ALLOWED = OLC_CONFIG(d)->play.pt_allowed; CONFIG_LEVEL_CAN_SHOUT = OLC_CONFIG(d)->play.level_can_shout; CONFIG_TUNNEL_SIZE = OLC_CONFIG(d)->play.tunnel_size; @@ -326,8 +324,6 @@ int save_config( IDXTYPE nowhere ) "* [ Game Play Options ]\n" ); - fprintf(fl, "* Is player killing allowed on the mud?\n" - "pk_allowed = %d\n\n", CONFIG_PK_ALLOWED); fprintf(fl, "* Is player thieving allowed on the mud?\n" "pt_allowed = %d\n\n", CONFIG_PT_ALLOWED); fprintf(fl, "* What is the minimum level a player can shout/gossip/etc?\n" @@ -591,7 +587,6 @@ static void cedit_disp_game_play_options(struct descriptor_data *d) write_to_output(d, "\r\n\r\n" - "%sA%s) Player Killing Allowed : %s%s\r\n" "%sB%s) Player Thieving Allowed : %s%s\r\n" "%sC%s) Minimum Level To Shout : %s%d\r\n" "%sE%s) Tunnel Size : %s%d\r\n" @@ -617,7 +612,6 @@ static void cedit_disp_game_play_options(struct descriptor_data *d) "%s8%s) Scripts on PC's : %s%s\r\n" "%sQ%s) Exit To The Main Menu\r\n" "Enter your choice : ", - grn, nrm, cyn, CHECK_VAR(OLC_CONFIG(d)->play.pk_allowed), grn, nrm, cyn, CHECK_VAR(OLC_CONFIG(d)->play.pt_allowed), grn, nrm, cyn, OLC_CONFIG(d)->play.level_can_shout, grn, nrm, cyn, OLC_CONFIG(d)->play.tunnel_size, @@ -844,11 +838,6 @@ void cedit_parse(struct descriptor_data *d, char *arg) case CEDIT_GAME_OPTIONS_MENU: switch (*arg) { - case 'a': - case 'A': - TOGGLE_VAR(OLC_CONFIG(d)->play.pk_allowed); - break; - case 'b': case 'B': TOGGLE_VAR(OLC_CONFIG(d)->play.pt_allowed); diff --git a/src/class.c b/src/class.c index 69da305..02d0719 100644 --- a/src/class.c +++ b/src/class.c @@ -234,6 +234,231 @@ void roll_real_abils(struct char_data *ch) ch->aff_abils = ch->real_abils; } +/* Per-class skill caps */ +#define DEFAULT_CLASS_SKILL_MAX 90 + +static int class_skill_maxes[NUM_CLASSES][MAX_SKILLS + 1]; +static bool class_skill_caps_ready = FALSE; + +static int clamp_skill_max(int max) +{ + if (max < 0) + return 0; + if (max > 100) + return 100; + return max; +} + +static void apply_class_skill(int chclass, struct char_data *ch, int skill, int start, int max) +{ + if (ch) + SET_SKILL(ch, skill, start); + if (chclass >= 0 && chclass < NUM_CLASSES && skill >= 0 && skill <= MAX_SKILLS) + class_skill_maxes[chclass][skill] = clamp_skill_max(max); +} + +static void apply_class_skills(int chclass, struct char_data *ch) +{ + switch (chclass) { + + case CLASS_SORCEROR: + apply_class_skill(chclass, ch, SPELL_MAGIC_MISSILE, 5, 90); + apply_class_skill(chclass, ch, SPELL_DETECT_INVIS, 5, 90); + apply_class_skill(chclass, ch, SPELL_DETECT_MAGIC, 5, 90); + apply_class_skill(chclass, ch, SPELL_CHILL_TOUCH, 5, 90); + apply_class_skill(chclass, ch, SPELL_INFRAVISION, 5, 90); + apply_class_skill(chclass, ch, SPELL_INVISIBLE, 5, 90); + apply_class_skill(chclass, ch, SPELL_ARMOR, 5, 90); + apply_class_skill(chclass, ch, SPELL_BURNING_HANDS, 5, 90); + apply_class_skill(chclass, ch, SPELL_LOCATE_OBJECT, 5, 90); + apply_class_skill(chclass, ch, SPELL_STRENGTH, 5, 90); + apply_class_skill(chclass, ch, SPELL_SHOCKING_GRASP, 5, 90); + apply_class_skill(chclass, ch, SPELL_SLEEP, 5, 90); + apply_class_skill(chclass, ch, SPELL_LIGHTNING_BOLT, 5, 90); + apply_class_skill(chclass, ch, SPELL_BLINDNESS, 5, 90); + apply_class_skill(chclass, ch, SPELL_DETECT_POISON, 5, 90); + apply_class_skill(chclass, ch, SPELL_COLOR_SPRAY, 5, 90); + apply_class_skill(chclass, ch, SPELL_ENERGY_DRAIN, 5, 90); + apply_class_skill(chclass, ch, SPELL_CURSE, 5, 90); + apply_class_skill(chclass, ch, SPELL_POISON, 5, 90); + apply_class_skill(chclass, ch, SPELL_FIREBALL, 5, 90); + apply_class_skill(chclass, ch, SPELL_CHARM, 5, 90); + apply_class_skill(chclass, ch, SPELL_IDENTIFY, 5, 90); + apply_class_skill(chclass, ch, SPELL_FLY, 5, 90); + apply_class_skill(chclass, ch, SPELL_ENCHANT_WEAPON, 5, 90); + apply_class_skill(chclass, ch, SPELL_CLONE, 5, 90); + apply_class_skill(chclass, ch, SKILL_UNARMED, 5, 90); + apply_class_skill(chclass, ch, SKILL_ARCANA, 5, 90); + apply_class_skill(chclass, ch, SKILL_HISTORY, 5, 90); + apply_class_skill(chclass, ch, SKILL_INSIGHT, 5, 90); + break; + + case CLASS_CLERIC: + apply_class_skill(chclass, ch, SPELL_CURE_LIGHT, 5, 90); + apply_class_skill(chclass, ch, SPELL_ARMOR, 5, 90); + apply_class_skill(chclass, ch, SPELL_CREATE_FOOD, 5, 90); + apply_class_skill(chclass, ch, SPELL_CREATE_WATER, 5, 90); + apply_class_skill(chclass, ch, SPELL_DETECT_POISON, 5, 90); + apply_class_skill(chclass, ch, SPELL_DETECT_ALIGN, 5, 90); + apply_class_skill(chclass, ch, SPELL_CURE_BLIND, 5, 90); + apply_class_skill(chclass, ch, SPELL_BLESS, 5, 90); + apply_class_skill(chclass, ch, SPELL_DETECT_INVIS, 5, 90); + apply_class_skill(chclass, ch, SPELL_BLINDNESS, 5, 90); + apply_class_skill(chclass, ch, SPELL_INFRAVISION, 5, 90); + apply_class_skill(chclass, ch, SPELL_PROT_FROM_EVIL, 5, 90); + apply_class_skill(chclass, ch, SPELL_POISON, 5, 90); + apply_class_skill(chclass, ch, SPELL_GROUP_ARMOR, 5, 90); + apply_class_skill(chclass, ch, SPELL_CURE_CRITIC, 5, 90); + apply_class_skill(chclass, ch, SPELL_SUMMON, 5, 90); + apply_class_skill(chclass, ch, SPELL_REMOVE_POISON, 5, 90); + apply_class_skill(chclass, ch, SPELL_IDENTIFY, 5, 90); + apply_class_skill(chclass, ch, SPELL_WORD_OF_RECALL, 5, 90); + apply_class_skill(chclass, ch, SPELL_DARKNESS, 5, 90); + apply_class_skill(chclass, ch, SPELL_EARTHQUAKE, 5, 90); + apply_class_skill(chclass, ch, SPELL_DISPEL_EVIL, 5, 90); + apply_class_skill(chclass, ch, SPELL_DISPEL_GOOD, 5, 90); + apply_class_skill(chclass, ch, SPELL_SANCTUARY, 5, 90); + apply_class_skill(chclass, ch, SPELL_CALL_LIGHTNING, 5, 90); + apply_class_skill(chclass, ch, SPELL_HEAL, 5, 90); + apply_class_skill(chclass, ch, SPELL_CONTROL_WEATHER, 5, 90); + apply_class_skill(chclass, ch, SPELL_SENSE_LIFE, 5, 90); + apply_class_skill(chclass, ch, SPELL_HARM, 5, 90); + apply_class_skill(chclass, ch, SPELL_GROUP_HEAL, 5, 90); + apply_class_skill(chclass, ch, SPELL_REMOVE_CURSE, 5, 90); + apply_class_skill(chclass, ch, SKILL_SHIELD_USE, 5, 90); + apply_class_skill(chclass, ch, SKILL_ACROBATICS, 5, 90); + apply_class_skill(chclass, ch, SKILL_ARCANA, 5, 90); + apply_class_skill(chclass, ch, SKILL_RELIGION, 5, 90); + break; + + case CLASS_ROGUE: + apply_class_skill(chclass, ch, SKILL_STEALTH, 5, 90); + apply_class_skill(chclass, ch, SKILL_TRACK, 5, 90); + apply_class_skill(chclass, ch, SKILL_BACKSTAB, 5, 90); + apply_class_skill(chclass, ch, SKILL_PICK_LOCK, 5, 90); + apply_class_skill(chclass, ch, SKILL_SLEIGHT_OF_HAND, 5, 90); + apply_class_skill(chclass, ch, SKILL_UNARMED, 5, 90); + apply_class_skill(chclass, ch, SKILL_SHIELD_USE, 5, 90); + apply_class_skill(chclass, ch, SKILL_PIERCING_WEAPONS, 5, 90); + apply_class_skill(chclass, ch, SKILL_PERCEPTION, 5, 90); + apply_class_skill(chclass, ch, SKILL_ACROBATICS, 5, 90); + apply_class_skill(chclass, ch, SKILL_DECEPTION, 5, 90); + apply_class_skill(chclass, ch, SKILL_INVESTIGATION, 5, 90); + break; + + case CLASS_FIGHTER: + apply_class_skill(chclass, ch, SKILL_KICK, 5, 90); + apply_class_skill(chclass, ch, SKILL_RESCUE, 5, 90); + apply_class_skill(chclass, ch, SKILL_BANDAGE, 5, 90); + apply_class_skill(chclass, ch, SKILL_BASH, 5, 90); + apply_class_skill(chclass, ch, SKILL_UNARMED, 5, 90); + apply_class_skill(chclass, ch, SKILL_SLASHING_WEAPONS, 5, 90); + apply_class_skill(chclass, ch, SKILL_PIERCING_WEAPONS, 5, 90); + apply_class_skill(chclass, ch, SKILL_BLUDGEONING_WEAPONS, 5, 90); + apply_class_skill(chclass, ch, SKILL_SHIELD_USE, 5, 90); + apply_class_skill(chclass, ch, SKILL_PERCEPTION, 5, 90); + apply_class_skill(chclass, ch, SKILL_ATHLETICS, 5, 90); + apply_class_skill(chclass, ch, SKILL_INTIMIDATION, 5, 90); + apply_class_skill(chclass, ch, SKILL_SURVIVAL, 5, 90); + break; + + case CLASS_BARBARIAN: + apply_class_skill(chclass, ch, SKILL_KICK, 5, 90); + apply_class_skill(chclass, ch, SKILL_RESCUE, 5, 90); + apply_class_skill(chclass, ch, SKILL_BANDAGE, 5, 90); + apply_class_skill(chclass, ch, SKILL_WHIRLWIND, 5, 90); + apply_class_skill(chclass, ch, SKILL_UNARMED, 5, 90); + apply_class_skill(chclass, ch, SKILL_PIERCING_WEAPONS, 5, 90); + apply_class_skill(chclass, ch, SKILL_BLUDGEONING_WEAPONS, 5, 90); + apply_class_skill(chclass, ch, SKILL_PERCEPTION, 5, 90); + apply_class_skill(chclass, ch, SKILL_ATHLETICS, 5, 90); + apply_class_skill(chclass, ch, SKILL_INTIMIDATION, 5, 90); + break; + + case CLASS_RANGER: + apply_class_skill(chclass, ch, SKILL_BANDAGE, 5, 90); + apply_class_skill(chclass, ch, SKILL_TRACK, 5, 90); + apply_class_skill(chclass, ch, SKILL_BASH, 5, 90); + apply_class_skill(chclass, ch, SKILL_SLEIGHT_OF_HAND, 5, 90); + apply_class_skill(chclass, ch, SKILL_UNARMED, 5, 90); + apply_class_skill(chclass, ch, SKILL_SLASHING_WEAPONS, 5, 90); + apply_class_skill(chclass, ch, SKILL_PIERCING_WEAPONS, 5, 90); + apply_class_skill(chclass, ch, SKILL_SHIELD_USE, 5, 90); + apply_class_skill(chclass, ch, SKILL_PERCEPTION, 5, 90); + apply_class_skill(chclass, ch, SKILL_NATURE, 5, 90); + apply_class_skill(chclass, ch, SKILL_ANIMAL_HANDLING, 5, 90); + apply_class_skill(chclass, ch, SKILL_SURVIVAL, 5, 90); + apply_class_skill(chclass, ch, SKILL_ATHLETICS, 5, 90); + apply_class_skill(chclass, ch, SKILL_PERSUASION, 5, 90); + apply_class_skill(chclass, ch, SKILL_STEALTH, 5, 90); + break; + + case CLASS_BARD: + apply_class_skill(chclass, ch, SPELL_ARMOR, 5, 90); + apply_class_skill(chclass, ch, SPELL_IDENTIFY, 5, 90); + apply_class_skill(chclass, ch, SKILL_BANDAGE, 5, 90); + apply_class_skill(chclass, ch, SKILL_TRACK, 5, 90); + apply_class_skill(chclass, ch, SKILL_PICK_LOCK, 5, 90); + apply_class_skill(chclass, ch, SKILL_SLEIGHT_OF_HAND, 5, 90); + apply_class_skill(chclass, ch, SKILL_UNARMED, 5, 90); + apply_class_skill(chclass, ch, SKILL_PIERCING_WEAPONS, 5, 90); + apply_class_skill(chclass, ch, SKILL_SHIELD_USE, 5, 90); + apply_class_skill(chclass, ch, SKILL_PERCEPTION, 5, 90); + apply_class_skill(chclass, ch, SKILL_ACROBATICS, 5, 90); + apply_class_skill(chclass, ch, SKILL_HISTORY, 5, 90); + apply_class_skill(chclass, ch, SKILL_INVESTIGATION, 5, 90); + apply_class_skill(chclass, ch, SKILL_SURVIVAL, 5, 90); + apply_class_skill(chclass, ch, SKILL_STEALTH, 5, 90); + break; + + case CLASS_DRUID: + apply_class_skill(chclass, ch, SPELL_DETECT_INVIS, 5, 90); + apply_class_skill(chclass, ch, SPELL_DETECT_MAGIC, 5, 90); + apply_class_skill(chclass, ch, SPELL_LOCATE_OBJECT, 5, 90); + apply_class_skill(chclass, ch, SKILL_BANDAGE, 5, 90); + apply_class_skill(chclass, ch, SKILL_TRACK, 5, 90); + apply_class_skill(chclass, ch, SKILL_UNARMED, 5, 90); + apply_class_skill(chclass, ch, SKILL_PIERCING_WEAPONS, 5, 90); + apply_class_skill(chclass, ch, SKILL_SHIELD_USE, 5, 90); + apply_class_skill(chclass, ch, SKILL_PERCEPTION, 5, 90); + apply_class_skill(chclass, ch, SKILL_ACROBATICS, 5, 90); + apply_class_skill(chclass, ch, SKILL_ARCANA, 5, 90); + apply_class_skill(chclass, ch, SKILL_HISTORY, 5, 90); + apply_class_skill(chclass, ch, SKILL_INSIGHT, 5, 90); + apply_class_skill(chclass, ch, SKILL_INVESTIGATION, 5, 90); + apply_class_skill(chclass, ch, SKILL_PERSUASION, 5, 90); + apply_class_skill(chclass, ch, SKILL_RELIGION, 5, 90); + apply_class_skill(chclass, ch, SKILL_SURVIVAL, 5, 90); + break; + } +} + +void init_class_skill_caps(void) +{ + int chclass, skill; + + for (chclass = 0; chclass < NUM_CLASSES; chclass++) { + for (skill = 0; skill <= MAX_SKILLS; skill++) + class_skill_maxes[chclass][skill] = DEFAULT_CLASS_SKILL_MAX; + } + + for (chclass = 0; chclass < NUM_CLASSES; chclass++) + apply_class_skills(chclass, NULL); + + class_skill_caps_ready = TRUE; +} + +int class_skill_max(int chclass, int skillnum) +{ + if (!class_skill_caps_ready) + return DEFAULT_CLASS_SKILL_MAX; + if (chclass < 0 || chclass >= NUM_CLASSES) + return DEFAULT_CLASS_SKILL_MAX; + if (skillnum < 0 || skillnum > MAX_SKILLS) + return DEFAULT_CLASS_SKILL_MAX; + return class_skill_maxes[chclass][skillnum]; +} + void grant_class_skills(struct char_data *ch, bool reset) { int i; @@ -248,179 +473,7 @@ void grant_class_skills(struct char_data *ch, bool reset) if (GET_CLASS(ch) < CLASS_SORCEROR || GET_CLASS(ch) >= NUM_CLASSES) return; - switch (GET_CLASS(ch)) { - - case CLASS_SORCEROR: - SET_SKILL(ch, SPELL_MAGIC_MISSILE, 5); - SET_SKILL(ch, SPELL_DETECT_INVIS, 5); - SET_SKILL(ch, SPELL_DETECT_MAGIC, 5); - SET_SKILL(ch, SPELL_CHILL_TOUCH, 5); - SET_SKILL(ch, SPELL_INFRAVISION, 5); - SET_SKILL(ch, SPELL_INVISIBLE, 5); - SET_SKILL(ch, SPELL_ARMOR, 5); - SET_SKILL(ch, SPELL_BURNING_HANDS, 5); - SET_SKILL(ch, SPELL_LOCATE_OBJECT, 5); - SET_SKILL(ch, SPELL_STRENGTH, 5); - SET_SKILL(ch, SPELL_SHOCKING_GRASP, 5); - SET_SKILL(ch, SPELL_SLEEP, 5); - SET_SKILL(ch, SPELL_LIGHTNING_BOLT, 5); - SET_SKILL(ch, SPELL_BLINDNESS, 5); - SET_SKILL(ch, SPELL_DETECT_POISON, 5); - SET_SKILL(ch, SPELL_COLOR_SPRAY, 5); - SET_SKILL(ch, SPELL_ENERGY_DRAIN, 5); - SET_SKILL(ch, SPELL_CURSE, 5); - SET_SKILL(ch, SPELL_POISON, 5); - SET_SKILL(ch, SPELL_FIREBALL, 5); - SET_SKILL(ch, SPELL_CHARM, 5); - SET_SKILL(ch, SPELL_IDENTIFY, 5); - SET_SKILL(ch, SPELL_FLY, 5); - SET_SKILL(ch, SPELL_ENCHANT_WEAPON, 5); - SET_SKILL(ch, SPELL_CLONE, 5); - SET_SKILL(ch, SKILL_UNARMED, 5); - SET_SKILL(ch, SKILL_ARCANA, 5); - SET_SKILL(ch, SKILL_HISTORY, 5); - SET_SKILL(ch, SKILL_INSIGHT, 5); - break; - - case CLASS_CLERIC: - SET_SKILL(ch, SPELL_CURE_LIGHT, 5); - SET_SKILL(ch, SPELL_ARMOR, 5); - SET_SKILL(ch, SPELL_CREATE_FOOD, 5); - SET_SKILL(ch, SPELL_CREATE_WATER, 5); - SET_SKILL(ch, SPELL_DETECT_POISON, 5); - SET_SKILL(ch, SPELL_DETECT_ALIGN, 5); - SET_SKILL(ch, SPELL_CURE_BLIND, 5); - SET_SKILL(ch, SPELL_BLESS, 5); - SET_SKILL(ch, SPELL_DETECT_INVIS, 5); - SET_SKILL(ch, SPELL_BLINDNESS, 5); - SET_SKILL(ch, SPELL_INFRAVISION, 5); - SET_SKILL(ch, SPELL_PROT_FROM_EVIL, 5); - SET_SKILL(ch, SPELL_POISON, 5); - SET_SKILL(ch, SPELL_GROUP_ARMOR, 5); - SET_SKILL(ch, SPELL_CURE_CRITIC, 5); - SET_SKILL(ch, SPELL_SUMMON, 5); - SET_SKILL(ch, SPELL_REMOVE_POISON, 5); - SET_SKILL(ch, SPELL_IDENTIFY, 5); - SET_SKILL(ch, SPELL_WORD_OF_RECALL, 5); - SET_SKILL(ch, SPELL_DARKNESS, 5); - SET_SKILL(ch, SPELL_EARTHQUAKE, 5); - SET_SKILL(ch, SPELL_DISPEL_EVIL, 5); - SET_SKILL(ch, SPELL_DISPEL_GOOD, 5); - SET_SKILL(ch, SPELL_SANCTUARY, 5); - SET_SKILL(ch, SPELL_CALL_LIGHTNING, 5); - SET_SKILL(ch, SPELL_HEAL, 5); - SET_SKILL(ch, SPELL_CONTROL_WEATHER, 5); - SET_SKILL(ch, SPELL_SENSE_LIFE, 5); - SET_SKILL(ch, SPELL_HARM, 5); - SET_SKILL(ch, SPELL_GROUP_HEAL, 5); - SET_SKILL(ch, SPELL_REMOVE_CURSE, 5); - SET_SKILL(ch, SKILL_SHIELD_USE, 5); - SET_SKILL(ch, SKILL_ACROBATICS, 5); - SET_SKILL(ch, SKILL_ARCANA, 5); - SET_SKILL(ch, SKILL_RELIGION, 5); - break; - - case CLASS_ROGUE: - SET_SKILL(ch, SKILL_STEALTH, 5); - SET_SKILL(ch, SKILL_TRACK, 5); - SET_SKILL(ch, SKILL_BACKSTAB, 5); - SET_SKILL(ch, SKILL_PICK_LOCK, 5); - SET_SKILL(ch, SKILL_SLEIGHT_OF_HAND, 5); - SET_SKILL(ch, SKILL_UNARMED, 5); - SET_SKILL(ch, SKILL_SHIELD_USE, 5); - SET_SKILL(ch, SKILL_PIERCING_WEAPONS, 5); - SET_SKILL(ch, SKILL_PERCEPTION, 5); - SET_SKILL(ch, SKILL_ACROBATICS, 5); - SET_SKILL(ch, SKILL_DECEPTION, 5); - SET_SKILL(ch, SKILL_INVESTIGATION, 5); - break; - - case CLASS_FIGHTER: - SET_SKILL(ch, SKILL_KICK, 5); - SET_SKILL(ch, SKILL_RESCUE, 5); - SET_SKILL(ch, SKILL_BANDAGE, 5); - SET_SKILL(ch, SKILL_BASH, 5); - SET_SKILL(ch, SKILL_UNARMED, 5); - SET_SKILL(ch, SKILL_SLASHING_WEAPONS, 5); - SET_SKILL(ch, SKILL_PIERCING_WEAPONS, 5); - SET_SKILL(ch, SKILL_BLUDGEONING_WEAPONS, 5); - SET_SKILL(ch, SKILL_SHIELD_USE, 5); - SET_SKILL(ch, SKILL_PERCEPTION, 5); - SET_SKILL(ch, SKILL_ATHLETICS, 5); - SET_SKILL(ch, SKILL_INTIMIDATION, 5); - SET_SKILL(ch, SKILL_SURVIVAL, 5); - break; - - case CLASS_BARBARIAN: - SET_SKILL(ch, SKILL_KICK, 5); - SET_SKILL(ch, SKILL_RESCUE, 5); - SET_SKILL(ch, SKILL_BANDAGE, 5); - SET_SKILL(ch, SKILL_WHIRLWIND, 5); - SET_SKILL(ch, SKILL_UNARMED, 5); - SET_SKILL(ch, SKILL_PIERCING_WEAPONS, 5); - SET_SKILL(ch, SKILL_BLUDGEONING_WEAPONS, 5); - SET_SKILL(ch, SKILL_PERCEPTION, 5); - SET_SKILL(ch, SKILL_ATHLETICS, 5); - SET_SKILL(ch, SKILL_INTIMIDATION, 5); - break; - - case CLASS_RANGER: - SET_SKILL(ch, SKILL_BANDAGE, 5); - SET_SKILL(ch, SKILL_TRACK, 5); - SET_SKILL(ch, SKILL_BASH, 5); - SET_SKILL(ch, SKILL_SLEIGHT_OF_HAND, 5); - SET_SKILL(ch, SKILL_UNARMED, 5); - SET_SKILL(ch, SKILL_SLASHING_WEAPONS, 5); - SET_SKILL(ch, SKILL_PIERCING_WEAPONS, 5); - SET_SKILL(ch, SKILL_SHIELD_USE, 5); - SET_SKILL(ch, SKILL_PERCEPTION, 5); - SET_SKILL(ch, SKILL_NATURE, 5); - SET_SKILL(ch, SKILL_ANIMAL_HANDLING, 5); - SET_SKILL(ch, SKILL_SURVIVAL, 5); - SET_SKILL(ch, SKILL_ATHLETICS, 5); - SET_SKILL(ch, SKILL_PERSUASION, 5); - SET_SKILL(ch, SKILL_STEALTH, 5); - break; - - case CLASS_BARD: - SET_SKILL(ch, SPELL_ARMOR, 5); - SET_SKILL(ch, SPELL_IDENTIFY, 5); - SET_SKILL(ch, SKILL_BANDAGE, 5); - SET_SKILL(ch, SKILL_TRACK, 5); - SET_SKILL(ch, SKILL_PICK_LOCK, 5); - SET_SKILL(ch, SKILL_SLEIGHT_OF_HAND, 5); - SET_SKILL(ch, SKILL_UNARMED, 5); - SET_SKILL(ch, SKILL_PIERCING_WEAPONS, 5); - SET_SKILL(ch, SKILL_SHIELD_USE, 5); - SET_SKILL(ch, SKILL_PERCEPTION, 5); - SET_SKILL(ch, SKILL_ACROBATICS, 5); - SET_SKILL(ch, SKILL_HISTORY, 5); - SET_SKILL(ch, SKILL_INVESTIGATION, 5); - SET_SKILL(ch, SKILL_SURVIVAL, 5); - SET_SKILL(ch, SKILL_STEALTH, 5); - break; - - case CLASS_DRUID: - SET_SKILL(ch, SPELL_DETECT_INVIS, 5); - SET_SKILL(ch, SPELL_DETECT_MAGIC, 5); - SET_SKILL(ch, SPELL_LOCATE_OBJECT, 5); - SET_SKILL(ch, SKILL_BANDAGE, 5); - SET_SKILL(ch, SKILL_TRACK, 5); - SET_SKILL(ch, SKILL_UNARMED, 5); - SET_SKILL(ch, SKILL_PIERCING_WEAPONS, 5); - SET_SKILL(ch, SKILL_SHIELD_USE, 5); - SET_SKILL(ch, SKILL_PERCEPTION, 5); - SET_SKILL(ch, SKILL_ACROBATICS, 5); - SET_SKILL(ch, SKILL_ARCANA, 5); - SET_SKILL(ch, SKILL_HISTORY, 5); - SET_SKILL(ch, SKILL_INSIGHT, 5); - SET_SKILL(ch, SKILL_INVESTIGATION, 5); - SET_SKILL(ch, SKILL_PERSUASION, 5); - SET_SKILL(ch, SKILL_RELIGION, 5); - SET_SKILL(ch, SKILL_SURVIVAL, 5); - break; - } - + apply_class_skills(GET_CLASS(ch), ch); } /* Some initializations for characters, including initial skills */ diff --git a/src/class.h b/src/class.h index 0502604..6c82a38 100644 --- a/src/class.h +++ b/src/class.h @@ -23,6 +23,8 @@ int parse_class(char arg); void roll_real_abils(struct char_data *ch); bool has_save_proficiency(int class_num, int ability); void grant_class_skills(struct char_data *ch, bool reset); +void init_class_skill_caps(void); +int class_skill_max(int chclass, int skillnum); /* Global variables */ diff --git a/src/config.c b/src/config.c index c9f8967..40dc346 100644 --- a/src/config.c +++ b/src/config.c @@ -39,13 +39,6 @@ /* Can Scripts be attached to players? */ int script_players = NO; -/* pk_allowed sets the tone of the entire game. If pk_allowed is set to NO, - * then players will not be allowed to kill, summon, charm, or sleep other - * players, as well as a variety of other "asshole player" protections. However, - * if you decide you want to have an all-out knock-down drag-out PK Mud, just - * set pk_allowed to YES - and anything goes. */ -int pk_allowed = NO; - /* Is playerthieving allowed? */ int pt_allowed = NO; diff --git a/src/config.h b/src/config.h index 0d69ad8..d7a65a0 100644 --- a/src/config.h +++ b/src/config.h @@ -14,7 +14,6 @@ #define _CONFIG_H_ /* Global variable declarations, all settable by cedit */ -extern int pk_allowed; extern int script_players; extern int pt_allowed; extern int level_can_shout; diff --git a/src/constants.c b/src/constants.c index 0bc0ac7..500c29c 100644 --- a/src/constants.c +++ b/src/constants.c @@ -189,8 +189,8 @@ const char *position_types[] = { * @pre Must be in the same order as the defines. * Must end array with a single newline. */ const char *player_bits[] = { - "KILLER", - "THIEF", + "UNUSED0", + "UNUSED1", "FROZEN", "DONTSET", "WRITING", diff --git a/src/db.c b/src/db.c index 7cf3153..8f76516 100644 --- a/src/db.c +++ b/src/db.c @@ -30,6 +30,7 @@ #include "genolc.h" #include "genobj.h" /* for free_object_strings */ #include "config.h" /* for the default config values. */ +#include "class.h" #include "fight.h" #include "modify.h" #include "shop.h" @@ -748,6 +749,7 @@ void boot_db(void) log("Assigning spell and skill levels."); init_spell_levels(); + init_class_skill_caps(); log("Sorting command list and spells."); sort_commands(); @@ -4128,7 +4130,6 @@ static void load_default_config( void ) /* This function is called only once, at boot-time. We assume config_info is * empty. -Welcor */ /* Game play options. */ - CONFIG_PK_ALLOWED = pk_allowed; CONFIG_PT_ALLOWED = pt_allowed; CONFIG_LEVEL_CAN_SHOUT = level_can_shout; CONFIG_TUNNEL_SIZE = tunnel_size; @@ -4388,9 +4389,7 @@ void load_config( void ) break; case 'p': - if (!str_cmp(tag, "pk_allowed")) - CONFIG_PK_ALLOWED = num; - else if (!str_cmp(tag, "protocol_negotiation")) + if (!str_cmp(tag, "protocol_negotiation")) CONFIG_PROTOCOL_NEGOTIATION = num; else if (!str_cmp(tag, "pt_allowed")) CONFIG_PT_ALLOWED = num; diff --git a/src/dg_variables.c b/src/dg_variables.c index ef7bff4..6ce2445 100644 --- a/src/dg_variables.c +++ b/src/dg_variables.c @@ -801,30 +801,6 @@ void find_replacement(void *go, struct script_data *sc, trig_data *trig, } } } - else if (!str_cmp(field, "is_killer")) { - if (subfield && *subfield) { - if (!str_cmp("on", subfield)) - SET_BIT_AR(PLR_FLAGS(c), PLR_KILLER); - else if (!str_cmp("off", subfield)) - REMOVE_BIT_AR(PLR_FLAGS(c), PLR_KILLER); - } - if (PLR_FLAGGED(c, PLR_KILLER)) - strcpy(str, "1"); - else - strcpy(str, "0"); - } - else if (!str_cmp(field, "is_thief")) { - if (subfield && *subfield) { - if (!str_cmp("on", subfield)) - SET_BIT_AR(PLR_FLAGS(c), PLR_THIEF); - else if (!str_cmp("off", subfield)) - REMOVE_BIT_AR(PLR_FLAGS(c), PLR_THIEF); - } - if (PLR_FLAGGED(c, PLR_THIEF)) - strcpy(str, "1"); - else - strcpy(str, "0"); - } break; case 'l': if (!str_cmp(field, "level")) { diff --git a/src/fight.c b/src/fight.c index ca6632b..0f9b384 100644 --- a/src/fight.c +++ b/src/fight.c @@ -72,8 +72,8 @@ static int roll_damage(struct char_data *ch, struct char_data *victim, int dam = 0; if (wielded && GET_OBJ_TYPE(wielded) == ITEM_WEAPON) { - int ndice = GET_OBJ_VAL(wielded, 1); /* #dice */ - int sdice = GET_OBJ_VAL(wielded, 2); /* sides */ + int ndice = GET_OBJ_VAL(wielded, 0); /* #dice */ + int sdice = GET_OBJ_VAL(wielded, 1); /* sides */ dam = dice(ndice, sdice); dam += GET_ABILITY_MOD(GET_STR(ch)); /* STR adds to weapon damage */ } else { @@ -92,7 +92,7 @@ static int weapon_family_skill_num(struct char_data *ch, struct obj_data *wielde if (!wielded || GET_OBJ_TYPE(wielded) != ITEM_WEAPON) return SKILL_UNARMED; - /* NOTE: w_type here is TYPE_HIT + GET_OBJ_VAL(wielded, 3) or mob attack type + TYPE_HIT. + /* NOTE: w_type here is TYPE_HIT + GET_OBJ_VAL(wielded, 2) or mob attack type + TYPE_HIT. Adjust the cases below to match your game's TYPE_* values. */ switch (w_type) { /* --- Piercing family --- */ @@ -176,20 +176,6 @@ void update_pos(struct char_data *victim) GET_POS(victim) = POS_STUNNED; } -void check_killer(struct char_data *ch, struct char_data *vict) -{ - if (PLR_FLAGGED(vict, PLR_KILLER) || PLR_FLAGGED(vict, PLR_THIEF)) - return; - if (PLR_FLAGGED(ch, PLR_KILLER) || IS_NPC(ch) || IS_NPC(vict) || ch == vict) - return; - - SET_BIT_AR(PLR_FLAGS(ch), PLR_KILLER); - send_to_char(ch, "If you want to be a PLAYER KILLER, so be it...\r\n"); - mudlog(BRF, MAX(LVL_IMMORT, MAX(GET_INVIS_LEV(ch), GET_INVIS_LEV(vict))), - TRUE, "PC Killer bit set on %s for initiating attack on %s at %s.", - GET_NAME(ch), GET_NAME(vict), world[IN_ROOM(vict)].name); -} - /* start one char fighting another (yes, it is horrible, I know... ) */ void set_fighting(struct char_data *ch, struct char_data *vict) { @@ -210,8 +196,6 @@ void set_fighting(struct char_data *ch, struct char_data *vict) FIGHTING(ch) = vict; GET_POS(ch) = POS_FIGHTING; - if (!CONFIG_PK_ALLOWED) - check_killer(ch, vict); } /* remove a char from the list of fighting chars */ @@ -363,8 +347,6 @@ struct char_data *i; void die(struct char_data * ch, struct char_data * killer) { if (!IS_NPC(ch)) { - REMOVE_BIT_AR(PLR_FLAGS(ch), PLR_KILLER); - REMOVE_BIT_AR(PLR_FLAGS(ch), PLR_THIEF); } raw_kill(ch, killer); } @@ -634,6 +616,7 @@ int damage(struct char_data *ch, struct char_data *victim, int dam, int attackty char local_buf[256]; struct char_data *tmp_char; struct obj_data *corpse_obj; + int prev_hit = 0; if (GET_POS(victim) <= POS_DEAD) { /* This is "normal"-ish now with delayed extraction. -gg 3/15/2001 */ @@ -659,8 +642,8 @@ int damage(struct char_data *ch, struct char_data *victim, int dam, int attackty return (0); } - /* You can't damage an immortal! */ - if (!IS_NPC(victim) && ((GET_LEVEL(victim) >= LVL_IMMORT) && PRF_FLAGGED(victim, PRF_NOHASSLE))) + /* Immortals cannot be damaged. */ + if (!IS_NPC(victim) && GET_REAL_LEVEL(victim) >= LVL_IMMORT) dam = 0; dam = damage_mtrigger(ch, victim, dam, attacktype); @@ -694,14 +677,9 @@ int damage(struct char_data *ch, struct char_data *victim, int dam, int attackty dam /= 2; /* Check for PK if this is not a PK MUD */ - if (!CONFIG_PK_ALLOWED) { - check_killer(ch, victim); - if (PLR_FLAGGED(ch, PLR_KILLER) && (ch != victim)) - dam = 0; - } - /* Set the maximum damage per round and subtract the hit points */ dam = MAX(MIN(dam, 100), 0); + prev_hit = GET_HIT(victim); GET_HIT(victim) -= dam; update_pos(victim); @@ -826,16 +804,30 @@ int damage(struct char_data *ch, struct char_data *victim, int dam, int attackty void hit(struct char_data *ch, struct char_data *victim, int type) { struct obj_data *wielded = GET_EQ(ch, WEAR_WIELD); + bool wielded_weapon = (wielded && GET_OBJ_TYPE(wielded) == ITEM_WEAPON); struct obj_data *shield = GET_EQ(victim, WEAR_SHIELD); int w_type, d20, attack_mod = 0, target_ac, dam = 0; bool hit_success = FALSE; + bool attacker_immortal, victim_immortal; + bool attacker_is_player, victim_is_player; + int unarmed_die_size = 0; + int unarmed_prof_bonus = 0; + int unarmed_str_mod = 0; /* Basic sanity */ if (!ch || !victim) return; + attacker_is_player = (ch->desc != NULL); + victim_is_player = (victim->desc != NULL); + + attacker_immortal = (attacker_is_player && + (GET_REAL_LEVEL(ch) >= LVL_IMMORT || PRF_FLAGGED(ch, PRF_NOHASSLE))); + victim_immortal = (victim_is_player && + (GET_REAL_LEVEL(victim) >= LVL_IMMORT || PRF_FLAGGED(victim, PRF_NOHASSLE))); + /* Determine attack message type exactly like stock code */ - if (wielded && GET_OBJ_TYPE(wielded) == ITEM_WEAPON) - w_type = GET_OBJ_VAL(wielded, 3) + TYPE_HIT; + if (wielded_weapon) + w_type = GET_OBJ_VAL(wielded, 2) + TYPE_HIT; else { if (IS_NPC(ch) && ch->mob_specials.attack_type != 0) w_type = ch->mob_specials.attack_type + TYPE_HIT; @@ -843,6 +835,39 @@ void hit(struct char_data *ch, struct char_data *victim, int type) w_type = TYPE_HIT; } /* matches stock message mapping */ + if (victim_immortal) { + damage(ch, victim, 0, w_type); + return; + } + + if (attacker_immortal) { + if (wielded_weapon) { + int ndice = GET_OBJ_VAL(wielded, 0); + int sdice = GET_OBJ_VAL(wielded, 1); + dam = (ndice * sdice) + GET_ABILITY_MOD(GET_STR(ch)); + } else { + int prof_bonus = (!IS_NPC(ch)) ? GET_PROFICIENCY(GET_SKILL(ch, SKILL_UNARMED)) : 0; + int str_mod = GET_ABILITY_MOD(GET_STR(ch)); + int die_size; + + switch (prof_bonus) { + case 0: die_size = 4; break; /* untrained */ + case 1: die_size = 6; break; /* trained */ + case 2: die_size = 8; break; /* expert */ + default: die_size = 10; break; /* master or above */ + } + + if (IS_NPC(ch) && prof_bonus <= 0) { + prof_bonus = MIN(6, (GET_LEVEL(ch) / 4)); + } + + dam = die_size + str_mod + prof_bonus; + } + + damage(ch, victim, dam, w_type); + return; + } + /* Roll d20 */ d20 = rand_number(1, 20); @@ -859,7 +884,7 @@ void hit(struct char_data *ch, struct char_data *victim, int type) attack_mod += GET_PROFICIENCY(GET_SKILL(ch, skillnum)); /* --- UNARMED ATTACK HANDLING --- */ - if (!wielded) { + if (!wielded_weapon) { int prof_bonus = (!IS_NPC(ch)) ? GET_PROFICIENCY(GET_SKILL(ch, SKILL_UNARMED)) : 0; int str_mod = GET_ABILITY_MOD(GET_STR(ch)); int die_size; @@ -871,6 +896,7 @@ void hit(struct char_data *ch, struct char_data *victim, int type) case 2: die_size = 8; break; /* expert */ default: die_size = 10; break; /* master or above */ } + unarmed_die_size = die_size; /* NPC fallback scaling */ if (IS_NPC(ch) && prof_bonus <= 0) { @@ -879,9 +905,11 @@ void hit(struct char_data *ch, struct char_data *victim, int type) /* base damage roll for unarmed attacks */ dam = dice(1, die_size) + str_mod + prof_bonus; + unarmed_prof_bonus = prof_bonus; + unarmed_str_mod = str_mod; /* mark attack type for damage() messaging */ - w_type = SKILL_UNARMED + TYPE_HIT; + w_type = TYPE_HIT; } /* Weapon magic (cap +3) */ @@ -901,8 +929,9 @@ void hit(struct char_data *ch, struct char_data *victim, int type) /* Ascending AC target */ target_ac = compute_armor_class_asc(victim); - /* Nat 1/20, then normal resolution */ - if (d20 == 1) hit_success = FALSE; + /* Nat 1/20, then normal resolution (immortals always hit). */ + if (attacker_immortal) hit_success = TRUE; + else if (d20 == 1) hit_success = FALSE; else if (d20 == 20) hit_success = TRUE; else hit_success = ((d20 + attack_mod) >= target_ac); @@ -912,13 +941,22 @@ void hit(struct char_data *ch, struct char_data *victim, int type) * If we are unarmed, dam was already rolled above. * If wielding a weapon, roll normally. */ - if (wielded) + if (wielded_weapon) dam = roll_damage(ch, victim, wielded, w_type); + if (attacker_immortal) { + if (wielded_weapon) { + int ndice = GET_OBJ_VAL(wielded, 0); + int sdice = GET_OBJ_VAL(wielded, 1); + dam = (ndice * sdice) + GET_ABILITY_MOD(GET_STR(ch)); + } else if (unarmed_die_size > 0) { + dam = unarmed_die_size + unarmed_str_mod + unarmed_prof_bonus; + } + } /* --- SHIELD BLOCK CHECK --- * Only happens if an attack actually lands. */ - if (shield) { + if (shield && !attacker_immortal) { int def_prof = (!IS_NPC(victim)) ? GET_PROFICIENCY(GET_SKILL(victim, SKILL_SHIELD_USE)) : 0; int block_chance = def_prof * 10; /* 0–60% total chance to block an attack */ diff --git a/src/fight.h b/src/fight.h index e24bc16..865d1c2 100644 --- a/src/fight.h +++ b/src/fight.h @@ -22,7 +22,6 @@ struct attack_hit_type { /* Functions available in fight.c */ void appear(struct char_data *ch); -void check_killer(struct char_data *ch, struct char_data *vict); int compute_armor_class(struct char_data *ch); int damage(struct char_data *ch, struct char_data *victim, int dam, int attacktype); void death_cry(struct char_data *ch); diff --git a/src/limits.c b/src/limits.c index b9f42fd..69f594f 100644 --- a/src/limits.c +++ b/src/limits.c @@ -209,12 +209,13 @@ void run_autowiz(void) /* Requires: find_skill_num(), GET_WIS(), wis_app[], GET_SKILL(), SET_SKILL(), rand_number() * Cooldown: 1 hour - 5 * WIS bonus minutes (floored at 0) * Rolls: failure -> 1..20, success -> 1..100 - * Cap: 90% (change MIN(90, ...) if you want a different cap) + * Cap: per-class max (see class.c) */ void gain_skill(struct char_data *ch, char *skill, bool success) { int skill_num, base, roll, increase; int wisb, cd_seconds; + int cap; time_t now; if (IS_NPC(ch)) @@ -233,8 +234,11 @@ void gain_skill(struct char_data *ch, char *skill, bool success) } base = GET_SKILL(ch, skill_num); + cap = class_skill_max(GET_CLASS(ch), skill_num); + if (cap <= 0) + return; /* If already capped, bail early (and don’t start cooldown) */ - if (base >= 90) + if (base >= cap) return; /* Wisdom bonus from wis_app[] (constants.c). Higher = better learning & shorter cooldown. */ @@ -246,7 +250,7 @@ void gain_skill(struct char_data *ch, char *skill, bool success) /* Old 1..400 with (400 - wisb*4) ⇒ scaled: (100 - wisb) */ if (roll >= (100 - wisb)) { increase = base + 1; - SET_SKILL(ch, skill_num, MIN(90, increase)); + SET_SKILL(ch, skill_num, MIN(cap, increase)); /* Cooldown only when an increase actually happens */ cd_seconds = 3600 - (wisb * 5 * 60); /* 1 hour - 5 * WIS minutes */ @@ -259,7 +263,7 @@ void gain_skill(struct char_data *ch, char *skill, bool success) /* Old 1..100 with (100 - wisb) ⇒ scaled: (20 - wisb) */ if (roll >= (20 - wisb)) { increase = base + 1; - SET_SKILL(ch, skill_num, MIN(90, increase)); + SET_SKILL(ch, skill_num, MIN(cap, increase)); /* Cooldown only when an increase actually happens */ cd_seconds = 3600 - (wisb * 5 * 60); /* 1 hour - 5 * WIS minutes */ diff --git a/src/magic.c b/src/magic.c index 1cb8fb6..83cd977 100644 --- a/src/magic.c +++ b/src/magic.c @@ -189,6 +189,7 @@ int mag_damage(int level, struct char_data *ch, struct char_data *victim, int spellnum, int savetype) { int dam = 0; + int save_dc; if (victim == NULL || ch == NULL) return (0); @@ -279,8 +280,12 @@ int mag_damage(int level, struct char_data *ch, struct char_data *victim, } /* switch(spellnum) */ + save_dc = compute_save_dc(ch, level, spellnum); + if (!IS_NPC(ch) && GET_REAL_LEVEL(ch) >= LVL_IMMORT) + save_dc = 1000; + /* divide damage by two if victim makes his saving throw */ - if (mag_savingthrow(victim, savetype, compute_save_dc(ch, level, spellnum))) + if (mag_savingthrow(victim, savetype, save_dc)) dam /= 2; /* and finally, inflict the damage */ @@ -307,6 +312,8 @@ void mag_affects(int level, struct char_data *ch, struct char_data *victim, return; save_dc = compute_save_dc(ch, level, spellnum); + if (!IS_NPC(ch) && GET_REAL_LEVEL(ch) >= LVL_IMMORT) + save_dc = 1000; for (i = 0; i < MAX_SPELL_AFFECTS; i++) { new_affect(&(af[i])); @@ -470,8 +477,6 @@ void mag_affects(int level, struct char_data *ch, struct char_data *victim, break; case SPELL_SLEEP: - if (!CONFIG_PK_ALLOWED && !IS_NPC(ch) && !IS_NPC(victim)) - return; if (MOB_FLAGGED(victim, MOB_NOSLEEP)) return; if (mag_savingthrow(victim, ABIL_WIS, save_dc)) @@ -645,8 +650,6 @@ void mag_areas(int level, struct char_data *ch, int spellnum, int savetype) continue; if (!IS_NPC(tch) && GET_LEVEL(tch) >= LVL_IMMORT) continue; - if (!CONFIG_PK_ALLOWED && !IS_NPC(ch) && !IS_NPC(tch)) - continue; if (!IS_NPC(ch) && IS_NPC(tch) && AFF_FLAGGED(tch, AFF_CHARM)) continue; if (!IS_NPC(tch) && spell_info[spellnum].violent && GROUP(tch) && GROUP(ch) && GROUP(ch) == GROUP(tch)) diff --git a/src/spec_procs.c b/src/spec_procs.c index 5b29ad1..7f3d80e 100644 --- a/src/spec_procs.c +++ b/src/spec_procs.c @@ -488,18 +488,6 @@ SPECIAL(cityguard) for (tch = world[IN_ROOM(ch)].people; tch; tch = tch->next_in_room) { if (!CAN_SEE(ch, tch)) continue; - if (!IS_NPC(tch) && PLR_FLAGGED(tch, PLR_KILLER)) { - act("$n screams 'HEY!!! You're one of those PLAYER KILLERS!!!!!!'", FALSE, ch, 0, 0, TO_ROOM); - hit(ch, tch, TYPE_UNDEFINED); - return (TRUE); - } - - if (!IS_NPC(tch) && PLR_FLAGGED(tch, PLR_THIEF)) { - act("$n screams 'HEY!!! You're one of those PLAYER THIEVES!!!!!!'", FALSE, ch, 0, 0, TO_ROOM); - hit(ch, tch, TYPE_UNDEFINED); - return (TRUE); - } - if (FIGHTING(tch) && GET_ALIGNMENT(tch) < max_evil && (IS_NPC(tch) || IS_NPC(FIGHTING(tch)))) { max_evil = GET_ALIGNMENT(tch); evil = tch; diff --git a/src/spells.c b/src/spells.c index 3c46e29..30b5aa2 100644 --- a/src/spells.c +++ b/src/spells.c @@ -124,28 +124,6 @@ ASPELL(spell_summon) return; } - if (!CONFIG_PK_ALLOWED) { - if (MOB_FLAGGED(victim, MOB_AGGRESSIVE)) { - act("As the words escape your lips and $N travels\r\n" - "through time and space towards you, you realize that $E is\r\n" - "aggressive and might harm you, so you wisely send $M back.", - FALSE, ch, 0, victim, TO_CHAR); - return; - } - if (!IS_NPC(victim) && !PRF_FLAGGED(victim, PRF_SUMMONABLE) && - !PLR_FLAGGED(victim, PLR_KILLER)) { - send_to_char(victim, "%s just tried to summon you to: %s.\r\n" - "This failed because you have summon protection on.\r\n" - "Type NOSUMMON to allow other players to summon you.\r\n", - GET_NAME(ch), world[IN_ROOM(ch)].name); - - send_to_char(ch, "You failed because %s has summon protection on.\r\n", GET_NAME(victim)); - mudlog(BRF, MAX(LVL_IMMORT, MAX(GET_INVIS_LEV(ch), GET_INVIS_LEV(victim))), TRUE, - "%s failed summoning %s to %s.", GET_NAME(ch), GET_NAME(victim), world[IN_ROOM(ch)].name); - return; - } - } - if (MOB_FLAGGED(victim, MOB_NOSUMMON) || (IS_NPC(victim) && mag_savingthrow(victim, SAVING_CHA, save_dc))) { send_to_char(ch, "%s", SUMMON_FAIL); @@ -272,8 +250,6 @@ ASPELL(spell_charm) else if (AFF_FLAGGED(victim, AFF_CHARM) || level < GET_LEVEL(victim)) send_to_char(ch, "You fail.\r\n"); /* player charming another player - no legal reason for this */ - else if (!CONFIG_PK_ALLOWED && !IS_NPC(victim)) - send_to_char(ch, "You fail - shouldn't be doing it anyway.\r\n"); else if (circle_follow(victim, ch)) send_to_char(ch, "Sorry, following in circles is not allowed.\r\n"); else if (mag_savingthrow(victim, SAVING_WIS, save_dc)) diff --git a/src/structs.h b/src/structs.h index 47ed124..03eca5b 100644 --- a/src/structs.h +++ b/src/structs.h @@ -193,8 +193,8 @@ #define NUM_POSITIONS 9 /* Player flags: used by char_data.char_specials.act */ -#define PLR_KILLER 0 /**< Player is a player-killer */ -#define PLR_THIEF 1 /**< Player is a player-thief */ +#define PLR_UNUSED0 0 /**< Reserved (unused) */ +#define PLR_UNUSED1 1 /**< Reserved (unused) */ #define PLR_FROZEN 2 /**< Player is frozen */ #define PLR_DONTSET 3 /**< Don't EVER set (ISNPC bit, set by mud) */ #define PLR_WRITING 4 /**< Player writing (board/mail/olc) */ @@ -1387,7 +1387,6 @@ struct forage_entry { * variables. */ struct game_data { - int pk_allowed; /**< Is player killing allowed? */ int pt_allowed; /**< Is player thieving allowed? */ int level_can_shout; /**< Level player must be to shout. */ int tunnel_size; /**< Number of people allowed in a tunnel.*/ diff --git a/src/utils.h b/src/utils.h index eb91d2d..faf2d40 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1021,7 +1021,6 @@ do \ #define CONFIG_CONFFILE config_info.CONFFILE /** Player killing allowed or not? */ -#define CONFIG_PK_ALLOWED config_info.play.pk_allowed /** Player thieving allowed or not? */ #define CONFIG_PT_ALLOWED config_info.play.pt_allowed /** What level to use the shout command? */ From 8018ed3fcf8a08d969fc359e0cd19efd89b00e32 Mon Sep 17 00:00:00 2001 From: kinther Date: Sun, 28 Dec 2025 16:56:57 -0800 Subject: [PATCH 03/40] Species update 1 --- lib/world/mob/1.mob | 57 +++--- src/act.wizard.c | 31 ++- src/class.c | 7 +- src/db.c | 6 + src/genmob.c | 4 + src/interpreter.c | 34 +++- src/medit.c | 75 +++++++- src/oasis.h | 59 +++--- src/pfdefaults.h | 1 + src/players.c | 10 +- src/species.c | 446 ++++++++++++++++++++++++++++++++++++++++++++ src/species.h | 29 +++ src/structs.h | 106 +++++++---- src/utils.h | 3 + 14 files changed, 773 insertions(+), 95 deletions(-) create mode 100644 src/species.c create mode 100644 src/species.h diff --git a/lib/world/mob/1.mob b/lib/world/mob/1.mob index 892c795..948687c 100644 --- a/lib/world/mob/1.mob +++ b/lib/world/mob/1.mob @@ -15,13 +15,14 @@ B + ~ 6218 0 0 0 0 0 0 0 0 E 1 3d20+40 8 8 1 Str: 16 Class: 3 -SaveStr: 3 +Species: 0 Skill 132 5 Skill 134 5 Skill 137 5 @@ -33,17 +34,17 @@ Skill 145 5 Skill 146 5 Skill 147 5 E -L 17 127 1 -L 16 117 1 -L 15 117 1 -L 11 111 1 -L 10 107 1 -L 9 124 1 -L 8 115 1 -L 7 108 1 -L 6 110 1 -L 5 131 1 L 3 118 1 +L 5 131 1 +L 6 110 1 +L 7 108 1 +L 8 115 1 +L 9 124 1 +L 10 107 1 +L 11 111 1 +L 15 117 1 +L 16 117 1 +L 17 127 1 #101 Sally~ slim lanky human soldier guard~ @@ -62,32 +63,38 @@ B + ~ 6218 0 0 0 0 0 0 0 0 E 1 3d20+40 8 8 2 +Class: 3 +Species: 0 Skill 132 5 Skill 134 5 Skill 137 5 +Skill 140 5 Skill 141 5 Skill 142 5 Skill 143 5 Skill 144 5 Skill 145 5 Skill 146 5 -Skill 147 5 +Skill 152 5 +Skill 156 5 +Skill 163 5 E -L 3 118 1 -L 5 131 1 -L 6 110 1 -L 7 108 1 -L 8 115 1 -L 9 124 1 -L 10 107 1 -L 11 111 1 -L 15 117 1 -L 16 117 1 L 17 127 1 +L 16 117 1 +L 15 117 1 +L 11 111 1 +L 10 107 1 +L 9 124 1 +L 8 115 1 +L 7 108 1 +L 6 110 1 +L 5 131 1 +L 3 118 1 #102 Baldy~ barkeep stocky bald~ @@ -106,13 +113,14 @@ B + ~ 10 0 0 0 0 0 0 0 0 E 1 3d12+60 8 8 1 E -L 9 112 1 L 14 113 1 +L 9 112 1 #103 Lanky~ woman lanky scarred~ @@ -132,6 +140,7 @@ B + ~ 10 0 0 0 0 0 0 0 0 E 1 3d8+60 @@ -161,6 +170,7 @@ appear thick and ready to propel the animal if it feels threatened. B + It's a rat. ~ 8 0 0 0 0 0 0 0 0 E @@ -172,6 +182,7 @@ Int: 4 Wis: 4 Con: 6 Cha: 3 +Species: 25 AtkT 4 E $ diff --git a/src/act.wizard.c b/src/act.wizard.c index f3943a0..ba56972 100644 --- a/src/act.wizard.c +++ b/src/act.wizard.c @@ -26,6 +26,7 @@ #include "act.h" #include "genzon.h" /* for real_zone_by_thing */ #include "class.h" +#include "species.h" #include "genmob.h" #include "genolc.h" #include "genobj.h" @@ -1818,6 +1819,7 @@ static void do_stat_character(struct char_data *ch, struct char_data *k) } stat_table_row_fmt(ch, "Class", "%s", CLASS_NAME(k)); + stat_table_row_fmt(ch, "Species", "%s", get_species_name(GET_SPECIES(k))); stat_table_row_fmt(ch, "Attributes", "Str %d Int %d Wis %d Dex %d Con %d Cha %d", @@ -3806,7 +3808,8 @@ static struct set_struct { { "weight", LVL_BUILDER, BOTH, NUMBER }, { "wis", LVL_BUILDER, BOTH, NUMBER }, { "questpoints", LVL_GOD, PC, NUMBER }, - { "questhistory", LVL_GOD, PC, NUMBER }, /* 55 */ + { "questhistory", LVL_GOD, PC, NUMBER }, + { "species", LVL_BUILDER, BOTH, MISC }, { "\n", 0, BOTH, MISC } }; @@ -4316,6 +4319,16 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c } break; } + case 54: /* species */ + if ((i = parse_species(val_arg)) == SPECIES_UNDEFINED) { + send_to_char(ch, "That is not a species.\r\n"); + return (0); + } + update_species(vict, i); + affect_total(vict); + send_to_char(ch, "You set %s's species to %s.\r\n", + get_char_sdesc(vict), get_species_name(GET_SPECIES(vict))); + break; default: send_to_char(ch, "Can't set that!\r\n"); return (0); @@ -4402,7 +4415,21 @@ ACMD(do_set) } else if (!str_cmp(name, "mob")) half_chop(buf, name, buf); - half_chop(buf, field, buf); + if (!is_file && !is_player && !str_cmp(name, "species")) { + char val[MAX_INPUT_LENGTH]; + char target[MAX_INPUT_LENGTH]; + + half_chop(buf, val, target); + if (!*val || !*target) { + send_to_char(ch, "Usage: set species \r\n"); + return; + } + strlcpy(field, "species", sizeof(field)); + strlcpy(name, target, sizeof(name)); + strlcpy(buf, val, sizeof(buf)); + } else { + half_chop(buf, field, buf); + } if (!*name || !*field) { send_to_char(ch, "Usage: set \r\n"); diff --git a/src/class.c b/src/class.c index 02d0719..fafc7a0 100644 --- a/src/class.c +++ b/src/class.c @@ -23,6 +23,7 @@ #include "constants.h" #include "act.h" #include "class.h" +#include "species.h" /* Names first */ const char *class_abbrevs[] = { @@ -231,7 +232,10 @@ void roll_real_abils(struct char_data *ch) ch->real_abils.cha = table[5]; break; } - ch->aff_abils = ch->real_abils; + if (HAS_VALID_SPECIES(ch)) + apply_species_bonuses(ch); + else + ch->aff_abils = ch->real_abils; } /* Per-class skill caps */ @@ -489,6 +493,7 @@ void do_start(struct char_data *ch) GET_MAX_MOVE(ch) = 90; grant_class_skills(ch, TRUE); + grant_species_skills(ch); advance_level(ch); diff --git a/src/db.c b/src/db.c index 8f76516..1cd9b68 100644 --- a/src/db.c +++ b/src/db.c @@ -1624,6 +1624,7 @@ static void parse_simple_mob(FILE *mob_f, int i, int nr) GET_SEX(mob_proto + i) = t[2]; GET_CLASS(mob_proto + i) = CLASS_UNDEFINED; + GET_SPECIES(mob_proto + i) = SPECIES_UNDEFINED; GET_WEIGHT(mob_proto + i) = 200; GET_HEIGHT(mob_proto + i) = 198; @@ -1707,6 +1708,10 @@ static void interpret_espec(const char *keyword, const char *value, int i, int n RANGE(CLASS_UNDEFINED, NUM_CLASSES - 1); mob_proto[i].player.chclass = num_arg; } + CASE("Species") { + RANGE(SPECIES_UNDEFINED, NUM_SPECIES - 1); + mob_proto[i].player.species = num_arg; + } /* --- 5e-style Saving Throws --- */ CASE("SaveStr") { @@ -3766,6 +3771,7 @@ void clear_char(struct char_data *ch) GET_PFILEPOS(ch) = -1; GET_MOB_RNUM(ch) = NOBODY; GET_CLASS(ch) = CLASS_UNDEFINED; + GET_SPECIES(ch) = SPECIES_UNDEFINED; GET_WAS_IN(ch) = NOWHERE; GET_POS(ch) = POS_STANDING; ch->mob_specials.default_pos = POS_STANDING; diff --git a/src/genmob.c b/src/genmob.c index 8722763..2285a5e 100644 --- a/src/genmob.c +++ b/src/genmob.c @@ -359,6 +359,10 @@ int write_mobile_espec(mob_vnum mvnum, struct char_data *mob, FILE *fd) fprintf(fd, "Class: %d\n", (int)GET_CLASS(mob)); count++; } + if (HAS_VALID_SPECIES(mob)) { + fprintf(fd, "Species: %d\n", (int)GET_SPECIES(mob)); + count++; + } /* --- 5e-style saving throws --- */ if (GET_SAVE(mob, ABIL_STR) != 0) { diff --git a/src/interpreter.c b/src/interpreter.c index 33f0938..073aaf0 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -27,6 +27,7 @@ #include "act.h" /* ACMDs located within the act*.c files */ #include "ban.h" #include "class.h" +#include "species.h" #include "graph.h" #include "hedit.h" #include "house.h" @@ -47,6 +48,7 @@ static int _parse_name(char *arg, char *name); static bool perform_new_char_dupe_check(struct descriptor_data *d); /* sort_commands utility */ static int sort_commands_helper(const void *a, const void *b); +static void show_species_menu(struct descriptor_data *d); /* globals defined here, used here and elsewhere */ int *cmd_sort_info = NULL; @@ -1303,6 +1305,18 @@ static bool perform_new_char_dupe_check(struct descriptor_data *d) return (found); } +static void show_species_menu(struct descriptor_data *d) +{ + int count = pc_species_count(); + + write_to_output(d, "Select a species:\r\n"); + for (int i = 0; i < count; i++) { + int species = pc_species_list[i]; + write_to_output(d, " %2d) %s\r\n", i + 1, species_types[species]); + } + write_to_output(d, "Species: "); +} + /* load the player, put them in the right room - used by copyover_recover too */ int enter_player_game (struct descriptor_data *d) { @@ -1869,10 +1883,26 @@ void nanny(struct descriptor_data *d, char *arg) return; } - write_to_output(d, "%s\r\nClass: ", class_menu); - STATE(d) = CON_QCLASS; + show_species_menu(d); + STATE(d) = CON_QSPECIES; break; +case CON_QSPECIES: { + int choice = atoi(arg); + int species = species_from_pc_choice(choice); + + if (species == SPECIES_UNDEFINED) { + write_to_output(d, "\r\nThat's not a species.\r\n"); + show_species_menu(d); + return; + } + + GET_SPECIES(d->character) = species; + write_to_output(d, "%s\r\nClass: ", class_menu); + STATE(d) = CON_QCLASS; + break; +} + case CON_QCLASS: load_result = parse_class(*arg); if (load_result == CLASS_UNDEFINED) { diff --git a/src/medit.c b/src/medit.c index 32ada44..637263f 100644 --- a/src/medit.c +++ b/src/medit.c @@ -13,6 +13,7 @@ #include "comm.h" #include "spells.h" #include "class.h" +#include "species.h" #include "db.h" #include "shop.h" #include "genolc.h" @@ -41,6 +42,7 @@ static void medit_disp_mob_flags(struct descriptor_data *d); static void medit_disp_aff_flags(struct descriptor_data *d); static void medit_disp_menu(struct descriptor_data *d); static void medit_disp_class_menu(struct descriptor_data *d); +static void medit_disp_species_menu(struct descriptor_data *d); /* utility functions */ ACMD(do_oasis_medit) @@ -419,13 +421,14 @@ static void medit_disp_menu(struct descriptor_data *d) { struct char_data *mob; char flags[MAX_STRING_LENGTH], flag2[MAX_STRING_LENGTH]; - const char *background, *classname; + const char *background, *classname, *speciesname; mob = OLC_MOB(d); get_char_colors(d->character); clear_screen(d); background = GET_BACKGROUND(mob) ? GET_BACKGROUND(mob) : "\r\n"; classname = HAS_VALID_CLASS(mob) ? pc_class_types[GET_CLASS(mob)] : "Unassigned"; + speciesname = HAS_VALID_SPECIES(mob) ? species_types[GET_SPECIES(mob)] : "Unassigned"; write_to_output(d, "-- Mob Number: [%s%d%s]\r\n" @@ -452,6 +455,7 @@ static void medit_disp_menu(struct descriptor_data *d) "%s8%s) Default : %s%s\r\n" "%s9%s) Attack : %s%s\r\n" "%sD%s) Class : %s%s\r\n" + "%sE%s) Species : %s%s\r\n" "%sK%s) Skinning Menu...\r\n" "%s0%s) Stats Menu...\r\n" "%s-%s) Skills Menu...\r\n" @@ -468,6 +472,7 @@ static void medit_disp_menu(struct descriptor_data *d) grn, nrm, yel, position_types[(int)GET_DEFAULT_POS(mob)], grn, nrm, yel, attack_hit_text[(int)GET_ATTACK(mob)].singular, grn, nrm, yel, classname, + grn, nrm, yel, speciesname, grn, nrm, grn, nrm, grn, nrm, @@ -523,6 +528,46 @@ static void medit_disp_class_menu(struct descriptor_data *d) OLC_MODE(d) = MEDIT_CLASS_MENU; } +static void medit_disp_species_menu(struct descriptor_data *d) +{ + struct char_data *mob = OLC_MOB(d); + const char *current = HAS_VALID_SPECIES(mob) ? species_types[GET_SPECIES(mob)] : "Unassigned"; + + get_char_colors(d->character); + clear_screen(d); + + write_to_output(d, + "-- Mob Number: %s[%s%d%s]%s\r\n" + "Species selection for %s%s%s\r\n\r\n", + cyn, yel, OLC_NUM(d), cyn, nrm, + yel, GET_SDESC(mob), nrm); + + for (int i = 0; i < NUM_SPECIES; i++) { + bool selected = HAS_VALID_SPECIES(mob) && (GET_SPECIES(mob) == i); + write_to_output(d, "%s%2d%s) %s%-12s%s%s\r\n", + cyn, i + 1, nrm, + selected ? grn : yel, + species_types[i], + nrm, + selected ? " (current)" : ""); + } + + write_to_output(d, "%s%2d%s) %sUnassigned%s%s\r\n", + cyn, NUM_SPECIES + 1, nrm, + !HAS_VALID_SPECIES(mob) ? grn : yel, + nrm, + !HAS_VALID_SPECIES(mob) ? " (current)" : ""); + + write_to_output(d, + "\r\nCurrent choice: %s%s%s\r\n" + "%s0%s) Return to main menu\r\n" + "Enter choice : ", + cyn, current, nrm, + cyn, nrm); + + OLC_MODE(d) = MEDIT_SPECIES_MENU; +} + /* Display main menu. */ static void medit_disp_stats_menu(struct descriptor_data *d) { @@ -757,6 +802,10 @@ void medit_parse(struct descriptor_data *d, char *arg) case 'D': medit_disp_class_menu(d); return; + case 'e': + case 'E': + medit_disp_species_menu(d); + return; case '0': OLC_MODE(d) = MEDIT_STATS_MENU; medit_disp_stats_menu(d); @@ -1165,6 +1214,30 @@ void medit_parse(struct descriptor_data *d, char *arg) medit_disp_menu(d); return; + case MEDIT_SPECIES_MENU: + i = atoi(arg); + if (i == 0) { + medit_disp_menu(d); + return; + } + if (i == NUM_SPECIES + 1) { + GET_SPECIES(OLC_MOB(d)) = SPECIES_UNDEFINED; + OLC_VAL(d) = TRUE; + write_to_output(d, "Species cleared.\r\n"); + medit_disp_menu(d); + return; + } + if (i < 1 || i > NUM_SPECIES + 1) { + write_to_output(d, "Invalid choice!\r\n"); + medit_disp_species_menu(d); + return; + } + GET_SPECIES(OLC_MOB(d)) = i - 1; + OLC_VAL(d) = TRUE; + write_to_output(d, "Species set to %s.\r\n", species_types[GET_SPECIES(OLC_MOB(d))]); + medit_disp_menu(d); + return; + case OLC_SCRIPT_EDIT: if (dg_script_edit_parse(d, arg)) return; break; diff --git a/src/oasis.h b/src/oasis.h index db6f738..6697cdb 100644 --- a/src/oasis.h +++ b/src/oasis.h @@ -269,39 +269,40 @@ extern const char *nrm, *grn, *cyn, *yel; #define MEDIT_SKILL_MENU 11 #define MEDIT_SKILL_EDIT 12 #define MEDIT_CLASS_MENU 13 +#define MEDIT_SPECIES_MENU 14 /* Numerical responses. */ -#define MEDIT_NUMERICAL_RESPONSE 14 -#define MEDIT_SEX 15 -#define MEDIT_NUM_HP_DICE 16 -#define MEDIT_SIZE_HP_DICE 17 -#define MEDIT_ADD_HP 18 -#define MEDIT_POS 19 -#define MEDIT_DEFAULT_POS 20 -#define MEDIT_ATTACK 21 -#define MEDIT_LEVEL 22 -#define MEDIT_ALIGNMENT 23 -#define MEDIT_DELETE 24 -#define MEDIT_COPY 25 -#define MEDIT_STR 26 -#define MEDIT_INT 27 -#define MEDIT_WIS 28 -#define MEDIT_DEX 29 -#define MEDIT_CON 30 -#define MEDIT_CHA 31 -#define MEDIT_SAVE_STR 32 -#define MEDIT_SAVE_DEX 33 -#define MEDIT_SAVE_CON 34 -#define MEDIT_SAVE_INT 35 -#define MEDIT_SAVE_WIS 36 -#define MEDIT_SAVE_CHA 37 -#define MEDIT_SKILL_VALUE 38 +#define MEDIT_NUMERICAL_RESPONSE 15 +#define MEDIT_SEX 16 +#define MEDIT_NUM_HP_DICE 17 +#define MEDIT_SIZE_HP_DICE 18 +#define MEDIT_ADD_HP 19 +#define MEDIT_POS 20 +#define MEDIT_DEFAULT_POS 21 +#define MEDIT_ATTACK 22 +#define MEDIT_LEVEL 23 +#define MEDIT_ALIGNMENT 24 +#define MEDIT_DELETE 25 +#define MEDIT_COPY 26 +#define MEDIT_STR 27 +#define MEDIT_INT 28 +#define MEDIT_WIS 29 +#define MEDIT_DEX 30 +#define MEDIT_CON 31 +#define MEDIT_CHA 32 +#define MEDIT_SAVE_STR 33 +#define MEDIT_SAVE_DEX 34 +#define MEDIT_SAVE_CON 35 +#define MEDIT_SAVE_INT 36 +#define MEDIT_SAVE_WIS 37 +#define MEDIT_SAVE_CHA 38 +#define MEDIT_SKILL_VALUE 39 /* Skinning yield editor */ -#define MEDIT_SKIN_MENU 39 -#define MEDIT_SKIN_ADD_VNUM 40 -#define MEDIT_SKIN_ADD_DC 41 -#define MEDIT_SKIN_DELETE 42 +#define MEDIT_SKIN_MENU 40 +#define MEDIT_SKIN_ADD_VNUM 41 +#define MEDIT_SKIN_ADD_DC 42 +#define MEDIT_SKIN_DELETE 43 /* Submodes of SEDIT connectedness. */ #define SEDIT_MAIN_MENU 0 diff --git a/src/pfdefaults.h b/src/pfdefaults.h index afd4ba9..4771360 100644 --- a/src/pfdefaults.h +++ b/src/pfdefaults.h @@ -15,6 +15,7 @@ #define PFDEF_SEX 0 #define PFDEF_CLASS 0 +#define PFDEF_SPECIES SPECIES_UNDEFINED #define PFDEF_LEVEL 0 #define PFDEF_HEIGHT 0 #define PFDEF_WEIGHT 0 diff --git a/src/players.c b/src/players.c index ce06c33..29866e8 100644 --- a/src/players.c +++ b/src/players.c @@ -255,6 +255,7 @@ int load_char(const char *name, struct char_data *ch) ch->player_specials->saved.skills[i] = 0; GET_SEX(ch) = PFDEF_SEX; GET_CLASS(ch) = PFDEF_CLASS; + GET_SPECIES(ch) = PFDEF_SPECIES; GET_LEVEL(ch) = PFDEF_LEVEL; GET_HEIGHT(ch) = PFDEF_HEIGHT; GET_WEIGHT(ch) = PFDEF_WEIGHT; @@ -437,7 +438,13 @@ int load_char(const char *name, struct char_data *ch) break; case 'S': - if (!strcmp(tag, "Sex ")) GET_SEX(ch) = atoi(line); + if (!strcmp(tag, "Spec")) { + int val = atoi(line); + if (val < SPECIES_UNDEFINED || val >= NUM_SPECIES) + val = SPECIES_UNDEFINED; + GET_SPECIES(ch) = val; + } + else if (!strcmp(tag, "Sex ")) GET_SEX(ch) = atoi(line); else if (!strcmp(tag, "Sdsc")) { /* Clear any existing sdesc to avoid leaks */ if (GET_SHORT_DESC(ch)) @@ -614,6 +621,7 @@ void save_char(struct char_data * ch) if (POOFOUT(ch)) fprintf(fl, "PfOt: %s\n", POOFOUT(ch)); if (GET_SEX(ch) != PFDEF_SEX) fprintf(fl, "Sex : %d\n", GET_SEX(ch)); if (GET_CLASS(ch) != PFDEF_CLASS) fprintf(fl, "Clas: %d\n", GET_CLASS(ch)); + if (GET_SPECIES(ch) != PFDEF_SPECIES) fprintf(fl, "Spec: %d\n", GET_SPECIES(ch)); if (GET_LEVEL(ch) != PFDEF_LEVEL) fprintf(fl, "Levl: %d\n", GET_LEVEL(ch)); fprintf(fl, "Id : %ld\n", GET_IDNUM(ch)); diff --git a/src/species.c b/src/species.c new file mode 100644 index 0000000..c94afde --- /dev/null +++ b/src/species.c @@ -0,0 +1,446 @@ +/** +* @file species.c +* Race/species related configuration, skill bonuses, modifiers, and stat limitations. +* +* This set of code was not originally part of the circlemud distribution. +*/ + +#include "conf.h" +#include "sysdep.h" + +#include "structs.h" +#include "utils.h" +#include "db.h" +#include "spells.h" +#include "species.h" + +struct species_skill_bonus { + int skill; + int start; +}; + +/* Keep species ordering in sync with the SPECIES_* defines. */ +const char *species_types[NUM_SPECIES] = { + "Human", + "City Elf", + "Desert Elf", + "Half-Elf", + "Dwarf", + "Mul", + "Half-Giant", + "Mantis", + "Gith", + "Aarakocra", + "Dray", + "Kenku", + "Jozhal", + "Pterran", + "Tarek", + "Aprig", + "Carru", + "Crodlu", + "Erdlu", + "Inix", + "Jhakar", + "Kank", + "Mekillot", + "Worm", + "Renk", + "Rat", + "Undead", + "Dragon" +}; + +/* PC creation options (1-based ordering in menus). */ +const int pc_species_list[] = { + SPECIES_HUMAN, + SPECIES_CITY_ELF, + SPECIES_DESERT_ELF, + SPECIES_HALF_ELF, + SPECIES_DWARF, + SPECIES_MUL, + SPECIES_HALF_GIANT, + SPECIES_MANTIS, + SPECIES_GITH, + -1 +}; + +static const struct species_skill_bonus species_skill_none[] = { + { -1, 0 } +}; + +/* Per-species skill bonuses. + * Usage: + * 1) Define a bonus list for a species (see commented example below). + * 2) In species_skill_bonuses[], point that species at the new list. + * 3) Keep the { -1, 0 } terminator as the final entry. + * + * Example (commented out): + * + * static const struct species_skill_bonus species_skill_human[] = { + * { SKILL_PERCEPTION, 5 }, + * { -1, 0 } + * }; + */ +static const struct species_skill_bonus *species_skill_bonuses[NUM_SPECIES] = { + /* species_skill_human, */ /* Human (example if you enable the list above) */ + species_skill_none, /* Human */ + species_skill_none, /* City Elf */ + species_skill_none, /* Desert Elf */ + species_skill_none, /* Half-Elf */ + species_skill_none, /* Dwarf */ + species_skill_none, /* Mul */ + species_skill_none, /* Half-Giant */ + species_skill_none, /* Mantis */ + species_skill_none, /* Gith */ + species_skill_none, /* Aarakocra */ + species_skill_none, /* Dray */ + species_skill_none, /* Kenku */ + species_skill_none, /* Jozhal */ + species_skill_none, /* Pterran */ + species_skill_none, /* Tarek */ + species_skill_none, /* Aprig */ + species_skill_none, /* Carru */ + species_skill_none, /* Crodlu */ + species_skill_none, /* Erdlu */ + species_skill_none, /* Inix */ + species_skill_none, /* Jhakar */ + species_skill_none, /* Kank */ + species_skill_none, /* Mekillot */ + species_skill_none, /* Worm */ + species_skill_none, /* Renk */ + species_skill_none, /* Rat */ + species_skill_none, /* Undead */ + species_skill_none /* Dragon */ +}; + +/* Ability minimums by species (STR, DEX, CON, INT, WIS, CHA). Zero = no min. */ +static const int species_ability_mins[NUM_SPECIES][NUM_ABILITIES] = { + { 0, 0, 0, 0, 0, 0 }, /* Human */ + { 0, 0, 0, 0, 0, 0 }, /* City Elf */ + { 0, 0, 0, 0, 0, 0 }, /* Desert Elf */ + { 0, 0, 0, 0, 0, 0 }, /* Half-Elf */ + { 0, 0, 0, 0, 0, 0 }, /* Dwarf */ + { 0, 0, 0, 0, 0, 0 }, /* Mul */ + { 0, 0, 0, 0, 0, 0 }, /* Half-Giant */ + { 0, 0, 0, 0, 0, 0 }, /* Mantis */ + { 0, 0, 0, 0, 0, 0 }, /* Gith */ + { 0, 0, 0, 0, 0, 0 }, /* Aarakocra */ + { 0, 0, 0, 0, 0, 0 }, /* Dray */ + { 0, 0, 0, 0, 0, 0 }, /* Kenku */ + { 0, 0, 0, 0, 0, 0 }, /* Jozhal */ + { 0, 0, 0, 0, 0, 0 }, /* Pterran */ + { 0, 0, 0, 0, 0, 0 }, /* Tarek */ + { 0, 0, 0, 0, 0, 0 }, /* Aprig */ + { 0, 0, 0, 0, 0, 0 }, /* Carru */ + { 0, 0, 0, 0, 0, 0 }, /* Crodlu */ + { 0, 0, 0, 0, 0, 0 }, /* Erdlu */ + { 0, 0, 0, 0, 0, 0 }, /* Inix */ + { 0, 0, 0, 0, 0, 0 }, /* Jhakar */ + { 0, 0, 0, 0, 0, 0 }, /* Kank */ + { 0, 0, 0, 0, 0, 0 }, /* Mekillot */ + { 0, 0, 0, 0, 0, 0 }, /* Worm */ + { 0, 0, 0, 0, 0, 0 }, /* Renk */ + { 0, 0, 0, 0, 0, 0 }, /* Rat */ + { 0, 0, 0, 0, 0, 0 }, /* Undead */ + { 0, 0, 0, 0, 0, 0 } /* Dragon */ +}; + +/* Ability modifiers by species (STR, DEX, CON, INT, WIS, CHA). */ +static const int species_ability_mods[NUM_SPECIES][NUM_ABILITIES] = { + { 0, 0, 0, 0, 0, 0 }, /* Human */ + { 0, 0, 0, 0, 0, 0 }, /* City Elf */ + { 0, 0, 0, 0, 0, 0 }, /* Desert Elf */ + { 0, 0, 0, 0, 0, 0 }, /* Half-Elf */ + { 0, 0, 0, 0, 0, 0 }, /* Dwarf */ + { 0, 0, 0, 0, 0, 0 }, /* Mul */ + { 0, 0, 0, 0, 0, 0 }, /* Half-Giant */ + { 0, 0, 0, 0, 0, 0 }, /* Mantis */ + { 0, 0, 0, 0, 0, 0 }, /* Gith */ + { 0, 0, 0, 0, 0, 0 }, /* Aarakocra */ + { 0, 0, 0, 0, 0, 0 }, /* Dray */ + { 0, 0, 0, 0, 0, 0 }, /* Kenku */ + { 0, 0, 0, 0, 0, 0 }, /* Jozhal */ + { 0, 0, 0, 0, 0, 0 }, /* Pterran */ + { 0, 0, 0, 0, 0, 0 }, /* Tarek */ + { 0, 0, 0, 0, 0, 0 }, /* Aprig */ + { 0, 0, 0, 0, 0, 0 }, /* Carru */ + { 0, 0, 0, 0, 0, 0 }, /* Crodlu */ + { 0, 0, 0, 0, 0, 0 }, /* Erdlu */ + { 0, 0, 0, 0, 0, 0 }, /* Inix */ + { 0, 0, 0, 0, 0, 0 }, /* Jhakar */ + { 0, 0, 0, 0, 0, 0 }, /* Kank */ + { 0, 0, 0, 0, 0, 0 }, /* Mekillot */ + { 0, 0, 0, 0, 0, 0 }, /* Worm */ + { 0, 0, 0, 0, 0, 0 }, /* Renk */ + { 0, 0, 0, 0, 0, 0 }, /* Rat */ + { 0, 0, 0, 0, 0, 0 }, /* Undead */ + { 0, 0, 0, 0, 0, 0 } /* Dragon */ +}; + +/* Ability caps by species (STR, DEX, CON, INT, WIS, CHA). Zero = no cap. */ +static const int species_ability_caps[NUM_SPECIES][NUM_ABILITIES] = { + { 16, 0, 0, 0, 0, 0 }, /* Human */ + { 14, 0, 0, 0, 0, 0 }, /* City Elf */ + { 14, 0, 0, 0, 0, 0 }, /* Desert Elf */ + { 14, 0, 0, 0, 0, 0 }, /* Half-Elf */ + { 18, 0, 0, 0, 0, 0 }, /* Dwarf */ + { 20, 0, 0, 0, 0, 0 }, /* Mul */ + { 24, 0, 0, 0, 0, 0 }, /* Half-Giant */ + { 0, 0, 0, 0, 0, 0 }, /* Mantis */ + { 0, 0, 0, 0, 0, 0 }, /* Gith */ + { 0, 0, 0, 0, 0, 0 }, /* Aarakocra */ + { 0, 0, 0, 0, 0, 0 }, /* Dray */ + { 0, 0, 0, 0, 0, 0 }, /* Kenku */ + { 0, 0, 0, 0, 0, 0 }, /* Jozhal */ + { 0, 0, 0, 0, 0, 0 }, /* Pterran */ + { 0, 0, 0, 0, 0, 0 }, /* Tarek */ + { 0, 0, 0, 0, 0, 0 }, /* Aprig */ + { 0, 0, 0, 0, 0, 0 }, /* Carru */ + { 0, 0, 0, 0, 0, 0 }, /* Crodlu */ + { 0, 0, 0, 0, 0, 0 }, /* Erdlu */ + { 0, 0, 0, 0, 0, 0 }, /* Inix */ + { 0, 0, 0, 0, 0, 0 }, /* Jhakar */ + { 0, 0, 0, 0, 0, 0 }, /* Kank */ + { 0, 0, 0, 0, 0, 0 }, /* Mekillot */ + { 0, 0, 0, 0, 0, 0 }, /* Worm */ + { 0, 0, 0, 0, 0, 0 }, /* Renk */ + { 0, 0, 0, 0, 0, 0 }, /* Rat */ + { 0, 0, 0, 0, 0, 0 }, /* Undead */ + { 0, 0, 0, 0, 0, 0 } /* Dragon */ +}; + +const char *get_species_name(int species) +{ + if (species >= 0 && species < NUM_SPECIES) + return species_types[species]; + return "Unassigned"; +} + +int pc_species_count(void) +{ + int count = 0; + while (pc_species_list[count] != -1) + count++; + return count; +} + +bool species_is_pc_selectable(int species) +{ + int i = 0; + + while (pc_species_list[i] != -1) { + if (pc_species_list[i] == species) + return TRUE; + i++; + } + return FALSE; +} + +int species_from_pc_choice(int choice) +{ + int count = pc_species_count(); + + if (choice < 1 || choice > count) + return SPECIES_UNDEFINED; + return pc_species_list[choice - 1]; +} + +int species_ability_mod(int species, int ability) +{ + if (species < 0 || species >= NUM_SPECIES) + return 0; + if (ability < 0 || ability >= NUM_ABILITIES) + return 0; + return species_ability_mods[species][ability]; +} + +int species_ability_min(int species, int ability) +{ + if (species < 0 || species >= NUM_SPECIES) + return 0; + if (ability < 0 || ability >= NUM_ABILITIES) + return 0; + return species_ability_mins[species][ability]; +} + +int species_ability_cap(int species, int ability) +{ + if (species < 0 || species >= NUM_SPECIES) + return 0; + if (ability < 0 || ability >= NUM_ABILITIES) + return 0; + return species_ability_caps[species][ability]; +} + +static void apply_species_ranges(struct char_data *ch) +{ + int species; + int cap, min; + + if (!ch) + return; + + species = GET_SPECIES(ch); + if (species < 0 || species >= NUM_SPECIES) + return; + + min = species_ability_min(species, ABIL_STR); + if (min > 0 && ch->real_abils.str < min) + ch->real_abils.str = min; + cap = species_ability_cap(species, ABIL_STR); + if (cap > 0 && ch->real_abils.str > cap) + ch->real_abils.str = cap; + + min = species_ability_min(species, ABIL_DEX); + if (min > 0 && ch->real_abils.dex < min) + ch->real_abils.dex = min; + cap = species_ability_cap(species, ABIL_DEX); + if (cap > 0 && ch->real_abils.dex > cap) + ch->real_abils.dex = cap; + + min = species_ability_min(species, ABIL_CON); + if (min > 0 && ch->real_abils.con < min) + ch->real_abils.con = min; + cap = species_ability_cap(species, ABIL_CON); + if (cap > 0 && ch->real_abils.con > cap) + ch->real_abils.con = cap; + + min = species_ability_min(species, ABIL_INT); + if (min > 0 && ch->real_abils.intel < min) + ch->real_abils.intel = min; + cap = species_ability_cap(species, ABIL_INT); + if (cap > 0 && ch->real_abils.intel > cap) + ch->real_abils.intel = cap; + + min = species_ability_min(species, ABIL_WIS); + if (min > 0 && ch->real_abils.wis < min) + ch->real_abils.wis = min; + cap = species_ability_cap(species, ABIL_WIS); + if (cap > 0 && ch->real_abils.wis > cap) + ch->real_abils.wis = cap; + + min = species_ability_min(species, ABIL_CHA); + if (min > 0 && ch->real_abils.cha < min) + ch->real_abils.cha = min; + cap = species_ability_cap(species, ABIL_CHA); + if (cap > 0 && ch->real_abils.cha > cap) + ch->real_abils.cha = cap; +} + +void apply_species_bonuses(struct char_data *ch) +{ + int species; + + if (!ch) + return; + + species = GET_SPECIES(ch); + if (species < 0 || species >= NUM_SPECIES) + return; + + apply_species_ranges(ch); + + ch->real_abils.str += species_ability_mod(species, ABIL_STR); + ch->real_abils.dex += species_ability_mod(species, ABIL_DEX); + ch->real_abils.con += species_ability_mod(species, ABIL_CON); + ch->real_abils.intel += species_ability_mod(species, ABIL_INT); + ch->real_abils.wis += species_ability_mod(species, ABIL_WIS); + ch->real_abils.cha += species_ability_mod(species, ABIL_CHA); + + apply_species_ranges(ch); + ch->aff_abils = ch->real_abils; +} + +void grant_species_skills(struct char_data *ch) +{ + int species; + const struct species_skill_bonus *bonus; + + if (!ch) + return; + + species = GET_SPECIES(ch); + if (species < 0 || species >= NUM_SPECIES) + return; + + for (bonus = species_skill_bonuses[species]; bonus->skill != -1; bonus++) { + if (bonus->skill >= 0 && bonus->skill <= MAX_SKILLS) { + if (GET_SKILL(ch, bonus->skill) < bonus->start) + SET_SKILL(ch, bonus->skill, bonus->start); + } + } +} + +static void remove_species_skills(struct char_data *ch, int species) +{ + const struct species_skill_bonus *bonus; + + if (!ch) + return; + if (species < 0 || species >= NUM_SPECIES) + return; + + for (bonus = species_skill_bonuses[species]; bonus->skill != -1; bonus++) { + if (bonus->skill >= 0 && bonus->skill <= MAX_SKILLS) { + if (GET_SKILL(ch, bonus->skill) <= bonus->start) + SET_SKILL(ch, bonus->skill, 0); + } + } +} + +static void remove_species_bonuses(struct char_data *ch, int species) +{ + if (!ch) + return; + if (species < 0 || species >= NUM_SPECIES) + return; + + ch->real_abils.str -= species_ability_mod(species, ABIL_STR); + ch->real_abils.dex -= species_ability_mod(species, ABIL_DEX); + ch->real_abils.con -= species_ability_mod(species, ABIL_CON); + ch->real_abils.intel -= species_ability_mod(species, ABIL_INT); + ch->real_abils.wis -= species_ability_mod(species, ABIL_WIS); + ch->real_abils.cha -= species_ability_mod(species, ABIL_CHA); +} + +int parse_species(const char *arg) +{ + int i; + + if (!arg || !*arg) + return SPECIES_UNDEFINED; + + for (i = 0; i < NUM_SPECIES; i++) { + if (!str_cmp(arg, species_types[i])) + return i; + } + + return SPECIES_UNDEFINED; +} + +void update_species(struct char_data *ch, int new_species) +{ + int old_species; + + if (!ch) + return; + + old_species = GET_SPECIES(ch); + if (old_species == new_species) + return; + + if (old_species >= 0 && old_species < NUM_SPECIES) { + remove_species_skills(ch, old_species); + remove_species_bonuses(ch, old_species); + } + + GET_SPECIES(ch) = new_species; + + if (new_species >= 0 && new_species < NUM_SPECIES) { + apply_species_bonuses(ch); + grant_species_skills(ch); + } else { + ch->aff_abils = ch->real_abils; + } +} diff --git a/src/species.h b/src/species.h new file mode 100644 index 0000000..34d80d1 --- /dev/null +++ b/src/species.h @@ -0,0 +1,29 @@ +/** +* @file species.h +* Race/species related header. +* +* This set of code was not originally part of the circlemud distribution. +*/ + +#ifndef _SPECIES_H_ +#define _SPECIES_H_ + +struct char_data; + +const char *get_species_name(int species); +int species_from_pc_choice(int choice); +int pc_species_count(void); +bool species_is_pc_selectable(int species); +int species_ability_mod(int species, int ability); +int species_ability_min(int species, int ability); +int species_ability_cap(int species, int ability); + +void apply_species_bonuses(struct char_data *ch); +void grant_species_skills(struct char_data *ch); +int parse_species(const char *arg); +void update_species(struct char_data *ch, int new_species); + +extern const char *species_types[]; +extern const int pc_species_list[]; + +#endif /* _SPECIES_H_ */ diff --git a/src/structs.h b/src/structs.h index 03eca5b..d396bbd 100644 --- a/src/structs.h +++ b/src/structs.h @@ -164,6 +164,38 @@ /** Total number of available PC Classes */ #define NUM_CLASSES 8 +/* Species */ +#define SPECIES_UNDEFINED (-1) /**< Species undefined */ +#define SPECIES_HUMAN 0 +#define SPECIES_CITY_ELF 1 +#define SPECIES_DESERT_ELF 2 +#define SPECIES_HALF_ELF 3 +#define SPECIES_DWARF 4 +#define SPECIES_MUL 5 +#define SPECIES_HALF_GIANT 6 +#define SPECIES_MANTIS 7 +#define SPECIES_GITH 8 +#define SPECIES_AARAKOCRA 9 +#define SPECIES_DRAY 10 +#define SPECIES_KENKU 11 +#define SPECIES_JOZHAL 12 +#define SPECIES_PTERRAN 13 +#define SPECIES_TAREK 14 +#define SPECIES_APRIG 15 +#define SPECIES_CARRU 16 +#define SPECIES_CRODLU 17 +#define SPECIES_ERDLU 18 +#define SPECIES_INIX 19 +#define SPECIES_JHAKAR 20 +#define SPECIES_KANK 21 +#define SPECIES_MEKILLOT 22 +#define SPECIES_WORM 23 +#define SPECIES_RENK 24 +#define SPECIES_RAT 25 +#define SPECIES_UNDEAD 26 +#define SPECIES_DRAGON 27 +#define NUM_SPECIES 28 + /* NPC classes (currently unused - feel free to implement!) */ #define CLASS_OTHER 0 /**< NPC Class Other (or undefined) */ #define CLASS_UNDEAD 1 /**< NPC Class Undead */ @@ -313,42 +345,43 @@ #define CON_NEWPASSWD 5 /**< New character, create password */ #define CON_CNFPASSWD 6 /**< New character, confirm password */ #define CON_QSEX 7 /**< Choose character sex */ -#define CON_QCLASS 8 /**< Choose character class */ -#define CON_QSHORTDESC 9 /**< Enter a new character short description prompt */ -#define CON_RMOTD 10 /**< Reading the message of the day */ -#define CON_MENU 11 /**< At the main menu */ -#define CON_PLR_DESC 12 /**< Enter a new character description prompt */ -#define CON_CHPWD_GETOLD 13 /**< Changing passwd: Get old */ -#define CON_CHPWD_GETNEW 14 /**< Changing passwd: Get new */ -#define CON_CHPWD_VRFY 15 /**< Changing passwd: Verify new password */ -#define CON_DELCNF1 16 /**< Character Delete: Confirmation 1 */ -#define CON_DELCNF2 17 /**< Character Delete: Confirmation 2 */ -#define CON_DISCONNECT 18 /**< In-game link loss (leave character) */ -#define CON_OEDIT 19 /**< OLC mode - object editor */ -#define CON_REDIT 20 /**< OLC mode - room editor */ -#define CON_ZEDIT 21 /**< OLC mode - zone info editor */ -#define CON_MEDIT 22 /**< OLC mode - mobile editor */ -#define CON_SEDIT 23 /**< OLC mode - shop editor */ -#define CON_TEDIT 24 /**< OLC mode - text editor */ -#define CON_CEDIT 25 /**< OLC mode - conf editor */ -#define CON_AEDIT 26 /**< OLC mode - social (action) edit */ -#define CON_TRIGEDIT 27 /**< OLC mode - trigger edit */ -#define CON_HEDIT 28 /**< OLC mode - help edit */ -#define CON_QEDIT 29 /**< OLC mode - quest edit */ -#define CON_PREFEDIT 30 /**< OLC mode - preference edit */ -#define CON_IBTEDIT 31 /**< OLC mode - idea/bug/typo edit */ -#define CON_MSGEDIT 32 /**< OLC mode - message editor */ -#define CON_PLR_BACKGROUND 33 /**< Entering a new character background */ -#define CON_GET_PROTOCOL 33 /**< Used at log-in while attempting to get protocols > */ -#define CON_GET_CONNECT 34 /**< Login connect/disconnect menu */ -#define CON_GET_ACCOUNT 35 /**< Login with account name */ -#define CON_ACCOUNT_CNFRM 36 /**< New account, confirm name */ -#define CON_ACCOUNT_PASSWORD 37 /**< Login with account password */ -#define CON_ACCOUNT_NEWPASSWD 38 /**< New account, create password */ -#define CON_ACCOUNT_CNFPASSWD 39 /**< New account, confirm password */ -#define CON_ACCOUNT_EMAIL 40 /**< New account, optional email */ -#define CON_ACCOUNT_MENU 41 /**< Account main menu */ -#define CON_ACCOUNT_LIST 42 /**< Viewing account character list */ +#define CON_QSPECIES 8 /**< Choose character species */ +#define CON_QCLASS 9 /**< Choose character class */ +#define CON_QSHORTDESC 10 /**< Enter a new character short description prompt */ +#define CON_RMOTD 11 /**< Reading the message of the day */ +#define CON_MENU 12 /**< At the main menu */ +#define CON_PLR_DESC 13 /**< Enter a new character description prompt */ +#define CON_CHPWD_GETOLD 14 /**< Changing passwd: Get old */ +#define CON_CHPWD_GETNEW 15 /**< Changing passwd: Get new */ +#define CON_CHPWD_VRFY 16 /**< Changing passwd: Verify new password */ +#define CON_DELCNF1 17 /**< Character Delete: Confirmation 1 */ +#define CON_DELCNF2 18 /**< Character Delete: Confirmation 2 */ +#define CON_DISCONNECT 19 /**< In-game link loss (leave character) */ +#define CON_OEDIT 20 /**< OLC mode - object editor */ +#define CON_REDIT 21 /**< OLC mode - room editor */ +#define CON_ZEDIT 22 /**< OLC mode - zone info editor */ +#define CON_MEDIT 23 /**< OLC mode - mobile editor */ +#define CON_SEDIT 24 /**< OLC mode - shop editor */ +#define CON_TEDIT 25 /**< OLC mode - text editor */ +#define CON_CEDIT 26 /**< OLC mode - conf editor */ +#define CON_AEDIT 27 /**< OLC mode - social (action) edit */ +#define CON_TRIGEDIT 28 /**< OLC mode - trigger edit */ +#define CON_HEDIT 29 /**< OLC mode - help edit */ +#define CON_QEDIT 30 /**< OLC mode - quest edit */ +#define CON_PREFEDIT 31 /**< OLC mode - preference edit */ +#define CON_IBTEDIT 32 /**< OLC mode - idea/bug/typo edit */ +#define CON_MSGEDIT 33 /**< OLC mode - message editor */ +#define CON_PLR_BACKGROUND 34 /**< Entering a new character background */ +#define CON_GET_PROTOCOL 34 /**< Used at log-in while attempting to get protocols > */ +#define CON_GET_CONNECT 35 /**< Login connect/disconnect menu */ +#define CON_GET_ACCOUNT 36 /**< Login with account name */ +#define CON_ACCOUNT_CNFRM 37 /**< New account, confirm name */ +#define CON_ACCOUNT_PASSWORD 38 /**< Login with account password */ +#define CON_ACCOUNT_NEWPASSWD 39 /**< New account, create password */ +#define CON_ACCOUNT_CNFPASSWD 40 /**< New account, confirm password */ +#define CON_ACCOUNT_EMAIL 41 /**< New account, optional email */ +#define CON_ACCOUNT_MENU 42 /**< Account main menu */ +#define CON_ACCOUNT_LIST 43 /**< Viewing account character list */ /* OLC States range - used by IS_IN_OLC and IS_PLAYING */ #define FIRST_OLC_STATE CON_OEDIT /**< The first CON_ state that is an OLC */ @@ -907,6 +940,7 @@ struct char_player_data char *background; /**< PC / NPC background / history text */ byte sex; /**< PC / NPC sex */ byte chclass; /**< PC / NPC class */ + byte species; /**< PC / NPC species */ byte level; /**< PC / NPC level */ struct time_data time; /**< PC AGE in days */ ubyte weight; /**< PC / NPC weight */ diff --git a/src/utils.h b/src/utils.h index faf2d40..2347914 100644 --- a/src/utils.h +++ b/src/utils.h @@ -556,6 +556,8 @@ do \ /** Class of ch. */ #define GET_CLASS(ch) ((ch)->player.chclass) +/** Species of ch. */ +#define GET_SPECIES(ch) ((ch)->player.species) /** Height of ch. */ #define GET_HEIGHT(ch) ((ch)->player.height) /** Weight of ch. */ @@ -936,6 +938,7 @@ do \ /** True if ch has a valid player class assigned. */ #define HAS_VALID_CLASS(ch) ((GET_CLASS(ch) >= CLASS_SORCEROR) && (GET_CLASS(ch) < NUM_CLASSES)) +#define HAS_VALID_SPECIES(ch) ((GET_SPECIES(ch) >= 0) && (GET_SPECIES(ch) < NUM_SPECIES)) /** Return the class abbreviation for ch. */ #define CLASS_ABBR(ch) (HAS_VALID_CLASS(ch) ? class_abbrevs[(int)GET_CLASS(ch)] : "--") From 01fd5ede9e24f60b3d186fb86c5138145452019b Mon Sep 17 00:00:00 2001 From: kinther Date: Sun, 28 Dec 2025 20:54:42 -0800 Subject: [PATCH 04/40] Minor species update to max stat values --- src/species.c | 72 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/src/species.c b/src/species.c index c94afde..aed2883 100644 --- a/src/species.c +++ b/src/species.c @@ -69,6 +69,18 @@ static const struct species_skill_bonus species_skill_none[] = { { -1, 0 } }; +/* Skill percent values map to proficiency tiers via GET_PROFICIENCY(). */ +static const struct species_skill_bonus species_skill_crodlu[] = { + { SKILL_PERCEPTION, 45 }, /* +3 proficiency */ + { -1, 0 } +}; + +static const struct species_skill_bonus species_skill_jhakar[] = { + { SKILL_PERCEPTION, 45 }, /* +3 proficiency */ + { SKILL_STEALTH, 60 }, /* +4 proficiency */ + { -1, 0 } +}; + /* Per-species skill bonuses. * Usage: * 1) Define a bonus list for a species (see commented example below). @@ -101,10 +113,10 @@ static const struct species_skill_bonus *species_skill_bonuses[NUM_SPECIES] = { species_skill_none, /* Tarek */ species_skill_none, /* Aprig */ species_skill_none, /* Carru */ - species_skill_none, /* Crodlu */ + species_skill_crodlu, /* Crodlu */ species_skill_none, /* Erdlu */ species_skill_none, /* Inix */ - species_skill_none, /* Jhakar */ + species_skill_jhakar, /* Jhakar */ species_skill_none, /* Kank */ species_skill_none, /* Mekillot */ species_skill_none, /* Worm */ @@ -180,34 +192,34 @@ static const int species_ability_mods[NUM_SPECIES][NUM_ABILITIES] = { /* Ability caps by species (STR, DEX, CON, INT, WIS, CHA). Zero = no cap. */ static const int species_ability_caps[NUM_SPECIES][NUM_ABILITIES] = { - { 16, 0, 0, 0, 0, 0 }, /* Human */ - { 14, 0, 0, 0, 0, 0 }, /* City Elf */ - { 14, 0, 0, 0, 0, 0 }, /* Desert Elf */ - { 14, 0, 0, 0, 0, 0 }, /* Half-Elf */ - { 18, 0, 0, 0, 0, 0 }, /* Dwarf */ - { 20, 0, 0, 0, 0, 0 }, /* Mul */ - { 24, 0, 0, 0, 0, 0 }, /* Half-Giant */ - { 0, 0, 0, 0, 0, 0 }, /* Mantis */ - { 0, 0, 0, 0, 0, 0 }, /* Gith */ - { 0, 0, 0, 0, 0, 0 }, /* Aarakocra */ - { 0, 0, 0, 0, 0, 0 }, /* Dray */ - { 0, 0, 0, 0, 0, 0 }, /* Kenku */ - { 0, 0, 0, 0, 0, 0 }, /* Jozhal */ - { 0, 0, 0, 0, 0, 0 }, /* Pterran */ - { 0, 0, 0, 0, 0, 0 }, /* Tarek */ - { 0, 0, 0, 0, 0, 0 }, /* Aprig */ - { 0, 0, 0, 0, 0, 0 }, /* Carru */ - { 0, 0, 0, 0, 0, 0 }, /* Crodlu */ - { 0, 0, 0, 0, 0, 0 }, /* Erdlu */ - { 0, 0, 0, 0, 0, 0 }, /* Inix */ - { 0, 0, 0, 0, 0, 0 }, /* Jhakar */ - { 0, 0, 0, 0, 0, 0 }, /* Kank */ - { 0, 0, 0, 0, 0, 0 }, /* Mekillot */ - { 0, 0, 0, 0, 0, 0 }, /* Worm */ - { 0, 0, 0, 0, 0, 0 }, /* Renk */ - { 0, 0, 0, 0, 0, 0 }, /* Rat */ - { 0, 0, 0, 0, 0, 0 }, /* Undead */ - { 0, 0, 0, 0, 0, 0 } /* Dragon */ + { 14, 14, 14, 14, 14, 14 }, /* Human */ + { 10, 18, 10, 14, 16, 14 }, /* City Elf */ + { 12, 18, 12, 12, 14, 12 }, /* Desert Elf */ + { 13, 16, 13, 13, 15, 10 }, /* Half-Elf */ + { 18, 10, 18, 10, 10, 10 }, /* Dwarf */ + { 20, 14, 18, 10, 10, 8 }, /* Mul */ + { 24, 8, 20, 6, 6, 6 }, /* Half-Giant */ + { 14, 14, 16, 10, 12, 6 }, /* Mantis */ + { 12, 16, 14, 10, 8, 6 }, /* Gith */ + { 13, 16, 14, 13, 13, 13 }, /* Aarakocra */ + { 15, 13, 15, 12, 12, 14 }, /* Dray */ + { 12, 16, 12, 15, 15, 13 }, /* Kenku */ + { 8, 10, 8, 8, 8, 6 }, /* Jozhal */ + { 15, 12, 15, 15, 12, 10 }, /* Pterran */ + { 17, 13, 18, 10, 10, 6 }, /* Tarek */ + { 8, 10, 12, 2, 10, 5 }, /* Aprig */ + { 21, 8, 15, 2, 12, 6 }, /* Carru */ + { 16, 15, 14, 4, 12, 6 }, /* Crodlu */ + { 16, 10, 12, 2, 11, 7 }, /* Erdlu */ + { 22, 12, 18, 2, 10, 7 }, /* Inix */ + { 17, 15, 16, 3, 12, 7 }, /* Jhakar */ + { 18, 10, 14, 2, 10, 4 }, /* Kank */ + { 24, 9, 21, 3, 11, 6 }, /* Mekillot */ + { 22, 8, 19, 2, 2, 6 }, /* Worm */ + { 2, 4, 10, 4, 10, 4 }, /* Renk */ + { 2, 11, 9, 2, 10, 4 }, /* Rat */ + { 18, 16, 18, 16, 16, 16 }, /* Undead */ + { 25, 25, 25, 25, 25, 25 } /* Dragon */ }; const char *get_species_name(int species) From 21a4d27f2dc19976521492595ff37a5fbe03cc1e Mon Sep 17 00:00:00 2001 From: kinther Date: Sun, 28 Dec 2025 20:55:43 -0800 Subject: [PATCH 05/40] Fix medit background issue --- src/medit.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/medit.c b/src/medit.c index 637263f..41c8688 100644 --- a/src/medit.c +++ b/src/medit.c @@ -421,12 +421,11 @@ static void medit_disp_menu(struct descriptor_data *d) { struct char_data *mob; char flags[MAX_STRING_LENGTH], flag2[MAX_STRING_LENGTH]; - const char *background, *classname, *speciesname; + const char *classname, *speciesname; mob = OLC_MOB(d); get_char_colors(d->character); clear_screen(d); - background = GET_BACKGROUND(mob) ? GET_BACKGROUND(mob) : "\r\n"; classname = HAS_VALID_CLASS(mob) ? pc_class_types[GET_CLASS(mob)] : "Unassigned"; speciesname = HAS_VALID_SPECIES(mob) ? species_types[GET_SPECIES(mob)] : "Unassigned"; @@ -461,7 +460,7 @@ static void medit_disp_menu(struct descriptor_data *d) "%s-%s) Skills Menu...\r\n" "%sA%s) NPC Flags : %s%s\r\n" "%sB%s) AFF Flags : %s%s\r\n" - "%sC%s) Background:-\r\n%s%s\r\n" + "%sC%s) Background...\r\n" "%sS%s) Script : %s%s\r\n" "%sW%s) Copy mob\r\n" "%sX%s) Delete mob\r\n" @@ -478,7 +477,7 @@ static void medit_disp_menu(struct descriptor_data *d) grn, nrm, grn, nrm, cyn, flags, grn, nrm, cyn, flag2, - grn, nrm, yel, background, + grn, nrm, grn, nrm, cyn, OLC_SCRIPT(d) ?"Set.":"Not Set.", grn, nrm, grn, nrm, From cd3743018b3cba6ed278d6461c6ae066d62f16db Mon Sep 17 00:00:00 2001 From: kinther Date: Sun, 28 Dec 2025 20:58:06 -0800 Subject: [PATCH 06/40] Stat command update for saving throws --- src/act.wizard.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/act.wizard.c b/src/act.wizard.c index ba56972..4413b97 100644 --- a/src/act.wizard.c +++ b/src/act.wizard.c @@ -1827,13 +1827,13 @@ static void do_stat_character(struct char_data *ch, struct char_data *k) GET_DEX(k), GET_CON(k), GET_CHA(k)); stat_table_row_fmt(ch, "Saving Throws", - "Str %+d (%+d) Dex %+d (%+d) Con %+d (%+d) Int %+d (%+d) Wis %+d (%+d) Cha %+d (%+d)", - get_save_mod(k, ABIL_STR), GET_SAVE(k, ABIL_STR), - get_save_mod(k, ABIL_DEX), GET_SAVE(k, ABIL_DEX), - get_save_mod(k, ABIL_CON), GET_SAVE(k, ABIL_CON), - get_save_mod(k, ABIL_INT), GET_SAVE(k, ABIL_INT), - get_save_mod(k, ABIL_WIS), GET_SAVE(k, ABIL_WIS), - get_save_mod(k, ABIL_CHA), GET_SAVE(k, ABIL_CHA)); + "Str %+d Dex %+d Con %+d Int %+d Wis %+d Cha %+d", + get_save_mod(k, ABIL_STR), + get_save_mod(k, ABIL_DEX), + get_save_mod(k, ABIL_CON), + get_save_mod(k, ABIL_INT), + get_save_mod(k, ABIL_WIS), + get_save_mod(k, ABIL_CHA)); stat_table_row_fmt(ch, "Vitals", "HP %d/%d (+%d) | Mana %d/%d (+%d) | Move %d/%d (+%d)", From 4f502a1801a3ed08d777bf117b5b0d101c5810b2 Mon Sep 17 00:00:00 2001 From: kinther Date: Sun, 28 Dec 2025 21:05:26 -0800 Subject: [PATCH 07/40] Weight handling update and reducing coin weight --- lib/world/mob/1.mob | 47 +++++++++++++++++++++++++-------------------- src/act.item.c | 3 +++ src/db.c | 3 +++ src/handler.c | 8 +++++++- src/objsave.c | 3 +++ src/roomsave.c | 3 +++ 6 files changed, 45 insertions(+), 22 deletions(-) diff --git a/lib/world/mob/1.mob b/lib/world/mob/1.mob index 948687c..41783ba 100644 --- a/lib/world/mob/1.mob +++ b/lib/world/mob/1.mob @@ -16,6 +16,7 @@ B + ~ 6218 0 0 0 0 0 0 0 0 E 1 3d20+40 @@ -34,17 +35,17 @@ Skill 145 5 Skill 146 5 Skill 147 5 E -L 3 118 1 -L 5 131 1 -L 6 110 1 -L 7 108 1 -L 8 115 1 -L 9 124 1 -L 10 107 1 -L 11 111 1 -L 15 117 1 -L 16 117 1 L 17 127 1 +L 16 117 1 +L 15 117 1 +L 11 111 1 +L 10 107 1 +L 9 124 1 +L 8 115 1 +L 7 108 1 +L 6 110 1 +L 5 131 1 +L 3 118 1 #101 Sally~ slim lanky human soldier guard~ @@ -64,6 +65,7 @@ B + ~ 6218 0 0 0 0 0 0 0 0 E 1 3d20+40 @@ -84,17 +86,17 @@ Skill 152 5 Skill 156 5 Skill 163 5 E -L 17 127 1 -L 16 117 1 -L 15 117 1 -L 11 111 1 -L 10 107 1 -L 9 124 1 -L 8 115 1 -L 7 108 1 -L 6 110 1 -L 5 131 1 L 3 118 1 +L 5 131 1 +L 6 110 1 +L 7 108 1 +L 8 115 1 +L 9 124 1 +L 10 107 1 +L 11 111 1 +L 15 117 1 +L 16 117 1 +L 17 127 1 #102 Baldy~ barkeep stocky bald~ @@ -114,13 +116,14 @@ B + ~ 10 0 0 0 0 0 0 0 0 E 1 3d12+60 8 8 1 E -L 14 113 1 L 9 112 1 +L 14 113 1 #103 Lanky~ woman lanky scarred~ @@ -141,6 +144,7 @@ B + ~ 10 0 0 0 0 0 0 0 0 E 1 3d8+60 @@ -171,6 +175,7 @@ B + It's a rat. ~ 8 0 0 0 0 0 0 0 0 E diff --git a/src/act.item.c b/src/act.item.c index 88a8742..5173d65 100644 --- a/src/act.item.c +++ b/src/act.item.c @@ -920,6 +920,9 @@ void weight_change_object(struct obj_data *obj, int weight) obj_from_char(obj); GET_OBJ_WEIGHT(obj) += weight; obj_to_char(obj, tmp_ch); + } else if ((tmp_ch = obj->worn_by)) { + IS_CARRYING_W(tmp_ch) += weight; + GET_OBJ_WEIGHT(obj) += weight; } else if ((tmp_obj = obj->in_obj)) { obj_from_obj(obj); GET_OBJ_WEIGHT(obj) += weight; diff --git a/src/db.c b/src/db.c index 1cd9b68..b0cef55 100644 --- a/src/db.c +++ b/src/db.c @@ -2801,6 +2801,9 @@ struct obj_data *read_object(obj_vnum nr, int type) /* and obj_rnum */ copy_proto_script(&obj_proto[i], obj, OBJ_TRIGGER); assign_triggers(obj, OBJ_TRIGGER); + if (GET_OBJ_TYPE(obj) == ITEM_MONEY) + update_money_obj(obj); + return (obj); } diff --git a/src/handler.c b/src/handler.c index b23111e..8d6747f 100644 --- a/src/handler.c +++ b/src/handler.c @@ -569,6 +569,7 @@ void equip_char(struct char_data *ch, struct obj_data *obj, int pos) GET_EQ(ch, pos) = obj; obj->worn_by = ch; obj->worn_on = pos; + IS_CARRYING_W(ch) += GET_OBJ_WEIGHT(obj); if (GET_OBJ_TYPE(obj) == ITEM_ARMOR) GET_AC(ch) -= apply_ac(ch, pos); @@ -601,6 +602,7 @@ struct obj_data *unequip_char(struct char_data *ch, int pos) obj = GET_EQ(ch, pos); obj->worn_by = NULL; obj->worn_on = -1; + IS_CARRYING_W(ch) -= GET_OBJ_WEIGHT(obj); if (GET_OBJ_TYPE(obj) == ITEM_ARMOR) GET_AC(ch) += apply_ac(ch, pos); @@ -798,6 +800,8 @@ void obj_to_obj(struct obj_data *obj, struct obj_data *obj_to) GET_OBJ_WEIGHT(tmp_obj) += GET_OBJ_WEIGHT(obj); if (tmp_obj->carried_by) IS_CARRYING_W(tmp_obj->carried_by) += GET_OBJ_WEIGHT(obj); + else if (tmp_obj->worn_by) + IS_CARRYING_W(tmp_obj->worn_by) += GET_OBJ_WEIGHT(obj); } } @@ -831,6 +835,8 @@ void obj_from_obj(struct obj_data *obj) GET_OBJ_WEIGHT(temp) -= GET_OBJ_WEIGHT(obj); if (temp->carried_by) IS_CARRYING_W(temp->carried_by) -= GET_OBJ_WEIGHT(obj); + else if (temp->worn_by) + IS_CARRYING_W(temp->worn_by) -= GET_OBJ_WEIGHT(obj); } obj->in_obj = NULL; obj->next_content = NULL; @@ -1456,7 +1462,7 @@ int get_obj_pos_in_equip_vis(struct char_data *ch, char *arg, int *number, struc static int money_weight(int amount) { - const int coins_per_weight = 10; + const int coins_per_weight = 30; if (amount <= 0) return 0; diff --git a/src/objsave.c b/src/objsave.c index 1094cdd..e3800e9 100644 --- a/src/objsave.c +++ b/src/objsave.c @@ -573,6 +573,9 @@ obj_save_data *objsave_parse_objects(FILE *fl) void commit_current(void) { if (!temp) return; + if (GET_OBJ_TYPE(temp) == ITEM_MONEY) + update_money_obj(temp); + /* sanitize top-level locate range only; children will be negative later */ int loc = pending_locate; if (pending_nest <= 0) { diff --git a/src/roomsave.c b/src/roomsave.c index 81e217a..02a37f3 100644 --- a/src/roomsave.c +++ b/src/roomsave.c @@ -182,6 +182,9 @@ static struct obj_data *roomsave_read_list_ctx(FILE *fl, int stop_on_E) } /* Append to this scope's list */ + if (GET_OBJ_TYPE(obj) == ITEM_MONEY) + update_money_obj(obj); + obj->next_content = NULL; if (!head) head = tail = obj; else { tail->next_content = obj; tail = obj; } From 0e2e80fd094550c36e2a5e8e916da7779eb00fea Mon Sep 17 00:00:00 2001 From: kinther Date: Sun, 28 Dec 2025 21:19:56 -0800 Subject: [PATCH 08/40] Species stat rolling update --- lib/world/mob/1.mob | 22 ++++++--- src/medit.c | 110 +++++++++++++++++++++++++++++++------------- 2 files changed, 95 insertions(+), 37 deletions(-) diff --git a/lib/world/mob/1.mob b/lib/world/mob/1.mob index 41783ba..da2a3a5 100644 --- a/lib/world/mob/1.mob +++ b/lib/world/mob/1.mob @@ -17,6 +17,8 @@ B + + ~ 6218 0 0 0 0 0 0 0 0 E 1 3d20+40 @@ -66,6 +68,8 @@ B + + ~ 6218 0 0 0 0 0 0 0 0 E 1 3d20+40 @@ -117,6 +121,8 @@ B + + ~ 10 0 0 0 0 0 0 0 0 E 1 3d12+60 @@ -145,6 +151,8 @@ B + + ~ 10 0 0 0 0 0 0 0 0 E 1 3d8+60 @@ -176,17 +184,19 @@ B + + It's a rat. ~ 8 0 0 0 0 0 0 0 0 E 1 0d0+10 8 8 2 -Str: 6 -Dex: 10 -Int: 4 -Wis: 4 -Con: 6 -Cha: 3 +Str: 2 +Dex: 7 +Int: 1 +Wis: 8 +Con: 8 +Cha: 1 Species: 25 AtkT 4 E diff --git a/src/medit.c b/src/medit.c index 41c8688..6ff3cdc 100644 --- a/src/medit.c +++ b/src/medit.c @@ -43,6 +43,8 @@ static void medit_disp_aff_flags(struct descriptor_data *d); static void medit_disp_menu(struct descriptor_data *d); static void medit_disp_class_menu(struct descriptor_data *d); static void medit_disp_species_menu(struct descriptor_data *d); +static int roll_stat_for_cap(int cap); +static int autoroll_species_stat(struct char_data *mob, int ability); /* utility functions */ ACMD(do_oasis_medit) @@ -584,26 +586,22 @@ static void medit_disp_stats_menu(struct descriptor_data *d) /* Top section - standard stats */ write_to_output(d, "-- Mob Number: %s[%s%d%s]%s\r\n" - "(%s1%s) Level: %s[%s%4d%s]%s\r\n" - "(%s2%s) %sAuto Set Stats (based on level)%s\r\n\r\n" + "(%s1%s) %sAuto Set Stats (species range)%s\r\n\r\n" "Hit Points (xdy+z):\r\n" - "(%s3%s) HP NumDice: %s[%s%5d%s]%s\r\n" - "(%s4%s) HP SizeDice: %s[%s%5d%s]%s\r\n" - "(%s5%s) HP Addition: %s[%s%5d%s]%s\r\n" - "(%s8%s) Alignment: %s[%s%5d%s]%s\r\n\r\n", + "(%s2%s) HP NumDice: %s[%s%5d%s]%s\r\n" + "(%s3%s) HP SizeDice: %s[%s%5d%s]%s\r\n" + "(%s4%s) HP Addition: %s[%s%5d%s]%s\r\n\r\n", cyn, yel, OLC_NUM(d), cyn, nrm, - cyn, nrm, cyn, yel, GET_LEVEL(mob), cyn, nrm, cyn, nrm, cyn, nrm, cyn, nrm, cyn, yel, GET_HIT(mob), cyn, nrm, cyn, nrm, cyn, yel, GET_MANA(mob), cyn, nrm, - cyn, nrm, cyn, yel, GET_MOVE(mob), cyn, nrm, - cyn, nrm, cyn, yel, GET_ALIGNMENT(mob), cyn, nrm + cyn, nrm, cyn, yel, GET_MOVE(mob), cyn, nrm ); if (CONFIG_MEDIT_ADVANCED) { /* Bottom section - non-standard stats, togglable in cedit */ write_to_output(d, - "%sAttributes Saving Throws\r\n" + "%sAttributes Saving Throw bonus\r\n" "(%sF%s) Str: %s[%s%3d%s]%s (%sR%s) Save STR %s[%s%3d%s]%s\r\n" "(%sG%s) Dex: %s[%s%3d%s]%s (%sS%s) Save DEX %s[%s%3d%s]%s\r\n" "(%sH%s) Con: %s[%s%3d%s]%s (%sT%s) Save CON %s[%s%3d%s]%s\r\n" @@ -962,31 +960,23 @@ void medit_parse(struct descriptor_data *d, char *arg) case 'Q': medit_disp_menu(d); return; - case '1': /* Edit level */ - OLC_MODE(d) = MEDIT_LEVEL; - i++; - break; - case '2': /* Autoroll stats */ + case '1': /* Autoroll stats */ medit_autoroll_stats(d); medit_disp_stats_menu(d); OLC_VAL(d) = TRUE; return; - case '3': + case '2': OLC_MODE(d) = MEDIT_NUM_HP_DICE; i++; break; - case '4': + case '3': OLC_MODE(d) = MEDIT_SIZE_HP_DICE; i++; break; - case '5': + case '4': OLC_MODE(d) = MEDIT_ADD_HP; i++; break; - case '8': - OLC_MODE(d) = MEDIT_ALIGNMENT; - i++; - break; case 'f': case 'F': if (!CONFIG_MEDIT_ADVANCED) { @@ -1485,12 +1475,70 @@ void medit_string_cleanup(struct descriptor_data *d, int terminator) } } +static int roll_stat_for_cap(int cap) +{ + int total = 0; + int dice_d4 = 0; + int remainder = 0; + + if (cap <= 0) + return 0; + + dice_d4 = cap / 4; + remainder = cap % 4; + + if (dice_d4 > 0) + total += dice(dice_d4, 4); + if (remainder > 0) + total += dice(1, remainder); + + return total; +} + +static int autoroll_species_stat(struct char_data *mob, int ability) +{ + int min = 0; + int cap = 0; + int mod = 0; + int roll_cap; + int total; + + if (HAS_VALID_SPECIES(mob)) { + int species = GET_SPECIES(mob); + int species_min = species_ability_min(species, ability); + int species_cap = species_ability_cap(species, ability); + + if (species_min > 0) + min = species_min; + if (species_cap > 0) + cap = species_cap; + + mod = species_ability_mod(species, ability); + } + + if (cap > 0 && min > cap) + min = cap; + + roll_cap = (cap > 0) ? (cap - mod) : (18 - mod); + if (roll_cap < 1) + roll_cap = 1; + + total = roll_stat_for_cap(roll_cap) + mod; + + if (cap > 0 && total > cap) + total = cap; + if (min > 0 && total < min) + total = min; + + return total; +} + void medit_autoroll_stats(struct descriptor_data *d) { - int mob_lev; + int mob_lev = GET_LEVEL(OLC_MOB(d)); - mob_lev = 1; - GET_LEVEL(OLC_MOB(d)) = 1; + if (mob_lev < 1) + mob_lev = 1; GET_MOVE(OLC_MOB(d)) = mob_lev * 10; /* hit point bonus (mobs don't use movement points) */ GET_HIT(OLC_MOB(d)) = mob_lev / 5; /* number of hitpoint dice */ @@ -1498,12 +1546,12 @@ void medit_autoroll_stats(struct descriptor_data *d) /* 'Advanced' stats are only rolled if advanced options are enabled */ if (CONFIG_MEDIT_ADVANCED) { - GET_STR(OLC_MOB(d)) = LIMIT((mob_lev * 2) / 3, 11, 18); /* 2/3 level in range 11 to 18 */ - GET_INT(OLC_MOB(d)) = LIMIT((mob_lev * 2) / 3, 11, 18); - GET_WIS(OLC_MOB(d)) = LIMIT((mob_lev * 2) / 3, 11, 18); - 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_STR(OLC_MOB(d)) = autoroll_species_stat(OLC_MOB(d), ABIL_STR); + GET_INT(OLC_MOB(d)) = autoroll_species_stat(OLC_MOB(d), ABIL_INT); + GET_WIS(OLC_MOB(d)) = autoroll_species_stat(OLC_MOB(d), ABIL_WIS); + GET_DEX(OLC_MOB(d)) = autoroll_species_stat(OLC_MOB(d), ABIL_DEX); + GET_CON(OLC_MOB(d)) = autoroll_species_stat(OLC_MOB(d), ABIL_CON); + GET_CHA(OLC_MOB(d)) = autoroll_species_stat(OLC_MOB(d), ABIL_CHA); /* New ability-based saving throws: all default to 1/4 of mob level */ GET_SAVE(OLC_MOB(d), ABIL_STR) = mob_lev / 4; From 5d4d724e73da3607daef1781e004e2549263bef1 Mon Sep 17 00:00:00 2001 From: kinther Date: Mon, 29 Dec 2025 07:16:47 -0800 Subject: [PATCH 09/40] Prioritize stats during chargen --- README.md | 4 +- src/class.c | 103 +++++++++++++++++++++++++++++++++++- src/interpreter.c | 129 +++++++++++++++++++++++++++++++++++++++++++++- src/structs.h | 5 ++ 4 files changed, 237 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d613d35..48ea3a0 100644 --- a/README.md +++ b/README.md @@ -43,12 +43,12 @@ Features in Miranthas MUD Alpha release: * PC's now use a short description for identification instead of name * Backgrounds are now available for PC's and NPC's * Account system for tracking players/characters over long periods of time + * Race/species selection and stat ranges (elves have higher dex, dwarves have higher str, etc) + * Prioritized stats during character generation Features to be implemented in the next few releases: -* Race/species selection and stat ranges (elves have higher dex, dwarves have higher str, etc) * Subclass selection to personalize character further -* Prioritized stats during character generation * Combat is slowed down so it isn't over in < 15 seconds (unless you're far outmatched) * Mounts added to help with long trips * Wagons added to help with caravans diff --git a/src/class.c b/src/class.c index fafc7a0..9a005d2 100644 --- a/src/class.c +++ b/src/class.c @@ -139,10 +139,103 @@ bool has_save_proficiency(int class_num, int ability) { } } +static void set_real_ability(struct char_data *ch, int ability, int value) +{ + switch (ability) { + case ABIL_STR: ch->real_abils.str = value; break; + case ABIL_DEX: ch->real_abils.dex = value; break; + case ABIL_CON: ch->real_abils.con = value; break; + case ABIL_INT: ch->real_abils.intel = value; break; + case ABIL_WIS: ch->real_abils.wis = value; break; + case ABIL_CHA: ch->real_abils.cha = value; break; + } +} + +static void roll_real_abils_preference(struct char_data *ch) +{ + int i, j, temp; + int rolls[NUM_ABILITIES]; + int sorted[NUM_ABILITIES]; + bool used[NUM_ABILITIES] = { FALSE }; + bool assigned[NUM_ABILITIES] = { FALSE }; + static const int default_order[NUM_ABILITIES] = { + ABIL_STR, ABIL_DEX, ABIL_CON, ABIL_INT, ABIL_WIS, ABIL_CHA + }; + + for (i = 0; i < NUM_ABILITIES; i++) { + int die[4]; + + for (j = 0; j < 4; j++) + die[j] = rand_number(1, 6); + + temp = die[0] + die[1] + die[2] + die[3] - + MIN(die[0], MIN(die[1], MIN(die[2], die[3]))); + + rolls[i] = temp; + sorted[i] = temp; + } + + for (i = 0; i < NUM_ABILITIES - 1; i++) { + for (j = i + 1; j < NUM_ABILITIES; j++) { + if (sorted[j] > sorted[i]) { + temp = sorted[i]; + sorted[i] = sorted[j]; + sorted[j] = temp; + } + } + } + + int pref_count = ch->stat_pref_count; + if (pref_count > NUM_ABILITIES) + pref_count = NUM_ABILITIES; + + for (i = 0; i < pref_count; i++) { + int ability = ch->stat_pref_order[i]; + + if (ability < 0 || ability >= NUM_ABILITIES) + continue; + + set_real_ability(ch, ability, sorted[i]); + assigned[ability] = TRUE; + + for (j = 0; j < NUM_ABILITIES; j++) { + if (!used[j] && rolls[j] == sorted[i]) { + used[j] = TRUE; + break; + } + } + } + + int fifo_idx = 0; + for (i = 0; i < NUM_ABILITIES; i++) { + int ability = default_order[i]; + + if (assigned[ability]) + continue; + + while (fifo_idx < NUM_ABILITIES && used[fifo_idx]) + fifo_idx++; + if (fifo_idx >= NUM_ABILITIES) + break; + + set_real_ability(ch, ability, rolls[fifo_idx]); + used[fifo_idx] = TRUE; + assigned[ability] = TRUE; + fifo_idx++; + } + + if (HAS_VALID_SPECIES(ch)) + apply_species_bonuses(ch); + else + ch->aff_abils = ch->real_abils; + + ch->stat_pref_use = FALSE; +} + /* 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) +static void roll_real_abils_classic(struct char_data *ch) { int i, j, k, temp; ubyte table[6]; @@ -238,6 +331,14 @@ void roll_real_abils(struct char_data *ch) ch->aff_abils = ch->real_abils; } +void roll_real_abils(struct char_data *ch) +{ + if (ch && ch->stat_pref_use) + roll_real_abils_preference(ch); + else + roll_real_abils_classic(ch); +} + /* Per-class skill caps */ #define DEFAULT_CLASS_SKILL_MAX 90 diff --git a/src/interpreter.c b/src/interpreter.c index 073aaf0..51fa507 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -49,6 +49,10 @@ static bool perform_new_char_dupe_check(struct descriptor_data *d); /* sort_commands utility */ static int sort_commands_helper(const void *a, const void *b); static void show_species_menu(struct descriptor_data *d); +static bool is_creation_state(int state); +static void show_stat_pref_prompt(struct descriptor_data *d); +static int ability_from_pref_arg(const char *arg); +static bool parse_stat_preference(char *input, ubyte *order, ubyte *count); /* globals defined here, used here and elsewhere */ int *cmd_sort_info = NULL; @@ -1270,7 +1274,7 @@ static bool perform_new_char_dupe_check(struct descriptor_data *d) /* Do the player names match? */ if (!strcmp(GET_NAME(k->character), GET_NAME(d->character))) { /* Check the other character is still in creation? */ - if ((STATE(k) > CON_PLAYING) && (STATE(k) < CON_QCLASS)) { + if (is_creation_state(STATE(k))) { /* Boot the older one */ k->character->desc = NULL; k->character = NULL; @@ -1317,6 +1321,107 @@ static void show_species_menu(struct descriptor_data *d) write_to_output(d, "Species: "); } +static bool is_creation_state(int state) +{ + switch (state) { + case CON_GET_NAME: + case CON_NAME_CNFRM: + case CON_PASSWORD: + case CON_NEWPASSWD: + case CON_CNFPASSWD: + case CON_QSEX: + case CON_QSPECIES: + case CON_QCLASS: + case CON_QSTAT_PREF: + case CON_QSHORTDESC: + case CON_PLR_DESC: + case CON_PLR_BACKGROUND: + return TRUE; + default: + return FALSE; + } +} + +static void show_stat_pref_prompt(struct descriptor_data *d) +{ + write_to_output(d, + "\r\nEnter your stat preference, with the first stat being your preferred highest,\r\n" + "followed by the others in descending order.\r\n" + "If you list fewer than six, those listed get the highest rolls; the rest are FIFO.\r\n" + "Example: strength dexterity constitution intelligence wisdom charisma\r\n" + " or: str dex con int wis cha\r\n" + "Press Enter to skip (first-in, first-out).\r\n" + "Stat preference: "); +} + +static int ability_from_pref_arg(const char *arg) +{ + if (!arg || !*arg) + return -1; + if (!str_cmp(arg, "str") || is_abbrev(arg, "strength")) + return ABIL_STR; + if (!str_cmp(arg, "dex") || is_abbrev(arg, "dexterity")) + return ABIL_DEX; + if (!str_cmp(arg, "con") || is_abbrev(arg, "constitution")) + return ABIL_CON; + if (!str_cmp(arg, "int") || is_abbrev(arg, "intelligence")) + return ABIL_INT; + if (!str_cmp(arg, "wis") || is_abbrev(arg, "wisdom")) + return ABIL_WIS; + if (!str_cmp(arg, "cha") || is_abbrev(arg, "charisma")) + return ABIL_CHA; + return -1; +} + +static bool parse_stat_preference(char *input, ubyte *order, ubyte *count) +{ + char arg[MAX_INPUT_LENGTH]; + bool seen[NUM_ABILITIES] = { FALSE }; + + if (!order || !count) + return FALSE; + + *count = 0; + skip_spaces(&input); + if (!*input) + return TRUE; + + if (!str_cmp(input, "none") || !str_cmp(input, "no") || !str_cmp(input, "skip")) + return TRUE; + + while (*input) { + size_t len; + int ability; + + input = one_argument(input, arg); + if (!*arg) + break; + + len = strlen(arg); + while (len > 0 && (arg[len - 1] == ',' || arg[len - 1] == '.')) { + arg[len - 1] = '\0'; + len--; + } + + if (!*arg) + continue; + + ability = ability_from_pref_arg(arg); + if (ability < 0 || ability >= NUM_ABILITIES) + return FALSE; + if (seen[ability]) + return FALSE; + if (*count >= NUM_ABILITIES) + return FALSE; + + order[*count] = (ubyte)ability; + (*count)++; + seen[ability] = TRUE; + } + + return TRUE; +} + /* load the player, put them in the right room - used by copyover_recover too */ int enter_player_game (struct descriptor_data *d) { @@ -1912,6 +2017,27 @@ case CON_QCLASS: GET_CLASS(d->character) = load_result; } + show_stat_pref_prompt(d); + STATE(d) = CON_QSTAT_PREF; + return; + +case CON_QSTAT_PREF: { + ubyte order[NUM_ABILITIES]; + ubyte count = 0; + + if (!parse_stat_preference(arg, order, &count)) { + write_to_output(d, + "\r\nInvalid stat list. Please enter a valid order, or press Enter to skip.\r\n"); + show_stat_pref_prompt(d); + return; + } + + d->character->stat_pref_use = TRUE; + d->character->stat_pref_count = count; + for (int i = 0; i < NUM_ABILITIES; i++) { + d->character->stat_pref_order[i] = (i < count) ? order[i] : 0; + } + /* Create player entry and initialize character now so file exists */ if (d->olc) { free(d->olc); @@ -1958,6 +2084,7 @@ case CON_QCLASS: STATE(d) = CON_QSHORTDESC; return; +} case CON_QSHORTDESC: { skip_spaces(&arg); diff --git a/src/structs.h b/src/structs.h index d396bbd..2341eea 100644 --- a/src/structs.h +++ b/src/structs.h @@ -347,6 +347,7 @@ #define CON_QSEX 7 /**< Choose character sex */ #define CON_QSPECIES 8 /**< Choose character species */ #define CON_QCLASS 9 /**< Choose character class */ +#define CON_QSTAT_PREF 44 /**< Choose character stat preference order */ #define CON_QSHORTDESC 10 /**< Enter a new character short description prompt */ #define CON_RMOTD 11 /**< Reading the message of the day */ #define CON_MENU 12 /**< At the main menu */ @@ -1162,6 +1163,10 @@ struct char_data struct group_data *group; /**< Character's Group */ long pref; /**< unique session id */ + + bool stat_pref_use; /**< Use stat preference ordering when rolling abilities */ + ubyte stat_pref_count; /**< Number of preferred stats entered */ + ubyte stat_pref_order[NUM_ABILITIES]; /**< Ability order preferences */ struct list_data * events; }; From d4a7ccea5d26051d12156fca9ad842f1a5b10313 Mon Sep 17 00:00:00 2001 From: kinther Date: Mon, 29 Dec 2025 08:20:07 -0800 Subject: [PATCH 10/40] Rename move to stamina --- lib/text/help/help.hlp | 45 ++++++++++++++------------ src/act.informative.c | 8 ++--- src/act.item.c | 4 +-- src/act.movement.c | 10 +++--- src/act.other.c | 29 +++++++++-------- src/act.wizard.c | 73 +++++++++++++++++++++--------------------- src/class.c | 8 ++--- src/comm.c | 12 +++---- src/constants.c | 4 +-- src/db.c | 18 +++++------ src/dg_variables.c | 12 +++---- src/genmob.c | 2 +- src/genolc.c | 2 +- src/handler.c | 2 +- src/limits.c | 4 +-- src/magic.c | 2 +- src/medit.c | 12 +++---- src/pfdefaults.h | 4 +-- src/players.c | 21 +++++++----- src/prefedit.c | 18 +++++------ src/protocol.c | 2 +- src/roomsave.c | 13 +++----- src/roomsave.h | 12 +++---- src/structs.h | 8 ++--- src/util/plrtoascii.c | 8 ++--- src/utils.h | 8 ++--- 26 files changed, 171 insertions(+), 170 deletions(-) diff --git a/lib/text/help/help.hlp b/lib/text/help/help.hlp index c1a9f5b..556e09e 100644 --- a/lib/text/help/help.hlp +++ b/lib/text/help/help.hlp @@ -1676,8 +1676,10 @@ mana() - The current mana points of the actor. Subfield adjusts. master - The master of the actor (as an id), or an empty return. maxhitp() - The maximum hit points of the actor. Subfield adjusts. maxmana() - The maximum mana points of the actor. Subfield adjusts. -maxmove() - The maximum movement points of the actor. Subfield adjusts. -move() - The movement points of the actor. Subfield adjusts. +maxstamina() - The maximum stamina points of the actor. Subfield adjusts. +stamina() - The stamina points of the actor. Subfield adjusts. +maxmove() - Alias for maxstamina(). +move() - Alias for stamina(). name - The actor's name (the short description for mobs). next_in_room - The next mob/player in the room as a variable (id) nice to use for loops, or an empty return @RTSTAT 23@n @@ -2561,13 +2563,13 @@ See also: DISPEL-EVIL #0 DISPLAYS PROMPTS HIT-PNT-DISPLAY -Usage: prompt < H | M | V | all | auto | off > +Usage: prompt < H | M | S | all | auto | off > -Modify your prompt to show your hit points, mana, and/or movement points. +Modify your prompt to show your hit points, mana, and/or stamina points. - > prompt hv Display hit points and movement points. + > prompt hs Display hit points and stamina points. > prompt off Return to no prompt. - > prompt all Display hit, mana, and movement points. + > prompt all Display hit, mana, and stamina points. > prompt auto A separate toggle that will only display your selected prompt if the values drop below 30% of max. @@ -4530,7 +4532,7 @@ OBJECT STANDARDS: |Age | 10 | -10 | |Weight | 50 | 1 | |Cost | 1000 | 1 | -|Hitpoints, Mana, Movement | 50 | -50 | +|Hitpoints, Mana, Stamina | 50 | -50 | |Coins | Do not use. | |Experience | Do not use. | |Armor Class Values | 10 | -10 | @@ -5459,10 +5461,11 @@ It is a toggle that can be turned on and off by the same command. See also: SKILLS #2 -MV MOVEPOINTS MOVE-POINTS MOVEMENTPOINTS MOVEMENT-POINTS +STAMINA STAMINA-POINTS STAMINAPOINTS MV MOVEPOINTS MOVE-POINTS MOVEMENTPOINTS MOVEMENT-POINTS - Depending on the type of terrain your character will tire from too much -traveling and require some rest to continue. + Stamina points measure how tired you are. Depending on the type of terrain, +your character will tire from too much traveling and require some rest to +continue. See also: MANA, HITPOINTS #0 @@ -5824,7 +5827,7 @@ applies. Suggested object standards are displayed at the end of each apply 12) CHAR_HEIGHT Apply to height. 13) MAXMANA Apply to MAX mana points. 14) MAXHIT Apply to MAX hit points. -15) MAXMOVE Apply to MAX movement points. +15) MAXSTAMINA Apply to MAX stamina points. 16) COINS Unimplemented. Do not use. 17) EXP Unimplemented. Do not use. 18) ARMOR Apply to armor class (AC). negative is better. @@ -7000,7 +7003,7 @@ NO_SHOUT - Player can not see shouts. NO_TELL - Player can not see tells. D_HP - Player can see their HP. D_MANA - Player can see their MANA. -D_MOVE - Player can see their MOVE. +D_STAMINA - Player can see their Stamina. AUTOEX - Player can see exits. NO_HASS - Builder is safe from aggressive mobs, triggers will not work. QUEST - Player is on a quest. @@ -7746,10 +7749,10 @@ and VNUM have the same first few numbers. REDIT-SECTOR-TYPE SECTORS SECTOR-TYPE TERRAIN-TYPE FIELDS FORESTS REDIT-SECTOR-FLAGS SCUBA UNDERWATER 4) Sector type : @cInside@n - This defines movement point, light, and boat requirements. + This defines stamina point, light, and boat requirements. The following terrains may be selected (only one): - Movement Points + Stamina Points 1) Inside Indoors (no light required) 1 2) City The streets of a city. 1 3) Field An open field. 2 @@ -7984,7 +7987,7 @@ RESTORE REVIVE Usage: restore - RESTORE restores a player or mobile to full hit, mana, and movement points. + RESTORE restores a player or mobile to full hit, mana, and stamina points. Restore all will restore all players in the game. If used on immortals, it also sets all skill levels to 100%. @@ -8113,7 +8116,7 @@ SCORE Summary: Score provides useful information about your character that you would find on a traditional tabletop character sheet. Examples: -HP, Mana, and Movement points +HP, Mana, and Stamina points Strength, Dexterity, Constituion, Intelligence, Wisdom, and Charisma scores Armor Class with breakdown Stealth Disadvantage @@ -8500,8 +8503,8 @@ loadroom Imm PC MISC mana Imm BOTH NUMBER maxhit Imm BOTH NUMBER maxmana Imm BOTH NUMBER -maxmove Imm BOTH NUMBER -move Imm BOTH NUMBER +maxstam Imm BOTH NUMBER +stam Imm BOTH NUMBER name Imm PC MISC nodelete God PC BINARY nohassle God PC BINARY @@ -9165,7 +9168,7 @@ A list is below: Wisdom - How wise you are. Helps in combat, and when regaining mana. Constitution - How healthy and robust you are. Determines how many hit points you gain per level, and how well you heal. -Dexterity - How agile you are. How many movement points you gain per level, +Dexterity - How agile you are. How many stamina points you gain per level, and how well you dodge attacks, pick locks, and kick without falling over. Charisma - How personable your character is. This can affect shop prices @@ -10317,7 +10320,7 @@ time you change it. Level IMP toggle includes: NoHassle: ON Holylight: ON ShowVnums: ON Syslog: normal Hit Pnt Display: OFF Brief: OFF Summonable: OFF - Move Display: OFF Compact: ON Quest: OFF + Stamina Display: OFF Compact: ON Quest: OFF Mana Display: OFF NoTell: OFF NoRepeat: OFF AutoExits: OFF NoShout: OFF Wimpy: OFF AutoLoot: ON AutoSplit: ON @@ -10338,7 +10341,7 @@ argument. When a toggle is set, it will be saved in that state until the next time you change it. Hit Pnt Display: OFF Brief: OFF Summonable: OFF - Move Display: OFF Compact: ON Quest: OFF + Stamina Display: OFF Compact: ON Quest: OFF Mana Display: OFF NoTell: OFF NoRepeat: OFF AutoExits: OFF NoShout: OFF Wimpy: OFF AutoLoot: ON AutoSplit: ON diff --git a/src/act.informative.c b/src/act.informative.c index 04c2183..b463cc9 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -1155,10 +1155,10 @@ ACMD(do_score) "====================[ Score ]====================\r\n"); send_to_char(ch, - "HP: %d/%d Mana: %d/%d Move: %d/%d\r\n", + "HP: %d/%d Mana: %d/%d Stamina: %d/%d\r\n", GET_HIT(ch), GET_MAX_HIT(ch), GET_MANA(ch), GET_MAX_MANA(ch), - GET_MOVE(ch), GET_MAX_MOVE(ch)); + GET_STAMINA(ch), GET_MAX_STAMINA(ch)); /* Abilities and 5e modifiers */ send_to_char(ch, @@ -2329,7 +2329,7 @@ ACMD(do_toggle) " Brief: %-3s " " Summonable: %-3s\r\n" - " Move Display: %-3s " + " Stamina Display: %-3s " " Compact: %-3s " " Quest: %-3s\r\n" @@ -2358,7 +2358,7 @@ ACMD(do_toggle) ONOFF(PRF_FLAGGED(ch, PRF_BRIEF)), ONOFF(PRF_FLAGGED(ch, PRF_SUMMONABLE)), - ONOFF(PRF_FLAGGED(ch, PRF_DISPMOVE)), + ONOFF(PRF_FLAGGED(ch, PRF_DISPSTAMINA)), ONOFF(PRF_FLAGGED(ch, PRF_COMPACT)), ONOFF(PRF_FLAGGED(ch, PRF_QUEST)), diff --git a/src/act.item.c b/src/act.item.c index 5173d65..9c753cc 100644 --- a/src/act.item.c +++ b/src/act.item.c @@ -2165,7 +2165,7 @@ ACMD(do_forage) prof_bonus = GET_PROFICIENCY(GET_SKILL(ch, SKILL_SURVIVAL)); cost = MAX(1, 10 - prof_bonus); - if (!IS_NPC(ch) && GET_MOVE(ch) < cost) { + if (!IS_NPC(ch) && GET_STAMINA(ch) < cost) { send_to_char(ch, "You are too exhausted to forage.\r\n"); return; } @@ -2174,7 +2174,7 @@ ACMD(do_forage) WAIT_STATE(ch, delay_seconds * PASSES_PER_SEC); if (!IS_NPC(ch)) - GET_MOVE(ch) = MAX(0, GET_MOVE(ch) - cost); + GET_STAMINA(ch) = MAX(0, GET_STAMINA(ch) - cost); total = roll_skill_check(ch, SKILL_SURVIVAL, 0, NULL); diff --git a/src/act.movement.c b/src/act.movement.c index 7f3eb59..29d0734 100644 --- a/src/act.movement.c +++ b/src/act.movement.c @@ -290,7 +290,7 @@ int do_simple_move(struct char_data *ch, int dir, int need_specials_check) room_rnum was_in = IN_ROOM(ch); /* ... and the room the character will move into. */ room_rnum going_to = EXIT(ch, dir)->to_room; - /* How many movement points are required to travel from was_in to going_to. + /* How many stamina points are required to travel from was_in to going_to. * We redefine this later when we need it. */ int need_movement = 0; /* Contains the "leave" message to display to the was_in room. */ @@ -400,13 +400,13 @@ int do_simple_move(struct char_data *ch, int dir, int need_specials_check) } /* All checks passed, nothing will prevent movement now other than lack of - * move points. */ - /* move points needed is avg. move loss for src and destination sect type */ + * stamina points. */ + /* stamina points needed is avg. move loss for src and destination sect type */ need_movement = (movement_loss[SECT(was_in)] + movement_loss[SECT(going_to)]) / 2; /* Move Point Requirement Check */ - if (GET_MOVE(ch) < need_movement && !IS_NPC(ch)) + if (GET_STAMINA(ch) < need_movement && !IS_NPC(ch)) { if (need_specials_check && ch->master) send_to_char(ch, "You are too exhausted to follow.\r\n"); @@ -424,7 +424,7 @@ int do_simple_move(struct char_data *ch, int dir, int need_specials_check) /*---------------------------------------------------------------------*/ /* If applicable, subtract movement cost. */ if (GET_LEVEL(ch) < LVL_IMMORT && !IS_NPC(ch)) - GET_MOVE(ch) -= need_movement; + GET_STAMINA(ch) -= need_movement; /* Generate the leave message and display to others in the was_in room. */ if (AFF_FLAGGED(ch, AFF_SNEAK)) { diff --git a/src/act.other.c b/src/act.other.c index 07e47f0..99d611f 100644 --- a/src/act.other.c +++ b/src/act.other.c @@ -557,7 +557,7 @@ ACMD(do_sneak) if (total < dc) { gain_skill(ch, "stealth", FALSE); WAIT_STATE(ch, PULSE_VIOLENCE / 2); - GET_MOVE(ch) -= 10; + GET_STAMINA(ch) -= 10; return; } @@ -576,7 +576,7 @@ ACMD(do_sneak) SET_STEALTH_CHECK(ch, MAX(GET_STEALTH_CHECK(ch), total)); gain_skill(ch, "stealth", TRUE); - GET_MOVE(ch) -= 10; + GET_STAMINA(ch) -= 10; } ACMD(do_hide) @@ -612,7 +612,7 @@ ACMD(do_hide) /* Failure */ gain_skill(ch, "stealth", FALSE); WAIT_STATE(ch, PULSE_VIOLENCE / 2); - GET_MOVE(ch) -= 10; + GET_STAMINA(ch) -= 10; return; } @@ -623,7 +623,7 @@ ACMD(do_hide) send_to_char(ch, "You hide yourself as best you can.\r\n"); gain_skill(ch, "stealth", TRUE); WAIT_STATE(ch, PULSE_VIOLENCE / 2); - GET_MOVE(ch) -= 10; + GET_STAMINA(ch) -= 10; } static void remember_scan_target(struct char_data *ch, struct char_data *tch) @@ -929,7 +929,7 @@ ACMD(do_scan) act("$n studies $s surroundings with a wary gaze.", TRUE, ch, 0, 0, TO_ROOM); WAIT_STATE(ch, PULSE_VIOLENCE / 2); - GET_MOVE(ch) -= 10; + GET_STAMINA(ch) -= 10; } ACMD(do_listen) @@ -959,7 +959,7 @@ ACMD(do_listen) send_to_char(ch, "You focus entirely on every whisper and distant sound.\r\n"); WAIT_STATE(ch, PULSE_VIOLENCE / 2); - GET_MOVE(ch) -= 10; + GET_STAMINA(ch) -= 10; } ACMD(do_palm) @@ -1307,7 +1307,7 @@ static void print_group(struct char_data *ch) GROUP_LEADER(GROUP(ch)) == k ? CBGRN(ch, C_NRM) : CCGRN(ch, C_NRM), GET_HIT(k), GET_MAX_HIT(k), GET_MANA(k), GET_MAX_MANA(k), - GET_MOVE(k), GET_MAX_MOVE(k), + GET_STAMINA(k), GET_MAX_STAMINA(k), CCNRM(ch, C_NRM)); } @@ -1464,7 +1464,7 @@ ACMD(do_report) GET_NAME(ch), GET_HIT(ch), GET_MAX_HIT(ch), GET_MANA(ch), GET_MAX_MANA(ch), - GET_MOVE(ch), GET_MAX_MOVE(ch)); + GET_STAMINA(ch), GET_MAX_STAMINA(ch)); } ACMD(do_split) @@ -1600,7 +1600,7 @@ ACMD(do_display) skip_spaces(&argument); if (!*argument) { - send_to_char(ch, "Usage: prompt { { H | M | V } | all | auto | none }\r\n"); + send_to_char(ch, "Usage: prompt { { H | M | S } | all | auto | none }\r\n"); return; } @@ -1613,15 +1613,15 @@ ACMD(do_display) if (!str_cmp(argument, "on") || !str_cmp(argument, "all")) { SET_BIT_AR(PRF_FLAGS(ch), PRF_DISPHP); SET_BIT_AR(PRF_FLAGS(ch), PRF_DISPMANA); - SET_BIT_AR(PRF_FLAGS(ch), PRF_DISPMOVE); + SET_BIT_AR(PRF_FLAGS(ch), PRF_DISPSTAMINA); } else if (!str_cmp(argument, "off") || !str_cmp(argument, "none")) { REMOVE_BIT_AR(PRF_FLAGS(ch), PRF_DISPHP); REMOVE_BIT_AR(PRF_FLAGS(ch), PRF_DISPMANA); - REMOVE_BIT_AR(PRF_FLAGS(ch), PRF_DISPMOVE); + REMOVE_BIT_AR(PRF_FLAGS(ch), PRF_DISPSTAMINA); } else { REMOVE_BIT_AR(PRF_FLAGS(ch), PRF_DISPHP); REMOVE_BIT_AR(PRF_FLAGS(ch), PRF_DISPMANA); - REMOVE_BIT_AR(PRF_FLAGS(ch), PRF_DISPMOVE); + REMOVE_BIT_AR(PRF_FLAGS(ch), PRF_DISPSTAMINA); for (i = 0; i < strlen(argument); i++) { switch (LOWER(argument[i])) { @@ -1631,11 +1631,12 @@ ACMD(do_display) case 'm': SET_BIT_AR(PRF_FLAGS(ch), PRF_DISPMANA); break; + case 's': case 'v': - SET_BIT_AR(PRF_FLAGS(ch), PRF_DISPMOVE); + SET_BIT_AR(PRF_FLAGS(ch), PRF_DISPSTAMINA); break; default: - send_to_char(ch, "Usage: prompt { { H | M | V } | all | auto | none }\r\n"); + send_to_char(ch, "Usage: prompt { { H | M | S } | all | auto | none }\r\n"); return; } } diff --git a/src/act.wizard.c b/src/act.wizard.c index 4413b97..720ad63 100644 --- a/src/act.wizard.c +++ b/src/act.wizard.c @@ -1836,10 +1836,10 @@ static void do_stat_character(struct char_data *ch, struct char_data *k) get_save_mod(k, ABIL_CHA)); stat_table_row_fmt(ch, "Vitals", - "HP %d/%d (+%d) | Mana %d/%d (+%d) | Move %d/%d (+%d)", + "HP %d/%d (+%d) | Mana %d/%d (+%d) | Stamina %d/%d (+%d)", GET_HIT(k), GET_MAX_HIT(k), hit_gain(k), GET_MANA(k), GET_MAX_MANA(k), mana_gain(k), - GET_MOVE(k), GET_MAX_MOVE(k), move_gain(k)); + GET_STAMINA(k), GET_MAX_STAMINA(k), move_gain(k)); stat_table_row_fmt(ch, "Currency", "Coins %d, Bank %d (Total %d)", GET_COINS(k), GET_BANK_COINS(k), GET_COINS(k) + GET_BANK_COINS(k)); @@ -2542,7 +2542,7 @@ ACMD(do_restore) GET_HIT(vict) = GET_MAX_HIT(vict); GET_MANA(vict) = GET_MAX_MANA(vict); - GET_MOVE(vict) = GET_MAX_MOVE(vict); + GET_STAMINA(vict) = GET_MAX_STAMINA(vict); update_pos(vict); send_to_char(ch, "%s has been fully healed.\r\n", GET_NAME(vict)); @@ -2558,7 +2558,7 @@ ACMD(do_restore) GET_HIT(vict) = GET_MAX_HIT(vict); GET_MANA(vict) = GET_MAX_MANA(vict); - GET_MOVE(vict) = GET_MAX_MOVE(vict); + GET_STAMINA(vict) = GET_MAX_STAMINA(vict); if (!IS_NPC(vict) && GET_LEVEL(ch) >= LVL_GRGOD) { if (GET_LEVEL(vict) >= LVL_IMMORT) @@ -3783,31 +3783,31 @@ static struct set_struct { { "mana", LVL_BUILDER, BOTH, NUMBER }, { "maxhit", LVL_BUILDER, BOTH, NUMBER }, { "maxmana", LVL_BUILDER, BOTH, NUMBER }, - { "maxmove", LVL_BUILDER, BOTH, NUMBER }, /* 30 */ - { "move", LVL_BUILDER, BOTH, NUMBER }, + { "maxstam", LVL_BUILDER, BOTH, NUMBER }, /* 28 */ { "name", LVL_IMMORT, PC, MISC }, { "nodelete", LVL_GOD, PC, BINARY }, { "nohassle", LVL_GOD, PC, BINARY }, - { "nosummon", LVL_BUILDER, PC, BINARY }, /* 35 */ + { "nosummon", LVL_BUILDER, PC, BINARY }, { "nowizlist", LVL_GRGOD, PC, BINARY }, { "olc", LVL_GRGOD, PC, MISC }, { "password", LVL_GRGOD, PC, MISC }, { "poofin", LVL_IMMORT, PC, MISC }, - { "poofout", LVL_IMMORT, PC, MISC }, /* 40 */ + { "poofout", LVL_IMMORT, PC, MISC }, { "quest", LVL_GOD, PC, BINARY }, { "room", LVL_BUILDER, BOTH, NUMBER }, - { "screenwidth", LVL_GOD, PC, NUMBER }, + { "screenwidth", LVL_GOD, PC, NUMBER }, /* 40 */ { "sex", LVL_GOD, BOTH, MISC }, - { "showvnums", LVL_BUILDER, PC, BINARY }, /* 45 */ + { "showvnums", LVL_BUILDER, PC, BINARY }, { "siteok", LVL_GOD, PC, BINARY }, { "skill", LVL_GOD, BOTH, NUMBER }, + { "stam", LVL_BUILDER, BOTH, NUMBER }, /* 45 */ { "str", LVL_BUILDER, BOTH, NUMBER }, - { "unused1", LVL_GOD, PC, BINARY }, - { "thirst", LVL_BUILDER, BOTH, MISC }, /* 50 */ + { "unused1", LVL_GOD, PC, BINARY }, + { "thirst", LVL_BUILDER, BOTH, MISC }, { "variable", LVL_GRGOD, PC, MISC }, { "weight", LVL_BUILDER, BOTH, NUMBER }, { "wis", LVL_BUILDER, BOTH, NUMBER }, - { "questpoints", LVL_GOD, PC, NUMBER }, + { "questpoints", LVL_GOD, PC, NUMBER }, /* 52 */ { "questhistory", LVL_GOD, PC, NUMBER }, { "species", LVL_BUILDER, BOTH, MISC }, { "\n", 0, BOTH, MISC } @@ -4060,15 +4060,11 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c vict->points.max_mana = RANGE(1, 5000); affect_total(vict); break; - case 28: /* maxmove */ - vict->points.max_move = RANGE(1, 5000); + case 28: /* maxstam */ + vict->points.max_stamina = RANGE(1, 5000); affect_total(vict); break; - case 29: /* move */ - vict->points.move = RANGE(0, vict->points.max_move); - affect_total(vict); - break; - case 30: /* name */ + case 29: /* name */ if (ch != vict && GET_LEVEL(ch) < LVL_IMPL) { send_to_char(ch, "Only Imps can change the name of other players.\r\n"); return (0); @@ -4078,24 +4074,24 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c return (0); } break; - case 31: /* nodelete */ + case 30: /* nodelete */ SET_OR_REMOVE(PLR_FLAGS(vict), PLR_NODELETE); break; - case 32: /* nohassle */ + case 31: /* nohassle */ if (GET_LEVEL(ch) < LVL_GOD && ch != vict) { send_to_char(ch, "You aren't godly enough for that!\r\n"); return (0); } SET_OR_REMOVE(PRF_FLAGS(vict), PRF_NOHASSLE); break; - case 33: /* nosummon */ + case 32: /* nosummon */ SET_OR_REMOVE(PRF_FLAGS(vict), PRF_SUMMONABLE); send_to_char(ch, "Nosummon %s for %s.\r\n", ONOFF(!on), GET_NAME(vict)); break; - case 34: /* nowiz */ + case 33: /* nowiz */ SET_OR_REMOVE(PLR_FLAGS(vict), PLR_NOWIZLIST); break; - case 35: /* olc */ + case 34: /* olc */ if (is_abbrev(val_arg, "socials") || is_abbrev(val_arg, "actions") || is_abbrev(val_arg, "aedit")) GET_OLC_ZONE(vict) = AEDIT_PERMISSION; else if (is_abbrev(val_arg, "hedit") || is_abbrev(val_arg, "help")) @@ -4110,7 +4106,7 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c } else GET_OLC_ZONE(vict) = atoi(val_arg); break; - case 36: /* password */ + case 35: /* password */ if (GET_LEVEL(vict) >= LVL_GRGOD) { send_to_char(ch, "You cannot change that.\r\n"); return (0); @@ -4119,7 +4115,7 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c *(GET_PASSWD(vict) + MAX_PWD_LENGTH) = '\0'; send_to_char(ch, "Password changed to '%s'.\r\n", val_arg); break; - case 37: /* poofin */ + case 36: /* poofin */ if ((vict == ch) || (GET_LEVEL(ch) == LVL_IMPL)) { skip_spaces(&val_arg); parse_at(val_arg); @@ -4133,7 +4129,7 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c POOFIN(vict) = strdup(val_arg); } break; - case 38: /* poofout */ + case 37: /* poofout */ if ((vict == ch) || (GET_LEVEL(ch) == LVL_IMPL)) { skip_spaces(&val_arg); parse_at(val_arg); @@ -4147,10 +4143,10 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c POOFOUT(vict) = strdup(val_arg); } break; - case 39: /* quest */ + case 38: /* quest */ SET_OR_REMOVE(PRF_FLAGS(vict), PRF_QUEST); break; - case 40: /* room */ + case 39: /* room */ if ((rnum = real_room(value)) == NOWHERE) { send_to_char(ch, "No room exists with that number.\r\n"); return (0); @@ -4159,23 +4155,23 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c char_from_room(vict); char_to_room(vict, rnum); break; - case 41: /* screenwidth */ + case 40: /* screenwidth */ GET_SCREEN_WIDTH(vict) = RANGE(40, 200); break; - case 42: /* sex */ + case 41: /* sex */ if ((i = search_block(val_arg, genders, FALSE)) < 0) { send_to_char(ch, "Must be 'male', 'female', or 'neutral'.\r\n"); return (0); } GET_SEX(vict) = i; break; - case 43: /* showvnums */ + case 42: /* showvnums */ SET_OR_REMOVE(PRF_FLAGS(vict), PRF_SHOWVNUMS); break; - case 44: /* siteok */ + case 43: /* siteok */ SET_OR_REMOVE(PLR_FLAGS(vict), PLR_SITEOK); break; - case 45: /* skills/spells */ + case 44: /* skills/spells */ { char local_buf[MAX_INPUT_LENGTH], *value_arg, *name_end; char skill_name[MAX_INPUT_LENGTH]; @@ -4260,6 +4256,11 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c } break; + case 45: /* stam */ + vict->points.stamina = RANGE(0, vict->points.max_stamina); + affect_total(vict); + break; + case 46: /* str */ if (IS_NPC(vict) || GET_LEVEL(vict) >= LVL_GRGOD) RANGE(3, 25); @@ -4615,7 +4616,7 @@ static struct zcheck_affs { {APPLY_CHAR_HEIGHT,-50, 50, "character height"}, {APPLY_MANA, -50, 50, "mana"}, {APPLY_HIT, -50, 50, "hit points"}, - {APPLY_MOVE, -50, 50, "movement"}, + {APPLY_STAMINA, -50, 50, "stamina"}, {APPLY_COINS, 0, 0, "coins"}, {APPLY_EXP, 0, 0, "experience"}, {APPLY_AC, -10, 10, "magical AC"}, diff --git a/src/class.c b/src/class.c index 9a005d2..77d80ad 100644 --- a/src/class.c +++ b/src/class.c @@ -591,7 +591,7 @@ void do_start(struct char_data *ch) GET_MAX_HIT(ch) = 90; GET_MAX_MANA(ch) = 100; - GET_MAX_MOVE(ch) = 90; + GET_MAX_STAMINA(ch) = 90; grant_class_skills(ch, TRUE); grant_species_skills(ch); @@ -600,7 +600,7 @@ void do_start(struct char_data *ch) GET_HIT(ch) = GET_MAX_HIT(ch); GET_MANA(ch) = GET_MAX_MANA(ch); - GET_MOVE(ch) = GET_MAX_MOVE(ch); + GET_STAMINA(ch) = GET_MAX_STAMINA(ch); GET_COND(ch, THIRST) = 24; GET_COND(ch, HUNGER) = 24; @@ -610,7 +610,7 @@ void do_start(struct char_data *ch) SET_BIT_AR(PLR_FLAGS(ch), PLR_SITEOK); } -/* This function controls the change to maxmove, maxmana, and maxhp for each +/* This function controls the change to maxstamina, maxmana, and maxhp for each * class every time they gain a level. */ void advance_level(struct char_data *ch) { @@ -674,7 +674,7 @@ void advance_level(struct char_data *ch) } ch->points.max_hit += MAX(1, add_hp); - ch->points.max_move += MAX(1, add_move); + ch->points.max_stamina += MAX(1, add_move); if (GET_LEVEL(ch) > 1) ch->points.max_mana += add_mana; diff --git a/src/comm.c b/src/comm.c index 95a9558..065da60 100644 --- a/src/comm.c +++ b/src/comm.c @@ -1145,8 +1145,8 @@ static char *make_prompt(struct descriptor_data *d) if (count >= 0) len += count; } - if (GET_MOVE(ch) << 2 < GET_MAX_MOVE(ch) && len < sizeof(prompt)) { - count = snprintf(prompt + len, sizeof(prompt) - len, "%dV ", GET_MOVE(ch)); + if (GET_STAMINA(ch) << 2 < GET_MAX_STAMINA(ch) && len < sizeof(prompt)) { + count = snprintf(prompt + len, sizeof(prompt) - len, "%dS ", GET_STAMINA(ch)); if (count >= 0) len += count; } @@ -1163,8 +1163,8 @@ static char *make_prompt(struct descriptor_data *d) len += count; } - if (PRF_FLAGGED(d->character, PRF_DISPMOVE) && len < sizeof(prompt)) { - count = snprintf(prompt + len, sizeof(prompt) - len, "%dV ", GET_MOVE(d->character)); + if (PRF_FLAGGED(d->character, PRF_DISPSTAMINA) && len < sizeof(prompt)) { + count = snprintf(prompt + len, sizeof(prompt) - len, "%dS ", GET_STAMINA(d->character)); if (count >= 0) len += count; } @@ -2795,8 +2795,8 @@ static void msdp_update( void ) MSDPSetNumber( d, eMSDP_MANA_MAX, GET_MAX_MANA(ch) ); MSDPSetNumber( d, eMSDP_WIMPY, GET_WIMP_LEV(ch) ); MSDPSetNumber( d, eMSDP_MONEY, GET_COINS(ch) ); - MSDPSetNumber( d, eMSDP_MOVEMENT, GET_MOVE(ch) ); - MSDPSetNumber( d, eMSDP_MOVEMENT_MAX, GET_MAX_MOVE(ch) ); + MSDPSetNumber( d, eMSDP_MOVEMENT, GET_STAMINA(ch) ); + MSDPSetNumber( d, eMSDP_MOVEMENT_MAX, GET_MAX_STAMINA(ch) ); MSDPSetNumber( d, eMSDP_AC, compute_armor_class(ch) ); /* This would be better moved elsewhere */ diff --git a/src/constants.c b/src/constants.c index 500c29c..e26e49d 100644 --- a/src/constants.c +++ b/src/constants.c @@ -253,7 +253,7 @@ const char *preference_bits[] = { "NO_TELL", "D_HP", "D_MANA", - "D_MOVE", + "D_STAMINA", "AUTOEX", "NO_HASS", "QUEST", @@ -511,7 +511,7 @@ const char *apply_types[] = { "CHAR_HEIGHT", "MAXMANA", "MAXHIT", - "MAXMOVE", + "MAXSTAMINA", "COINS", "EXP", "ARMOR", diff --git a/src/db.c b/src/db.c index b0cef55..f93dc14 100644 --- a/src/db.c +++ b/src/db.c @@ -1602,10 +1602,10 @@ static void parse_simple_mob(FILE *mob_f, int i, int nr) GET_MAX_HIT(mob_proto + i) = 0; GET_HIT(mob_proto + i) = t[1]; GET_MANA(mob_proto + i) = t[2]; - GET_MOVE(mob_proto + i) = t[3]; + GET_STAMINA(mob_proto + i) = t[3]; GET_MAX_MANA(mob_proto + i) = 10; - GET_MAX_MOVE(mob_proto + i) = 50; + GET_MAX_STAMINA(mob_proto + i) = 50; if (!get_line(mob_f, line)) { log("SYSERR: Format error in last line of mob #%d\n" @@ -2736,13 +2736,13 @@ struct char_data *read_mobile(mob_vnum nr, int type) /* and mob_rnum */ if (!mob->points.max_hit) { mob->points.max_hit = dice(mob->points.hit, mob->points.mana) + - mob->points.move; + mob->points.stamina; } else mob->points.max_hit = rand_number(mob->points.hit, mob->points.mana); mob->points.hit = mob->points.max_hit; mob->points.mana = mob->points.max_mana; - mob->points.move = mob->points.max_move; + mob->points.stamina = mob->points.max_stamina; mob->player.time.birth = time(0); mob->player.time.played = 0; @@ -3757,8 +3757,8 @@ void reset_char(struct char_data *ch) if (GET_HIT(ch) <= 0) GET_HIT(ch) = 1; - if (GET_MOVE(ch) <= 0) - GET_MOVE(ch) = 1; + if (GET_STAMINA(ch) <= 0) + GET_STAMINA(ch) = 1; if (GET_MANA(ch) <= 0) GET_MANA(ch) = 1; @@ -3815,10 +3815,10 @@ void init_char(struct char_data *ch) /* The implementor never goes through do_start(). */ GET_MAX_HIT(ch) = 500; GET_MAX_MANA(ch) = 100; - GET_MAX_MOVE(ch) = 82; + GET_MAX_STAMINA(ch) = 82; GET_HIT(ch) = GET_MAX_HIT(ch); GET_MANA(ch) = GET_MAX_MANA(ch); - GET_MOVE(ch) = GET_MAX_MOVE(ch); + GET_STAMINA(ch) = GET_MAX_STAMINA(ch); } ch->player.short_descr = NULL; @@ -3891,7 +3891,7 @@ void init_char(struct char_data *ch) } SET_BIT_AR(PRF_FLAGS(ch), PRF_DISPHP); SET_BIT_AR(PRF_FLAGS(ch), PRF_DISPMANA); - SET_BIT_AR(PRF_FLAGS(ch), PRF_DISPMOVE); + SET_BIT_AR(PRF_FLAGS(ch), PRF_DISPSTAMINA); } /* returns the real number of the room with given virtual number */ diff --git a/src/dg_variables.c b/src/dg_variables.c index 6ce2445..8fade8b 100644 --- a/src/dg_variables.c +++ b/src/dg_variables.c @@ -843,19 +843,19 @@ void find_replacement(void *go, struct script_data *sc, trig_data *trig, } snprintf(str, slen, "%d", GET_MAX_MANA(c)); } - else if (!str_cmp(field, "maxmove")) { + else if (!str_cmp(field, "maxmove") || !str_cmp(field, "maxstamina")) { if (subfield && *subfield) { int addition = atoi(subfield); - GET_MAX_MOVE(c) = MAX(GET_MAX_MOVE(c) + addition, 1); + GET_MAX_STAMINA(c) = MAX(GET_MAX_STAMINA(c) + addition, 1); } - snprintf(str, slen, "%d", GET_MAX_MOVE(c)); + snprintf(str, slen, "%d", GET_MAX_STAMINA(c)); } - else if (!str_cmp(field, "move")) { + else if (!str_cmp(field, "move") || !str_cmp(field, "stamina")) { if (subfield && *subfield) { int addition = atoi(subfield); - GET_MOVE(c) += addition; + GET_STAMINA(c) += addition; } - snprintf(str, slen, "%d", GET_MOVE(c)); + snprintf(str, slen, "%d", GET_STAMINA(c)); } break; case 'n': diff --git a/src/genmob.c b/src/genmob.c index 2285a5e..313ff08 100644 --- a/src/genmob.c +++ b/src/genmob.c @@ -451,7 +451,7 @@ int write_mobile_record(mob_vnum mvnum, struct char_data *mob, FILE *fd) GET_LEVEL(mob), GET_HIT(mob), GET_MANA(mob), - GET_MOVE(mob)); + GET_STAMINA(mob)); /* --- Position / default position / sex --- */ fprintf(fd, "%d %d %d\n", diff --git a/src/genolc.c b/src/genolc.c index f5e5baa..ec4f65d 100644 --- a/src/genolc.c +++ b/src/genolc.c @@ -629,7 +629,7 @@ static int export_mobile_record(mob_vnum mvnum, struct char_data *mob, FILE *fd) AFF_FLAGS(mob)[2], AFF_FLAGS(mob)[3], GET_ALIGNMENT(mob), GET_LEVEL(mob), GET_HIT(mob), - GET_MANA(mob), GET_MOVE(mob)); + GET_MANA(mob), GET_STAMINA(mob)); fprintf(fd, "%d %d %d\n", GET_POS(mob), GET_DEFAULT_POS(mob), GET_SEX(mob) diff --git a/src/handler.c b/src/handler.c index 8d6747f..25d7749 100644 --- a/src/handler.c +++ b/src/handler.c @@ -148,7 +148,7 @@ static void aff_apply_modify(struct char_data *ch, byte loc, sbyte mod, char *ms case APPLY_CHAR_HEIGHT: GET_HEIGHT(ch) += mod; break; case APPLY_MANA: GET_MAX_MANA(ch) += mod; break; case APPLY_HIT: GET_MAX_HIT(ch) += mod; break; - case APPLY_MOVE: GET_MAX_MOVE(ch) += mod; break; + case APPLY_STAMINA: GET_MAX_STAMINA(ch) += mod; break; case APPLY_COINS: break; case APPLY_EXP: break; diff --git a/src/limits.c b/src/limits.c index 69f594f..4d0bb7e 100644 --- a/src/limits.c +++ b/src/limits.c @@ -142,7 +142,7 @@ int hit_gain(struct char_data *ch) return (gain); } -/* move gain pr. game hour */ +/* stamina gain pr. game hour */ int move_gain(struct char_data *ch) { int gain; @@ -417,7 +417,7 @@ void point_update(void) if (GET_POS(i) >= POS_STUNNED) { GET_HIT(i) = MIN(GET_HIT(i) + hit_gain(i), GET_MAX_HIT(i)); GET_MANA(i) = MIN(GET_MANA(i) + mana_gain(i), GET_MAX_MANA(i)); - GET_MOVE(i) = MIN(GET_MOVE(i) + move_gain(i), GET_MAX_MOVE(i)); + GET_STAMINA(i) = MIN(GET_STAMINA(i) + move_gain(i), GET_MAX_STAMINA(i)); if (AFF_FLAGGED(i, AFF_POISON)) if (damage(i, i, 2, SPELL_POISON) == -1) continue; /* Oops, they died. -gg 6/24/98 */ diff --git a/src/magic.c b/src/magic.c index 83cd977..8eae632 100644 --- a/src/magic.c +++ b/src/magic.c @@ -819,7 +819,7 @@ void mag_points(int level, struct char_data *ch, struct char_data *victim, break; } GET_HIT(victim) = MIN(GET_MAX_HIT(victim), GET_HIT(victim) + healing); - GET_MOVE(victim) = MIN(GET_MAX_MOVE(victim), GET_MOVE(victim) + move); + GET_STAMINA(victim) = MIN(GET_MAX_STAMINA(victim), GET_STAMINA(victim) + move); update_pos(victim); } diff --git a/src/medit.c b/src/medit.c index 6ff3cdc..e08ae3c 100644 --- a/src/medit.c +++ b/src/medit.c @@ -238,7 +238,7 @@ static void init_mobile(struct char_data *mob) clear_char(mob); GET_HIT(mob) = GET_MANA(mob) = 1; - GET_MAX_MANA(mob) = GET_MAX_MOVE(mob) = 100; + GET_MAX_MANA(mob) = GET_MAX_STAMINA(mob) = 100; GET_WEIGHT(mob) = 200; GET_HEIGHT(mob) = 198; @@ -580,8 +580,8 @@ static void medit_disp_stats_menu(struct descriptor_data *d) clear_screen(d); /* Color codes have to be used here, for count_color_codes to work */ - sprintf(buf, "(range \ty%d\tn to \ty%d\tn)", GET_HIT(mob) + GET_MOVE(mob), - (GET_HIT(mob) * GET_MANA(mob)) + GET_MOVE(mob)); + sprintf(buf, "(range \ty%d\tn to \ty%d\tn)", GET_HIT(mob) + GET_STAMINA(mob), + (GET_HIT(mob) * GET_MANA(mob)) + GET_STAMINA(mob)); /* Top section - standard stats */ write_to_output(d, @@ -595,7 +595,7 @@ static void medit_disp_stats_menu(struct descriptor_data *d) cyn, nrm, cyn, nrm, cyn, nrm, cyn, yel, GET_HIT(mob), cyn, nrm, cyn, nrm, cyn, yel, GET_MANA(mob), cyn, nrm, - cyn, nrm, cyn, yel, GET_MOVE(mob), cyn, nrm + cyn, nrm, cyn, yel, GET_STAMINA(mob), cyn, nrm ); if (CONFIG_MEDIT_ADVANCED) { @@ -1321,7 +1321,7 @@ void medit_parse(struct descriptor_data *d, char *arg) return; case MEDIT_ADD_HP: - GET_MOVE(OLC_MOB(d)) = LIMIT(i, 0, 30000); + GET_STAMINA(OLC_MOB(d)) = LIMIT(i, 0, 30000); OLC_VAL(d) = TRUE; medit_disp_stats_menu(d); return; @@ -1540,7 +1540,7 @@ void medit_autoroll_stats(struct descriptor_data *d) if (mob_lev < 1) mob_lev = 1; - GET_MOVE(OLC_MOB(d)) = mob_lev * 10; /* hit point bonus (mobs don't use movement points) */ + GET_STAMINA(OLC_MOB(d)) = mob_lev * 10; /* hit point bonus (mobs don't use stamina points) */ GET_HIT(OLC_MOB(d)) = mob_lev / 5; /* number of hitpoint dice */ GET_MANA(OLC_MOB(d)) = mob_lev / 5; /* size of hitpoint dice */ diff --git a/src/pfdefaults.h b/src/pfdefaults.h index 4771360..36d30f2 100644 --- a/src/pfdefaults.h +++ b/src/pfdefaults.h @@ -44,8 +44,8 @@ #define PFDEF_MAXHIT 0 #define PFDEF_MANA 0 #define PFDEF_MAXMANA 0 -#define PFDEF_MOVE 0 -#define PFDEF_MAXMOVE 0 +#define PFDEF_STAMINA 0 +#define PFDEF_MAXSTAMINA 0 #define PFDEF_HUNGER 0 #define PFDEF_THIRST 0 #define PFDEF_DRUNK 0 diff --git a/src/players.c b/src/players.c index 29866e8..a83094d 100644 --- a/src/players.c +++ b/src/players.c @@ -25,7 +25,7 @@ #define LOAD_HIT 0 #define LOAD_MANA 1 -#define LOAD_MOVE 2 +#define LOAD_STAMINA 2 #define LOAD_STRENGTH 3 #define PT_PNAME(i) (player_table[(i)].name) @@ -232,6 +232,7 @@ int load_char(const char *name, struct char_data *ch) char filename[40]; char buf[128], buf2[128], line[MAX_INPUT_LENGTH + 1], tag[6]; char f1[128], f2[128], f3[128], f4[128]; + bool loaded_stamina = FALSE; trig_data *t = NULL; trig_rnum t_rnum = NOTHING; @@ -284,8 +285,8 @@ int load_char(const char *name, struct char_data *ch) GET_MAX_HIT(ch) = PFDEF_MAXHIT; GET_MANA(ch) = PFDEF_MANA; GET_MAX_MANA(ch) = PFDEF_MAXMANA; - GET_MOVE(ch) = PFDEF_MOVE; - GET_MAX_MOVE(ch) = PFDEF_MAXMOVE; + GET_STAMINA(ch) = PFDEF_STAMINA; + GET_MAX_STAMINA(ch) = PFDEF_MAXSTAMINA; GET_OLC_ZONE(ch) = PFDEF_OLC; GET_PAGE_LENGTH(ch) = PFDEF_PAGELENGTH; GET_SCREEN_WIDTH(ch) = PFDEF_SCREENWIDTH; @@ -397,7 +398,7 @@ int load_char(const char *name, struct char_data *ch) case 'M': if (!strcmp(tag, "Mana")) load_HMVS(ch, line, LOAD_MANA); - else if (!strcmp(tag, "Move")) load_HMVS(ch, line, LOAD_MOVE); + else if (!strcmp(tag, "Move") && !loaded_stamina) load_HMVS(ch, line, LOAD_STAMINA); break; case 'N': @@ -444,6 +445,10 @@ int load_char(const char *name, struct char_data *ch) val = SPECIES_UNDEFINED; GET_SPECIES(ch) = val; } + else if (!strcmp(tag, "Stam")) { + load_HMVS(ch, line, LOAD_STAMINA); + loaded_stamina = TRUE; + } else if (!strcmp(tag, "Sex ")) GET_SEX(ch) = atoi(line); else if (!strcmp(tag, "Sdsc")) { /* Clear any existing sdesc to avoid leaks */ @@ -677,7 +682,7 @@ void save_char(struct char_data * ch) if (GET_HIT(ch) != PFDEF_HIT || GET_MAX_HIT(ch) != PFDEF_MAXHIT) fprintf(fl, "Hit : %d/%d\n", GET_HIT(ch), GET_MAX_HIT(ch)); if (GET_MANA(ch) != PFDEF_MANA || GET_MAX_MANA(ch) != PFDEF_MAXMANA) fprintf(fl, "Mana: %d/%d\n", GET_MANA(ch), GET_MAX_MANA(ch)); - if (GET_MOVE(ch) != PFDEF_MOVE || GET_MAX_MOVE(ch) != PFDEF_MAXMOVE) fprintf(fl, "Move: %d/%d\n", GET_MOVE(ch), GET_MAX_MOVE(ch)); + if (GET_STAMINA(ch) != PFDEF_STAMINA || GET_MAX_STAMINA(ch) != PFDEF_MAXSTAMINA) fprintf(fl, "Stam: %d/%d\n", GET_STAMINA(ch), GET_MAX_STAMINA(ch)); if (GET_STR(ch) != PFDEF_STR) fprintf(fl, "Str : %d\n", GET_STR(ch)); if (GET_INT(ch) != PFDEF_INT) fprintf(fl, "Int : %d\n", GET_INT(ch)); @@ -954,9 +959,9 @@ static void load_HMVS(struct char_data *ch, const char *line, int mode) GET_MAX_MANA(ch) = num2; break; - case LOAD_MOVE: - GET_MOVE(ch) = num; - GET_MAX_MOVE(ch) = num2; + case LOAD_STAMINA: + GET_STAMINA(ch) = num; + GET_MAX_STAMINA(ch) = num2; break; case LOAD_STRENGTH: diff --git a/src/prefedit.c b/src/prefedit.c index 4aa65b7..014deab 100755 --- a/src/prefedit.c +++ b/src/prefedit.c @@ -104,7 +104,7 @@ static void prefedit_disp_main_menu(struct descriptor_data *d) vict = PREFEDIT_GET_CHAR; sprintf(prompt_string, "%s%s%s", PREFEDIT_FLAGGED(PRF_DISPHP) ? "H" : "", PREFEDIT_FLAGGED(PRF_DISPMANA) ? "M" : "", - PREFEDIT_FLAGGED(PRF_DISPMOVE) ? "V" : "" ); + PREFEDIT_FLAGGED(PRF_DISPSTAMINA) ? "S" : "" ); sprintf(color_string, "%s", multi_types[(PREFEDIT_FLAGGED(PRF_COLOR_1) ? 1 : 0) + (PREFEDIT_FLAGGED(PRF_COLOR_2) ? 2 : 0)]); @@ -292,12 +292,12 @@ static void prefedit_disp_prompt_menu(struct descriptor_data *d) sprintf(prompt_string, ""); else sprintf(prompt_string, "%s%s%s", PREFEDIT_FLAGGED(PRF_DISPHP) ? "H" : "", PREFEDIT_FLAGGED(PRF_DISPMANA) ? "M" : "", - PREFEDIT_FLAGGED(PRF_DISPMOVE) ? "V" : ""); + PREFEDIT_FLAGGED(PRF_DISPSTAMINA) ? "S" : ""); send_to_char(d->character, "%sPrompt Settings\r\n" "%s1%s) Toggle HP\r\n" "%s2%s) Toggle Mana\r\n" - "%s3%s) Toggle Moves\r\n" + "%s3%s) Toggle Stamina\r\n" "%s4%s) Toggle auto flag\r\n\r\n" "%sCurrent Prompt: %s%s%s\r\n\r\n" "%s0%s) Quit (to main menu)\r\n", @@ -730,10 +730,10 @@ void prefedit_parse(struct descriptor_data * d, char *arg) } else if (number == 3) { - if (PREFEDIT_FLAGGED(PRF_DISPMOVE)) - REMOVE_BIT_AR(PREFEDIT_GET_FLAGS, PRF_DISPMOVE); + if (PREFEDIT_FLAGGED(PRF_DISPSTAMINA)) + REMOVE_BIT_AR(PREFEDIT_GET_FLAGS, PRF_DISPSTAMINA); else - SET_BIT_AR(PREFEDIT_GET_FLAGS, PRF_DISPMOVE); + SET_BIT_AR(PREFEDIT_GET_FLAGS, PRF_DISPSTAMINA); } else if (number == 4) { @@ -784,9 +784,9 @@ void prefedit_Restore_Defaults(struct descriptor_data *d) if (!PREFEDIT_FLAGGED(PRF_DISPMANA)) SET_BIT_AR(PREFEDIT_GET_FLAGS, PRF_DISPMANA); - /* PRF_DISPMOVE - On */ - if (!PREFEDIT_FLAGGED(PRF_DISPMOVE)) - SET_BIT_AR(PREFEDIT_GET_FLAGS, PRF_DISPMOVE); + /* PRF_DISPSTAMINA - On */ + if (!PREFEDIT_FLAGGED(PRF_DISPSTAMINA)) + SET_BIT_AR(PREFEDIT_GET_FLAGS, PRF_DISPSTAMINA); /* PRF_AUTOEXIT - On */ if (!PREFEDIT_FLAGGED(PRF_AUTOEXIT)) diff --git a/src/protocol.c b/src/protocol.c index e9ad34c..1efab4b 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -106,7 +106,7 @@ static const char s_Button5[] = "\005\002Inventory\002inventory\006"; static const char s_Gauge1[] = "\005\002Health\002red\002HEALTH\002HEALTH_MAX\006"; static const char s_Gauge2[] = "\005\002Mana\002blue\002MANA\002MANA_MAX\006"; -static const char s_Gauge3[] = "\005\002Movement\002green\002MOVEMENT\002MOVEMENT_MAX\006"; +static const char s_Gauge3[] = "\005\002Stamina\002green\002MOVEMENT\002MOVEMENT_MAX\006"; static const char s_Gauge4[] = "\005\002Exp TNL\002yellow\002EXPERIENCE\002EXPERIENCE_MAX\006"; static const char s_Gauge5[] = "\005\002Opponent\002darkred\002OPPONENT_HEALTH\002OPPONENT_HEALTH_MAX\006"; diff --git a/src/roomsave.c b/src/roomsave.c index 02a37f3..611b5cc 100644 --- a/src/roomsave.c +++ b/src/roomsave.c @@ -1,15 +1,10 @@ /** * @file roomsave.c -* Numeric and string contants used by the MUD. -* -* An addition to 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. -* +* Room file loading/saving and utility routines. +* +* This set of code was not originally part of the circlemud distribution. */ + #include "conf.h" #include "sysdep.h" diff --git a/src/roomsave.h b/src/roomsave.h index 53912e5..c037af2 100644 --- a/src/roomsave.h +++ b/src/roomsave.h @@ -1,14 +1,10 @@ /** * @file roomsave.h -* Core structures used within the core mud code. -* -* An addition to 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. +* Room file loading/saving and utility headers. +* +* This set of code was not originally part of the circlemud distribution. */ + #ifndef ROOMSAVE_H_ #define ROOMSAVE_H_ diff --git a/src/structs.h b/src/structs.h index 2341eea..95ca614 100644 --- a/src/structs.h +++ b/src/structs.h @@ -277,7 +277,7 @@ #define PRF_NOTELL 3 /**< Can't receive tells */ #define PRF_DISPHP 4 /**< Display hit points in prompt */ #define PRF_DISPMANA 5 /**< Display mana points in prompt */ -#define PRF_DISPMOVE 6 /**< Display move points in prompt */ +#define PRF_DISPSTAMINA 6 /**< Display stamina points in prompt */ #define PRF_AUTOEXIT 7 /**< Display exits in a room */ #define PRF_NOHASSLE 8 /**< Aggr mobs won't attack */ #define PRF_QUEST 9 /**< On quest */ @@ -506,7 +506,7 @@ #define APPLY_CHAR_HEIGHT 11 /**< Apply to height */ #define APPLY_MANA 12 /**< Apply to max mana */ #define APPLY_HIT 13 /**< Apply to max hit points */ -#define APPLY_MOVE 14 /**< Apply to max move points */ +#define APPLY_STAMINA 14 /**< Apply to max stamina points */ #define APPLY_COINS 15 /**< Reserved */ #define APPLY_EXP 16 /**< Reserved */ #define APPLY_AC 17 /**< Apply to Armor Class */ @@ -980,8 +980,8 @@ struct char_point_data sh_int max_mana; /**< Max mana level */ sh_int hit; /**< Curent hit point, or health, level */ sh_int max_hit; /**< Max hit point, or health, level */ - sh_int move; /**< Current move point, or stamina, level */ - sh_int max_move; /**< Max move point, or stamina, level */ + sh_int stamina; /**< Current stamina level */ + sh_int max_stamina; /**< Max stamina level */ /** Current armor class. Internal use goes from -100 (totally armored) to * 100 (totally naked). Externally expressed as -10 (totally armored) to diff --git a/src/util/plrtoascii.c b/src/util/plrtoascii.c index 8888a2f..daeb277 100755 --- a/src/util/plrtoascii.c +++ b/src/util/plrtoascii.c @@ -39,8 +39,8 @@ struct char_point_data_plrtoascii { sh_int max_mana; /* Max mana for PC/NPC */ sh_int hit; sh_int max_hit; /* Max hit for PC/NPC */ - sh_int move; - sh_int max_move; /* Max move for PC/NPC */ + sh_int stamina; + sh_int max_stamina; /* Max stamina for PC/NPC */ sh_int armor; /* Internal -100..100, external -10..10 AC */ int coins; /* Money carried */ @@ -285,8 +285,8 @@ void convert(char *filename) fprintf(outfile, "Hit : %d/%d\n", cpd->hit, cpd->max_hit); if (cpd->mana != PFDEF_MANA || cpd->max_mana != PFDEF_MAXMANA) fprintf(outfile, "Mana: %d/%d\n", cpd->mana, cpd->max_mana); - if (cpd->move != PFDEF_MOVE || cpd->max_move != PFDEF_MAXMOVE) - fprintf(outfile, "Move: %d/%d\n", cpd->move, cpd->max_move); + if (cpd->stamina != PFDEF_STAMINA || cpd->max_stamina != PFDEF_MAXSTAMINA) + fprintf(outfile, "Stam: %d/%d\n", cpd->stamina, cpd->max_stamina); if (cpd->armor != PFDEF_AC) fprintf(outfile, "Ac : %d\n", cpd->armor); if (cpd->coins != PFDEF_COINS) diff --git a/src/utils.h b/src/utils.h index 2347914..ecfa653 100644 --- a/src/utils.h +++ b/src/utils.h @@ -598,10 +598,10 @@ do \ #define GET_HIT(ch) ((ch)->points.hit) /** Maximum hit points of ch. */ #define GET_MAX_HIT(ch) ((ch)->points.max_hit) -/** Current move points (stamina) of ch. */ -#define GET_MOVE(ch) ((ch)->points.move) -/** Maximum move points (stamina) of ch. */ -#define GET_MAX_MOVE(ch) ((ch)->points.max_move) +/** Current stamina points of ch. */ +#define GET_STAMINA(ch) ((ch)->points.stamina) +/** Maximum stamina points of ch. */ +#define GET_MAX_STAMINA(ch) ((ch)->points.max_stamina) /** Current mana points (magic) of ch. */ #define GET_MANA(ch) ((ch)->points.mana) /** Maximum mana points (magic) of ch. */ From e19b48175988d3b1a2ea13d1fbe6fc90f03cd130 Mon Sep 17 00:00:00 2001 From: kinther Date: Mon, 29 Dec 2025 08:26:12 -0800 Subject: [PATCH 11/40] Clean up set command options --- lib/text/help/help.hlp | 7 +--- src/act.wizard.c | 84 +++++++++++++++++++----------------------- 2 files changed, 40 insertions(+), 51 deletions(-) diff --git a/lib/text/help/help.hlp b/lib/text/help/help.hlp index 556e09e..0947a09 100644 --- a/lib/text/help/help.hlp +++ b/lib/text/help/help.hlp @@ -1646,7 +1646,7 @@ Excluding the subfield () returns the value. Adding a subfield adjusts it. @uField@n - @uvariable returns:@n cha/con/dex/int - Checks the stat. @RHELP TRIG-STAT@n. Subfield adjusts. -str/stradd/wis() () is a subfield and allows a change to the variable. +str/wis() () is a subfield and allows a change to the variable. alias - The list of aliases of the mob or the player name. align() - The actor's alignment @RHELP ALIGN@n. Subfield adjusts. affect() - Checks the actor for the affect. @RHELP AFFECT@n @@ -8497,7 +8497,6 @@ hunger Imm BOTH MISC int Imm BOTH NUMBER invis God PC NUMBER invstart Imm PC BINARY -killer God PC BINARY level GrGod BOTH NUMBER loadroom Imm PC MISC mana Imm BOTH NUMBER @@ -8523,8 +8522,6 @@ sex God BOTH MISC showvnums Imm PC BINARY siteok God PC BINARY str Imm BOTH NUMBER -stradd Imm BOTH NUMBER -thief God PC BINARY thirst Imm BOTH MISC title God PC MISC variable GrGod PC MISC @@ -10567,7 +10564,7 @@ Trig Usage: %actor.(<#>)% %actor.str(18) sets it to 18 Checks the actor's stat. A number in the subfield sets. -Stats include: cha, con, dex, int, str, stradd (only if str is 18). +Stats include: cha, con, dex, int, str, wis. See also: STATS #2 diff --git a/src/act.wizard.c b/src/act.wizard.c index 720ad63..1755b58 100644 --- a/src/act.wizard.c +++ b/src/act.wizard.c @@ -3769,21 +3769,20 @@ static struct set_struct { { "dex", LVL_BUILDER, BOTH, NUMBER }, { "drunk", LVL_BUILDER, BOTH, MISC }, { "exp", LVL_GOD, BOTH, NUMBER }, - { "frozen", LVL_GRGOD, PC, BINARY }, /* 15 */ + { "frozen", LVL_GRGOD, PC, BINARY }, /* 14 */ { "coins", LVL_BUILDER, BOTH, NUMBER }, { "height", LVL_BUILDER, BOTH, NUMBER }, { "hitpoints", LVL_BUILDER, BOTH, NUMBER }, - { "hunger", LVL_BUILDER, BOTH, MISC }, /* 20 */ + { "hunger", LVL_BUILDER, BOTH, MISC }, /* 18 */ { "int", LVL_BUILDER, BOTH, NUMBER }, { "invis", LVL_GOD, PC, NUMBER }, { "invstart", LVL_BUILDER, PC, BINARY }, - { "unused0", LVL_GOD, PC, BINARY }, - { "level", LVL_GRGOD, BOTH, NUMBER }, /* 25 */ + { "level", LVL_GRGOD, BOTH, NUMBER }, /* 22 */ { "loadroom", LVL_BUILDER, PC, MISC }, { "mana", LVL_BUILDER, BOTH, NUMBER }, { "maxhit", LVL_BUILDER, BOTH, NUMBER }, { "maxmana", LVL_BUILDER, BOTH, NUMBER }, - { "maxstam", LVL_BUILDER, BOTH, NUMBER }, /* 28 */ + { "maxstam", LVL_BUILDER, BOTH, NUMBER }, /* 27 */ { "name", LVL_IMMORT, PC, MISC }, { "nodelete", LVL_GOD, PC, BINARY }, { "nohassle", LVL_GOD, PC, BINARY }, @@ -3795,19 +3794,18 @@ static struct set_struct { { "poofout", LVL_IMMORT, PC, MISC }, { "quest", LVL_GOD, PC, BINARY }, { "room", LVL_BUILDER, BOTH, NUMBER }, - { "screenwidth", LVL_GOD, PC, NUMBER }, /* 40 */ + { "screenwidth", LVL_GOD, PC, NUMBER }, /* 39 */ { "sex", LVL_GOD, BOTH, MISC }, { "showvnums", LVL_BUILDER, PC, BINARY }, { "siteok", LVL_GOD, PC, BINARY }, { "skill", LVL_GOD, BOTH, NUMBER }, - { "stam", LVL_BUILDER, BOTH, NUMBER }, /* 45 */ + { "stam", LVL_BUILDER, BOTH, NUMBER }, /* 44 */ { "str", LVL_BUILDER, BOTH, NUMBER }, - { "unused1", LVL_GOD, PC, BINARY }, { "thirst", LVL_BUILDER, BOTH, MISC }, { "variable", LVL_GRGOD, PC, MISC }, { "weight", LVL_BUILDER, BOTH, NUMBER }, { "wis", LVL_BUILDER, BOTH, NUMBER }, - { "questpoints", LVL_GOD, PC, NUMBER }, /* 52 */ + { "questpoints", LVL_GOD, PC, NUMBER }, /* 50 */ { "questhistory", LVL_GOD, PC, NUMBER }, { "species", LVL_BUILDER, BOTH, MISC }, { "\n", 0, BOTH, MISC } @@ -4019,10 +4017,7 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c case 21: /* invistart */ SET_OR_REMOVE(PLR_FLAGS(vict), PLR_INVSTART); break; - case 22: /* unused0 (removed killer flag) */ - send_to_char(ch, "That flag is no longer in use.\r\n"); - return (0); - case 23: /* level */ + case 22: /* level */ if ((!IS_NPC(vict) && value > GET_LEVEL(ch)) || value > LVL_IMPL) { send_to_char(ch, "You can't do that.\r\n"); return (0); @@ -4030,7 +4025,7 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c RANGE(1, LVL_IMPL); vict->player.level = value; break; - case 24: /* loadroom */ + case 23: /* loadroom */ if (!str_cmp(val_arg, "off")) { REMOVE_BIT_AR(PLR_FLAGS(vict), PLR_LOADROOM); } else if (is_number(val_arg)) { @@ -4048,23 +4043,23 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c return (0); } break; - case 25: /* mana */ + case 24: /* mana */ vict->points.mana = RANGE(0, vict->points.max_mana); affect_total(vict); break; - case 26: /* maxhit */ + case 25: /* maxhit */ vict->points.max_hit = RANGE(1, 5000); affect_total(vict); break; - case 27: /* maxmana */ + case 26: /* maxmana */ vict->points.max_mana = RANGE(1, 5000); affect_total(vict); break; - case 28: /* maxstam */ + case 27: /* maxstam */ vict->points.max_stamina = RANGE(1, 5000); affect_total(vict); break; - case 29: /* name */ + case 28: /* name */ if (ch != vict && GET_LEVEL(ch) < LVL_IMPL) { send_to_char(ch, "Only Imps can change the name of other players.\r\n"); return (0); @@ -4074,24 +4069,24 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c return (0); } break; - case 30: /* nodelete */ + case 29: /* nodelete */ SET_OR_REMOVE(PLR_FLAGS(vict), PLR_NODELETE); break; - case 31: /* nohassle */ + case 30: /* nohassle */ if (GET_LEVEL(ch) < LVL_GOD && ch != vict) { send_to_char(ch, "You aren't godly enough for that!\r\n"); return (0); } SET_OR_REMOVE(PRF_FLAGS(vict), PRF_NOHASSLE); break; - case 32: /* nosummon */ + case 31: /* nosummon */ SET_OR_REMOVE(PRF_FLAGS(vict), PRF_SUMMONABLE); send_to_char(ch, "Nosummon %s for %s.\r\n", ONOFF(!on), GET_NAME(vict)); break; - case 33: /* nowiz */ + case 32: /* nowiz */ SET_OR_REMOVE(PLR_FLAGS(vict), PLR_NOWIZLIST); break; - case 34: /* olc */ + case 33: /* olc */ if (is_abbrev(val_arg, "socials") || is_abbrev(val_arg, "actions") || is_abbrev(val_arg, "aedit")) GET_OLC_ZONE(vict) = AEDIT_PERMISSION; else if (is_abbrev(val_arg, "hedit") || is_abbrev(val_arg, "help")) @@ -4106,7 +4101,7 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c } else GET_OLC_ZONE(vict) = atoi(val_arg); break; - case 35: /* password */ + case 34: /* password */ if (GET_LEVEL(vict) >= LVL_GRGOD) { send_to_char(ch, "You cannot change that.\r\n"); return (0); @@ -4115,7 +4110,7 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c *(GET_PASSWD(vict) + MAX_PWD_LENGTH) = '\0'; send_to_char(ch, "Password changed to '%s'.\r\n", val_arg); break; - case 36: /* poofin */ + case 35: /* poofin */ if ((vict == ch) || (GET_LEVEL(ch) == LVL_IMPL)) { skip_spaces(&val_arg); parse_at(val_arg); @@ -4129,7 +4124,7 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c POOFIN(vict) = strdup(val_arg); } break; - case 37: /* poofout */ + case 36: /* poofout */ if ((vict == ch) || (GET_LEVEL(ch) == LVL_IMPL)) { skip_spaces(&val_arg); parse_at(val_arg); @@ -4143,10 +4138,10 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c POOFOUT(vict) = strdup(val_arg); } break; - case 38: /* quest */ + case 37: /* quest */ SET_OR_REMOVE(PRF_FLAGS(vict), PRF_QUEST); break; - case 39: /* room */ + case 38: /* room */ if ((rnum = real_room(value)) == NOWHERE) { send_to_char(ch, "No room exists with that number.\r\n"); return (0); @@ -4155,23 +4150,23 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c char_from_room(vict); char_to_room(vict, rnum); break; - case 40: /* screenwidth */ + case 39: /* screenwidth */ GET_SCREEN_WIDTH(vict) = RANGE(40, 200); break; - case 41: /* sex */ + case 40: /* sex */ if ((i = search_block(val_arg, genders, FALSE)) < 0) { send_to_char(ch, "Must be 'male', 'female', or 'neutral'.\r\n"); return (0); } GET_SEX(vict) = i; break; - case 42: /* showvnums */ + case 41: /* showvnums */ SET_OR_REMOVE(PRF_FLAGS(vict), PRF_SHOWVNUMS); break; - case 43: /* siteok */ + case 42: /* siteok */ SET_OR_REMOVE(PLR_FLAGS(vict), PLR_SITEOK); break; - case 44: /* skills/spells */ + case 43: /* skills/spells */ { char local_buf[MAX_INPUT_LENGTH], *value_arg, *name_end; char skill_name[MAX_INPUT_LENGTH]; @@ -4256,12 +4251,12 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c } break; - case 45: /* stam */ + case 44: /* stam */ vict->points.stamina = RANGE(0, vict->points.max_stamina); affect_total(vict); break; - case 46: /* str */ + case 45: /* str */ if (IS_NPC(vict) || GET_LEVEL(vict) >= LVL_GRGOD) RANGE(3, 25); else @@ -4269,10 +4264,7 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c vict->real_abils.str = value; affect_total(vict); break; - case 47: /* unused1 (removed thief flag) */ - send_to_char(ch, "That flag is no longer in use.\r\n"); - return (0); - case 48: /* thirst */ + case 46: /* thirst */ if (!str_cmp(val_arg, "off")) { GET_COND(vict, THIRST) = -1; send_to_char(ch, "%s's thirst is now off.\r\n", GET_NAME(vict)); @@ -4286,13 +4278,13 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c return (0); } break; - case 49: /* variable */ + case 47: /* variable */ return perform_set_dg_var(ch, vict, val_arg); - case 50: /* weight */ + case 48: /* weight */ GET_WEIGHT(vict) = value; affect_total(vict); break; - case 51: /* wis */ + case 49: /* wis */ if (IS_NPC(vict) || GET_LEVEL(vict) >= LVL_GRGOD) RANGE(3, 25); else @@ -4300,10 +4292,10 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c vict->real_abils.wis = value; affect_total(vict); break; - case 52: /* questpoints */ + case 50: /* questpoints */ GET_QUESTPOINTS(vict) = RANGE(0, 100000000); break; - case 53: /* questhistory */ + case 51: /* questhistory */ qvnum = atoi(val_arg); if (real_quest(qvnum) == NOTHING) { send_to_char(ch, "That quest doesn't exist.\r\n"); @@ -4320,7 +4312,7 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c } break; } - case 54: /* species */ + case 52: /* species */ if ((i = parse_species(val_arg)) == SPECIES_UNDEFINED) { send_to_char(ch, "That is not a species.\r\n"); return (0); From 9443bab159d896f84051114908324f5ca53d3db5 Mon Sep 17 00:00:00 2001 From: kinther Date: Mon, 29 Dec 2025 08:37:45 -0800 Subject: [PATCH 12/40] Look directional output --- src/act.informative.c | 106 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 95 insertions(+), 11 deletions(-) diff --git a/src/act.informative.c b/src/act.informative.c index b463cc9..2053b90 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -41,6 +41,8 @@ static void look_at_target(struct char_data *ch, char *arg); static void look_in_direction(struct char_data *ch, int dir); static void look_in_obj(struct char_data *ch, char *arg); static void look_at_tables(struct char_data *ch); +static bool look_can_spot_hidden(struct char_data *ch, struct char_data *tch, room_rnum room); +static bool look_list_direction_chars(struct char_data *ch, room_rnum room); /* do_look, do_inventory utility functions */ static void list_obj_to_char(struct obj_data *list, struct char_data *ch, int mode, int show); /* do_look, do_equipment, do_examine, do_inventory */ @@ -809,18 +811,100 @@ void look_at_room(struct char_data *ch, int ignore_brief) static void look_in_direction(struct char_data *ch, int dir) { - if (EXIT(ch, dir)) { - if (EXIT(ch, dir)->general_description) - send_to_char(ch, "%s", EXIT(ch, dir)->general_description); - else - send_to_char(ch, "You see nothing special.\r\n"); + static const char *range_labels[] = { "[near]", "[far]", "[very far]" }; + room_rnum room = IN_ROOM(ch); + int distance; + bool blocked = FALSE; - if (EXIT_FLAGGED(EXIT(ch, dir), EX_CLOSED) && EXIT(ch, dir)->keyword) - send_to_char(ch, "The %s is closed.\r\n", fname(EXIT(ch, dir)->keyword)); - else if (EXIT_FLAGGED(EXIT(ch, dir), EX_ISDOOR) && EXIT(ch, dir)->keyword) - send_to_char(ch, "The %s is open.\r\n", fname(EXIT(ch, dir)->keyword)); - } else - send_to_char(ch, "Nothing special there...\r\n"); + send_to_char(ch, ">look %s\r\n\r\n", dirs[dir]); + send_to_char(ch, "You look to the %s and see:\r\n", dirs[dir]); + + for (distance = 0; distance < 3; distance++) { + struct room_direction_data *exit = NULL; + + send_to_char(ch, "%s\r\n", range_labels[distance]); + + if (!blocked) { + exit = W_EXIT(room, dir); + + if (!exit || exit->to_room == NOWHERE) + blocked = TRUE; + else if (EXIT_FLAGGED(exit, EX_HIDDEN) && !PRF_FLAGGED(ch, PRF_HOLYLIGHT)) + blocked = TRUE; + else if (EXIT_FLAGGED(exit, EX_CLOSED)) + blocked = TRUE; + else + room = exit->to_room; + } + + if (blocked || !VALID_ROOM_RNUM(room)) { + send_to_char(ch, "nothing\r\n"); + continue; + } + + if (!look_list_direction_chars(ch, room)) + send_to_char(ch, "nothing\r\n"); + } +} + +static bool look_can_spot_hidden(struct char_data *ch, struct char_data *tch, room_rnum room) +{ + int total; + + if (!ch || !tch) + return FALSE; + if (!AFF_FLAGGED(tch, AFF_HIDE)) + return FALSE; + if (!GET_SKILL(ch, SKILL_PERCEPTION)) + return FALSE; + if (AFF_FLAGGED(ch, AFF_BLIND)) + return FALSE; + if (IS_DARK(room) && !CAN_SEE_IN_DARK(ch)) + return FALSE; + + total = roll_scan_perception(ch); + + if (AFF_FLAGGED(ch, AFF_SCAN)) + total += 5; /* Match scan bonus from other detection checks. */ + + if (GET_STEALTH_CHECK(tch) <= 0) + SET_STEALTH_CHECK(tch, 5); + + return (total >= (GET_STEALTH_CHECK(tch) + 2)); +} + +static bool look_list_direction_chars(struct char_data *ch, room_rnum room) +{ + struct char_data *tch; + bool found = FALSE; + + if (!VALID_ROOM_RNUM(room)) + return FALSE; + if (IS_DARK(room) && !CAN_SEE_IN_DARK(ch)) + return FALSE; + + for (tch = world[room].people; tch; tch = tch->next_in_room) { + if (tch == ch) + continue; + if (!IS_NPC(ch) && !PRF_FLAGGED(ch, PRF_HOLYLIGHT) && + IS_NPC(tch) && tch->player.long_descr && *tch->player.long_descr == '.') + continue; + + if (AFF_FLAGGED(tch, AFF_HIDE)) { + if (CAN_SEE(ch, tch) || look_can_spot_hidden(ch, tch, room)) { + send_to_char(ch, "a shadowy figure\r\n"); + found = TRUE; + } + continue; + } + + if (CAN_SEE(ch, tch)) { + send_to_char(ch, "%s\r\n", get_char_sdesc(tch)); + found = TRUE; + } + } + + return found; } static void look_in_obj(struct char_data *ch, char *arg) From 497218958e1ee96e7eaa9c64e6123073d8f70b1b Mon Sep 17 00:00:00 2001 From: kinther Date: Mon, 29 Dec 2025 09:07:21 -0800 Subject: [PATCH 13/40] Species update with base hit/mana/stam --- src/class.c | 30 ++++++++++++++++++++++++++--- src/db.c | 19 ++++++++++++++++--- src/species.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/species.h | 1 + 4 files changed, 96 insertions(+), 6 deletions(-) diff --git a/src/class.c b/src/class.c index 77d80ad..ae7e43a 100644 --- a/src/class.c +++ b/src/class.c @@ -584,14 +584,24 @@ void grant_class_skills(struct char_data *ch, bool reset) /* Some initializations for characters, including initial skills */ void do_start(struct char_data *ch) { + int base_hit = 90; + int base_mana = 100; + int base_stamina = 90; + GET_LEVEL(ch) = 1; GET_EXP(ch) = 1; roll_real_abils(ch); - GET_MAX_HIT(ch) = 90; - GET_MAX_MANA(ch) = 100; - GET_MAX_STAMINA(ch) = 90; + if (!get_species_base_points(GET_SPECIES(ch), &base_hit, &base_mana, &base_stamina)) { + base_hit = 90; + base_mana = 100; + base_stamina = 90; + } + + GET_MAX_HIT(ch) = base_hit; + GET_MAX_MANA(ch) = base_mana; + GET_MAX_STAMINA(ch) = base_stamina; grant_class_skills(ch, TRUE); grant_species_skills(ch); @@ -616,6 +626,20 @@ void advance_level(struct char_data *ch) { int add_hp, add_mana = 0, add_move = 0, i; + if (GET_LEVEL(ch) >= LVL_IMMORT) { + GET_MAX_HIT(ch) = 999; + GET_MAX_MANA(ch) = 999; + GET_MAX_STAMINA(ch) = 999; + + for (i = 0; i < 3; i++) + GET_COND(ch, i) = (char) -1; + SET_BIT_AR(PRF_FLAGS(ch), PRF_HOLYLIGHT); + + snoop_check(ch); + save_char(ch); + return; + } + add_hp = GET_ABILITY_MOD(GET_CON(ch)); switch (GET_CLASS(ch)) { diff --git a/src/db.c b/src/db.c index f93dc14..25634a6 100644 --- a/src/db.c +++ b/src/db.c @@ -21,6 +21,7 @@ #include "house.h" #include "constants.h" #include "oasis.h" +#include "species.h" #include "dg_scripts.h" #include "dg_event.h" #include "act.h" @@ -2740,6 +2741,18 @@ struct char_data *read_mobile(mob_vnum nr, int type) /* and mob_rnum */ } else mob->points.max_hit = rand_number(mob->points.hit, mob->points.mana); + { + int base_hit = 0; + int base_mana = 0; + int base_stamina = 0; + + if (get_species_base_points(GET_SPECIES(mob), &base_hit, &base_mana, &base_stamina)) { + mob->points.max_hit += base_hit; + mob->points.max_mana += base_mana; + mob->points.max_stamina += base_stamina; + } + } + mob->points.hit = mob->points.max_hit; mob->points.mana = mob->points.max_mana; mob->points.stamina = mob->points.max_stamina; @@ -3813,9 +3826,9 @@ void init_char(struct char_data *ch) GET_EXP(ch) = 7000000; /* The implementor never goes through do_start(). */ - GET_MAX_HIT(ch) = 500; - GET_MAX_MANA(ch) = 100; - GET_MAX_STAMINA(ch) = 82; + GET_MAX_HIT(ch) = 999; + GET_MAX_MANA(ch) = 999; + GET_MAX_STAMINA(ch) = 999; GET_HIT(ch) = GET_MAX_HIT(ch); GET_MANA(ch) = GET_MAX_MANA(ch); GET_STAMINA(ch) = GET_MAX_STAMINA(ch); diff --git a/src/species.c b/src/species.c index aed2883..a4414a6 100644 --- a/src/species.c +++ b/src/species.c @@ -65,6 +65,43 @@ const int pc_species_list[] = { -1 }; +struct species_base_points { + int hit; + int mana; + int stamina; +}; + +static const struct species_base_points species_base_points[NUM_SPECIES] = { + { 100, 90, 100 }, /* Human */ + { 90, 110, 90 }, /* City Elf */ + { 100, 80, 140 }, /* Desert Elf */ + { 95, 90, 95 }, /* Half-Elf */ + { 110, 75, 110 }, /* Dwarf */ + { 110, 80, 110 }, /* Mul */ + { 180, 50, 180 }, /* Half-Giant */ + { 90, 90, 90 }, /* Mantis */ + { 90, 100, 90 }, /* Gith */ + { 90, 90, 90 }, /* Aarakocra */ + { 100, 100, 100 }, /* Dray */ + { 70, 120, 80 }, /* Kenku */ + { 60, 10, 80 }, /* Jozhal */ + { 120, 10, 120 }, /* Pterran */ + { 100, 60, 100 }, /* Tarek */ + { 60, 10, 80 }, /* Aprig */ + { 100, 10, 100 }, /* Carru */ + { 100, 10, 80 }, /* Crodlu */ + { 80, 10, 200 }, /* Erdlu */ + { 120, 10, 400 }, /* Inix */ + { 75, 10, 75 }, /* Jhakar */ + { 100, 10, 300 }, /* Kank */ + { 200, 10, 150 }, /* Mekillot */ + { 100, 10, 150 }, /* Worm */ + { 10, 10, 20 }, /* Renk */ + { 10, 10, 20 }, /* Rat */ + { 110, 110, 110 }, /* Undead */ + { 250, 250, 250 } /* Dragon */ +}; + static const struct species_skill_bonus species_skill_none[] = { { -1, 0 } }; @@ -285,6 +322,21 @@ int species_ability_cap(int species, int ability) return species_ability_caps[species][ability]; } +bool get_species_base_points(int species, int *hit, int *mana, int *stamina) +{ + if (species < 0 || species >= NUM_SPECIES) + return FALSE; + + if (hit) + *hit = species_base_points[species].hit; + if (mana) + *mana = species_base_points[species].mana; + if (stamina) + *stamina = species_base_points[species].stamina; + + return TRUE; +} + static void apply_species_ranges(struct char_data *ch) { int species; diff --git a/src/species.h b/src/species.h index 34d80d1..f4b7535 100644 --- a/src/species.h +++ b/src/species.h @@ -17,6 +17,7 @@ bool species_is_pc_selectable(int species); int species_ability_mod(int species, int ability); int species_ability_min(int species, int ability); int species_ability_cap(int species, int ability); +bool get_species_base_points(int species, int *hit, int *mana, int *stamina); void apply_species_bonuses(struct char_data *ch); void grant_species_skills(struct char_data *ch); From be79603e8f32c7fd0c66b317a1c569e63e22726d Mon Sep 17 00:00:00 2001 From: kinther Date: Mon, 29 Dec 2025 10:55:09 -0800 Subject: [PATCH 14/40] Change ldesc update --- README.md | 1 + src/act.h | 1 + src/act.informative.c | 32 ++++++++++++-- src/act.movement.c | 16 +++++++ src/act.other.c | 99 ++++++++++++++++++++++++++++++++++++++++++- src/interpreter.c | 6 ++- src/structs.h | 1 + src/utils.c | 68 +++++++++++++++++++++++++++++ src/utils.h | 2 + 9 files changed, 220 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 48ea3a0..adc073c 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,7 @@ Features in Miranthas MUD Alpha release: * Account system for tracking players/characters over long periods of time * Race/species selection and stat ranges (elves have higher dex, dwarves have higher str, etc) * Prioritized stats during character generation + * Ability to change ldesc of PC/NPC's in some situations Features to be implemented in the next few releases: diff --git a/src/act.h b/src/act.h index ef84127..405a7a0 100644 --- a/src/act.h +++ b/src/act.h @@ -257,6 +257,7 @@ ACMD(do_group); ACMD(do_hide); ACMD(do_listen); ACMD(do_not_here); +ACMD(do_change); ACMD(do_report); ACMD(do_save); ACMD(do_skills); diff --git a/src/act.informative.c b/src/act.informative.c index 2053b90..423929e 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -569,8 +569,30 @@ static void list_one_char(struct char_data *i, struct char_data *ch) CCNRM(ch, C_NRM)); } - /* NPCs with a full long description at default position: print that and bail. */ - if (IS_NPC(i) && i->player.long_descr && GET_POS(i) == GET_DEFAULT_POS(i)) { + /* Custom ldesc overrides position-based output. */ + if (i->char_specials.custom_ldesc && i->player.long_descr) { + if (AFF_FLAGGED(i, AFF_INVISIBLE)) + send_to_char(ch, "*"); + + if (AFF_FLAGGED(ch, AFF_DETECT_ALIGN)) { + if (IS_EVIL(i)) + send_to_char(ch, "(Red Aura) "); + else if (IS_GOOD(i)) + send_to_char(ch, "(Blue Aura) "); + } + + send_to_char(ch, "%s", i->player.long_descr); + + if (AFF_FLAGGED(i, AFF_SANCTUARY)) + act("...$e glows with a bright light!", FALSE, i, 0, ch, TO_VICT); + if (AFF_FLAGGED(i, AFF_BLIND) && GET_LEVEL(i) < LVL_IMMORT) + act("...$e is groping around blindly!", FALSE, i, 0, ch, TO_VICT); + + return; + } + + /* Characters with a full long description at default position: print that and bail. */ + if (i->player.long_descr && GET_POS(i) == GET_DEFAULT_POS(i)) { if (AFF_FLAGGED(i, AFF_INVISIBLE)) send_to_char(ch, "*"); @@ -892,7 +914,11 @@ static bool look_list_direction_chars(struct char_data *ch, room_rnum room) if (AFF_FLAGGED(tch, AFF_HIDE)) { if (CAN_SEE(ch, tch) || look_can_spot_hidden(ch, tch, room)) { - send_to_char(ch, "a shadowy figure\r\n"); + char hidden_ldesc[MAX_STRING_LENGTH]; + if (build_hidden_ldesc(tch, hidden_ldesc, sizeof(hidden_ldesc))) + send_to_char(ch, "%s", hidden_ldesc); + else + send_to_char(ch, "a shadowy figure\r\n"); found = TRUE; } continue; diff --git a/src/act.movement.c b/src/act.movement.c index 29d0734..224993f 100644 --- a/src/act.movement.c +++ b/src/act.movement.c @@ -492,6 +492,7 @@ int do_simple_move(struct char_data *ch, int dir, int need_specials_check) /* Only here is the move successful *and* complete. Return success for * calling functions to handle post move operations. */ + clear_custom_ldesc(ch); return (1); } @@ -1000,6 +1001,7 @@ ACMD(do_stand) act(self_msg, TRUE, ch, furniture, 0, TO_CHAR); act(room_msg, TRUE, ch, furniture, 0, TO_ROOM); GET_POS(ch) = FIGHTING(ch) ? POS_FIGHTING : POS_STANDING; + clear_custom_ldesc(ch); return; } @@ -1020,6 +1022,7 @@ ACMD(do_stand) char_from_furniture(ch); /* Will be standing after a successful bash and may still be fighting. */ GET_POS(ch) = FIGHTING(ch) ? POS_FIGHTING : POS_STANDING; + clear_custom_ldesc(ch); break; case POS_RESTING: @@ -1033,6 +1036,7 @@ ACMD(do_stand) GET_POS(ch) = POS_STANDING; /* Were they sitting in something. */ char_from_furniture(ch); + clear_custom_ldesc(ch); break; case POS_SLEEPING: @@ -1050,6 +1054,7 @@ ACMD(do_stand) else act("$n stops floating around, and puts $s feet on the ground.", TRUE, ch, 0, 0, TO_ROOM); GET_POS(ch) = POS_STANDING; + clear_custom_ldesc(ch); break; } } @@ -1122,6 +1127,7 @@ ACMD(do_sit) act(self_msg, TRUE, ch, furniture, 0, TO_CHAR); act(room_msg, TRUE, ch, furniture, 0, TO_ROOM); GET_POS(ch) = POS_SITTING; + clear_custom_ldesc(ch); return; } @@ -1130,6 +1136,7 @@ ACMD(do_sit) send_to_char(ch, "You sit down.\r\n"); act("$n sits down.", FALSE, ch, 0, 0, TO_ROOM); GET_POS(ch) = POS_SITTING; + clear_custom_ldesc(ch); break; case POS_SITTING: send_to_char(ch, "You're sitting already.\r\n"); @@ -1141,6 +1148,7 @@ ACMD(do_sit) else act("$n stops resting and sits up.", TRUE, ch, 0, 0, TO_ROOM); GET_POS(ch) = POS_SITTING; + clear_custom_ldesc(ch); break; case POS_SLEEPING: send_to_char(ch, "You have to wake up first.\r\n"); @@ -1155,6 +1163,7 @@ ACMD(do_sit) else act("$n stops floating around, and sits down.", TRUE, ch, 0, 0, TO_ROOM); GET_POS(ch) = POS_SITTING; + clear_custom_ldesc(ch); break; } } @@ -1227,6 +1236,7 @@ ACMD(do_rest) act(self_msg, TRUE, ch, furniture, 0, TO_CHAR); act(room_msg, TRUE, ch, furniture, 0, TO_ROOM); GET_POS(ch) = POS_RESTING; + clear_custom_ldesc(ch); return; } @@ -1240,6 +1250,7 @@ ACMD(do_rest) act("$n sits down and rests.", TRUE, ch, 0, 0, TO_ROOM); } GET_POS(ch) = POS_RESTING; + clear_custom_ldesc(ch); break; case POS_SITTING: @@ -1258,6 +1269,7 @@ ACMD(do_rest) act("$n rests.", TRUE, ch, 0, 0, TO_ROOM); } GET_POS(ch) = POS_RESTING; + clear_custom_ldesc(ch); break; case POS_RESTING: @@ -1279,6 +1291,7 @@ ACMD(do_rest) else act("$n stops floating around, and rests.", FALSE, ch, 0, 0, TO_ROOM); GET_POS(ch) = POS_RESTING; + clear_custom_ldesc(ch); break; } } @@ -1332,6 +1345,7 @@ ACMD(do_sleep) act("You go to sleep on $p.", TRUE, ch, furniture, 0, TO_CHAR); act("$n lies down and falls asleep on $p.", TRUE, ch, furniture, 0, TO_ROOM); GET_POS(ch) = POS_SLEEPING; + clear_custom_ldesc(ch); return; } @@ -1354,6 +1368,7 @@ ACMD(do_sleep) act("$n lies down and falls asleep.", TRUE, ch, 0, 0, TO_ROOM); } GET_POS(ch) = POS_SLEEPING; + clear_custom_ldesc(ch); break; case POS_SLEEPING: @@ -1371,6 +1386,7 @@ ACMD(do_sleep) else act("$n stops floating around, and lies down to sleep.", TRUE, ch, 0, 0, TO_ROOM); GET_POS(ch) = POS_SLEEPING; + clear_custom_ldesc(ch); break; } } diff --git a/src/act.other.c b/src/act.other.c index 99d611f..a61dae5 100644 --- a/src/act.other.c +++ b/src/act.other.c @@ -36,6 +36,36 @@ static void print_group(struct char_data *ch); static void display_group_list(struct char_data * ch); +static bool change_has_emote_tokens(const char *text) +{ + for (; text && *text; text++) { + switch (*text) { + case '~': case '!': case '%': case '^': + case '#': case '&': case '=': case '+': + case '@': + return TRUE; + } + } + return FALSE; +} + +static bool change_ends_with_punct(const char *text) +{ + size_t len = text ? strlen(text) : 0; + if (len == 0) + return FALSE; + return (text[len - 1] == '.' || text[len - 1] == '!' || text[len - 1] == '?'); +} + +static void change_trim_trailing_spaces(char *text) +{ + size_t len = text ? strlen(text) : 0; + while (len > 0 && isspace((unsigned char)text[len - 1])) { + text[len - 1] = '\0'; + len--; + } +} + ACMD(do_quit) { char first[MAX_INPUT_LENGTH]; @@ -182,6 +212,69 @@ ACMD(do_save) Crash_crashsave(ch); } +ACMD(do_change) +{ + char option[MAX_INPUT_LENGTH]; + char suffix[MAX_INPUT_LENGTH]; + char base_buf[MAX_INPUT_LENGTH]; + char ldesc[MAX_STRING_LENGTH]; + char *rest = argument; + const char *base; + + rest = one_argument(rest, option); + if (!*option) { + send_to_char(ch, "Usage: change ldesc \r\n"); + return; + } + + if (!is_abbrev(option, "ldesc")) { + send_to_char(ch, "Unknown change option. Available: ldesc\r\n"); + return; + } + + skip_spaces(&rest); + if (!*rest) { + send_to_char(ch, "Usage: change ldesc \r\n"); + return; + } + + if (change_has_emote_tokens(rest)) { + send_to_char(ch, "You can't use emote tokens in your ldesc.\r\n"); + return; + } + + strlcpy(suffix, rest, sizeof(suffix)); + change_trim_trailing_spaces(suffix); + if (!*suffix) { + send_to_char(ch, "Usage: change ldesc \r\n"); + return; + } + + if (!change_ends_with_punct(suffix)) + strlcat(suffix, ".", sizeof(suffix)); + + base = (GET_SHORT_DESC(ch) && *GET_SHORT_DESC(ch)) ? GET_SHORT_DESC(ch) : GET_NAME(ch); + if (!base || !*base) + base = "someone"; + + strlcpy(base_buf, base, sizeof(base_buf)); + if (*base_buf) + base_buf[0] = UPPER(*base_buf); + + snprintf(ldesc, sizeof(ldesc), "%s %s\r\n", base_buf, suffix); + + if (ch->player.long_descr) { + if (!IS_NPC(ch) || GET_MOB_RNUM(ch) == NOBODY || + ch->player.long_descr != mob_proto[GET_MOB_RNUM(ch)].player.long_descr) { + free(ch->player.long_descr); + } + } + ch->player.long_descr = strdup(ldesc); + ch->char_specials.custom_ldesc = TRUE; + + send_to_char(ch, "Long description updated.\r\n"); +} + /* Generic function for commands which are normally overridden by special * procedures - i.e., shop commands, mail commands, etc. */ ACMD(do_not_here) @@ -886,7 +979,11 @@ bool perform_scan_sweep(struct char_data *ch) continue; if (total >= scan_target_dc(tch)) { - send_to_char(ch, "A shadowy figure.\r\n"); + char hidden_ldesc[MAX_STRING_LENGTH]; + if (build_hidden_ldesc(tch, hidden_ldesc, sizeof(hidden_ldesc))) + send_to_char(ch, "%s", hidden_ldesc); + else + send_to_char(ch, "A shadowy figure.\r\n"); remember_scan_target(ch, tch); found_any = TRUE; } else { diff --git a/src/interpreter.c b/src/interpreter.c index 51fa507..0748ed4 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -118,6 +118,7 @@ cpp_extern const struct command_info cmd_info[] = { { "cast" , "c" , POS_SITTING , do_cast , 1, 0 }, { "cedit" , "cedit" , POS_DEAD , do_oasis_cedit, LVL_IMPL, 0 }, + { "change" , "chang" , POS_RESTING , do_change , 0, 0 }, { "changelog", "cha" , POS_DEAD , do_changelog, LVL_IMPL, 0 }, { "check" , "ch" , POS_STANDING, do_not_here , 1, 0 }, { "checkload", "checkl" , POS_DEAD , do_checkloadstatus, LVL_GOD, 0 }, @@ -483,8 +484,6 @@ void command_interpreter(struct char_data *ch, char *argument) char *line; char arg[MAX_INPUT_LENGTH]; - REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_HIDE); - /* just drop to next line for hitting CR */ skip_spaces(&argument); if (!*argument) @@ -500,6 +499,9 @@ void command_interpreter(struct char_data *ch, char *argument) } else line = any_one_arg(argument, arg); + if (!is_abbrev(arg, "change")) + REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_HIDE); + /* Since all command triggers check for valid_dg_target before acting, the levelcheck * here has been removed. Otherwise, find the command. */ { diff --git a/src/structs.h b/src/structs.h index 95ca614..febbccf 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1021,6 +1021,7 @@ struct char_special_data byte carry_items; /**< Number of items carried */ int timer; /**< Timer for update */ int stealth_check; /* last rolled Stealth value for Hide; 0 = not hiding/opposed */ + bool custom_ldesc; /* temporary ldesc override from change command */ struct char_special_data_saved saved; /**< Constants saved for PCs. */ }; diff --git a/src/utils.c b/src/utils.c index 1751511..43aaeb1 100644 --- a/src/utils.c +++ b/src/utils.c @@ -1700,6 +1700,74 @@ const char *get_char_sdesc(const struct char_data *ch) return "someone"; } +void clear_custom_ldesc(struct char_data *ch) +{ + char base_buf[MAX_INPUT_LENGTH]; + char ldesc[MAX_STRING_LENGTH]; + const char *base; + + if (!ch || !ch->char_specials.custom_ldesc) + return; + + ch->char_specials.custom_ldesc = FALSE; + + if (ch->player.long_descr) { + if (!IS_NPC(ch) || GET_MOB_RNUM(ch) == NOBODY || + ch->player.long_descr != mob_proto[GET_MOB_RNUM(ch)].player.long_descr) { + free(ch->player.long_descr); + } + ch->player.long_descr = NULL; + } + + base = (GET_SHORT_DESC(ch) && *GET_SHORT_DESC(ch)) ? GET_SHORT_DESC(ch) : GET_NAME(ch); + if (!base || !*base) + base = "someone"; + + strlcpy(base_buf, base, sizeof(base_buf)); + if (*base_buf) + base_buf[0] = UPPER(*base_buf); + + snprintf(ldesc, sizeof(ldesc), "%s is standing here.\r\n", base_buf); + ch->player.long_descr = strdup(ldesc); +} + +bool build_hidden_ldesc(const struct char_data *ch, char *out, size_t outsz) +{ + char base_buf[MAX_INPUT_LENGTH]; + const char *base; + size_t base_len; + const char *suffix; + + if (!out || outsz == 0) return FALSE; + *out = '\0'; + + if (!ch || !ch->char_specials.custom_ldesc || !ch->player.long_descr) + return FALSE; + if (GET_POS(ch) != GET_DEFAULT_POS(ch)) + return FALSE; + + base = (GET_SHORT_DESC(ch) && *GET_SHORT_DESC(ch)) ? GET_SHORT_DESC(ch) : GET_NAME(ch); + if (!base || !*base) + base = "someone"; + + strlcpy(base_buf, base, sizeof(base_buf)); + if (*base_buf) + base_buf[0] = UPPER(*base_buf); + + base_len = strlen(base_buf); + if (strncmp(ch->player.long_descr, base_buf, base_len) != 0) + return FALSE; + + suffix = ch->player.long_descr + base_len; + if (*suffix == ' ') + suffix++; + else + return FALSE; + + snprintf(out, outsz, "A shadowy figure %s", suffix); + return TRUE; +} + /* 5e system helpers */ extern const struct armor_slot armor_slots[]; /* in constants.c */ diff --git a/src/utils.h b/src/utils.h index ecfa653..a674a6d 100644 --- a/src/utils.h +++ b/src/utils.h @@ -80,6 +80,8 @@ char *right_trim_whitespace(const char *string); void remove_from_string(char *string, const char *to_remove); const char *const *obj_value_labels(int item_type); const char *get_char_sdesc(const struct char_data *ch); +void clear_custom_ldesc(struct char_data *ch); +bool build_hidden_ldesc(const struct char_data *ch, char *out, size_t outsz); int obj_is_storage(const struct obj_data *obj); int obj_storage_is_closed(const struct obj_data *obj); int roll_skill_check(struct char_data *ch, int skillnum, int mode, int *out_d20); From 3344074ea2df1ad92a67d80a505dbf1f939f4bde Mon Sep 17 00:00:00 2001 From: kinther Date: Mon, 29 Dec 2025 18:08:53 -0800 Subject: [PATCH 15/40] Add age and time played functionality --- README.md | 24 +++++++++++++++---- lib/world/mob/1.mob | 54 ++++++++++++++++++++++++------------------- src/act.informative.c | 26 ++++++++++++--------- src/act.wizard.c | 25 ++++++++++---------- src/constants.c | 15 +++++++++++- src/db.c | 21 +++++++++++++++-- src/genmob.c | 8 +++++++ src/interpreter.c | 30 ++++++++++++++++++++++++ src/medit.c | 23 ++++++++++++++++++ src/oasis.h | 1 + src/players.c | 25 ++++++++++++++++++++ src/structs.h | 7 ++++-- src/utils.c | 19 ++++++++++----- src/utils.h | 6 +++++ 14 files changed, 222 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index adc073c..275df22 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ -***Files for Miranthas MUD.*** +***Files for Cataclysm MUD.*** -Miranthas MUD is a continuation of tbaMUD/CircleMUD, which is built on DIKU MUD. -The code here is freeware to honor that tradition. +Cataclysm MUD is a continuation of tbaMUD/CircleMUD, which is built on DIKU MUD. +The code here is freeware to honor that tradition. Licensing and use should be based +on what was outlined previously. Any new code added here is released under the same +license. Due to the sensitive nature of topics found in this setting, all characters and players are 18+. The game world is derived from several inspirational sources, @@ -9,7 +11,7 @@ most notably the former Armageddon MUD. Roleplay is highly encouraged, but not enforced. -Features in Miranthas MUD Alpha release: +Features in Cataclysm MUD Alpha release: * The city of Caleran is available for exploration * Experience points and levels are removed in favor of skill based progression @@ -43,12 +45,22 @@ Features in Miranthas MUD Alpha release: * PC's now use a short description for identification instead of name * Backgrounds are now available for PC's and NPC's * Account system for tracking players/characters over long periods of time + +Alpha 1.1 release: + + * Cleaned up legacy practice system code + * Added skill caps for classes to limit ability of everyone to reach skill leve 100 (and respective proficiency) * Race/species selection and stat ranges (elves have higher dex, dwarves have higher str, etc) + * Renamed move to stamina in code to reflect how much energy is used for certain actions + * Species have base hit/mana/stamina now, plus their class modifier rolls * Prioritized stats during character generation * Ability to change ldesc of PC/NPC's in some situations + * Ability to look in certain directions to see what is 1-3 rooms away + * PC's and NPC's can now have an age set between 18-65 Features to be implemented in the next few releases: +* "acaudit" command to be "audit ac", allowing for further audit commands in the future * Subclass selection to personalize character further * Combat is slowed down so it isn't over in < 15 seconds (unless you're far outmatched) * Mounts added to help with long trips @@ -78,6 +90,10 @@ Features to be implemented in the next few releases: * Additional zones/cities based on Miranthas world map * Resources on the world map can be claimed by different city-states or independent factions * Claimed resources improve quality of armor/weapons/food/prices available +* Death from old age if you roll badly on your birthday after the expected lifespan of a species +* Attacks hit different parts of the body and have different damage effects +* Armor degradation based on damage taken per body part +* Weapon degradation based on damage dealt - potentially shattering weapons ...and down the road: diff --git a/lib/world/mob/1.mob b/lib/world/mob/1.mob index da2a3a5..6defa73 100644 --- a/lib/world/mob/1.mob +++ b/lib/world/mob/1.mob @@ -19,6 +19,7 @@ B + ~ 6218 0 0 0 0 0 0 0 0 E 1 3d20+40 @@ -37,17 +38,17 @@ Skill 145 5 Skill 146 5 Skill 147 5 E -L 17 127 1 -L 16 117 1 -L 15 117 1 -L 11 111 1 -L 10 107 1 -L 9 124 1 -L 8 115 1 -L 7 108 1 -L 6 110 1 -L 5 131 1 L 3 118 1 +L 5 131 1 +L 6 110 1 +L 7 108 1 +L 8 115 1 +L 9 124 1 +L 10 107 1 +L 11 111 1 +L 15 117 1 +L 16 117 1 +L 17 127 1 #101 Sally~ slim lanky human soldier guard~ @@ -70,6 +71,7 @@ B + ~ 6218 0 0 0 0 0 0 0 0 E 1 3d20+40 @@ -90,17 +92,17 @@ Skill 152 5 Skill 156 5 Skill 163 5 E -L 3 118 1 -L 5 131 1 -L 6 110 1 -L 7 108 1 -L 8 115 1 -L 9 124 1 -L 10 107 1 -L 11 111 1 -L 15 117 1 -L 16 117 1 L 17 127 1 +L 16 117 1 +L 15 117 1 +L 11 111 1 +L 10 107 1 +L 9 124 1 +L 8 115 1 +L 7 108 1 +L 6 110 1 +L 5 131 1 +L 3 118 1 #102 Baldy~ barkeep stocky bald~ @@ -123,13 +125,14 @@ B + ~ 10 0 0 0 0 0 0 0 0 E 1 3d12+60 8 8 1 E -L 9 112 1 L 14 113 1 +L 9 112 1 #103 Lanky~ woman lanky scarred~ @@ -153,6 +156,7 @@ B + ~ 10 0 0 0 0 0 0 0 0 E 1 3d8+60 @@ -186,18 +190,20 @@ B + It's a rat. ~ 8 0 0 0 0 0 0 0 0 E 1 0d0+10 8 8 2 -Str: 2 +Str: 3 Dex: 7 -Int: 1 +Int: 3 Wis: 8 Con: 8 -Cha: 1 +Cha: 3 Species: 25 +Age: 42 AtkT 4 E $ diff --git a/src/act.informative.c b/src/act.informative.c index 423929e..ef938ea 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -1254,7 +1254,10 @@ ACMD(do_coins) ACMD(do_score) { - struct time_info_data playing_time; + time_t played_seconds; + int played_minutes; + int played_hours; + int played_days; struct ac_breakdown acb; bool ismob = IS_NPC(ch); @@ -1299,12 +1302,9 @@ ACMD(do_score) send_to_char(ch, "Stealth Disadvantage: %s\r\n", has_stealth_disadv(ch) ? "Yes" : "No"); - send_to_char(ch, "You are %d years old.", GET_AGE(ch)); + send_to_char(ch, "You are %d years old.", GET_ROLEPLAY_AGE(ch)); - if (age(ch)->month == 0 && age(ch)->day == 0) - send_to_char(ch, " It's your birthday today.\r\n"); - else - send_to_char(ch, "\r\n"); + send_to_char(ch, "\r\n"); /* Only players have quest data */ if (!ismob) { @@ -1324,11 +1324,15 @@ ACMD(do_score) /* Only players have valid playtime data */ if (!ismob) { - playing_time = *real_time_passed((time(0) - ch->player.time.logon) + - ch->player.time.played, 0); - send_to_char(ch, "You have been playing for %d day%s and %d hour%s.\r\n", - playing_time.day, playing_time.day == 1 ? "" : "s", - playing_time.hours, playing_time.hours == 1 ? "" : "s"); + played_seconds = get_total_played_seconds(ch); + played_minutes = (played_seconds / SECS_PER_REAL_MIN) % 60; + played_hours = (played_seconds / SECS_PER_REAL_HOUR) % 24; + played_days = played_seconds / SECS_PER_REAL_DAY; + send_to_char(ch, + "You have been playing for %d minute%s, %d hour%s, and %d day%s.\r\n", + played_minutes, played_minutes == 1 ? "" : "s", + played_hours, played_hours == 1 ? "" : "s", + played_days, played_days == 1 ? "" : "s"); } /* Position */ diff --git a/src/act.wizard.c b/src/act.wizard.c index 1755b58..4b2ac78 100644 --- a/src/act.wizard.c +++ b/src/act.wizard.c @@ -1793,8 +1793,7 @@ static void do_stat_character(struct char_data *ch, struct char_data *k) zone_table[world[IN_ROOM(k)].zone].number); if (!IS_NPC(k)) { - char created[64], logon[64], olc[64] = ""; - strftime(created, sizeof(created), "%b %d %Y", localtime(&(k->player.time.birth))); + char logon[64], olc[64] = ""; strftime(logon, sizeof(logon), "%b %d %Y", localtime(&(k->player.time.logon))); if (GET_LEVEL(k) >= LVL_BUILDER) { @@ -1810,12 +1809,16 @@ static void do_stat_character(struct char_data *ch, struct char_data *k) snprintf(olc, sizeof(olc), ", OLC %d", GET_OLC_ZONE(k)); } - stat_table_row_fmt(ch, "Account", "Created %s, Last %s%s", - created, logon, olc); - stat_table_row_fmt(ch, "Age/Play", "Age %d, Played %dh %dm", - age(k)->year, - k->player.time.played / 3600, - (k->player.time.played % 3600) / 60); + stat_table_row_fmt(ch, "Account", "Last %s%s", + logon, olc); + { + time_t played_seconds = get_total_played_seconds(k); + int played_minutes = (played_seconds / SECS_PER_REAL_MIN) % 60; + int played_hours = (played_seconds / SECS_PER_REAL_HOUR) % 24; + int played_days = played_seconds / SECS_PER_REAL_DAY; + stat_table_row_fmt(ch, "Age/Playtime", "Age %d, %dd %dh %dm", + GET_ROLEPLAY_AGE(k), played_days, played_hours, played_minutes); + } } stat_table_row_fmt(ch, "Class", "%s", CLASS_NAME(k)); @@ -3864,10 +3867,8 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c send_to_char(ch, "Ages 2 to 200 accepted.\r\n"); return (0); } - /* NOTE: May not display the exact age specified due to the integer - * division used elsewhere in the code. Seems to only happen for - * some values below the starting age (17) anyway. -gg 5/27/98 */ - vict->player.time.birth = time(0) - ((value - 17) * SECS_PER_MUD_YEAR); + GET_ROLEPLAY_AGE(vict) = LIMIT(value, MIN_CHAR_AGE, MAX_CHAR_AGE); + GET_ROLEPLAY_AGE_YEAR(vict) = time_info.year; break; case 3: /* align */ GET_ALIGNMENT(vict) = RANGE(-1000, 1000); diff --git a/src/constants.c b/src/constants.c index e26e49d..59de100 100644 --- a/src/constants.c +++ b/src/constants.c @@ -326,7 +326,9 @@ const char *connected_types[] = { "Get new PW", "Confirm new PW", "Select sex", + "Select species", "Select class", + "Short description", "Reading MOTD", "Main Menu", "Get descript.", @@ -350,7 +352,18 @@ const char *connected_types[] = { "Preference edit", "IBT edit", "Message edit", - "Protocol Detection", + "Background/Protocol", + "Connect menu", + "Get account", + "Confirm account", + "Account password", + "New account PW", + "Confirm account PW", + "Account email", + "Account menu", + "Account list", + "Stat preference", + "Select age", "\n" }; diff --git a/src/db.c b/src/db.c index 25634a6..9a5c124 100644 --- a/src/db.c +++ b/src/db.c @@ -1713,6 +1713,10 @@ static void interpret_espec(const char *keyword, const char *value, int i, int n RANGE(SPECIES_UNDEFINED, NUM_SPECIES - 1); mob_proto[i].player.species = num_arg; } + CASE("Age") { + RANGE(MIN_CHAR_AGE, MAX_CHAR_AGE); + mob_proto[i].player.roleplay_age = num_arg; + } /* --- 5e-style Saving Throws --- */ CASE("SaveStr") { @@ -1963,6 +1967,13 @@ void parse_mobile(FILE *mob_f, int nr) exit(1); } + if (mob_proto[i].player.time.birth == 0) + mob_proto[i].player.time.birth = time(0); + if (mob_proto[i].player.roleplay_age == 0) + mob_proto[i].player.roleplay_age = MIN_CHAR_AGE; + if (mob_proto[i].player.roleplay_age_year == 0) + mob_proto[i].player.roleplay_age_year = time_info.year; + letter = fread_letter(mob_f); while (letter == 'L') { int wpos = -1, vnum = -1, qty = 1; @@ -2757,7 +2768,8 @@ struct char_data *read_mobile(mob_vnum nr, int type) /* and mob_rnum */ mob->points.mana = mob->points.max_mana; mob->points.stamina = mob->points.max_stamina; - mob->player.time.birth = time(0); + if (mob->player.time.birth == 0) + mob->player.time.birth = time(0); mob->player.time.played = 0; mob->player.time.logon = time(0); @@ -3843,7 +3855,12 @@ void init_char(struct char_data *ch) ch->player_specials->saved.completed_quests = NULL; GET_QUEST(ch) = NOTHING; - ch->player.time.birth = time(0); + if (ch->player.time.birth == 0) + ch->player.time.birth = time(0); + if (GET_ROLEPLAY_AGE(ch) == 0) + GET_ROLEPLAY_AGE(ch) = MIN_CHAR_AGE; + if (GET_ROLEPLAY_AGE_YEAR(ch) == 0) + GET_ROLEPLAY_AGE_YEAR(ch) = time_info.year; ch->player.time.logon = time(0); ch->player.time.played = 0; diff --git a/src/genmob.c b/src/genmob.c index 313ff08..4927b0b 100644 --- a/src/genmob.c +++ b/src/genmob.c @@ -363,6 +363,14 @@ int write_mobile_espec(mob_vnum mvnum, struct char_data *mob, FILE *fd) fprintf(fd, "Species: %d\n", (int)GET_SPECIES(mob)); count++; } + { + int age_years = GET_ROLEPLAY_AGE(mob); + if (age_years >= MIN_CHAR_AGE && age_years <= MAX_CHAR_AGE && + age_years != MIN_CHAR_AGE) { + fprintf(fd, "Age: %d\n", age_years); + count++; + } + } /* --- 5e-style saving throws --- */ if (GET_SAVE(mob, ABIL_STR) != 0) { diff --git a/src/interpreter.c b/src/interpreter.c index 0748ed4..8281f88 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -1323,6 +1323,11 @@ static void show_species_menu(struct descriptor_data *d) write_to_output(d, "Species: "); } +static void show_age_prompt(struct descriptor_data *d) +{ + write_to_output(d, "Age (%d-%d): ", MIN_CHAR_AGE, MAX_CHAR_AGE); +} + static bool is_creation_state(int state) { switch (state) { @@ -1334,6 +1339,7 @@ static bool is_creation_state(int state) case CON_QSEX: case CON_QSPECIES: case CON_QCLASS: + case CON_QAGE: case CON_QSTAT_PREF: case CON_QSHORTDESC: case CON_PLR_DESC: @@ -2019,9 +2025,33 @@ case CON_QCLASS: GET_CLASS(d->character) = load_result; } + show_age_prompt(d); + STATE(d) = CON_QAGE; + return; + +case CON_QAGE: { + if (!is_number(arg)) { + write_to_output(d, "\r\nPlease enter a number between %d and %d.\r\n", + MIN_CHAR_AGE, MAX_CHAR_AGE); + show_age_prompt(d); + return; + } + + int age_years = atoi(arg); + if (age_years < MIN_CHAR_AGE || age_years > MAX_CHAR_AGE) { + write_to_output(d, "\r\nAge must be between %d and %d.\r\n", + MIN_CHAR_AGE, MAX_CHAR_AGE); + show_age_prompt(d); + return; + } + + GET_ROLEPLAY_AGE(d->character) = age_years; + GET_ROLEPLAY_AGE_YEAR(d->character) = time_info.year; + show_stat_pref_prompt(d); STATE(d) = CON_QSTAT_PREF; return; +} case CON_QSTAT_PREF: { ubyte order[NUM_ABILITIES]; diff --git a/src/medit.c b/src/medit.c index e08ae3c..65406b3 100644 --- a/src/medit.c +++ b/src/medit.c @@ -241,6 +241,9 @@ static void init_mobile(struct char_data *mob) GET_MAX_MANA(mob) = GET_MAX_STAMINA(mob) = 100; GET_WEIGHT(mob) = 200; GET_HEIGHT(mob) = 198; + mob->player.time.birth = time(0); + mob->player.roleplay_age = MIN_CHAR_AGE; + mob->player.roleplay_age_year = time_info.year; /* Only assign defaults if the individual stat is unset (zero) */ if (!mob->real_abils.str) mob->real_abils.str = 11; @@ -436,6 +439,7 @@ static void medit_disp_menu(struct descriptor_data *d) "%s1%s) Name: %s%s\r\n" "%s2%s) Keywords: %s%s\r\n" "%s3%s) Sex: %s%-7.7s%s\r\n" + "%sG%s) Age: %s%d%s\r\n" "%s4%s) S-Desc: %s%s\r\n" "%s5%s) L-Desc:-\r\n%s%s\r\n" "%s6%s) D-Desc:-\r\n%s%s\r\n", @@ -444,6 +448,7 @@ static void medit_disp_menu(struct descriptor_data *d) grn, nrm, yel, GET_NAME(mob), grn, nrm, yel, GET_KEYWORDS(mob), grn, nrm, yel, genders[(int)GET_SEX(mob)], nrm, + grn, nrm, yel, GET_ROLEPLAY_AGE(mob), nrm, grn, nrm, yel, GET_SDESC(mob), grn, nrm, yel, GET_LDESC(mob), grn, nrm, yel, GET_DDESC(mob) @@ -764,6 +769,11 @@ void medit_parse(struct descriptor_data *d, char *arg) OLC_MODE(d) = MEDIT_SEX; medit_disp_sex(d); return; + case 'g': + case 'G': + OLC_MODE(d) = MEDIT_AGE; + write_to_output(d, "Enter age (%d-%d): ", MIN_CHAR_AGE, MAX_CHAR_AGE); + return; case '4': OLC_MODE(d) = MEDIT_S_DESC; i--; @@ -1308,6 +1318,19 @@ void medit_parse(struct descriptor_data *d, char *arg) GET_SEX(OLC_MOB(d)) = LIMIT(i - 1, 0, NUM_GENDERS - 1); break; + case MEDIT_AGE: + if (i < MIN_CHAR_AGE || i > MAX_CHAR_AGE) { + write_to_output(d, "Age must be between %d and %d.\r\n", + MIN_CHAR_AGE, MAX_CHAR_AGE); + write_to_output(d, "Enter age (%d-%d): ", MIN_CHAR_AGE, MAX_CHAR_AGE); + return; + } + GET_ROLEPLAY_AGE(OLC_MOB(d)) = i; + GET_ROLEPLAY_AGE_YEAR(OLC_MOB(d)) = time_info.year; + OLC_VAL(d) = TRUE; + medit_disp_menu(d); + return; + case MEDIT_NUM_HP_DICE: GET_HIT(OLC_MOB(d)) = LIMIT(i, 0, 30); OLC_VAL(d) = TRUE; diff --git a/src/oasis.h b/src/oasis.h index 6697cdb..582bcbf 100644 --- a/src/oasis.h +++ b/src/oasis.h @@ -274,6 +274,7 @@ extern const char *nrm, *grn, *cyn, *yel; /* Numerical responses. */ #define MEDIT_NUMERICAL_RESPONSE 15 #define MEDIT_SEX 16 +#define MEDIT_AGE 44 #define MEDIT_NUM_HP_DICE 17 #define MEDIT_SIZE_HP_DICE 18 #define MEDIT_ADD_HP 19 diff --git a/src/players.c b/src/players.c index a83094d..8e50050 100644 --- a/src/players.c +++ b/src/players.c @@ -222,6 +222,20 @@ char *get_name_by_id(long id) return (NULL); } +static void update_roleplay_age(struct char_data *ch) +{ + if (GET_ROLEPLAY_AGE(ch) == 0) + GET_ROLEPLAY_AGE(ch) = MIN_CHAR_AGE; + + if (GET_ROLEPLAY_AGE_YEAR(ch) == 0) + GET_ROLEPLAY_AGE_YEAR(ch) = time_info.year; + + if (time_info.year > GET_ROLEPLAY_AGE_YEAR(ch)) { + GET_ROLEPLAY_AGE(ch) += (time_info.year - GET_ROLEPLAY_AGE_YEAR(ch)); + GET_ROLEPLAY_AGE_YEAR(ch) = time_info.year; + } +} + /* Stuff related to the save/load player system. */ /* New load_char reads ASCII Player Files. Load a char, TRUE if loaded, FALSE * if not. */ @@ -260,6 +274,8 @@ int load_char(const char *name, struct char_data *ch) GET_LEVEL(ch) = PFDEF_LEVEL; GET_HEIGHT(ch) = PFDEF_HEIGHT; GET_WEIGHT(ch) = PFDEF_WEIGHT; + GET_ROLEPLAY_AGE(ch) = 0; + GET_ROLEPLAY_AGE_YEAR(ch) = 0; GET_ALIGNMENT(ch) = PFDEF_ALIGNMENT; for (i = 0; i < NUM_OF_SAVING_THROWS; i++) GET_SAVE(ch, i) = PFDEF_SAVETHROW; @@ -317,6 +333,8 @@ int load_char(const char *name, struct char_data *ch) switch (*tag) { case 'A': if (!strcmp(tag, "Ac ")) GET_AC(ch) = atoi(line); + else if (!strcmp(tag, "AgYr")) GET_ROLEPLAY_AGE_YEAR(ch) = atoi(line); + else if (!strcmp(tag, "Age ")) GET_ROLEPLAY_AGE(ch) = LIMIT(atoi(line), MIN_CHAR_AGE, MAX_CHAR_AGE); else if (!strcmp(tag, "Acct")) { if (GET_ACCOUNT(ch)) free(GET_ACCOUNT(ch)); @@ -515,6 +533,8 @@ int load_char(const char *name, struct char_data *ch) } } + update_roleplay_age(ch); + ch->player.time.birth = time(0) - get_total_played_seconds(ch); affect_total(ch); /* initialization for imms */ @@ -564,6 +584,9 @@ void save_char(struct char_data * ch) } } + update_roleplay_age(ch); + ch->player.time.birth = time(0) - get_total_played_seconds(ch); + if (!get_filename(filename, sizeof(filename), PLR_FILE, GET_NAME(ch))) return; if (!(fl = fopen(filename, "w"))) { @@ -631,6 +654,8 @@ void save_char(struct char_data * ch) fprintf(fl, "Id : %ld\n", GET_IDNUM(ch)); fprintf(fl, "Brth: %ld\n", (long)ch->player.time.birth); + fprintf(fl, "Age : %d\n", GET_ROLEPLAY_AGE(ch)); + fprintf(fl, "AgYr: %d\n", GET_ROLEPLAY_AGE_YEAR(ch)); fprintf(fl, "Plyd: %d\n", ch->player.time.played); fprintf(fl, "Last: %ld\n", (long)ch->player.time.logon); diff --git a/src/structs.h b/src/structs.h index febbccf..fdb09e0 100644 --- a/src/structs.h +++ b/src/structs.h @@ -348,6 +348,7 @@ #define CON_QSPECIES 8 /**< Choose character species */ #define CON_QCLASS 9 /**< Choose character class */ #define CON_QSTAT_PREF 44 /**< Choose character stat preference order */ +#define CON_QAGE 45 /**< Choose character age */ #define CON_QSHORTDESC 10 /**< Enter a new character short description prompt */ #define CON_RMOTD 11 /**< Reading the message of the day */ #define CON_MENU 12 /**< At the main menu */ @@ -906,7 +907,7 @@ struct time_info_data /** Player specific time information. */ struct time_data { - time_t birth; /**< Represents the PCs birthday, used to calculate age. */ + time_t birth; /**< Anchor for calculating mechanical age from played time. */ time_t logon; /**< Time of the last logon, used to calculate time played */ int played; /**< This is the total accumulated time played in secs */ }; @@ -943,7 +944,9 @@ struct char_player_data byte chclass; /**< PC / NPC class */ byte species; /**< PC / NPC species */ byte level; /**< PC / NPC level */ - struct time_data time; /**< PC AGE in days */ + struct time_data time; /**< Playtime tracking */ + int roleplay_age; /**< Roleplay age in years */ + int roleplay_age_year; /**< Last mud year roleplay age was updated */ ubyte weight; /**< PC / NPC weight */ ubyte height; /**< PC / NPC height */ }; diff --git a/src/utils.c b/src/utils.c index 43aaeb1..894c1e9 100644 --- a/src/utils.c +++ b/src/utils.c @@ -570,17 +570,24 @@ time_t mud_time_to_secs(struct time_info_data *now) return (time(NULL) - when); } -/** Calculate a player's MUD age. - * @todo The minimum starting age of 17 is hardcoded in this function. Recommend - * changing the minimum age to a property (variable) external to this function. +time_t get_total_played_seconds(const struct char_data *ch) +{ + time_t played = ch->player.time.played; + + if (ch->desc && STATE(ch->desc) == CON_PLAYING) + played += time(0) - ch->player.time.logon; + + return played; +} + +/** Calculate a player's mechanical age based on total played time. * @param ch A valid player character. */ struct time_info_data *age(struct char_data *ch) { static struct time_info_data player_age; - player_age = *mud_time_passed(time(0), ch->player.time.birth); - - player_age.year += 17; /* All players start at 17 */ + time_t played = get_total_played_seconds(ch); + player_age = *mud_time_passed(time(0), time(0) - played); return (&player_age); } diff --git a/src/utils.h b/src/utils.h index a674a6d..8702064 100644 --- a/src/utils.h +++ b/src/utils.h @@ -54,6 +54,7 @@ void sprintbitarray(int bitvector[], const char *names[], int maxar, char *resul int get_line(FILE *fl, char *buf); int get_filename(char *filename, size_t fbufsize, int mode, const char *orig_name); time_t mud_time_to_secs(struct time_info_data *now); +time_t get_total_played_seconds(const struct char_data *ch); struct time_info_data *age(struct char_data *ch); int num_pc_in_room(struct room_data *room); void core_dump_real(const char *who, int line); @@ -236,6 +237,9 @@ void char_from_furniture(struct char_data *ch); * Current calculation ~= 12.4 real life days */ #define SECS_PER_MUD_YEAR (17*SECS_PER_MUD_MONTH) +#define MIN_CHAR_AGE 18 +#define MAX_CHAR_AGE 65 + /** The number of seconds in a real minute. */ #define SECS_PER_REAL_MIN 60 /** The number of seconds in a real hour. */ @@ -516,6 +520,8 @@ do \ #define GET_WAS_IN(ch) ((ch)->was_in_room) /** How old is PC/NPC, at last recorded time? */ #define GET_AGE(ch) (age(ch)->year) +#define GET_ROLEPLAY_AGE(ch) ((ch)->player.roleplay_age) +#define GET_ROLEPLAY_AGE_YEAR(ch) ((ch)->player.roleplay_age_year) /** Proper name for PCs and NPCs. */ #define GET_NAME(ch) ((ch)->player.name) From 1aa14abdb4f39ec70d51934dce2251d353db49cb Mon Sep 17 00:00:00 2001 From: kinther Date: Mon, 29 Dec 2025 18:12:25 -0800 Subject: [PATCH 16/40] acaudit migration to audit command --- README.md | 4 ++-- lib/text/help/help.hlp | 8 +++++--- src/act.h | 2 +- src/act.wizard.c | 13 ++++++++++++- src/interpreter.c | 2 +- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 275df22..6689c51 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Features in Cataclysm MUD Alpha release: Alpha 1.1 release: * Cleaned up legacy practice system code - * Added skill caps for classes to limit ability of everyone to reach skill leve 100 (and respective proficiency) + * Added skill caps for classes to limit ability of everyone to reach skill level 100 (and respective proficiency) * Race/species selection and stat ranges (elves have higher dex, dwarves have higher str, etc) * Renamed move to stamina in code to reflect how much energy is used for certain actions * Species have base hit/mana/stamina now, plus their class modifier rolls @@ -57,10 +57,10 @@ Alpha 1.1 release: * Ability to change ldesc of PC/NPC's in some situations * Ability to look in certain directions to see what is 1-3 rooms away * 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 Features to be implemented in the next few releases: -* "acaudit" command to be "audit ac", allowing for further audit commands in the future * Subclass selection to personalize character further * Combat is slowed down so it isn't over in < 15 seconds (unless you're far outmatched) * Mounts added to help with long trips diff --git a/lib/text/help/help.hlp b/lib/text/help/help.hlp index 0947a09..e78109d 100644 --- a/lib/text/help/help.hlp +++ b/lib/text/help/help.hlp @@ -315,14 +315,16 @@ Situational: cover (+2/+5), spells (Shield, Haste, etc.) See Also: SCORE #0 -ACAUDIT ARMOR-AUDIT AUDIT-ARMOR IMMORTAL +AUDIT AC AUDIT-AC ACAUDIT ARMOR-AUDIT AUDIT-ARMOR IMMORTAL Summary: Imm-only tool that scans all ITEM\_ARMOR prototypes and reports per-piece fields against slot caps. Use this to catch outliers and quickly rebalance items to the Light/Medium/Heavy targets. Usage: -acaudit +audit ac + +If you omit the option, you'll be prompted with "Audit what?" What it does: @@ -12644,7 +12646,7 @@ ban copyover freeze hcontrol reroll skillset thaw unban wizupdate Level 32 (God): -acaudit advance aedit checkload dc file +audit advance aedit checkload dc file force gecho hedit helpcheck hsedit last links mcopy mute notitle ocopy pardon plist qecho rcopy restore scopy send diff --git a/src/act.h b/src/act.h index 405a7a0..732141d 100644 --- a/src/act.h +++ b/src/act.h @@ -343,7 +343,7 @@ ACMD(do_wizutil); #define SCMD_THAW 4 #define SCMD_UNAFFECT 5 /* Functions without subcommands */ -ACMD(do_acaudit); +ACMD(do_audit); ACMD(do_advance); ACMD(do_at); ACMD(do_checkloadstatus); diff --git a/src/act.wizard.c b/src/act.wizard.c index 4b2ac78..2e950f9 100644 --- a/src/act.wizard.c +++ b/src/act.wizard.c @@ -6186,9 +6186,20 @@ static const char *slot_name_from_index(int idx) { } /* Wizard command: scan armor prototypes, validate per-piece fields (compact, paged, 25 lines) */ -ACMD(do_acaudit) +ACMD(do_audit) { int found = 0, warned = 0; + char arg[MAX_INPUT_LENGTH]; + + one_argument(argument, arg); + if (!*arg) { + send_to_char(ch, "Audit what?\r\n"); + return; + } + if (!is_abbrev(arg, "ac")) { + send_to_char(ch, "Usage: audit ac\r\n"); + return; + } if (IS_NPC(ch) || GET_LEVEL(ch) < LVL_IMMORT) { send_to_char(ch, "You lack the authority to use this.\r\n"); diff --git a/src/interpreter.c b/src/interpreter.c index 8281f88..6666667 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -87,7 +87,7 @@ cpp_extern const struct command_info cmd_info[] = { { "sw" , "sw" , POS_STANDING, do_move , 0, SCMD_SW }, /* now, the main list */ - { "acaudit" , "acaudi" , POS_DEAD , do_acaudit , LVL_IMMORT, 0 }, + { "audit" , "aud" , POS_DEAD , do_audit , LVL_IMMORT, 0 }, { "at" , "at" , POS_DEAD , do_at , LVL_IMMORT, 0 }, { "advance" , "adv" , POS_DEAD , do_advance , LVL_GRGOD, 0 }, { "aedit" , "aed" , POS_DEAD , do_oasis_aedit, LVL_GOD, 0 }, From 4f5ee09ee4981f457b4a1344c8909a1989f3d617 Mon Sep 17 00:00:00 2001 From: kinther Date: Mon, 29 Dec 2025 18:20:07 -0800 Subject: [PATCH 17/40] Score command update --- README.md | 5 +- src/act.informative.c | 113 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 103 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 6689c51..edf5324 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ most notably the former Armageddon MUD. Roleplay is highly encouraged, but not enforced. -Features in Cataclysm MUD Alpha release: +Changes from stock tbaMUD 2025 to Cataclysm MUD v1.0.0-alpha: * The city of Caleran is available for exploration * Experience points and levels are removed in favor of skill based progression @@ -46,7 +46,7 @@ Features in Cataclysm MUD Alpha release: * Backgrounds are now available for PC's and NPC's * Account system for tracking players/characters over long periods of time -Alpha 1.1 release: +Changes in v1.1.0-alpha: * Cleaned up legacy practice system code * Added skill caps for classes to limit ability of everyone to reach skill level 100 (and respective proficiency) @@ -58,6 +58,7 @@ Alpha 1.1 release: * Ability to look in certain directions to see what is 1-3 rooms away * 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 Features to be implemented in the next few releases: diff --git a/src/act.informative.c b/src/act.informative.c index ef938ea..121594d 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -674,6 +674,89 @@ static void list_one_char(struct char_data *i, struct char_data *ch) act("...$e glows with a bright light!", FALSE, i, 0, ch, TO_VICT); } +static void strip_trailing_crlf(char *str) +{ + size_t len; + + if (!str) + return; + + len = strlen(str); + while (len > 0 && (str[len - 1] == '\n' || str[len - 1] == '\r')) + str[--len] = '\0'; +} + +static void build_current_ldesc(const struct char_data *ch, char *out, size_t outsz) +{ + struct obj_data *furniture; + const char *positions[] = { + " is lying here, dead.", + " is lying here, mortally wounded.", + " is lying here, incapacitated.", + " is lying here, stunned.", + " is sleeping here.", + " is resting here.", + " is sitting here.", + " is here, fighting someone.", + " is standing here." + }; + const char *sdesc; + char base[MAX_INPUT_LENGTH]; + + if (!out || outsz == 0) + return; + + *out = '\0'; + + if (!ch) { + strlcpy(out, "Someone is here.", outsz); + return; + } + + if (ch->char_specials.custom_ldesc && ch->player.long_descr) { + strlcpy(out, ch->player.long_descr, outsz); + strip_trailing_crlf(out); + return; + } + + if (ch->player.long_descr && GET_POS(ch) == GET_DEFAULT_POS(ch)) { + strlcpy(out, ch->player.long_descr, outsz); + strip_trailing_crlf(out); + return; + } + + sdesc = get_char_sdesc(ch); + if (!sdesc || !*sdesc) + sdesc = "someone"; + + strlcpy(base, sdesc, sizeof(base)); + if (*base) + base[0] = UPPER(*base); + + if (GET_POS(ch) != POS_FIGHTING) { + if (!SITTING(ch)) { + snprintf(out, outsz, "%s%s", base, positions[(int) GET_POS(ch)]); + } else { + furniture = SITTING(ch); + snprintf(out, outsz, "%s is %s upon %s.", base, + (GET_POS(ch) == POS_SLEEPING ? "sleeping" : + (GET_POS(ch) == POS_RESTING ? "resting" : "sitting")), + OBJS(furniture, ch)); + } + } else { + if (FIGHTING(ch)) { + if (IN_ROOM(ch) == IN_ROOM(FIGHTING(ch))) + snprintf(out, outsz, "%s is here, fighting %s!", base, PERS(FIGHTING(ch), ch)); + else + snprintf(out, outsz, "%s is here, fighting someone who has already left!", base); + } else { + snprintf(out, outsz, "%s is here, fighting someone who has already left!", base); + } + } + + strip_trailing_crlf(out); +} + static void list_char_to_char(struct char_data *list, struct char_data *ch) { struct char_data *i; @@ -1260,6 +1343,8 @@ ACMD(do_score) int played_days; struct ac_breakdown acb; bool ismob = IS_NPC(ch); + char ldesc[MAX_STRING_LENGTH]; + const char *sdesc = get_char_sdesc(ch); compute_ac_breakdown(ch, &acb); @@ -1267,12 +1352,20 @@ ACMD(do_score) "\r\n" "====================[ Score ]====================\r\n"); + build_current_ldesc(ch, ldesc, sizeof(ldesc)); + send_to_char(ch, "Name: %s\r\n", GET_NAME(ch) ? GET_NAME(ch) : "someone"); + send_to_char(ch, "Sdesc: %s\r\n", sdesc && *sdesc ? sdesc : "someone"); + send_to_char(ch, "Ldesc: %s\r\n", *ldesc ? ldesc : "None"); + send_to_char(ch, "HP: %d/%d Mana: %d/%d Stamina: %d/%d\r\n", GET_HIT(ch), GET_MAX_HIT(ch), GET_MANA(ch), GET_MAX_MANA(ch), GET_STAMINA(ch), GET_MAX_STAMINA(ch)); + send_to_char(ch, "Carrying Weight: %d/%d\r\n", + IS_CARRYING_W(ch), CAN_CARRY_W(ch)); + /* Abilities and 5e modifiers */ send_to_char(ch, "STR %2d (%+d) DEX %2d (%+d) CON %2d (%+d)\r\n" @@ -1307,19 +1400,13 @@ ACMD(do_score) send_to_char(ch, "\r\n"); /* Only players have quest data */ - if (!ismob) { - send_to_char(ch, "You have %d questpoints.\r\n", GET_QUESTPOINTS(ch)); - - if (GET_QUEST(ch) == NOTHING) - send_to_char(ch, "You are not on a quest at the moment.\r\n"); - else { - send_to_char(ch, "Your current quest is: %s", - QST_NAME(real_quest(GET_QUEST(ch)))); - if (PRF_FLAGGED(ch, PRF_SHOWVNUMS)) - send_to_char(ch, " [%d]\r\n", GET_QUEST(ch)); - else - send_to_char(ch, "\r\n"); - } + if (!ismob && GET_QUEST(ch) != NOTHING) { + send_to_char(ch, "Your current quest is: %s", + QST_NAME(real_quest(GET_QUEST(ch)))); + if (PRF_FLAGGED(ch, PRF_SHOWVNUMS)) + send_to_char(ch, " [%d]\r\n", GET_QUEST(ch)); + else + send_to_char(ch, "\r\n"); } /* Only players have valid playtime data */ From b186c7e87c0d5947d8998b5eca2a04f1a7f06ad8 Mon Sep 17 00:00:00 2001 From: kinther Date: Tue, 30 Dec 2025 08:22:48 -0800 Subject: [PATCH 18/40] Reroll update --- README.md | 1 + lib/text/help/help.hlp | 10 +++- src/act.h | 1 + src/act.other.c | 107 +++++++++++++++++++++++++++++++++++++++++ src/interpreter.c | 2 +- src/pfdefaults.h | 2 + src/players.c | 29 +++++++++++ src/structs.h | 3 ++ src/utils.h | 3 ++ 9 files changed, 156 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index edf5324..5982e3d 100644 --- a/README.md +++ b/README.md @@ -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: diff --git a/lib/text/help/help.hlp b/lib/text/help/help.hlp index e78109d..5d90e7a 100644 --- a/lib/text/help/help.hlp +++ b/lib/text/help/help.hlp @@ -7962,7 +7962,15 @@ From: justo #2 REROLL -Usage: reroll +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 rerolls that player's stats. REROLL gives a player new stats (i.e., Str, Int, Wis, Dex, Con, and Cha) diff --git a/src/act.h b/src/act.h index 732141d..fc47183 100644 --- a/src/act.h +++ b/src/act.h @@ -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); diff --git a/src/act.other.c b/src/act.other.c index a61dae5..1f58185 100644 --- a/src/act.other.c +++ b/src/act.other.c @@ -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) diff --git a/src/interpreter.c b/src/interpreter.c index 6666667..64b7687 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -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 }, diff --git a/src/pfdefaults.h b/src/pfdefaults.h index 36d30f2..27bf28e 100644 --- a/src/pfdefaults.h +++ b/src/pfdefaults.h @@ -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_ */ diff --git a/src/players.c b/src/players.c index 8e50050..b149aaf 100644 --- a/src/players.c +++ b/src/players.c @@ -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)); diff --git a/src/structs.h b/src/structs.h index fdb09e0..7d753b4 100644 --- a/src/structs.h +++ b/src/structs.h @@ -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 */ }; diff --git a/src/utils.h b/src/utils.h index 8702064..2fd607d 100644 --- a/src/utils.h +++ b/src/utils.h @@ -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. */ From 59a38beb3dce1f53ec62a0643c770665a33cce69 Mon Sep 17 00:00:00 2001 From: kinther Date: Tue, 30 Dec 2025 10:11:20 -0800 Subject: [PATCH 19/40] Alignment update 1 --- README.md | 7 +- doc/building.txt | 85 ++++++++--------- doc/coding.txt | 6 +- doc/msgedit.txt | 10 +- doc/syserr.txt | 44 ++++----- lib/text/help/help.hlp | 209 ++++++++++------------------------------- src/act.informative.c | 21 ----- src/act.wizard.c | 128 ++++++++++++------------- src/constants.c | 16 ++-- src/db.c | 7 -- src/fight.c | 19 +--- src/handler.c | 13 +-- src/handler.h | 1 - src/magic.c | 21 ----- src/mobact.c | 6 +- src/objsave.c | 4 +- src/pfdefaults.h | 1 - src/players.c | 3 - src/sedit.c | 42 +++++++-- src/shop.c | 19 ++-- src/shop.h | 13 ++- src/spec_procs.c | 7 -- src/spells.c | 9 +- src/structs.h | 16 ++-- src/util/plrtoascii.c | 4 +- src/utils.h | 7 -- 26 files changed, 252 insertions(+), 466 deletions(-) diff --git a/README.md b/README.md index 5982e3d..69e1118 100644 --- a/README.md +++ b/README.md @@ -60,13 +60,18 @@ Changes in v1.1.0-alpha: * "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 + * Removed alignment from game - no more GOOD/EVIL flags and restrictions on items/shops Features to be implemented in the next few releases: +* Updated door code so that it can be closed/locked/saved with rsave code +* SECTOR/ROOM type changes to make terrain movement easier or more difficult * Subclass selection to personalize character further * Combat is slowed down so it isn't over in < 15 seconds (unless you're far outmatched) * Mounts added to help with long trips * Wagons added to help with caravans +* BUILDING object type created to allow enter/leave +* Updated BUILDING object type so that it can be damaged and no longer enterable (but someone can leave at cost to health) * Plantlife introduced * Updated lockpicking skill * Trap as a skill - one focused on city and one focused on desert @@ -81,7 +86,7 @@ Features to be implemented in the next few releases: * Haggling and bartering system * New calendar and moon cycles * Heat based on time of day increases/decreases, changing hunger/thirst levels -* Sandstorms limiting visibility +* Weather updates and sandstorms limiting visibility * Shaded rooms providing bonuses to regeneration * Criminal system for cities and jails * Basic Psionics diff --git a/doc/building.txt b/doc/building.txt index 13001c7..0d5f26c 100644 --- a/doc/building.txt +++ b/doc/building.txt @@ -632,7 +632,7 @@ The format of a mobile is: ~ ~ - + {type-specific information; see below for details} Virtual Number This number is critical; it is the identity of the mobile within @@ -687,9 +687,9 @@ L) NPC Flags : ISNPC its hit points. If the WIMPY bit is set in conjunction with any of the forms of the AGGRESSIVE bit, the mob will only attack mobs that are unconscious (sleeping or incapacitated). -9) AGGR_EVIL Mob will attack players that are evil-aligned. -10) AGGR_GOOD Mob will attack players that are good-aligned. -11) AGGR_NEU Mob will attack players that are neutrally aligned. +9) RESERVED Not used. +10) RESERVED Not used. +11) RESERVED Not used. 12) MEMORY Mob will remember players that initiate attacks on it, and will attack that player if it ever runs into him again. 13) HELPER The mob will attack any player it sees in the room that is @@ -710,7 +710,7 @@ following values: M) AFF Flags : NOBITS 1) BLIND Mob is blind. 2) INVIS Mob is invisible. -3) DET-ALIGN NOT USED. +3) RESERVED NOT USED. 4) DET-INVIS Mob can see invisible characters and objects. 5) DET-MAGIC Mob is sensitive to magical presence. 6) SENSE-LIFE Mob can sense hidden life. @@ -721,23 +721,17 @@ M) AFF Flags : NOBITS 10) CURSE Mob is cursed. 11) INFRA Mob can see in dark. 12) POISON Reserved for internal use. Do not set. -13) PROT-EVIL Mob is protected from evil characters. -14) PROT-GOOD Mob is protected from good characters. +13) RESERVED NOT USED. +14) RESERVED NOT USED. 15) SLEEP Reserved for internal use. Do not set. 16) NO_TRACK Mob cannot be tracked. -17) UNUSED Unused (room for future expansion). -18) UNUSED Unused (room for future expansion). +17) FLY Mob is flying. +18) SCUBA Mob can breathe underwater. 19) SNEAK Mob can move quietly without room being informed. 20) HIDE Mob is hidden; can only be seen with sense life. -21) UNUSED Unused (room for future expansion). +21) SCAN Actively scanning for hidden threats. 22) CHARM Reserved for internal use. Do not set. -Alignment A number from -1000 to 1000 representing the mob’s initial alignment. - --1000.....-350 Evil - -349......349 Neutral - 350.....1000 Good - Type Flag This flag is a single letter which indicates what type of mobile is currently being defined, and controls what information tbaMUD expects to find next (i.e., in the file from the current point to the end of the current @@ -748,7 +742,7 @@ Standard tbaMUD supports two types of mobiles: S (for Simple), and E (for Enhanc 4.2 Type S Mobiles For type S mobs, the type-specific information should be in the following format: - S + S @@ -840,13 +834,13 @@ A beastly fido is mucking through the garbage looking for food here. The fido is a small dog that has a foul smell and pieces of rotted meat hanging around his teeth. ~ -65738 0 0 0 65536 0 0 0 -200 S +65738 0 0 0 65536 0 0 0 0 S 1 20 9 0d0+10 1d2+0 10 100 8 8 1 -This is mobile vnum 3062. The Fido has mob and affect flags set and has an -initial alignment of -200. After the S flag we see that the Fido is level 1, +This is mobile vnum 3062. The Fido has mob and affect flags set and has a +reserved value of 0. After the S flag we see that the Fido is level 1, has a THAC0 of 20, an Armor Class of 9, 0d0+10 hit points (10 hitpoints), and will do 1d2 hit points of bare hand damage per round. The Fido has 10 coins and 100 experience points, has a load position and default position of @@ -865,7 +859,7 @@ literal letter Emust then come after all E-specs to signal the end of the mob. The format of an E mobile is as follows: - E + E @@ -886,7 +880,7 @@ A beastly fido is mucking through the garbage looking for food here. The fido is a small dog that has a foul smell and pieces of rotted meat hanging around his teeth. ~ -65738 0 0 0 65536 0 0 0 -200 E +65738 0 0 0 65536 0 0 0 0 E 1 20 9 0d0+10 1d2+0 10 100 8 8 1 @@ -1026,16 +1020,16 @@ but has no substantive effect otherwise. The flags have the following values: 1) GLOW Item is glowing (cosmetic). 2) HUM Item is humming (cosmetic). -3) UNUSED Reserved (unused). +3) RESERVED Reserved (unused). 4) NODONATE Item cannot be donated. 5) NOINVIS Item cannot be made invisible. 6) INVISIBLE Item is invisible. 7) MAGIC Item has a magical aura and cannot be enchanted. 8) NODROP Item is cursed and cannot be removed or dropped. 9) BLESS Item is blessed (cosmetic). -10) ANTI_GOOD Item cannot be used by good-aligned characters. -11) ANTI_EVIL Item cannot be used by evil-aligned characters. -12) ANTI_NEUTRAL Item cannot be used by neutral align characters. +10) RESERVED Not used. +11) RESERVED Not used. +12) RESERVED Not used. 13) ANTI_MAGIC_USER Item cannot be used by the Mage class. 14) ANTI_CLERIC Item cannot be used by the Cleric class. 15) ANTI_THIEF Item cannot be used by the Thief class. @@ -1611,16 +1605,16 @@ monty-haul campaigns. Shop Keeper Mobile Number Virtual number of the shopkeeper mobile. With Who Bitvector A bitvector (see section 2.4 on ‘Using Bitvectors’) used to -designate certain alignments or classes that the shop will not trade with, with +designate certain classes that the shop will not trade with, with the following values: E) No Trade With : NOBITS - Designates certain alignments or classes that the shop will not trade with: + Designates certain classes that the shop will not trade with: - 1) Good 2) Evil - 3) Neutral 4) Magic User - 5) Cleric 6) Thief - 7) Warrior + 1) Sorceror 2) Cleric + 3) Rogue 4) Fighter + 5) Barbarian 6) Ranger + 7) Bard 8) Druid Shop Room 1...Shop Room n The virtual numbers the mobile must be in for the shop to be effective. (So transferred shopkeepers can’t sell in the desert). @@ -1737,15 +1731,16 @@ Shop Keeper Mobile Number Virtual number of the shopkeeper mobile. With Who Bitvector A bitvector (see section ‘Using Bitvectors’) used to designate certain -alignments or classes that the shop will not trade with, with the following +classes that the shop will not trade with, with the following values: -1 a NOGOOD Keeper won’t trade with positively-aligned players. -2 b NOEVIL Keeper won’t trade with evilly-aligned players. -4 c NONEUTRAL Keeper won’t trade with neutrally-aligned players. -8 d NOMAGIC_USER Keeper won’t trade with the Mage class. +8 d NOSORCEROR Keeper won’t trade with the Sorceror class. 16 e NOCLERIC Keeper won’t trade with the Cleric class. -32 f NOTHIEF Keeper won’t trade with the Thief class. -64 g NOWARRIOR Keeper won’t trade with the Warrior class. +32 f NOROGUE Keeper won’t trade with the Rogue class. +64 g NOFIGHTER Keeper won’t trade with the Fighter class. +128 h NOBARBARIAN Keeper won’t trade with the Barbarian class. +256 i NORANGER Keeper won’t trade with the Ranger class. +512 j NOBARD Keeper won’t trade with the Bard class. +1024 k NODRUID Keeper won’t trade with the Druid class. Shop Room Number The virtual number the mobile must be in for the shop to be effective. (So @@ -1848,18 +1843,18 @@ particular MUD. Check with your implementor for details. 7) charm person 8) chill touch 9) clone 10) color spray 11) control weather 12) create food 13) create water 14) cure blind 15) cure critic -16) cure light 17) curse 18) detect alignment +16) cure light 17) curse 18) reserved 19) detect invisibility 20) detect magic 21) detect poison -22) dispel evil 23) earthquake 24) enchant weapon +22) reserved 23) earthquake 24) enchant weapon 25) energy drain 26) fireball 27) harm 28) heal 29) invisibility 30) lightning bolt 31) locate object 32) magic missile 33) poison -34) protection from evil 35) remove curse 36) sanctuary +34) reserved 35) remove curse 36) sanctuary 37) shocking grasp 38) sleep 39) strength -40) summon 41) !UNUSED! 42) word of recall +40) summon 41) !RESERVED! 42) word of recall 43) remove poison 44) sense life 45) animate dead -46) dispel good 47) group armor 48) group heal -49) !UNUSED! 50) infravision 51) waterwalk +46) reserved 47) group armor 48) group heal +49) !RESERVED! 50) infravision 51) waterwalk B Item Values for Drink Containers diff --git a/doc/coding.txt b/doc/coding.txt index 6f4613b..6b50241 100644 --- a/doc/coding.txt +++ b/doc/coding.txt @@ -813,7 +813,7 @@ equips it to the character for the specified location. unequip_char() does the opposite; it removes the object from the character’s equipment list and returns it as a free-floating object. The object being unequipped must be placed elsewhere or destroyed. Note that some objects may not be equipped by characters of certain -classes and/or alignments. +classes. void obj_to_char (struct obj_data *object, struct char_data *ch) @@ -1427,9 +1427,9 @@ search it for "ITEM_x (extra bits)". Add a string giving a short name for the ne ITEM_ANTI_xxx flag, in the appropriate order, before the "\n" entry near the bottom. -The shops have a similar "don’t trade" setup, so search shop.hfor "TRADE_NOGOOD" +The shops have a similar "don’t trade" setup, so search shop.h for "TRADE_NOSORCEROR" to add a new TRADE_NOxxx item to the list for the class to be added. Below that -(near "NOTRADE_GOOD"), a line will need to be added for each new class so the ’no +(near "NOTRADE_SORCEROR"), a line will need to be added for each new class so the ’no trade’ status of a shop can be tested for the class. With the definitions in shop.h, the shop code in shop.c can then be modified to diff --git a/doc/msgedit.txt b/doc/msgedit.txt index cd1ae8c..c96a98d 100644 --- a/doc/msgedit.txt +++ b/doc/msgedit.txt @@ -16,11 +16,11 @@ Message List: 0 ) [5 ] 1, burning hands 30) [314] 2, Unknown 1 ) [6 ] 1, call lightning 31) [399] 2, Unknown 2 ) [8 ] 1, chill touch 32) [33 ] 1, poison -3 ) [10 ] 1, color spray 33) [202] 1, !UNUSED! -4 ) [22 ] 1, dispel evil 34) [203] 1, !UNUSED! -5 ) [23 ] 1, earthquake 35) [204] 1, !UNUSED! -6 ) [25 ] 1, energy drain 36) [205] 1, !UNUSED! -7 ) [26 ] 1, fireball 37) [206] 1, !UNUSED! +3 ) [10 ] 1, color spray 33) [202] 1, !RESERVED! +4 ) [22 ] 1, dispel 34) [203] 1, !RESERVED! +5 ) [23 ] 1, earthquake 35) [204] 1, !RESERVED! +6 ) [25 ] 1, energy drain 36) [205] 1, !RESERVED! +7 ) [26 ] 1, fireball 37) [206] 1, !RESERVED! ========================================= diff --git a/doc/syserr.txt b/doc/syserr.txt index 35318a7..361335d 100644 --- a/doc/syserr.txt +++ b/doc/syserr.txt @@ -9,17 +9,16 @@ rumble@tbamud.com -- Rumble 1. Errant Rooms (show error command) 2. SYSERR: Object # (oedit-s-desc) doesn't have drink type as last alias. -3. SYSERR: Mob # both Aggressive and Aggressive_to_Alignment. -4. SYSERR: Object # (oedit-s-desc) has out of range level #. -5. SYSERR: Object # (oedit-s-desc) has negative weight (-2147483644). +3. SYSERR: Object # (oedit-s-desc) has out of range level #. +4. SYSERR: Object # (oedit-s-desc) has negative weight (-2147483644). SYSERR: Object # (oedit-s-desc) has out of range level #2147483647. -6. SYSERR: Object # (oedit-s-desc) uses 'UNDEFINED' spell #. -7. SYSERR: Object # (oedit-s-desc) contains (5) more than maximum (3). -8. Char is already equipped: (medit-s-desc), (oedit-s-desc) -9. SYSERR: Attempt to assign spec to non-existant mob # -10. No associated object exists when attempting to create a board [vnum #]. -11. SYSERR: Mob using >'((ch)-)player_specials.... -12: SYSERR: Object # (keyword) is type NOTE and has extra description with +5. SYSERR: Object # (oedit-s-desc) uses 'UNDEFINED' spell #. +6. SYSERR: Object # (oedit-s-desc) contains (5) more than maximum (3). +7. Char is already equipped: (medit-s-desc), (oedit-s-desc) +8. SYSERR: Attempt to assign spec to non-existant mob # +9. No associated object exists when attempting to create a board [vnum #]. +10. SYSERR: Mob using >'((ch)-)player_specials.... +11. SYSERR: Object # (keyword) is type NOTE and has extra description with same name (keyword) 1: Errant Rooms @@ -44,30 +43,23 @@ the drink aliases). i.e. a shot of whisky should have the namelist: whisky shot whisky a cup of slime mold juice namelist should be: juice cup slime juice -3: SYSERR: Mob # both Aggressive and Aggressive_to_Alignment. - - Another harmless error. If your mob is aggressive there is no need to also -make it aggressive to certain alignments since AGGR means it will attack any -player it can see. Choose to make it aggressive to an alignment or aggressive -to all. - -4: SYSERR: Object # (oedit-s-desc) has out of range level #. +3: SYSERR: Object # (oedit-s-desc) has out of range level #. A simple one. Limit spell levels to the levels available, on tbaMUD that would be 1-34. -5: SYSERR: Object # (oedit-s-desc) has negative weight (-2147483644). +4: SYSERR: Object # (oedit-s-desc) has negative weight (-2147483644). SYSERR: Object # (oedit-s-desc) has out of range level #2147483647. These are really annoying. This happens on older versions of CircleMUD when you use numbers larger than necessary. This will actually crash many older versions of CircleMUD. Just do not do it. Use realistic numbers. -6: SYSERR: Object # (oedit-s-desc) uses 'UNDEFINED' spell #. +5: SYSERR: Object # (oedit-s-desc) uses 'UNDEFINED' spell #. There is no spell zero. Either select a spell or put -1 for none. -7: SYSERR: Object # (oedit-s-desc) contains (#) more than maximum (#). +6: SYSERR: Object # (oedit-s-desc) contains (#) more than maximum (#). When making a drink container you will set how much it initially contains on creation and the max it can hold if a player were to fill it. Common sense @@ -75,24 +67,24 @@ tells us that you can not create a container that initially holds more than the max you set. To simplify the max must always be greater than or equal to the initial amount. -8: Char is already equipped: (medit-s-desc), (oedit-s-desc) +7: Char is already equipped: (medit-s-desc), (oedit-s-desc) This happens when someone tries to equip a mob with one or more object in a single location. HELP ZEDIT-EQUIP for all the possible object equipping locations. All you have to do to fix this is pick a different equip location that is not used. -9: SYSERR: Attempt to assign spec to non-existant mob # +8: SYSERR: Attempt to assign spec to non-existant mob # To get rid of this "grep # spec_assign.c" and remove this assignment. -10: No associated object exists when attempting to create a board [vnum #]. +9: No associated object exists when attempting to create a board [vnum #]. You need to delete this board from lib/etc/boards/ and modify boards.c and boards.h. Again "grep #" *.[ch] to search for this vnum in all of your .c and .h files to remove the reference. -11: SYSERR: Mob using >'((ch)-)player_specials.... +10: SYSERR: Mob using >'((ch)-)player_specials.... Players and mobs (NPC's) share many of the same data fields, but not all. So when a mob tries to access player data it gives a SYSERR like this: @@ -110,7 +102,7 @@ know this is confusing, but just copy the example below. The changed line now will not just check for a flag, instead it will check if it is a player (not an NPC) and it is flagged then continue. -12: SYSERR: Object # (keyword) is type NOTE and has extra description with +11: SYSERR: Object # (keyword) is type NOTE and has extra description with same name (keyword) Object type NOTE is meant to be written on using the action-description. So if diff --git a/lib/text/help/help.hlp b/lib/text/help/help.hlp index 5d90e7a..c04f09d 100644 --- a/lib/text/help/help.hlp +++ b/lib/text/help/help.hlp @@ -474,7 +474,7 @@ set one of these: P) Perm Affects: @cNOBITS@n 1) BLIND DO NOT USE. 2) INVIS The wearer becomes invisible. -3) DET-ALIGN The wearer detects alignments. +3) RESERVED DO NOT USE. 4) DET-INVIS The wearer sees invisible objects and players. 5) DET-MAGIC The wearer sees a magic flag on magical objects. 6) SENSE-LIFE The wearer sees hidden mobs/players. @@ -484,15 +484,15 @@ P) Perm Affects: @cNOBITS@n 10) CURSE DO NOT USE. 11) INFRA The wearer sees in the dark. 12) POISON The wearer is poisoned. -13) PROT-EVIL The wearer is protected from evil. -14) PROT-GOOD The wearer is protected from good. +13) RESERVED DO NOT USE. +14) RESERVED DO NOT USE. 15) SLEEP DO NOT USE. 16) NO_TRACK DO NOT USE. 17) FLYING The wearer can travel through room sector type IN FLIGHT. 18) SCUBA The wearer can travel through room sector type UNDERWATER. 19) SNEAK DO NOT USE. 20) HIDE DO NOT USE. -21) UNUSED DO NOT USE. +21) SCAN Actively scanning for hidden threats. 22) CHARM DO NOT USE. #2 @@ -572,45 +572,6 @@ I would type "all 13" to list everything in zone 13. I use this to check what people have done with their zone. See also: ^, RUMBLE-ALIASES -#0 -ALIGNMENT GOOD NEUTRAL EVIL %ACTOR.ALIGN% %ALIGN% %ALIGNMENT% - - Different characters and mobs have different alignments depending upon their -way of life. Because of this, they may be aggressive or friendly depending on -the mix. Some objects cannot be used by certain alignments. For mobs alignment -ranges from: - - -1000 to -350 Evil - -350 to 350 Neutral - 350 to 1000 Good - -See also: ALIGNMENTS -#2 -ALIGNMENTS - - Many good areas stick to a defined level range, such as 10-20 or 25-30. Do -not try and make your new area cover the entire range of levels. Every area -should have its moment in the sun. Conversely, it would be nice if there were -something really unique and challenging to do at every stage in a characters -history. Your area might be the most successful if you can gear it for a range -of levels that people believe is otherwise boring or neglected. - You should always try to match your mobiles to the area and the players you -want to play there. For example, you should make the mobs in the area a -similar level to the players you want to play there since a level X warrior -should be able to kill a level X mobile if the warrior is at full health. Also, -the quality of objects or mobiles should be matched with their level. - Will your area be mostly good, neutral, or evil. If it is mostly good or -mostly evil, is it strongly good or evil or just weakly aligned? In any case -try not to make your area completely homogenous (equal). In neutral -communities there is going to be some evil and good elements, and likewise with -other communities. To some extent this goes along with the question about zone -level, consider what seem to be "gaps" among the zones in the world as far as -good or evil aligned areas for a particular level range, and try to fill those -needs. Everyone's first tendency is to make extremists--The ultimate evil hell -area, or the blindingly good paladin fortress. Keep in mind that there are -many layers in between, and these are often more interesting. - -See also: ALIGN #2 ANIMATE-DEAD @@ -1650,7 +1611,6 @@ Excluding the subfield () returns the value. Adding a subfield adjusts it. cha/con/dex/int - Checks the stat. @RHELP TRIG-STAT@n. Subfield adjusts. str/wis() () is a subfield and allows a change to the variable. alias - The list of aliases of the mob or the player name. -align() - The actor's alignment @RHELP ALIGN@n. Subfield adjusts. affect() - Checks the actor for the affect. @RHELP AFFECT@n armor - Checks the actor's armor class. canbeseen - Checks if the the mob can see the actor. @RHELP CANBESEEN@n @@ -2366,18 +2326,6 @@ detach obj sword 1300 - You guessed it - same as above. detach sword all - detach all triggers from the sword. See also: ATTACH, TRIG-DETACH, TRIG-ATTACH, OLC, TRIGEDIT, TSTAT, STAT, ROOMFLAGS -#2 -DETECT-ALIGNMENT - -Usage : cast 'detect alignment' -Accumulative: Yes (Duration) -Duration : 12 hours + level -Level : Cleric level 4. - -Allows the caster to detect the alignment of those around them. -Evil will show as a red aura, good in a blue aura. - -See also: "DETECT INVISIBILITY" #0 DETECT-INVISIBILITY @@ -2530,38 +2478,6 @@ when done type /fi to format with indent. See also: TEXT-EDITOR -#2 -DISPEL-EVIL - -Usage : cast 'dispel evil' -Accumulative: - -Duration : Instantaneous -Level : Cleric level 14. -Save : Special - -This spell will only affect evil creatures. An evil person of level -equal or less than caster will suffer 100 damage points. - -If the victim is higher level than caster, the spell will inflict -(caster_level)d4 damage points, saving throw versus half damage. - -See also: DISPEL-GOOD -#0 -DISPEL-GOOD - -Usage : cast 'dispel good' -Accumulative: - -Duration : Instantaneous -Level : Cleric level 14. -Save : Special - -This spell will only affect good creatures. A good person of level -equal or less than caster will suffer 100 damage points. - -If the victim is higher level than caster, the spell will inflict -(caster_level)d4 damage points, saving throw versus half damage. - -See also: DISPEL-EVIL #0 DISPLAYS PROMPTS HIT-PNT-DISPLAY @@ -2825,30 +2741,23 @@ of CircleMUD expect it first). i.e. a shot of whisky should have the keyword: whisky shot whisky a cup of slime mold juice keyword should be: juice cup slime juice -3: SYSERR: Mob #5 both Aggressive and Aggressive_to_Alignment. - - Another harmless error. If your mob is aggressive there is no need to also -make it aggressive to certain alignments since AGGR means it will attack any -player it can see. Choose to make it aggressive to an alignment or aggressive -to all. - -4: SYSERR: Object # (oedit-s-desc) has out of range level #. +3: SYSERR: Object # (oedit-s-desc) has out of range level #. A simple one. Limit spell levels to the levels available, on TBA that would be 1-30. -5: SYSERR: Object # (oedit-s-desc) has negative weight (-2147483644). +4: SYSERR: Object # (oedit-s-desc) has negative weight (-2147483644). SYSERR: Object # (oedit-s-desc) has out of range level #2147483647. These are really annoying. This happens when you use numbers larger than necessary. This will actually crash many older versions of CircleMUD. Just do not do it. Use realistic numbers. -6: SYSERR: Object # (oedit-s-desc) uses 'UNDEFINED' spell #. +5: SYSERR: Object # (oedit-s-desc) uses 'UNDEFINED' spell #. There is no spell zero. Either select a spell or put -1 for none. -7: SYSERR: Object # (oedit-s-desc) contains (5) more than maximum (3). +6: SYSERR: Object # (oedit-s-desc) contains (5) more than maximum (3). When making a drink container you will set how much it initially contains on creation and the max it can hold if a player were to fill it. Common sense @@ -2930,7 +2839,7 @@ Objects : 42 Triggers : 129 Theme : Its purpose, hack & slash, quest, rescue princess, kill ogre... Completion : When do you expect to finish it, how is the progress going? -Notes : Such things as zone alignment, economy, quests, special mobs and +Notes : Such things as zone economy, quests, special mobs and objs, and anything else I should know about your zone. What makes it unique? @@ -2985,8 +2894,8 @@ right. Parenthesis can be used to create priority. | | | (if actor age is not equal to 1) | < | less than | if %actor.dex% < 16 | | | (if actor dexterity is less than 16) -| > | greater than | if %actor.align% > 349 -| | | (if actor alignment is greater than 349) +| > | greater than | if %actor.level% > 30 +| | | (if actor level is greater than 30) | <= | less than or equal | if %actor.exp% <= 2 | | | (if actor experience is less than or equal to 1) | >= | greater than or equal | if %actor.mana% >= 1 @@ -4852,7 +4761,7 @@ MEDIT-AFF-FLAGS AFFECTIONS AFFECTS M) AFF Flags : @cNOBITS@n 1) BLIND Mob is blind. 2) INVIS Mob is invisible. -3) DET-ALIGN NOT USED. +3) RESERVED NOT USED. 4) DET-INVIS Mob can see invisible characters and objects. 5) DET-MAGIC Mob is sensitive to magical presence. 6) SENSE-LIFE Mob can sense hidden life. @@ -4863,15 +4772,15 @@ M) AFF Flags : @cNOBITS@n 10) CURSE Mob is cursed. 11) INFRA Mob can see in dark. 12) POISON Reserved for internal use. Do not set. -13) PROT-EVIL Mob is protected from evil characters. -14) PROT-GOOD Mob is protected from good characters. +13) RESERVED NOT USED. +14) RESERVED NOT USED. 15) SLEEP Reserved for internal use. Do not set. 16) NO_TRACK Mob cannot be tracked. 17) FLY Mob is flying. 18) SCUBA Mob can breathe underwater. 19) SNEAK Mob can move quietly without room being informed. 20) HIDE Mob is hidden; can only be seen with sense life. -21) UNUSED Unused (room for future expansion). +21) SCAN Actively scanning for hidden threats. 22) CHARM Reserved for internal use. Do not set. See also: INVIS, MEDIT-NPC-FLAGS, DG_AFFECT, TRIG-AFFECT @@ -4903,20 +4812,9 @@ should be one of the following numbers: 5) bludgeon #2 -MEDIT-EXPERIENCE MEDIT-XP MEDIT-ALIGNMENT +MEDIT-EXPERIENCE MEDIT-XP -(B) Exp Points: [ 115600] (E) Alignment: [ 1000] - -Alignment -A number from -1000 to 1000 representing the mobs initial alignment. - -Evil -1000 to -350 -Neutral -349 to 349 -Good 350 to 1000 - -The alignment of a mobile is determined entirely by you, depending on -the type of area you are creating. The alignment can be from -1000 -(extremely evil) to +1000 (divinely good). +(B) Exp Points: [ 115600] Experience is simply the number of experience points the mobile is born with. This is not the exact number of experience points the player will get @@ -5019,7 +4917,7 @@ X) Delete Mob @RHELP MEDIT-DELETE@n Q) Quit Enter choice : #2 -MEDIT-NPC-FLAGS MEDIT-FLAGS SPEC STAYZONE AGGRESSIVE AGGR_GOOD AGGR_NEU AGGR_EVIL STAY-ZONE STAY_ZONE SCAVENGER NPCFLAGS NPC-FLAGS MOBFLAGS MOB-FLAGS SENTINEL AWARE NOCHARM MOB-NPC NPC_FLAGS HELPER +MEDIT-NPC-FLAGS MEDIT-FLAGS SPEC STAYZONE AGGRESSIVE STAY-ZONE STAY_ZONE SCAVENGER NPCFLAGS NPC-FLAGS MOBFLAGS MOB-FLAGS SENTINEL AWARE NOCHARM MOB-NPC NPC_FLAGS HELPER NPC stands for non-player-character (mob) @@ -5042,9 +4940,9 @@ L) NPC Flags : @cISNPC@n its hit points. If the WIMPY bit is set in conjunction with any of the forms of the AGGRESSIVE bit, the mob will only attack mobs that are unconscious (sleeping or incapacitated). -8) AGGR_EVIL Mob will attack players that are evil-aligned. -9) AGGR_GOOD Mob will attack players that are good-aligned. -10) AGGR_NEU Mob will attack players that are neutrally aligned. +8) RESERVED Not used. +9) RESERVED Not used. +10) RESERVED Not used. 11) MEMORY Mob will remember players that initiate attacks on it, and will attack that player if it ever runs into him again. 12) HELPER The mob will attack any player it sees in the room that is @@ -5332,7 +5230,7 @@ MOBILE-FORMATS MOB-FORMATS MOB-FILES ~ ~ - + @@ -5382,11 +5280,11 @@ Message List: 0 ) [5 ] 1, burning hands 30) [314] 2, Unknown 1 ) [6 ] 1, call lightning 31) [399] 2, Unknown 2 ) [8 ] 1, chill touch 32) [33 ] 1, poison -3 ) [10 ] 1, color spray 33) [202] 1, !UNUSED! -4 ) [22 ] 1, dispel evil 34) [203] 1, !UNUSED! -5 ) [23 ] 1, earthquake 35) [204] 1, !UNUSED! -6 ) [25 ] 1, energy drain 36) [205] 1, !UNUSED! -7 ) [26 ] 1, fireball 37) [206] 1, !UNUSED! +3 ) [10 ] 1, color spray 33) [202] 1, !RESERVED! +4 ) [22 ] 1, dispel 34) [203] 1, !RESERVED! +5 ) [23 ] 1, earthquake 35) [204] 1, !RESERVED! +6 ) [25 ] 1, energy drain 36) [205] 1, !RESERVED! +7 ) [26 ] 1, fireball 37) [206] 1, !RESERVED! ========================================= MSG #, SKILL NUMBER, NUMBER OF ENTRIES, NAME (if applicable) 0 ) [5 ] 1, burning hands @@ -5901,9 +5799,9 @@ OEDIT-EXTRA-FLAGS OEDIT-FLAGS OBJECT-FLAGS OBJECTFLAGS GLOW HUM NODROP NO_DROP O 7) MAGIC Item has a magical aura and cannot be enchanted. 8) NODROP Item is cursed and cannot be removed or dropped. 9) BLESS Item is blessed (cosmetic). -10) ANTI_GOOD Item cannot be used by good-aligned characters. -11) ANTI_EVIL Item cannot be used by evil-aligned characters. -12) ANTI_NEUTRAL Item cannot be used by neutral align characters. +10) RESERVED Not used. +11) RESERVED Not used. +12) RESERVED Not used. 13) ANTI_MAGIC_USER Item cannot be used by the Mage class. 14) ANTI_CLERIC Item cannot be used by the Cleric class. 15) ANTI_THIEF Item cannot be used by the Thief class. @@ -6516,7 +6414,7 @@ this method is that if you accidentally wipe out your work on the MUD you will have a ready backup. Be careful cutting and pasting to the MUD; if you send too much text at once you will be disconnected. -See also: WORK, CARTOGRAPHY, LOCATION, THEME, PLOT, SIZE, ALIGN, BIAS +See also: WORK, CARTOGRAPHY, LOCATION, THEME, PLOT, SIZE, BIAS #2 PLAYER-SHOPS PLAYER-OWNED-SHOPS @@ -7079,7 +6977,7 @@ what it takes to properly plan out your first zone. It is extremely important that you put some forethought into what you will be creating. Remember, zones are built for others to play. Be sure to make it something a player will enjoy. A zone proposal consists of an informal MUDmail to your Head Builder. It should -contain: the location, level, alignment, theme, plot, size, and any other +contain: the location, level, theme, plot, size, and any other important notes about the zone. Detailed descriptions and help files are available in the hallways starting from room 14 and 15. @@ -7089,15 +6987,6 @@ deadlines, so take the time to give your zone character. Required Reading: @RHELP PLANNING, HELP STYLISTICS@n See also: EXAMPLE-PROPOSAL -#2 -PROTECTION-FROM-EVIL PROT-EVIL - -Usage : cast 'protection from evil' [self] -Accumulative: Yes (Duration) -Duration : 24 hours -Level : Cleric level 8. - -The meaning of this spell is not yet fully defined. #0 PURGE DESTROY UNLOAD DELETE-MOBILE DISINTEGRATE DECOMPOSE CLEANUP @@ -8396,12 +8285,12 @@ Enter choice : SEDIT-TRADE E) No Trade With : @cNOBITS@n - Designates certain alignments or classes that the shop will not trade with: + Designates certain classes that the shop will not trade with: - 1) Good 2) Evil - 3) Neutral 4) Magic User - 5) Cleric 6) Thief - 7) Warrior + 1) Sorceror 2) Cleric + 3) Rogue 4) Fighter + 5) Barbarian 6) Ranger + 7) Bard 8) Druid Currently will not trade with: @cNOBITS@n Enter choice (-1 for none): @@ -8700,11 +8589,11 @@ The following room flags can be selected: 16) * - DO NOT USE. Breadth-first search mark used by track and hunt. 17) WORLDMAP - DO NOT USE. World Map style maps. -Never set UNUSED or DO NOT USE bits, if you find them anywhere. If you +Never set RESERVED or DO NOT USE bits, if you find them anywhere. If you do not know what a flag does, DO NOT SET IT! This requires repeating since it is so often ignored: - @YIf a flag says UNUSED; DO NOT SET IT. If you do not know what it does; DO NOT SET IT!@n + @YIf a flag says RESERVED; DO NOT SET IT. If you do not know what it does; DO NOT SET IT!@n See Also: TOGGLE #2 @@ -8973,18 +8862,18 @@ SPELLS 7) charm person 8) chill touch 9) clone 10) color spray 11) control weather 12) create food 13) create water 14) cure blind 15) cure critic -16) cure light 17) curse 18) detect alignment +16) cure light 17) curse 18) reserved 19) detect invisibility 20) detect magic 21) detect poison -22) dispel evil 23) earthquake 24) enchant weapon +22) reserved 23) earthquake 24) enchant weapon 25) energy drain 26) fireball 27) harm 28) heal 29) invisibility 30) lightning bolt 31) locate object 32) magic missile 33) poison -34) protection from evil 35) remove curse 36) sanctuary +34) reserved 35) remove curse 36) sanctuary 37) shocking grasp 38) sleep 39) strength -40) summon 41) !UNUSED! 42) word of recall +40) summon 41) !RESERVED! 42) word of recall 43) remove poison 44) sense life 45) animate dead -46) dispel good 47) group armor 48) group heal -49) !UNUSED! 50) infravision 51) waterwalk +46) reserved 47) group armor 48) group heal +49) !RESERVED! 50) infravision 51) waterwalk 52) identify #2 @@ -8997,13 +8886,13 @@ SPELLS MAGICS SPELLBOOKS TOMBS SPELL-LEVELS SPELLS-STOCK SPELLLIST | Detect Magic 2 | Create Food 2 | | Chill Touch 3 | Create Water 2 | | Infravision 3 | Detect Poison 3 | -| Invisibility 4 | Detect Alignment 4 | +| Invisibility 4 | Reserved 4 | | Armor 4 | Cure Blind 4 | | Burning Hands 5 | Bless 5 | | Locate Object 6 | Detect Invisibility 6 | | Strength 6 | Blindness 6 | | Shocking Grasp 7 | Infravision 7 | -| Sleep 8 | Protection from Evil 8 | +| Sleep 8 | Reserved 8 | | Lightning Bolt 9 | Poison 8 | | Blindness 9 | Group Armor 9 | | Detect Poison 10 | Cure Crit 9 | @@ -9013,8 +8902,8 @@ SPELLS MAGICS SPELLBOOKS TOMBS SPELL-LEVELS SPELLS-STOCK SPELLLIST | Poison 14 | Word of Recall 12 | | Fireball 15 | Earthquake 12 | | Charm 16 | Darkness 13 | -| Identify 20 | Dispel Evil 14 | -| Enchant Weapon 26 | Dispel Good 14 | +| Identify 20 | Reserved 14 | +| Enchant Weapon 26 | Reserved 14 | | Clone 30 | Sanctuary 15 | | | Call Lightning 15 | | | Heal 16 | diff --git a/src/act.informative.c b/src/act.informative.c index 121594d..957ff6b 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -574,13 +574,6 @@ static void list_one_char(struct char_data *i, struct char_data *ch) if (AFF_FLAGGED(i, AFF_INVISIBLE)) send_to_char(ch, "*"); - if (AFF_FLAGGED(ch, AFF_DETECT_ALIGN)) { - if (IS_EVIL(i)) - send_to_char(ch, "(Red Aura) "); - else if (IS_GOOD(i)) - send_to_char(ch, "(Blue Aura) "); - } - send_to_char(ch, "%s", i->player.long_descr); if (AFF_FLAGGED(i, AFF_SANCTUARY)) @@ -596,13 +589,6 @@ static void list_one_char(struct char_data *i, struct char_data *ch) if (AFF_FLAGGED(i, AFF_INVISIBLE)) send_to_char(ch, "*"); - if (AFF_FLAGGED(ch, AFF_DETECT_ALIGN)) { - if (IS_EVIL(i)) - send_to_char(ch, "(Red Aura) "); - else if (IS_GOOD(i)) - send_to_char(ch, "(Blue Aura) "); - } - send_to_char(ch, "%s", i->player.long_descr); if (AFF_FLAGGED(i, AFF_SANCTUARY)) @@ -661,13 +647,6 @@ static void list_one_char(struct char_data *i, struct char_data *ch) send_to_char(ch, " is here struggling with thin air."); } - if (AFF_FLAGGED(ch, AFF_DETECT_ALIGN)) { - if (IS_EVIL(i)) - send_to_char(ch, " (Red Aura)"); - else if (IS_GOOD(i)) - send_to_char(ch, " (Blue Aura)"); - } - send_to_char(ch, "\r\n"); if (AFF_FLAGGED(i, AFF_SANCTUARY)) diff --git a/src/act.wizard.c b/src/act.wizard.c index 2e950f9..67d6b70 100644 --- a/src/act.wizard.c +++ b/src/act.wizard.c @@ -3564,9 +3564,8 @@ ACMD(do_show) send_to_char(ch, "Player: %-12s (%s) [%2d %s]\r\n", GET_NAME(vict), genders[(int) GET_SEX(vict)], GET_LEVEL(vict), CLASS_ABBR(vict)); - send_to_char(ch, "Coins: %-8d Bal: %-8d Exp: %-8d Align: %-5d\r\n", - GET_COINS(vict), GET_BANK_COINS(vict), GET_EXP(vict), - GET_ALIGNMENT(vict)); + send_to_char(ch, "Coins: %-8d Bal: %-8d Exp: %-8d\r\n", + GET_COINS(vict), GET_BANK_COINS(vict), GET_EXP(vict)); send_to_char(ch, "Started: %-25.25s Last: %-25.25s\r\n", buf1, buf2); send_to_char(ch, "Played: %dh %dm\r\n", (int) (vict->player.time.played / 3600), @@ -3761,9 +3760,8 @@ static struct set_struct { { "ac", LVL_BUILDER, BOTH, NUMBER }, /* 0 */ { "afk", LVL_BUILDER, PC, BINARY }, /* 1 */ { "age", LVL_GOD, BOTH, NUMBER }, - { "align", LVL_BUILDER, BOTH, NUMBER }, { "bank", LVL_BUILDER, PC, NUMBER }, - { "brief", LVL_GOD, PC, BINARY }, /* 5 */ + { "brief", LVL_GOD, PC, BINARY }, /* 4 */ { "cha", LVL_BUILDER, BOTH, NUMBER }, { "class", LVL_BUILDER, BOTH, MISC }, { "color", LVL_GOD, PC, BINARY }, @@ -3772,20 +3770,20 @@ static struct set_struct { { "dex", LVL_BUILDER, BOTH, NUMBER }, { "drunk", LVL_BUILDER, BOTH, MISC }, { "exp", LVL_GOD, BOTH, NUMBER }, - { "frozen", LVL_GRGOD, PC, BINARY }, /* 14 */ + { "frozen", LVL_GRGOD, PC, BINARY }, /* 13 */ { "coins", LVL_BUILDER, BOTH, NUMBER }, { "height", LVL_BUILDER, BOTH, NUMBER }, { "hitpoints", LVL_BUILDER, BOTH, NUMBER }, - { "hunger", LVL_BUILDER, BOTH, MISC }, /* 18 */ + { "hunger", LVL_BUILDER, BOTH, MISC }, /* 17 */ { "int", LVL_BUILDER, BOTH, NUMBER }, { "invis", LVL_GOD, PC, NUMBER }, { "invstart", LVL_BUILDER, PC, BINARY }, - { "level", LVL_GRGOD, BOTH, NUMBER }, /* 22 */ + { "level", LVL_GRGOD, BOTH, NUMBER }, /* 21 */ { "loadroom", LVL_BUILDER, PC, MISC }, { "mana", LVL_BUILDER, BOTH, NUMBER }, { "maxhit", LVL_BUILDER, BOTH, NUMBER }, { "maxmana", LVL_BUILDER, BOTH, NUMBER }, - { "maxstam", LVL_BUILDER, BOTH, NUMBER }, /* 27 */ + { "maxstam", LVL_BUILDER, BOTH, NUMBER }, /* 26 */ { "name", LVL_IMMORT, PC, MISC }, { "nodelete", LVL_GOD, PC, BINARY }, { "nohassle", LVL_GOD, PC, BINARY }, @@ -3797,18 +3795,18 @@ static struct set_struct { { "poofout", LVL_IMMORT, PC, MISC }, { "quest", LVL_GOD, PC, BINARY }, { "room", LVL_BUILDER, BOTH, NUMBER }, - { "screenwidth", LVL_GOD, PC, NUMBER }, /* 39 */ + { "screenwidth", LVL_GOD, PC, NUMBER }, /* 38 */ { "sex", LVL_GOD, BOTH, MISC }, { "showvnums", LVL_BUILDER, PC, BINARY }, { "siteok", LVL_GOD, PC, BINARY }, { "skill", LVL_GOD, BOTH, NUMBER }, - { "stam", LVL_BUILDER, BOTH, NUMBER }, /* 44 */ + { "stam", LVL_BUILDER, BOTH, NUMBER }, /* 43 */ { "str", LVL_BUILDER, BOTH, NUMBER }, { "thirst", LVL_BUILDER, BOTH, MISC }, { "variable", LVL_GRGOD, PC, MISC }, { "weight", LVL_BUILDER, BOTH, NUMBER }, { "wis", LVL_BUILDER, BOTH, NUMBER }, - { "questpoints", LVL_GOD, PC, NUMBER }, /* 50 */ + { "questpoints", LVL_GOD, PC, NUMBER }, /* 49 */ { "questhistory", LVL_GOD, PC, NUMBER }, { "species", LVL_BUILDER, BOTH, MISC }, { "\n", 0, BOTH, MISC } @@ -3870,17 +3868,13 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c GET_ROLEPLAY_AGE(vict) = LIMIT(value, MIN_CHAR_AGE, MAX_CHAR_AGE); GET_ROLEPLAY_AGE_YEAR(vict) = time_info.year; break; - case 3: /* align */ - GET_ALIGNMENT(vict) = RANGE(-1000, 1000); - affect_total(vict); - break; - case 4: /* bank */ + case 3: /* bank */ GET_BANK_COINS(vict) = RANGE(0, 100000000); break; - case 5: /* brief */ + case 4: /* brief */ SET_OR_REMOVE(PRF_FLAGS(vict), PRF_BRIEF); break; - case 6: /* cha */ + case 5: /* cha */ if (IS_NPC(vict) || GET_LEVEL(vict) >= LVL_GRGOD) RANGE(3, 25); else @@ -3888,18 +3882,18 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c vict->real_abils.cha = value; affect_total(vict); break; - case 7: /* class */ + case 6: /* class */ if ((i = parse_class(*val_arg)) == CLASS_UNDEFINED) { send_to_char(ch, "That is not a class.\r\n"); return (0); } GET_CLASS(vict) = i; break; - case 8: /* color */ + case 7: /* color */ SET_OR_REMOVE(PRF_FLAGS(vict), (PRF_COLOR_1)); SET_OR_REMOVE(PRF_FLAGS(vict), (PRF_COLOR_2)); break; - case 9: /* con */ + case 8: /* con */ if (IS_NPC(vict) || GET_LEVEL(vict) >= LVL_GRGOD) RANGE(3, 25); else @@ -3907,10 +3901,10 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c vict->real_abils.con = value; affect_total(vict); break; - case 10: /* delete */ + case 9: /* delete */ SET_OR_REMOVE(PLR_FLAGS(vict), PLR_DELETED); break; - case 11: /* dex */ + case 10: /* dex */ if (IS_NPC(vict) || GET_LEVEL(vict) >= LVL_GRGOD) RANGE(3, 25); else @@ -3918,7 +3912,7 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c vict->real_abils.dex = value; affect_total(vict); break; - case 12: /* drunk */ + case 11: /* drunk */ if (!str_cmp(val_arg, "off")) { GET_COND(vict, DRUNK) = -1; send_to_char(ch, "%s's drunkenness is now off.\r\n", GET_NAME(vict)); @@ -3932,17 +3926,17 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c return (0); } break; - case 13: /* exp */ + case 12: /* exp */ vict->points.exp = RANGE(0, 50000000); break; - case 14: /* frozen */ + case 13: /* frozen */ if (ch == vict && on) { send_to_char(ch, "Better not -- could be a long winter!\r\n"); return (0); } SET_OR_REMOVE(PLR_FLAGS(vict), PLR_FROZEN); break; - case 15: { /* coins */ + case 14: { /* coins */ struct obj_data *coin_obj; int i; @@ -3978,15 +3972,15 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c send_to_char(ch, "Ok.\r\n"); return (1); } - case 16: /* height */ + case 15: /* height */ GET_HEIGHT(vict) = value; affect_total(vict); break; - case 17: /* hit */ + case 16: /* hit */ vict->points.hit = RANGE(-9, vict->points.max_hit); affect_total(vict); break; - case 18: /* hunger */ + case 17: /* hunger */ if (!str_cmp(val_arg, "off")) { GET_COND(vict, HUNGER) = -1; send_to_char(ch, "%s's hunger is now off.\r\n", GET_NAME(vict)); @@ -4000,7 +3994,7 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c return (0); } break; - case 19: /* int */ + case 18: /* int */ if (IS_NPC(vict) || GET_LEVEL(vict) >= LVL_GRGOD) RANGE(3, 25); else @@ -4008,17 +4002,17 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c vict->real_abils.intel = value; affect_total(vict); break; - case 20: /* invis */ + case 19: /* invis */ if (GET_LEVEL(ch) < LVL_IMPL && ch != vict) { send_to_char(ch, "You aren't godly enough for that!\r\n"); return (0); } GET_INVIS_LEV(vict) = RANGE(0, GET_LEVEL(vict)); break; - case 21: /* invistart */ + case 20: /* invistart */ SET_OR_REMOVE(PLR_FLAGS(vict), PLR_INVSTART); break; - case 22: /* level */ + case 21: /* level */ if ((!IS_NPC(vict) && value > GET_LEVEL(ch)) || value > LVL_IMPL) { send_to_char(ch, "You can't do that.\r\n"); return (0); @@ -4026,7 +4020,7 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c RANGE(1, LVL_IMPL); vict->player.level = value; break; - case 23: /* loadroom */ + case 22: /* loadroom */ if (!str_cmp(val_arg, "off")) { REMOVE_BIT_AR(PLR_FLAGS(vict), PLR_LOADROOM); } else if (is_number(val_arg)) { @@ -4044,23 +4038,23 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c return (0); } break; - case 24: /* mana */ + case 23: /* mana */ vict->points.mana = RANGE(0, vict->points.max_mana); affect_total(vict); break; - case 25: /* maxhit */ + case 24: /* maxhit */ vict->points.max_hit = RANGE(1, 5000); affect_total(vict); break; - case 26: /* maxmana */ + case 25: /* maxmana */ vict->points.max_mana = RANGE(1, 5000); affect_total(vict); break; - case 27: /* maxstam */ + case 26: /* maxstam */ vict->points.max_stamina = RANGE(1, 5000); affect_total(vict); break; - case 28: /* name */ + case 27: /* name */ if (ch != vict && GET_LEVEL(ch) < LVL_IMPL) { send_to_char(ch, "Only Imps can change the name of other players.\r\n"); return (0); @@ -4070,24 +4064,24 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c return (0); } break; - case 29: /* nodelete */ + case 28: /* nodelete */ SET_OR_REMOVE(PLR_FLAGS(vict), PLR_NODELETE); break; - case 30: /* nohassle */ + case 29: /* nohassle */ if (GET_LEVEL(ch) < LVL_GOD && ch != vict) { send_to_char(ch, "You aren't godly enough for that!\r\n"); return (0); } SET_OR_REMOVE(PRF_FLAGS(vict), PRF_NOHASSLE); break; - case 31: /* nosummon */ + case 30: /* nosummon */ SET_OR_REMOVE(PRF_FLAGS(vict), PRF_SUMMONABLE); send_to_char(ch, "Nosummon %s for %s.\r\n", ONOFF(!on), GET_NAME(vict)); break; - case 32: /* nowiz */ + case 31: /* nowiz */ SET_OR_REMOVE(PLR_FLAGS(vict), PLR_NOWIZLIST); break; - case 33: /* olc */ + case 32: /* olc */ if (is_abbrev(val_arg, "socials") || is_abbrev(val_arg, "actions") || is_abbrev(val_arg, "aedit")) GET_OLC_ZONE(vict) = AEDIT_PERMISSION; else if (is_abbrev(val_arg, "hedit") || is_abbrev(val_arg, "help")) @@ -4102,7 +4096,7 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c } else GET_OLC_ZONE(vict) = atoi(val_arg); break; - case 34: /* password */ + case 33: /* password */ if (GET_LEVEL(vict) >= LVL_GRGOD) { send_to_char(ch, "You cannot change that.\r\n"); return (0); @@ -4111,7 +4105,7 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c *(GET_PASSWD(vict) + MAX_PWD_LENGTH) = '\0'; send_to_char(ch, "Password changed to '%s'.\r\n", val_arg); break; - case 35: /* poofin */ + case 34: /* poofin */ if ((vict == ch) || (GET_LEVEL(ch) == LVL_IMPL)) { skip_spaces(&val_arg); parse_at(val_arg); @@ -4125,7 +4119,7 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c POOFIN(vict) = strdup(val_arg); } break; - case 36: /* poofout */ + case 35: /* poofout */ if ((vict == ch) || (GET_LEVEL(ch) == LVL_IMPL)) { skip_spaces(&val_arg); parse_at(val_arg); @@ -4139,10 +4133,10 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c POOFOUT(vict) = strdup(val_arg); } break; - case 37: /* quest */ + case 36: /* quest */ SET_OR_REMOVE(PRF_FLAGS(vict), PRF_QUEST); break; - case 38: /* room */ + case 37: /* room */ if ((rnum = real_room(value)) == NOWHERE) { send_to_char(ch, "No room exists with that number.\r\n"); return (0); @@ -4151,23 +4145,23 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c char_from_room(vict); char_to_room(vict, rnum); break; - case 39: /* screenwidth */ + case 38: /* screenwidth */ GET_SCREEN_WIDTH(vict) = RANGE(40, 200); break; - case 40: /* sex */ + case 39: /* sex */ if ((i = search_block(val_arg, genders, FALSE)) < 0) { send_to_char(ch, "Must be 'male', 'female', or 'neutral'.\r\n"); return (0); } GET_SEX(vict) = i; break; - case 41: /* showvnums */ + case 40: /* showvnums */ SET_OR_REMOVE(PRF_FLAGS(vict), PRF_SHOWVNUMS); break; - case 42: /* siteok */ + case 41: /* siteok */ SET_OR_REMOVE(PLR_FLAGS(vict), PLR_SITEOK); break; - case 43: /* skills/spells */ + case 42: /* skills/spells */ { char local_buf[MAX_INPUT_LENGTH], *value_arg, *name_end; char skill_name[MAX_INPUT_LENGTH]; @@ -4252,12 +4246,12 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c } break; - case 44: /* stam */ + case 43: /* stam */ vict->points.stamina = RANGE(0, vict->points.max_stamina); affect_total(vict); break; - case 45: /* str */ + case 44: /* str */ if (IS_NPC(vict) || GET_LEVEL(vict) >= LVL_GRGOD) RANGE(3, 25); else @@ -4265,7 +4259,7 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c vict->real_abils.str = value; affect_total(vict); break; - case 46: /* thirst */ + case 45: /* thirst */ if (!str_cmp(val_arg, "off")) { GET_COND(vict, THIRST) = -1; send_to_char(ch, "%s's thirst is now off.\r\n", GET_NAME(vict)); @@ -4279,13 +4273,13 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c return (0); } break; - case 47: /* variable */ + case 46: /* variable */ return perform_set_dg_var(ch, vict, val_arg); - case 48: /* weight */ + case 47: /* weight */ GET_WEIGHT(vict) = value; affect_total(vict); break; - case 49: /* wis */ + case 48: /* wis */ if (IS_NPC(vict) || GET_LEVEL(vict) >= LVL_GRGOD) RANGE(3, 25); else @@ -4293,10 +4287,10 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c vict->real_abils.wis = value; affect_total(vict); break; - case 50: /* questpoints */ + case 49: /* questpoints */ GET_QUESTPOINTS(vict) = RANGE(0, 100000000); break; - case 51: /* questhistory */ + case 50: /* questhistory */ qvnum = atoi(val_arg); if (real_quest(qvnum) == NOTHING) { send_to_char(ch, "That quest doesn't exist.\r\n"); @@ -4313,7 +4307,7 @@ static int perform_set(struct char_data *ch, struct char_data *vict, int mode, c } break; } - case 52: /* species */ + case 51: /* species */ if ((i = parse_species(val_arg)) == SPECIES_UNDEFINED) { send_to_char(ch, "That is not a species.\r\n"); return (0); @@ -4718,10 +4712,6 @@ ACMD (do_zcheck) "- No unarmed combat proficiency set (add skill or weapon)\r\n"); } - if (MOB_FLAGGED(mob, MOB_AGGRESSIVE) && (MOB_FLAGGED(mob, MOB_AGGR_GOOD) || MOB_FLAGGED(mob, MOB_AGGR_EVIL) || MOB_FLAGGED(mob, MOB_AGGR_NEUTRAL)) && (found=1)) - len += snprintf(buf + len, sizeof(buf) - len, - "- Both aggresive and agressive to align.\r\n"); - if (GET_EXP(mob)>MAX_EXP_ALLOWED && (found=1)) len += snprintf(buf + len, sizeof(buf) - len, "- Has %d experience (limit: %d)\r\n", diff --git a/src/constants.c b/src/constants.c index 59de100..4a2d915 100644 --- a/src/constants.c +++ b/src/constants.c @@ -228,9 +228,9 @@ const char *action_bits[] = { "AGGR", "STAY-ZONE", "WIMPY", - "AGGR_EVIL", - "AGGR_GOOD", - "AGGR_NEUTRAL", + "RESERVED", + "RESERVED", + "RESERVED", "MEMORY", "HELPER", "NO_CHARM", @@ -299,8 +299,8 @@ const char *affected_bits[] = "CURSE", "INFRA", "POISON", - "PROT-EVIL", - "PROT-GOOD", + "RESERVED", + "RESERVED", "SLEEP", "NO_TRACK", "FLY", @@ -485,9 +485,9 @@ const char *extra_bits[] = { "MAGIC", "NO_DROP", "BLESS", - "ANTI_GOOD", - "ANTI_EVIL", - "ANTI_NEUTRAL", + "RESERVED", + "RESERVED", + "RESERVED", "ANTI_SORCEROR", "ANTI_CLERIC", "ANTI_ROGUE", diff --git a/src/db.c b/src/db.c index 9a5c124..506aef4 100644 --- a/src/db.c +++ b/src/db.c @@ -1902,13 +1902,6 @@ void parse_mobile(FILE *mob_f, int nr) REMOVE_BIT_AR(AFF_FLAGS(mob_proto + i), AFF_CHARM); REMOVE_BIT_AR(AFF_FLAGS(mob_proto + i), AFF_POISON); REMOVE_BIT_AR(AFF_FLAGS(mob_proto + i), AFF_SLEEP); - if (MOB_FLAGGED(mob_proto + i, MOB_AGGRESSIVE) && MOB_FLAGGED(mob_proto + i, MOB_AGGR_GOOD)) - REMOVE_BIT_AR(MOB_FLAGS(mob_proto + i), MOB_AGGR_GOOD); - if (MOB_FLAGGED(mob_proto + i, MOB_AGGRESSIVE) && MOB_FLAGGED(mob_proto + i, MOB_AGGR_NEUTRAL)) - REMOVE_BIT_AR(MOB_FLAGS(mob_proto + i), MOB_AGGR_NEUTRAL); - if (MOB_FLAGGED(mob_proto + i, MOB_AGGRESSIVE) && MOB_FLAGGED(mob_proto + i, MOB_AGGR_EVIL)) - REMOVE_BIT_AR(MOB_FLAGS(mob_proto + i), MOB_AGGR_EVIL); - check_bitvector_names(AFF_FLAGS(mob_proto + i)[0], affected_bits_count, buf2, "mobile affect"); /* This is necessary, since if we have conventional world files, &letter is diff --git a/src/fight.c b/src/fight.c index 0f9b384..ba9357b 100644 --- a/src/fight.c +++ b/src/fight.c @@ -57,7 +57,6 @@ static struct char_data *next_combat_list = NULL; static void perform_group_gain(struct char_data *ch, int base, struct char_data *victim); static void dam_message(int dam, struct char_data *ch, struct char_data *victim, int w_type); static void make_corpse(struct char_data *ch); -static void change_alignment(struct char_data *ch, struct char_data *victim); static void group_gain(struct char_data *ch, struct char_data *victim); static void solo_gain(struct char_data *ch, struct char_data *victim); /** @todo refactor this function name */ @@ -281,14 +280,6 @@ static void make_corpse(struct char_data *ch) obj_to_room(corpse, IN_ROOM(ch)); } -/* When ch kills victim */ -static void change_alignment(struct char_data *ch, struct char_data *victim) -{ - /* new alignment change algorithm: if you kill a monster with alignment A, - * you move 1/16th of the way to having alignment -A. Simple and fast. */ - GET_ALIGNMENT(ch) += (-GET_ALIGNMENT(victim) - GET_ALIGNMENT(ch)) / 16; -} - void death_cry(struct char_data *ch) { int door; @@ -354,11 +345,9 @@ void die(struct char_data * ch, struct char_data * killer) static void perform_group_gain(struct char_data *ch, int base, struct char_data *victim) { - int share; - - share = MIN(CONFIG_MAX_EXP_GAIN, MAX(1, base)); - - change_alignment(ch, victim); + (void)ch; + (void)base; + (void)victim; } static void group_gain(struct char_data *ch, struct char_data *victim) @@ -400,8 +389,6 @@ static void solo_gain(struct char_data *ch, struct char_data *victim) exp += MAX(0, (exp * MIN(8, (GET_LEVEL(victim) - GET_LEVEL(ch)))) / 8); exp = MAX(exp, 1); - - change_alignment(ch, victim); } static char *replace_string(const char *str, const char *weapon_singular, const char *weapon_plural) diff --git a/src/handler.c b/src/handler.c index 25d7749..314dba7 100644 --- a/src/handler.c +++ b/src/handler.c @@ -525,17 +525,6 @@ static int apply_ac(struct char_data *ch, int eq_pos) return (factor * GET_OBJ_VAL(GET_EQ(ch, eq_pos), 0)); } -int invalid_align(struct char_data *ch, struct obj_data *obj) -{ - if (OBJ_FLAGGED(obj, ITEM_ANTI_EVIL) && IS_EVIL(ch)) - return TRUE; - if (OBJ_FLAGGED(obj, ITEM_ANTI_GOOD) && IS_GOOD(ch)) - return TRUE; - if (OBJ_FLAGGED(obj, ITEM_ANTI_NEUTRAL) && IS_NEUTRAL(ch)) - return TRUE; - return FALSE; -} - void equip_char(struct char_data *ch, struct obj_data *obj, int pos) { int j; @@ -558,7 +547,7 @@ void equip_char(struct char_data *ch, struct obj_data *obj, int pos) log("SYSERR: EQUIP: Obj is in_room when equip."); return; } - if (invalid_align(ch, obj) || invalid_class(ch, obj)) { + if (invalid_class(ch, obj)) { act("You are zapped by $p and instantly let go of it.", FALSE, ch, obj, 0, TO_CHAR); act("$n is zapped by $p and instantly lets go of it.", FALSE, ch, obj, 0, TO_ROOM); /* Changed to drop in inventory instead of the ground. */ diff --git a/src/handler.h b/src/handler.h index 5ae73bf..9dfa986 100644 --- a/src/handler.h +++ b/src/handler.h @@ -40,7 +40,6 @@ void obj_from_char(struct obj_data *object); void equip_char(struct char_data *ch, struct obj_data *obj, int pos); struct obj_data *unequip_char(struct char_data *ch, int pos); -int invalid_align(struct char_data *ch, struct obj_data *obj); void obj_to_room(struct obj_data *object, room_rnum room); void obj_from_room(struct obj_data *object); diff --git a/src/magic.c b/src/magic.c index 8eae632..9ca8389 100644 --- a/src/magic.c +++ b/src/magic.c @@ -237,23 +237,9 @@ int mag_damage(int level, struct char_data *ch, struct char_data *victim, /* Mostly clerics */ case SPELL_DISPEL_EVIL: dam = dice(6, 8) + 6; - if (IS_EVIL(ch)) { - victim = ch; - dam = GET_HIT(ch) - 1; - } else if (IS_GOOD(victim)) { - act("The gods protect $N.", FALSE, ch, 0, victim, TO_CHAR); - return (0); - } break; case SPELL_DISPEL_GOOD: dam = dice(6, 8) + 6; - if (IS_GOOD(ch)) { - victim = ch; - dam = GET_HIT(ch) - 1; - } else if (IS_EVIL(victim)) { - act("The gods protect $N.", FALSE, ch, 0, victim, TO_CHAR); - return (0); - } break; @@ -461,13 +447,6 @@ void mag_affects(int level, struct char_data *ch, struct char_data *victim, to_room = "$n gets violently ill!"; break; - case SPELL_PROT_FROM_EVIL: - af[0].duration = 24; - SET_BIT_AR(af[0].bitvector, AFF_PROTECT_EVIL); - accum_duration = TRUE; - to_vict = "You feel invulnerable!"; - break; - case SPELL_SANCTUARY: af[0].duration = 4; SET_BIT_AR(af[0].bitvector, AFF_SANCTUARY); diff --git a/src/mobact.c b/src/mobact.c index 1696cdd..2e38d39 100644 --- a/src/mobact.c +++ b/src/mobact.c @@ -99,10 +99,7 @@ void mobile_activity(void) if (MOB_FLAGGED(ch, MOB_WIMPY) && AWAKE(vict)) continue; - if (MOB_FLAGGED(ch, MOB_AGGRESSIVE ) || - (MOB_FLAGGED(ch, MOB_AGGR_EVIL ) && IS_EVIL(vict)) || - (MOB_FLAGGED(ch, MOB_AGGR_NEUTRAL) && IS_NEUTRAL(vict)) || - (MOB_FLAGGED(ch, MOB_AGGR_GOOD ) && IS_GOOD(vict))) { + if (MOB_FLAGGED(ch, MOB_AGGRESSIVE)) { /* Can a master successfully control the charmed monster? */ if (aggressive_mob_on_a_leash(ch, ch->master, vict)) @@ -267,4 +264,3 @@ static bool aggressive_mob_on_a_leash(struct char_data *slave, struct char_data /* So sorry, now you're a player killer... Tsk tsk. */ return (FALSE); } - diff --git a/src/objsave.c b/src/objsave.c index e3800e9..5bc10a6 100644 --- a/src/objsave.c +++ b/src/objsave.c @@ -226,9 +226,7 @@ static void auto_equip(struct char_data *ch, struct obj_data *obj, int location) if (location > 0) { /* Wearable. */ if (!GET_EQ(ch,j)) { - /* Check the characters's alignment to prevent them from being zapped - * through the auto-equipping. */ - if (invalid_align(ch, obj) || invalid_class(ch, obj)) + if (invalid_class(ch, obj)) location = LOC_INVENTORY; else equip_char(ch, obj, j); diff --git a/src/pfdefaults.h b/src/pfdefaults.h index 27bf28e..5463e92 100644 --- a/src/pfdefaults.h +++ b/src/pfdefaults.h @@ -19,7 +19,6 @@ #define PFDEF_LEVEL 0 #define PFDEF_HEIGHT 0 #define PFDEF_WEIGHT 0 -#define PFDEF_ALIGNMENT 0 #define PFDEF_PLRFLAGS 0 #define PFDEF_AFFFLAGS 0 #define PFDEF_SAVETHROW 0 diff --git a/src/players.c b/src/players.c index b149aaf..eace528 100644 --- a/src/players.c +++ b/src/players.c @@ -276,7 +276,6 @@ int load_char(const char *name, struct char_data *ch) GET_WEIGHT(ch) = PFDEF_WEIGHT; GET_ROLEPLAY_AGE(ch) = 0; GET_ROLEPLAY_AGE_YEAR(ch) = 0; - GET_ALIGNMENT(ch) = PFDEF_ALIGNMENT; for (i = 0; i < NUM_OF_SAVING_THROWS; i++) GET_SAVE(ch, i) = PFDEF_SAVETHROW; GET_LOADROOM(ch) = PFDEF_LOADROOM; @@ -361,7 +360,6 @@ int load_char(const char *name, struct char_data *ch) AFF_FLAGS(ch)[0] = asciiflag_conv(line); } if (!strcmp(tag, "Affs")) load_affects(fl, ch); - else if (!strcmp(tag, "Alin")) GET_ALIGNMENT(ch) = atoi(line); else if (!strcmp(tag, "Alis")) read_aliases_ascii(fl, ch, atoi(line)); break; @@ -696,7 +694,6 @@ void save_char(struct char_data * ch) 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)); if (GET_WEIGHT(ch) != PFDEF_WEIGHT) fprintf(fl, "Wate: %d\n", GET_WEIGHT(ch)); - if (GET_ALIGNMENT(ch) != PFDEF_ALIGNMENT) fprintf(fl, "Alin: %d\n", GET_ALIGNMENT(ch)); sprintascii(bits, PLR_FLAGS(ch)[0]); diff --git a/src/sedit.c b/src/sedit.c index d38e502..3f48d36 100644 --- a/src/sedit.c +++ b/src/sedit.c @@ -31,6 +31,7 @@ static void sedit_shop_flags_menu(struct descriptor_data *d); static void sedit_no_trade_menu(struct descriptor_data *d); static void sedit_types_menu(struct descriptor_data *d); static void sedit_disp_menu(struct descriptor_data *d); +static void format_notrade_classes(bitvector_t flags, char *out, size_t outsz); void sedit_save_internally(struct descriptor_data *d) @@ -44,6 +45,34 @@ static void sedit_save_to_disk(int num) save_shops(num); } +static void format_notrade_classes(bitvector_t flags, char *out, size_t outsz) +{ + size_t len = 0; + int i, found = 0; + + if (!out || outsz == 0) + return; + + out[0] = '\0'; + + for (i = TRADE_CLASS_START; i < NUM_TRADERS; i++) { + if (IS_SET(flags, 1 << i)) { + int n = snprintf(out + len, outsz - len, "%s%s", found ? " " : "", trade_letters[i]); + + if (n < 0 || (size_t)n >= outsz - len) { + out[outsz - 1] = '\0'; + return; + } + + len += (size_t)n; + found = 1; + } + } + + if (!found) + strlcpy(out, "NOBITS", outsz); +} + /* utility functions */ ACMD(do_oasis_sedit) { @@ -346,11 +375,12 @@ static void sedit_no_trade_menu(struct descriptor_data *d) get_char_colors(d->character); clear_screen(d); - for (i = 0; i < NUM_TRADERS; i++) { - write_to_output(d, "%s%2d%s) %-20.20s %s", grn, i + 1, nrm, trade_letters[i], + for (i = 0; i < NUM_TRADE_CLASSES; i++) { + write_to_output(d, "%s%2d%s) %-20.20s %s", grn, i + 1, nrm, + trade_letters[TRADE_CLASS_START + i], !(++count % 2) ? "\r\n" : ""); } - sprintbit(S_NOTRADE(OLC_SHOP(d)), trade_letters, bits, sizeof(bits)); + format_notrade_classes(S_NOTRADE(OLC_SHOP(d)), bits, sizeof(bits)); write_to_output(d, "\r\nCurrently won't trade with: %s%s%s\r\n" "Enter choice : ", cyn, bits, nrm); OLC_MODE(d) = SEDIT_NOTRADE; @@ -382,7 +412,7 @@ static void sedit_disp_menu(struct descriptor_data *d) get_char_colors(d->character); clear_screen(d); - sprintbit(S_NOTRADE(shop), trade_letters, buf1, sizeof(buf1)); + format_notrade_classes(S_NOTRADE(shop), buf1, sizeof(buf1)); sprintbit(S_BITVECTOR(shop), shop_bits, buf2, sizeof(buf2)); write_to_output(d, "-- Shop Number : [%s%d%s]\r\n" @@ -756,8 +786,8 @@ void sedit_parse(struct descriptor_data *d, char *arg) } break; case SEDIT_NOTRADE: - if ((i = LIMIT(atoi(arg), 0, NUM_TRADERS)) > 0) { - TOGGLE_BIT(S_NOTRADE(OLC_SHOP(d)), 1 << (i - 1)); + if ((i = LIMIT(atoi(arg), 0, NUM_TRADE_CLASSES)) > 0) { + TOGGLE_BIT(S_NOTRADE(OLC_SHOP(d)), 1 << (TRADE_CLASS_START + i - 1)); sedit_no_trade_menu(d); return; } diff --git a/src/shop.c b/src/shop.c index 1be4ac5..44dd985 100644 --- a/src/shop.c +++ b/src/shop.c @@ -29,9 +29,9 @@ /* Global variables definitions used externally */ /* Constant list for printing out who we sell to */ const char *trade_letters[] = { - "Good", /* First, the alignment based ones */ - "Evil", - "Neutral", + "RESERVED1", + "RESERVED2", + "RESERVED3", "Sorceror", /* Then the class based ones */ "Cleric", "Rogue", @@ -119,13 +119,6 @@ static int is_ok_char(struct char_data *keeper, struct char_data *ch, int shop_n if (IS_GOD(ch)) return (TRUE); - if ((IS_GOOD(ch) && NOTRADE_GOOD(shop_nr)) || - (IS_EVIL(ch) && NOTRADE_EVIL(shop_nr)) || - (IS_NEUTRAL(ch) && NOTRADE_NEUTRAL(shop_nr))) { - snprintf(buf, sizeof(buf), "%s %s", GET_NAME(ch), MSG_NO_SELL_ALIGN); - do_tell(keeper, buf, cmd_tell, 0); - return (FALSE); - } if (IS_NPC(ch)) return (TRUE); @@ -1361,7 +1354,7 @@ void assign_the_shopkeepers(void) static char *customer_string(int shop_nr, int detailed) { - int sindex = 0, flag = 1, nlen; + int sindex = TRADE_CLASS_START, flag = (1 << TRADE_CLASS_START), nlen; size_t len = 0; static char buf[256]; @@ -1433,7 +1426,7 @@ static void list_all_shops(struct char_data *ch) static void list_detailed_shop(struct char_data *ch, int shop_nr) { struct char_data *k; - int sindex, column, flag = 1, found = 0; + int sindex, column, flag = (1 << TRADE_CLASS_START), found = 0; /* char *ptrsave; */ send_to_char(ch, "Vnum: [%5d], Rnum: [%5d]\r\n", SHOP_NUM(shop_nr), shop_nr + 1); @@ -1484,7 +1477,7 @@ static void list_detailed_shop(struct char_data *ch, int shop_nr) /* send_to_char(ch, "Customers: %s\r\n", (ptrsave = customer_string(shop_nr, TRUE)) ? ptrsave : "None"); */ send_to_char(ch, "Customers: "); column = 12; /* ^^^ strlen ^^^ */ - for (sindex = 0; *trade_letters[sindex] != '\n'; sindex++) { + for (sindex = TRADE_CLASS_START; *trade_letters[sindex] != '\n'; sindex++) { char buf1[128]; int linelen; diff --git a/src/shop.h b/src/shop.h index cc4e8d9..4ea8c7a 100644 --- a/src/shop.h +++ b/src/shop.h @@ -74,9 +74,9 @@ struct shop_data { #define LIST_ROOM 2 /* Whom will we not trade with (bitvector for SHOP_TRADE_WITH()) */ -#define TRADE_NOGOOD (1 << 0) -#define TRADE_NOEVIL (1 << 1) -#define TRADE_NONEUTRAL (1 << 2) +#define TRADE_RESERVED1 (1 << 0) +#define TRADE_RESERVED2 (1 << 1) +#define TRADE_RESERVED3 (1 << 2) #define TRADE_NOSORCEROR (1 << 3) #define TRADE_NOCLERIC (1 << 4) #define TRADE_NOROGUE (1 << 5) @@ -87,6 +87,9 @@ struct shop_data { #define TRADE_NODRUID (1 << 10) /** Total number of trade types */ #define NUM_TRADERS 11 +#define TRADE_RESERVED_COUNT 3 +#define TRADE_CLASS_START TRADE_RESERVED_COUNT +#define NUM_TRADE_CLASSES (NUM_TRADERS - TRADE_RESERVED_COUNT) struct stack_data { int data[100]; @@ -123,9 +126,6 @@ struct stack_data { #define SHOP_SELLPROFIT(i) (shop_index[(i)].profit_sell) #define SHOP_FUNC(i) (shop_index[(i)].func) -#define NOTRADE_GOOD(i) (IS_SET(SHOP_TRADE_WITH((i)), TRADE_NOGOOD)) -#define NOTRADE_EVIL(i) (IS_SET(SHOP_TRADE_WITH((i)), TRADE_NOEVIL)) -#define NOTRADE_NEUTRAL(i) (IS_SET(SHOP_TRADE_WITH((i)), TRADE_NONEUTRAL)) #define NOTRADE_SORCEROR(i) (IS_SET(SHOP_TRADE_WITH((i)), TRADE_NOSORCEROR)) #define NOTRADE_CLERIC(i) (IS_SET(SHOP_TRADE_WITH((i)), TRADE_NOCLERIC)) #define NOTRADE_ROGUE(i) (IS_SET(SHOP_TRADE_WITH((i)), TRADE_NOROGUE)) @@ -153,7 +153,6 @@ struct stack_data { #define MSG_CLOSED_FOR_DAY "Sorry, come back tomorrow." #define MSG_NO_STEAL_HERE "$n is a bloody thief!" #define MSG_NO_SEE_CHAR "I don't trade with someone I can't see!" -#define MSG_NO_SELL_ALIGN "Get out of here before I call the guards!" #define MSG_NO_SELL_CLASS "We don't serve your kind here!" #define MSG_NO_USED_WANDSTAFF "I don't buy used up wands or staves!" #define MSG_CANT_KILL_KEEPER "Get out of here before I call the guards!" diff --git a/src/spec_procs.c b/src/spec_procs.c index 7f3d80e..9ad4d2a 100644 --- a/src/spec_procs.c +++ b/src/spec_procs.c @@ -319,13 +319,6 @@ SPECIAL(sorceror) if (GET_LEVEL(ch) > 7 && rand_number(0, 8) == 0) cast_spell(ch, vict, NULL, SPELL_BLINDNESS); - if (GET_LEVEL(ch) > 12 && rand_number(0, 12) == 0) { - if (IS_EVIL(ch)) - cast_spell(ch, vict, NULL, SPELL_ENERGY_DRAIN); - else if (IS_GOOD(ch)) - cast_spell(ch, vict, NULL, SPELL_DISPEL_EVIL); - } - if (rand_number(0, 4)) return (TRUE); diff --git a/src/spells.c b/src/spells.c index 30b5aa2..7bdcda1 100644 --- a/src/spells.c +++ b/src/spells.c @@ -388,14 +388,7 @@ ASPELL(spell_enchant_weapon) obj->affected[1].location = APPLY_PROFICIENCY; obj->affected[1].modifier = 1 + (level >= 20); - if (IS_GOOD(ch)) { - SET_BIT_AR(GET_OBJ_EXTRA(obj), ITEM_ANTI_EVIL); - act("$p glows blue.", FALSE, ch, obj, 0, TO_CHAR); - } else if (IS_EVIL(ch)) { - SET_BIT_AR(GET_OBJ_EXTRA(obj), ITEM_ANTI_GOOD); - act("$p glows red.", FALSE, ch, obj, 0, TO_CHAR); - } else - act("$p glows yellow.", FALSE, ch, obj, 0, TO_CHAR); + act("$p glows yellow.", FALSE, ch, obj, 0, TO_CHAR); } ASPELL(spell_detect_poison) diff --git a/src/structs.h b/src/structs.h index 7d753b4..22473cd 100644 --- a/src/structs.h +++ b/src/structs.h @@ -255,9 +255,9 @@ #define MOB_AGGRESSIVE 5 /**< Mob auto-attacks everybody nearby */ #define MOB_STAY_ZONE 6 /**< Mob shouldn't wander out of zone */ #define MOB_WIMPY 7 /**< Mob flees if severely injured */ -#define MOB_AGGR_EVIL 8 /**< Auto-attack any evil PC's */ -#define MOB_AGGR_GOOD 9 /**< Auto-attack any good PC's */ -#define MOB_AGGR_NEUTRAL 10 /**< Auto-attack any neutral PC's */ +#define MOB_AGGR_RESERVED1 8 /**< Reserved (unused) */ +#define MOB_AGGR_RESERVED2 9 /**< Reserved (unused) */ +#define MOB_AGGR_RESERVED3 10 /**< Reserved (unused) */ #define MOB_MEMORY 11 /**< remember attackers if attacked */ #define MOB_HELPER 12 /**< attack PCs fighting other NPCs */ #define MOB_NOCHARM 13 /**< Mob can't be charmed */ @@ -321,8 +321,8 @@ #define AFF_CURSE 10 /**< Char is cursed */ #define AFF_INFRAVISION 11 /**< Char can see in dark */ #define AFF_POISON 12 /**< (R) Char is poisoned */ -#define AFF_PROTECT_EVIL 13 /**< Char protected from evil */ -#define AFF_PROTECT_GOOD 14 /**< Char protected from good */ +#define AFF_RESERVED13 13 /**< Reserved (unused) */ +#define AFF_RESERVED14 14 /**< Reserved (unused) */ #define AFF_SLEEP 15 /**< (R) Char magically asleep */ #define AFF_NOTRACK 16 /**< Char can't be tracked */ #define AFF_FLYING 17 /**< Char is flying */ @@ -474,9 +474,9 @@ #define ITEM_MAGIC 6 /**< Item is magical */ #define ITEM_NODROP 7 /**< Item is cursed: can't drop */ #define ITEM_BLESS 8 /**< Item is blessed */ -#define ITEM_ANTI_GOOD 9 /**< Not usable by good people */ -#define ITEM_ANTI_EVIL 10 /**< Not usable by evil people */ -#define ITEM_ANTI_NEUTRAL 11 /**< Not usable by neutral people */ +#define ITEM_RESERVED9 9 /**< Reserved (unused) */ +#define ITEM_RESERVED10 10 /**< Reserved (unused) */ +#define ITEM_RESERVED11 11 /**< Reserved (unused) */ #define ITEM_ANTI_SORCEROR 12 /**< Not usable by sorcerors */ #define ITEM_ANTI_CLERIC 13 /**< Not usable by clerics */ #define ITEM_ANTI_ROGUE 14 /**< Not usable by rogues */ diff --git a/src/util/plrtoascii.c b/src/util/plrtoascii.c index daeb277..398cb72 100755 --- a/src/util/plrtoascii.c +++ b/src/util/plrtoascii.c @@ -59,7 +59,7 @@ struct char_point_data_plrtoascii { * in player_special_data. */ struct char_special_data_saved_plrtoascii { - int alignment; /* +-1000 for alignments */ + int alignment; long idnum; /* player's idnum; -1 for mobiles */ long /*bitvector_t*/ act; /* act flag for NPC's; player flag for PC's */ @@ -212,8 +212,6 @@ void convert(char *filename) /* char_special_data_saved */ csds = &(player.char_specials_saved); - if (csds->alignment != PFDEF_ALIGNMENT) - fprintf(outfile, "Alin: %d\n", csds->alignment); fprintf(outfile, "Id : %d\n", (int)csds->idnum); if (csds->act != PFDEF_PLRFLAGS) fprintf(outfile, "Act : %d\n", (int)csds->act); diff --git a/src/utils.h b/src/utils.h index 2fd607d..49a3b74 100644 --- a/src/utils.h +++ b/src/utils.h @@ -749,13 +749,6 @@ do \ #define CAN_SEE_IN_DARK(ch) \ (AFF_FLAGGED(ch, AFF_INFRAVISION) || (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_HOLYLIGHT))) -/** Defines if ch is good. */ -#define IS_GOOD(ch) (GET_ALIGNMENT(ch) >= 350) -/** Defines if ch is evil. */ -#define IS_EVIL(ch) (GET_ALIGNMENT(ch) <= -350) -/** Defines if ch is neither good nor evil. */ -#define IS_NEUTRAL(ch) (!IS_GOOD(ch) && !IS_EVIL(ch)) - /** Old wait state function. * @deprecated Use GET_WAIT_STATE */ #define WAIT_STATE(ch, cycle) do { GET_WAIT_STATE(ch) = (cycle); } while(0) From 8fe4702bbce85f841ebe082a8fa22508a5495b7f Mon Sep 17 00:00:00 2001 From: kinther Date: Tue, 30 Dec 2025 10:12:10 -0800 Subject: [PATCH 20/40] Initial AGENTS.md commit --- AGENTS.md | 220 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..8c86bd6 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,220 @@ +# AGENTS.md + +## Purpose + +This file defines the rules, expectations, and constraints for **automated agents** +(including AI coding assistants, LLMs, bots, and scripted tools) contributing to this +codebase. + +The goal is to: +- Preserve long-term maintainability +- Avoid licensing and provenance risk +- Prevent architectural drift +- Ensure consistency with established design decisions +- Make human review straightforward and reliable + +All automated agents MUST comply with the requirements in this document. + +--- + +## Scope + +This repository is a **C-based MUD engine** derived from CircleMUD/tbaMUD and is +under active development, including significant refactors to core systems such as: + +- Skills and proficiency +- Combat resolution +- Object and mobile data models +- Online Creation (OLC) +- Persistence and serialization +- Builder and immortal tooling + +Changes often have **far-reaching consequences** across gameplay, balance, and +world data integrity. + +--- + +## General Rules for Automated Agents + +### 1. No Unreviewed Structural Changes + +Automated agents MUST NOT: +- Reorganize directories +- Rename files +- Merge or split source files +- Introduce new subsystems +- Replace existing systems wholesale + +Unless **explicitly instructed** to do so. + +Incremental, targeted changes are required. + +--- + +### 2. Preserve Existing Behavior Unless Directed + +If a function, macro, or subsystem already exists: +- Do NOT change semantics +- Do NOT “simplify” logic +- Do NOT remove edge-case handling +- Do NOT refactor stylistically + +Unless the user **explicitly requests** that behavior be changed. + +Backward compatibility is a priority. + +--- + +### 3. Minimal Diffs Are Mandatory + +Automated agents must: +- Change only what is necessary +- Avoid drive-by formatting edits +- Avoid re-indentation unless required +- Avoid renaming variables unless necessary for correctness + +If a fix can be achieved with a 3-line change, a 30-line rewrite is unacceptable. + +--- + +### 4. Follow Existing Code Style Exactly + +This codebase intentionally reflects legacy CircleMUD conventions. + +Agents MUST: +- Match indentation style +- Match brace placement +- Match naming conventions +- Match macro usage patterns + +Do not introduce modern C idioms, new abstractions, or stylistic preferences. + +--- + +## Licensing and Provenance Requirements + +### 5. No Third-Party Code Injection + +Automated agents MUST NOT: +- Paste code from external projects +- Introduce snippets from blogs, gists, StackOverflow, or forums +- Reproduce code from GPL-incompatible sources + +All code must be **original**, **derivative of existing repository code**, or +**explicitly authorized** by the user. + +If uncertain, ask before proceeding. + +--- + +### 6. Do Not Assume License Changes + +Do NOT: +- Modify license headers +- Remove attribution +- Add new license files +- Assume relicensing is permitted + +Licensing is handled deliberately and conservatively. + +--- + +## Technical Expectations + +### 7. Full-Context Awareness Required + +Before modifying a subsystem, automated agents MUST: +- Read all related `.c` and `.h` files +- Identify existing macros, helpers, and patterns +- Understand how data flows through the system + +Guessing or partial understanding is not acceptable. + +--- + +### 8. Prefer Existing Helpers and Macros + +If functionality already exists: +- Reuse it +- Extend it minimally if needed +- Do not reimplement logic elsewhere + +Duplication increases maintenance cost and risk. + +--- + +### 9. Explicitly Note Assumptions + +When producing code or recommendations, agents MUST: +- State assumptions clearly +- Identify uncertainties +- Call out areas that require human confirmation + +Silent assumptions are dangerous. + +--- + +## Data Integrity and World Safety + +### 10. Protect World Files and Player Data + +Automated agents must treat: +- World files +- Player files +- OLC data +- Serialized objects/mobs/rooms + +As **production data**. + +Do NOT: +- Change file formats casually +- Break backward compatibility +- Introduce implicit migrations + +Any data format change must be explicit and documented. + +--- + +## Communication Expectations + +### 11. Be Direct and Precise + +Agent output should: +- Use technical language appropriate to experienced developers +- Avoid verbosity for its own sake +- Avoid motivational or conversational filler +- Focus on correctness and clarity + +--- + +### 12. Ask Before Acting When Uncertain + +If instructions are ambiguous or risky: +- STOP +- Ask clarifying questions +- Do not guess intent + +Incorrect confidence is worse than delay. + +--- + +## Enforcement + +Failure to comply with this document may result in: +- Rejection of changes +- Reversion of commits +- Loss of permission to contribute + +This applies equally to humans and automated agents. + +--- + +## Summary + +This codebase prioritizes: +- Stability over novelty +- Clarity over cleverness +- Intentional design over convenience + +Automated agents are welcome collaborators **only** when they operate within +these constraints. From b8e581884b98f3996d12ebc949fb14c826db4a14 Mon Sep 17 00:00:00 2001 From: kinther Date: Tue, 30 Dec 2025 12:22:47 -0800 Subject: [PATCH 21/40] Fix player menu change after death --- src/handler.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/handler.c b/src/handler.c index 314dba7..3b2acbc 100644 --- a/src/handler.c +++ b/src/handler.c @@ -985,6 +985,13 @@ void extract_char_final(struct char_data *ch) STATE(d) = CON_CLOSE; } if (GET_POS(ch) == POS_DEAD) { + int pfilepos = GET_PFILEPOS(ch); + + if (pfilepos < 0) + pfilepos = get_ptable_by_name(GET_NAME(ch)); + if (pfilepos >= 0) + SET_BIT(player_table[pfilepos].flags, PINDEX_DELETED); + STATE(ch->desc) = CON_ACCOUNT_MENU; send_account_menu(ch->desc); ch->desc->character = NULL; From 7b49ddd9d7866474f5cddcecb34ee9a21b370452 Mon Sep 17 00:00:00 2001 From: kinther Date: Tue, 30 Dec 2025 12:30:25 -0800 Subject: [PATCH 22/40] Fix look direction bugs --- README.md | 1 + src/act.informative.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 69e1118..bc81ff2 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ Features to be implemented in the next few releases: * New elemental classes * Introduction of gathering mana/magic for sorceror class * Highly modified magic system +* Ranged weapons and ammo * Components for some magical spells * Reading/writing limited to specific castes of society * Haggling and bartering system diff --git a/src/act.informative.c b/src/act.informative.c index 957ff6b..b972054 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -900,7 +900,6 @@ static void look_in_direction(struct char_data *ch, int dir) int distance; bool blocked = FALSE; - send_to_char(ch, ">look %s\r\n\r\n", dirs[dir]); send_to_char(ch, "You look to the %s and see:\r\n", dirs[dir]); for (distance = 0; distance < 3; distance++) { @@ -987,7 +986,10 @@ static bool look_list_direction_chars(struct char_data *ch, room_rnum room) } if (CAN_SEE(ch, tch)) { - send_to_char(ch, "%s\r\n", get_char_sdesc(tch)); + char ldesc[MAX_STRING_LENGTH]; + + build_current_ldesc(tch, ldesc, sizeof(ldesc)); + send_to_char(ch, "%s\r\n", ldesc); found = TRUE; } } From ee735d612b12143e1c0945aa8c02e5eb44b06d2b Mon Sep 17 00:00:00 2001 From: kinther Date: Tue, 30 Dec 2025 12:31:15 -0800 Subject: [PATCH 23/40] Fix ldesc issue while sleeping --- src/interpreter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interpreter.c b/src/interpreter.c index 64b7687..1b63132 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -118,7 +118,7 @@ cpp_extern const struct command_info cmd_info[] = { { "cast" , "c" , POS_SITTING , do_cast , 1, 0 }, { "cedit" , "cedit" , POS_DEAD , do_oasis_cedit, LVL_IMPL, 0 }, - { "change" , "chang" , POS_RESTING , do_change , 0, 0 }, + { "change" , "chang" , POS_SLEEPING , do_change , 0, 0 }, { "changelog", "cha" , POS_DEAD , do_changelog, LVL_IMPL, 0 }, { "check" , "ch" , POS_STANDING, do_not_here , 1, 0 }, { "checkload", "checkl" , POS_DEAD , do_checkloadstatus, LVL_GOD, 0 }, From dedc5b7def3adae0233407d55049f030975b14f4 Mon Sep 17 00:00:00 2001 From: kinther Date: Tue, 30 Dec 2025 12:37:32 -0800 Subject: [PATCH 24/40] Remove ANTI_ class flags and restrictions --- doc/building.txt | 14 +++++--------- doc/coding.txt | 9 --------- lib/text/help/help.hlp | 29 +++++------------------------ src/class.c | 28 ++++------------------------ src/constants.c | 11 ----------- src/structs.h | 21 +++++---------------- 6 files changed, 19 insertions(+), 93 deletions(-) diff --git a/doc/building.txt b/doc/building.txt index 0d5f26c..1d3c84d 100644 --- a/doc/building.txt +++ b/doc/building.txt @@ -1020,21 +1020,17 @@ but has no substantive effect otherwise. The flags have the following values: 1) GLOW Item is glowing (cosmetic). 2) HUM Item is humming (cosmetic). -3) RESERVED Reserved (unused). +3) UNUSED Reserved (unused). 4) NODONATE Item cannot be donated. 5) NOINVIS Item cannot be made invisible. 6) INVISIBLE Item is invisible. 7) MAGIC Item has a magical aura and cannot be enchanted. 8) NODROP Item is cursed and cannot be removed or dropped. 9) BLESS Item is blessed (cosmetic). -10) RESERVED Not used. -11) RESERVED Not used. -12) RESERVED Not used. -13) ANTI_MAGIC_USER Item cannot be used by the Mage class. -14) ANTI_CLERIC Item cannot be used by the Cleric class. -15) ANTI_THIEF Item cannot be used by the Thief class. -16) ANTI_WARRIOR Item cannot be used by the Warrior class. -17) NOSELL Shopkeepers will not buy or sell the item. +10) NOSELL Shopkeepers will not buy or sell the item. +11) QUEST_ITEM Shopkeepers will only accept questpoints for this item. +12) HOOD_UP WORN item hood is currently up. +13) SKINNED Item/corpse can be skinned. Wear Bitvector A bitvector (see section 2.4 on ‘Using Bitvectors’) with the following values: diff --git a/doc/coding.txt b/doc/coding.txt index 6b50241..eabc075 100644 --- a/doc/coding.txt +++ b/doc/coding.txt @@ -1418,15 +1418,6 @@ search for CLASS_UNDEFINEDand add a new CLASS_xxxdefinition for your class name with the next available number. Remember to bump the value of NUM_CLASSES, just below, by 1. -Then search structs.hfor "Extra object flags" so you can add an "ITEM_ANTI_xxx" -flag for your new class. As before, use the next available number in the sequence -for ITEM_xxx flags. - -The "ITEM_xxx" extra flags have a corresponding text description in constants.c, so -search it for "ITEM_x (extra bits)". Add a string giving a short name for the new -ITEM_ANTI_xxx flag, in the appropriate order, before the "\n" entry near the -bottom. - The shops have a similar "don’t trade" setup, so search shop.h for "TRADE_NOSORCEROR" to add a new TRADE_NOxxx item to the list for the class to be added. Below that (near "NOTRADE_SORCEROR"), a line will need to be added for each new class so the ’no diff --git a/lib/text/help/help.hlp b/lib/text/help/help.hlp index c04f09d..79f623e 100644 --- a/lib/text/help/help.hlp +++ b/lib/text/help/help.hlp @@ -5793,36 +5793,17 @@ OEDIT-EXTRA-FLAGS OEDIT-FLAGS OBJECT-FLAGS OBJECTFLAGS GLOW HUM NODROP NO_DROP O 1) GLOW Item is glowing (cosmetic). 2) HUM Item is humming (cosmetic). +3) UNUSED Reserved (unused). 4) NODONATE Item cannot be donated. 5) NOINVIS Item cannot be made invisible. 6) INVISIBLE Item is invisible. 7) MAGIC Item has a magical aura and cannot be enchanted. 8) NODROP Item is cursed and cannot be removed or dropped. 9) BLESS Item is blessed (cosmetic). -10) RESERVED Not used. -11) RESERVED Not used. -12) RESERVED Not used. -13) ANTI_MAGIC_USER Item cannot be used by the Mage class. -14) ANTI_CLERIC Item cannot be used by the Cleric class. -15) ANTI_THIEF Item cannot be used by the Thief class. -16) ANTI_WARRIOR Item cannot be used by the Warrior class. -17) NOSELL Shopkeepers will not buy or sell the item. -18) QUEST_ITEM Shopkeepers will only accept questpoints for this item. - - Always try to promote role-playing. The last thing you should do is have -Thieves running around wearing dangly bracelets making noise, Clerics and Mages -wearing large suits of armor and Warriors wearing delicate clothing. None of -that makes sense! So, use your head a little while creating equipment. If the -equipment gives addition hitpoints then it should probably be made of metal and -should be geared for Warrior types. We do not need Mages out there with bonus -hitpoints on all their eq. - Class and Race restrictions are very important. Be sure to know what your -MUD uses for both and build for them. For example, a Minotaur would not wear -a regular helmet on his head. Minotaurs take pride in their horns, so their -horns must be showing. Minotaurs also have hooves for feet. It would be tough -for most to wear regular boots. Use some common sense when creating your -equipment. Think about each object you create. Think about who you are creating -it for. +10) NOSELL Shopkeepers will not buy or sell the item. +11) QUEST_ITEM Shopkeepers will only accept questpoints for this item. +12) HOOD_UP WORN item hood is currently up. +13) SKINNED Item/corpse can be skinned. #2 OEDIT-ITEM-NUMBER OEDIT-NUMBER diff --git a/src/class.c b/src/class.c index ae7e43a..a801670 100644 --- a/src/class.c +++ b/src/class.c @@ -726,32 +726,12 @@ int backstab_mult(int level) } /* invalid_class is used by handler.c to determine if a piece of equipment is - * usable by a particular class, based on the ITEM_ANTI_{class} bitvectors. */ + * usable by a particular class. Class-based anti item flags are no longer + * enforced. */ int invalid_class(struct char_data *ch, struct obj_data *obj) { - if (OBJ_FLAGGED(obj, ITEM_ANTI_SORCEROR) && IS_SORCEROR(ch)) - return TRUE; - - if (OBJ_FLAGGED(obj, ITEM_ANTI_CLERIC) && IS_CLERIC(ch)) - return TRUE; - - if (OBJ_FLAGGED(obj, ITEM_ANTI_FIGHTER) && IS_FIGHTER(ch)) - return TRUE; - - if (OBJ_FLAGGED(obj, ITEM_ANTI_ROGUE) && IS_ROGUE(ch)) - return TRUE; - - if (OBJ_FLAGGED(obj, ITEM_ANTI_BARBARIAN) && IS_BARBARIAN(ch)) - return TRUE; - - if (OBJ_FLAGGED(obj, ITEM_ANTI_RANGER) && IS_RANGER(ch)) - return TRUE; - - if (OBJ_FLAGGED(obj, ITEM_ANTI_BARD) && IS_BARD(ch)) - return TRUE; - - if (OBJ_FLAGGED(obj, ITEM_ANTI_DRUID) && IS_DRUID(ch)) - return TRUE; + (void) ch; + (void) obj; return FALSE; } diff --git a/src/constants.c b/src/constants.c index 4a2d915..6fe471b 100644 --- a/src/constants.c +++ b/src/constants.c @@ -485,17 +485,6 @@ const char *extra_bits[] = { "MAGIC", "NO_DROP", "BLESS", - "RESERVED", - "RESERVED", - "RESERVED", - "ANTI_SORCEROR", - "ANTI_CLERIC", - "ANTI_ROGUE", - "ANTI_FIGHTER", - "ANTI_BARBARIAN", - "ANTI_RANGER", - "ANTI_BARD", - "ANTI_DRUID", "NO_SELL", "QUEST_ITEM", "HOOD_UP", diff --git a/src/structs.h b/src/structs.h index 22473cd..9653622 100644 --- a/src/structs.h +++ b/src/structs.h @@ -474,23 +474,12 @@ #define ITEM_MAGIC 6 /**< Item is magical */ #define ITEM_NODROP 7 /**< Item is cursed: can't drop */ #define ITEM_BLESS 8 /**< Item is blessed */ -#define ITEM_RESERVED9 9 /**< Reserved (unused) */ -#define ITEM_RESERVED10 10 /**< Reserved (unused) */ -#define ITEM_RESERVED11 11 /**< Reserved (unused) */ -#define ITEM_ANTI_SORCEROR 12 /**< Not usable by sorcerors */ -#define ITEM_ANTI_CLERIC 13 /**< Not usable by clerics */ -#define ITEM_ANTI_ROGUE 14 /**< Not usable by rogues */ -#define ITEM_ANTI_FIGHTER 15 /**< Not usable by fighters */ -#define ITEM_ANTI_BARBARIAN 16 /**< Not usable by barbarians */ -#define ITEM_ANTI_RANGER 17 /**< Not usable by rangers */ -#define ITEM_ANTI_BARD 18 /**< Not usable by bards */ -#define ITEM_ANTI_DRUID 19 /**< Not usable by druids */ -#define ITEM_NOSELL 20 /**< Shopkeepers won't touch it */ -#define ITEM_QUEST 21 /**< Item is a quest item */ -#define ITEM_HOOD_UP 22 /**< WORN item hood is currently up */ -#define ITEM_SKINNED 23 /* Item/corpse can be skinned */ +#define ITEM_NOSELL 9 /**< Shopkeepers won't touch it */ +#define ITEM_QUEST 10 /**< Item is a quest item */ +#define ITEM_HOOD_UP 11 /**< WORN item hood is currently up */ +#define ITEM_SKINNED 12 /* Item/corpse can be skinned */ /** Total number of item flags */ -#define NUM_ITEM_FLAGS 24 +#define NUM_ITEM_FLAGS 13 /* Modifier constants used with obj affects ('A' fields) */ #define APPLY_NONE 0 /**< No effect */ From b6bbe522bbb61ea952fa2757a566c16760c7c884 Mon Sep 17 00:00:00 2001 From: kinther Date: Tue, 30 Dec 2025 13:31:56 -0800 Subject: [PATCH 25/40] Mount update 1 --- README.md | 5 +- lib/world/mob/1.mob | 70 ++++++++++++----- src/act.h | 2 + src/act.informative.c | 104 ++++++++++++++++++++++++- src/act.movement.c | 177 ++++++++++++++++++++++++++++++++++++++++-- src/constants.c | 2 + src/handler.c | 16 ++++ src/interpreter.c | 2 + src/mobact.c | 1 + src/structs.h | 8 +- src/utils.h | 4 + 11 files changed, 359 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index bc81ff2..de12984 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,9 @@ Changes in v1.1.0-alpha: * "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 - * Removed alignment from game - no more GOOD/EVIL flags and restrictions on items/shops + * Removed alignment from game - no more GOOD/EVIL flags or restrictions on shops + * Removed ANTI_ flags related to class restrictions on what objects they can use + * Mounts added to help with long trips, and ability to use them as pack animals Features to be implemented in the next few releases: @@ -68,7 +70,6 @@ Features to be implemented in the next few releases: * SECTOR/ROOM type changes to make terrain movement easier or more difficult * Subclass selection to personalize character further * Combat is slowed down so it isn't over in < 15 seconds (unless you're far outmatched) -* Mounts added to help with long trips * Wagons added to help with caravans * BUILDING object type created to allow enter/leave * Updated BUILDING object type so that it can be damaged and no longer enterable (but someone can leave at cost to health) diff --git a/lib/world/mob/1.mob b/lib/world/mob/1.mob index 6defa73..3be2f7b 100644 --- a/lib/world/mob/1.mob +++ b/lib/world/mob/1.mob @@ -20,6 +20,7 @@ B + ~ 6218 0 0 0 0 0 0 0 0 E 1 3d20+40 @@ -38,17 +39,17 @@ Skill 145 5 Skill 146 5 Skill 147 5 E -L 3 118 1 -L 5 131 1 -L 6 110 1 -L 7 108 1 -L 8 115 1 -L 9 124 1 -L 10 107 1 -L 11 111 1 -L 15 117 1 -L 16 117 1 L 17 127 1 +L 16 117 1 +L 15 117 1 +L 11 111 1 +L 10 107 1 +L 9 124 1 +L 8 115 1 +L 7 108 1 +L 6 110 1 +L 5 131 1 +L 3 118 1 #101 Sally~ slim lanky human soldier guard~ @@ -72,6 +73,7 @@ B + ~ 6218 0 0 0 0 0 0 0 0 E 1 3d20+40 @@ -92,17 +94,17 @@ Skill 152 5 Skill 156 5 Skill 163 5 E -L 17 127 1 -L 16 117 1 -L 15 117 1 -L 11 111 1 -L 10 107 1 -L 9 124 1 -L 8 115 1 -L 7 108 1 -L 6 110 1 -L 5 131 1 L 3 118 1 +L 5 131 1 +L 6 110 1 +L 7 108 1 +L 8 115 1 +L 9 124 1 +L 10 107 1 +L 11 111 1 +L 15 117 1 +L 16 117 1 +L 17 127 1 #102 Baldy~ barkeep stocky bald~ @@ -126,13 +128,14 @@ B + ~ 10 0 0 0 0 0 0 0 0 E 1 3d12+60 8 8 1 E -L 14 113 1 L 9 112 1 +L 14 113 1 #103 Lanky~ woman lanky scarred~ @@ -157,6 +160,7 @@ B + ~ 10 0 0 0 0 0 0 0 0 E 1 3d8+60 @@ -191,6 +195,7 @@ B + It's a rat. ~ 8 0 0 0 0 0 0 0 0 E @@ -206,4 +211,27 @@ Species: 25 Age: 42 AtkT 4 E +#105 +Kank~ +kank sandy brown~ +a sandy brown kank~ +A sandy brown kank is here, clacking its pincers. +~ +It looks unfinished. +~ +B +No background has been recorded. +~ +1048584 0 0 0 0 0 0 0 0 E +0 0d0+10 +8 8 0 +Str: 18 +Dex: 5 +Int: 2 +Wis: 7 +Con: 18 +Cha: 1 +Species: 21 +AtkT 4 +E $ diff --git a/src/act.h b/src/act.h index fc47183..38971b9 100644 --- a/src/act.h +++ b/src/act.h @@ -176,8 +176,10 @@ ACMD(do_gen_door); ACMD(do_enter); ACMD(do_follow); ACMD(do_leave); +ACMD(do_mount); ACMD(do_move); ACMD(do_rest); +ACMD(do_dismount); ACMD(do_sit); ACMD(do_sleep); ACMD(do_stand); diff --git a/src/act.informative.c b/src/act.informative.c index b972054..19d3328 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -569,6 +569,43 @@ static void list_one_char(struct char_data *i, struct char_data *ch) CCNRM(ch, C_NRM)); } + if (AFF_FLAGGED(i, AFF_MOUNTED) && MOUNT(i) && + IN_ROOM(MOUNT(i)) == IN_ROOM(i) && + MOB_FLAGGED(MOUNT(i), MOB_MOUNT)) { + const char *rdesc = get_char_sdesc(i); + const char *mdesc = get_char_sdesc(MOUNT(i)); + + if (rdesc && *rdesc) + send_to_char(ch, "%c%s", UPPER(*rdesc), rdesc + 1); + else + send_to_char(ch, "Someone"); + + if (mdesc && *mdesc) + send_to_char(ch, " is riding %s here.", mdesc); + else + send_to_char(ch, " is riding someone here."); + + if (AFF_FLAGGED(i, AFF_INVISIBLE)) + send_to_char(ch, " (invisible)"); + if (AFF_FLAGGED(i, AFF_HIDE)) + send_to_char(ch, " (hidden)"); + if (!IS_NPC(i) && !i->desc) + send_to_char(ch, " (linkless)"); + if (!IS_NPC(i) && PLR_FLAGGED(i, PLR_WRITING)) + send_to_char(ch, " (writing)"); + if (!IS_NPC(i) && PRF_FLAGGED(i, PRF_BUILDWALK)) + send_to_char(ch, " (buildwalk)"); + if (!IS_NPC(i) && PRF_FLAGGED(i, PRF_AFK)) + send_to_char(ch, " (AFK)"); + + send_to_char(ch, "\r\n"); + + if (AFF_FLAGGED(i, AFF_SANCTUARY)) + act("...$e glows with a bright light!", FALSE, i, 0, ch, TO_VICT); + + return; + } + /* Custom ldesc overrides position-based output. */ if (i->char_specials.custom_ldesc && i->player.long_descr) { if (AFF_FLAGGED(i, AFF_INVISIBLE)) @@ -692,6 +729,23 @@ static void build_current_ldesc(const struct char_data *ch, char *out, size_t ou return; } + if (AFF_FLAGGED(ch, AFF_MOUNTED) && MOUNT(ch) && + IN_ROOM(MOUNT(ch)) == IN_ROOM(ch) && + MOB_FLAGGED(MOUNT(ch), MOB_MOUNT)) { + const char *rdesc = get_char_sdesc(ch); + const char *mdesc = get_char_sdesc(MOUNT(ch)); + + if (!rdesc || !*rdesc) + rdesc = "someone"; + if (!mdesc || !*mdesc) + mdesc = "someone"; + + snprintf(out, outsz, "%c%s is riding %s here.", + UPPER(*rdesc), rdesc + 1, mdesc); + strip_trailing_crlf(out); + return; + } + if (ch->char_specials.custom_ldesc && ch->player.long_descr) { strlcpy(out, ch->player.long_descr, outsz); strip_trailing_crlf(out); @@ -746,6 +800,9 @@ static void list_char_to_char(struct char_data *list, struct char_data *ch) if (!IS_NPC(ch) && !PRF_FLAGGED(ch, PRF_HOLYLIGHT) && IS_NPC(i) && i->player.long_descr && *i->player.long_descr == '.') continue; + if (RIDDEN_BY(i) && IN_ROOM(RIDDEN_BY(i)) == IN_ROOM(i) && + CAN_SEE(ch, RIDDEN_BY(i))) + continue; send_to_char(ch, "%s", CCYEL(ch, C_NRM)); if (CAN_SEE(ch, i)) list_one_char(i, ch); @@ -972,6 +1029,9 @@ static bool look_list_direction_chars(struct char_data *ch, room_rnum room) if (!IS_NPC(ch) && !PRF_FLAGGED(ch, PRF_HOLYLIGHT) && IS_NPC(tch) && tch->player.long_descr && *tch->player.long_descr == '.') continue; + if (RIDDEN_BY(tch) && IN_ROOM(RIDDEN_BY(tch)) == room && + CAN_SEE(ch, RIDDEN_BY(tch))) + continue; if (AFF_FLAGGED(tch, AFF_HIDE)) { if (CAN_SEE(ch, tch) || look_can_spot_hidden(ch, tch, room)) { @@ -1135,6 +1195,42 @@ static void look_at_target(struct char_data *ch, char *arg) return; } + if (!found_char) { + struct char_data *tch; + char tmp[MAX_INPUT_LENGTH]; + char *name = tmp; + int matchnum; + + strlcpy(tmp, arg, sizeof(tmp)); + matchnum = get_number(&name); + if (matchnum > 0) { + for (tch = world[IN_ROOM(ch)].people; tch && matchnum; tch = tch->next_in_room) { + if (tch == ch) + continue; + if (!AFF_FLAGGED(tch, AFF_MOUNTED)) + continue; + if (!CAN_SEE(ch, tch)) + continue; + if (isname(name, (char *)get_char_sdesc(tch))) { + if (--matchnum == 0) { + found_char = tch; + break; + } + } + } + } + } + + if (found_char != NULL) { + look_at_char(found_char, ch); + if (ch != found_char) { + if (CAN_SEE(found_char, ch)) + act("$n looks at you.", TRUE, ch, 0, found_char, TO_VICT); + act("$n looks at $N.", TRUE, ch, 0, found_char, TO_NOTVICT); + } + return; + } + /* Strip off "number." from 2.foo and friends. */ if (!(fnum = get_number(&arg))) { send_to_char(ch, "Look at what?\r\n"); @@ -1436,7 +1532,13 @@ ACMD(do_score) FIGHTING(ch) ? PERS(FIGHTING(ch), ch) : "thin air"); break; case POS_STANDING: - send_to_char(ch, "You are standing.\r\n"); + if (AFF_FLAGGED(ch, AFF_MOUNTED) && MOUNT(ch) && + IN_ROOM(MOUNT(ch)) == IN_ROOM(ch) && + MOB_FLAGGED(MOUNT(ch), MOB_MOUNT)) { + send_to_char(ch, "You are riding %s.\r\n", get_char_sdesc(MOUNT(ch))); + } else { + send_to_char(ch, "You are standing.\r\n"); + } break; default: send_to_char(ch, "You are floating.\r\n"); diff --git a/src/act.movement.c b/src/act.movement.c index 224993f..036c5ab 100644 --- a/src/act.movement.c +++ b/src/act.movement.c @@ -44,6 +44,9 @@ static bool validate_furniture_use(struct char_data *ch, struct obj_data *furnit bool already_there); static void attach_char_to_furniture(struct char_data *ch, struct obj_data *furniture); static const char *position_gerund(int pos); +static void clear_mount_state(struct char_data *ch); +static bool mount_skill_check(struct char_data *ch, int dc); +static bool resolve_mounted_move(struct char_data *ch, struct char_data **mount); /* simple function to determine if char can walk on water */ @@ -263,6 +266,67 @@ static const char *position_gerund(int pos) return "using"; } } + +static void clear_mount_state(struct char_data *ch) +{ + struct char_data *mount; + + if (!ch) + return; + + mount = MOUNT(ch); + if (mount && RIDDEN_BY(mount) == ch) + RIDDEN_BY(mount) = NULL; + MOUNT(ch) = NULL; + REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_MOUNTED); +} + +static bool mount_skill_check(struct char_data *ch, int dc) +{ + int total = roll_skill_check(ch, SKILL_ANIMAL_HANDLING, 0, NULL); + bool success = (total >= dc); + + gain_skill(ch, "animal handling", success); + return success; +} + +static bool resolve_mounted_move(struct char_data *ch, struct char_data **mount) +{ + struct char_data *mount_ch; + + if (!AFF_FLAGGED(ch, AFF_MOUNTED)) + return FALSE; + + mount_ch = MOUNT(ch); + if (!mount_ch || IN_ROOM(mount_ch) != IN_ROOM(ch)) { + clear_mount_state(ch); + send_to_char(ch, "You aren't mounted on anything.\r\n"); + return FALSE; + } + + if (!mount_skill_check(ch, 5)) { + send_to_char(ch, "%s refuses to move.\r\n", get_char_sdesc(mount_ch)); + act("$n tries to urge $N forward, but $N refuses to move.", + TRUE, ch, 0, mount_ch, TO_ROOM); + return FALSE; + } + + if (!mount_skill_check(ch, 3)) { + int dam = dice(1, 8); + + send_to_char(ch, "You are thrown from %s!\r\n", get_char_sdesc(mount_ch)); + act("$n is thrown from $N!", TRUE, ch, 0, mount_ch, TO_ROOM); + clear_mount_state(ch); + GET_POS(ch) = POS_RESTING; + WAIT_STATE(ch, PULSE_VIOLENCE); + damage(ch, ch, dam, TYPE_SUFFERING); + return FALSE; + } + + if (mount) + *mount = mount_ch; + return TRUE; +} /** Move a PC/NPC character from their current location to a new location. This * is the standard movement locomotion function that all normal walking * movement by characters should be sent through. This function also defines @@ -293,6 +357,9 @@ int do_simple_move(struct char_data *ch, int dir, int need_specials_check) /* How many stamina points are required to travel from was_in to going_to. * We redefine this later when we need it. */ int need_movement = 0; + /* Character whose stamina is used for movement (mounts override). */ + struct char_data *stamina_ch = ch; + bool mounted_move = FALSE; /* Contains the "leave" message to display to the was_in room. */ char leave_message[SMALL_BUFSIZE]; /*---------------------------------------------------------------------*/ @@ -406,10 +473,18 @@ int do_simple_move(struct char_data *ch, int dir, int need_specials_check) movement_loss[SECT(going_to)]) / 2; /* Move Point Requirement Check */ - if (GET_STAMINA(ch) < need_movement && !IS_NPC(ch)) + if (AFF_FLAGGED(ch, AFF_MOUNTED) && MOUNT(ch) && IN_ROOM(MOUNT(ch)) == was_in) + { + stamina_ch = MOUNT(ch); + mounted_move = TRUE; + } + + if (GET_STAMINA(stamina_ch) < need_movement && (mounted_move || !IS_NPC(ch))) { if (need_specials_check && ch->master) send_to_char(ch, "You are too exhausted to follow.\r\n"); + else if (mounted_move) + send_to_char(ch, "Your mount is too exhausted.\r\n"); else send_to_char(ch, "You are too exhausted.\r\n"); @@ -423,8 +498,8 @@ int do_simple_move(struct char_data *ch, int dir, int need_specials_check) /* Begin: the leave operation. */ /*---------------------------------------------------------------------*/ /* If applicable, subtract movement cost. */ - if (GET_LEVEL(ch) < LVL_IMMORT && !IS_NPC(ch)) - GET_STAMINA(ch) -= need_movement; + if (GET_LEVEL(ch) < LVL_IMMORT && (mounted_move || !IS_NPC(ch))) + GET_STAMINA(stamina_ch) -= need_movement; /* Generate the leave message and display to others in the was_in room. */ if (AFF_FLAGGED(ch, AFF_SNEAK)) { @@ -500,6 +575,7 @@ int perform_move(struct char_data *ch, int dir, int need_specials_check) { room_rnum was_in; struct follow_type *k, *next; + struct char_data *mount = NULL; if (ch == NULL || dir < 0 || dir >= NUM_OF_DIRS || FIGHTING(ch)) return (0); @@ -513,13 +589,22 @@ int perform_move(struct char_data *ch, int dir, int need_specials_check) else send_to_char(ch, "It seems to be closed.\r\n"); } else { - if (!ch->followers) - return (do_simple_move(ch, dir, need_specials_check)); - was_in = IN_ROOM(ch); + if (AFF_FLAGGED(ch, AFF_MOUNTED) && + !resolve_mounted_move(ch, &mount)) + return (0); + if (!do_simple_move(ch, dir, need_specials_check)) return (0); + if (mount && IN_ROOM(mount) == was_in) { + char_from_room(mount); + char_to_room(mount, IN_ROOM(ch)); + } + + if (!ch->followers) + return (1); + for (k = ch->followers; k; k = next) { next = k->next; if ((IN_ROOM(k->follower) == was_in) && @@ -941,6 +1026,11 @@ ACMD(do_stand) int ordinal = 0; int orig_pos = GET_POS(ch); + if (AFF_FLAGGED(ch, AFF_MOUNTED)) { + send_to_char(ch, "You must dismount first.\r\n"); + return; + } + if (*argument) { if (!extract_furniture_token(ch, argument, token, sizeof(token), "Stand")) return; @@ -1067,6 +1157,11 @@ ACMD(do_sit) int ordinal = 0; int orig_pos = GET_POS(ch); + if (AFF_FLAGGED(ch, AFF_MOUNTED)) { + send_to_char(ch, "You must dismount first.\r\n"); + return; + } + if (*argument) { if (!extract_furniture_token(ch, argument, token, sizeof(token), "Sit")) return; @@ -1175,6 +1270,11 @@ ACMD(do_rest) bool has_target = FALSE, used_number = FALSE; int ordinal = 0; + if (AFF_FLAGGED(ch, AFF_MOUNTED)) { + send_to_char(ch, "You must dismount first.\r\n"); + return; + } + if (*argument) { if (!extract_furniture_token(ch, argument, token, sizeof(token), "Rest")) return; @@ -1303,6 +1403,11 @@ ACMD(do_sleep) bool has_target = FALSE, used_number = FALSE; int ordinal = 0; + if (AFF_FLAGGED(ch, AFF_MOUNTED)) { + send_to_char(ch, "You must dismount first.\r\n"); + return; + } + if (*argument) { if (!extract_furniture_token(ch, argument, token, sizeof(token), "Sleep")) return; @@ -1484,6 +1589,66 @@ ACMD(do_follow) } } +ACMD(do_mount) +{ + char arg[MAX_INPUT_LENGTH]; + struct char_data *mount; + + one_argument(argument, arg); + + if (!*arg) { + send_to_char(ch, "Mount what?\r\n"); + return; + } + + if (AFF_FLAGGED(ch, AFF_MOUNTED)) { + send_to_char(ch, "You are already mounted.\r\n"); + return; + } + + if (!(mount = get_char_vis(ch, arg, NULL, FIND_CHAR_ROOM))) { + send_to_char(ch, "%s", CONFIG_NOPERSON); + return; + } + + if (mount == ch) { + send_to_char(ch, "You can't mount yourself.\r\n"); + return; + } + + if (!IS_NPC(mount) || !MOB_FLAGGED(mount, MOB_MOUNT)) { + send_to_char(ch, "You can't mount %s!\r\n", get_char_sdesc(mount)); + return; + } + + if (RIDDEN_BY(mount)) { + act("$N is already being ridden.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + + SET_BIT_AR(AFF_FLAGS(ch), AFF_MOUNTED); + MOUNT(ch) = mount; + RIDDEN_BY(mount) = ch; + + act("You mount $N.", FALSE, ch, 0, mount, TO_CHAR); + act("$n mounts $N.", TRUE, ch, 0, mount, TO_ROOM); +} + +ACMD(do_dismount) +{ + struct char_data *mount = MOUNT(ch); + + if (!AFF_FLAGGED(ch, AFF_MOUNTED) || !mount) { + clear_mount_state(ch); + send_to_char(ch, "You aren't mounted on anything.\r\n"); + return; + } + + act("You dismount $N.", FALSE, ch, 0, mount, TO_CHAR); + act("$n dismounts $N.", TRUE, ch, 0, mount, TO_ROOM); + clear_mount_state(ch); +} + ACMD(do_unfollow) { if (ch->master) { diff --git a/src/constants.c b/src/constants.c index 6fe471b..dd7a187 100644 --- a/src/constants.c +++ b/src/constants.c @@ -240,6 +240,7 @@ const char *action_bits[] = { "NO_BLIND", "NO_KILL", "DEAD", /* You should never see this. */ + "MOUNT", "\n" }; @@ -311,6 +312,7 @@ const char *affected_bits[] = "CHARM", "BANDAGED", "LISTEN", + "MOUNTED", "\n" }; diff --git a/src/handler.c b/src/handler.c index 3b2acbc..ec6c3d1 100644 --- a/src/handler.c +++ b/src/handler.c @@ -1003,6 +1003,22 @@ void extract_char_final(struct char_data *ch) } } + if (AFF_FLAGGED(ch, AFF_MOUNTED) || MOUNT(ch)) { + struct char_data *mount = MOUNT(ch); + if (mount && RIDDEN_BY(mount) == ch) + RIDDEN_BY(mount) = NULL; + MOUNT(ch) = NULL; + REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_MOUNTED); + } + if (RIDDEN_BY(ch)) { + struct char_data *rider = RIDDEN_BY(ch); + if (rider && MOUNT(rider) == ch) { + MOUNT(rider) = NULL; + REMOVE_BIT_AR(AFF_FLAGS(rider), AFF_MOUNTED); + } + RIDDEN_BY(ch) = NULL; + } + /* On with the character's assets... */ if (ch->followers || ch->master) die_follower(ch); diff --git a/src/interpreter.c b/src/interpreter.c index 1b63132..99a938a 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -137,6 +137,7 @@ cpp_extern const struct command_info cmd_info[] = { { "detach" , "detach" , POS_DEAD , do_detach , LVL_BUILDER, 0 }, { "diagnose" , "diag" , POS_RESTING , do_diagnose , 0, 0 }, { "dig" , "dig" , POS_DEAD , do_dig , LVL_BUILDER, 0 }, + { "dismount" , "dism" , POS_STANDING, do_dismount , 0, 0 }, { "display" , "disp" , POS_DEAD , do_display , 0, 0 }, { "drink" , "dri" , POS_RESTING , do_drink , 0, SCMD_DRINK }, { "drop" , "dro" , POS_RESTING , do_drop , 0, SCMD_DROP }, @@ -198,6 +199,7 @@ cpp_extern const struct command_info cmd_info[] = { { "last" , "last" , POS_DEAD , do_last , LVL_GOD, 0 }, { "leave" , "lea" , POS_STANDING, do_leave , 0, 0 }, { "list" , "lis" , POS_STANDING, do_not_here , 0, 0 }, + { "mount" , "mou" , POS_STANDING, do_mount , 0, 0 }, { "listen" , "lisn" , POS_RESTING , do_listen , 0, 0 }, { "links" , "lin" , POS_STANDING, do_links , LVL_GOD, 0 }, { "lock" , "loc" , POS_SITTING , do_gen_door , 0, SCMD_LOCK }, diff --git a/src/mobact.c b/src/mobact.c index 2e38d39..9f5bf34 100644 --- a/src/mobact.c +++ b/src/mobact.c @@ -81,6 +81,7 @@ void mobile_activity(void) ((door = rand_number(0, 18)) < DIR_COUNT) && CAN_GO(ch, door) && !ROOM_FLAGGED(EXIT(ch, door)->to_room, ROOM_NOMOB) && !ROOM_FLAGGED(EXIT(ch, door)->to_room, ROOM_DEATH) && + !RIDDEN_BY(ch) && (!MOB_FLAGGED(ch, MOB_STAY_ZONE) || (world[EXIT(ch, door)->to_room].zone == world[IN_ROOM(ch)].zone))) { diff --git a/src/structs.h b/src/structs.h index 9653622..ce16dcb 100644 --- a/src/structs.h +++ b/src/structs.h @@ -267,8 +267,9 @@ #define MOB_NOBLIND 17 /**< Mob can't be blinded */ #define MOB_NOKILL 18 /**< Mob can't be attacked */ #define MOB_NOTDEADYET 19 /**< (R) Mob being extracted */ +#define MOB_MOUNT 20 /**< Mob can be mounted */ -#define NUM_MOB_FLAGS 19 +#define NUM_MOB_FLAGS 21 /* Preference flags: used by char_data.player_specials.pref */ #define PRF_BRIEF 0 /**< Room descs won't normally be shown */ @@ -333,8 +334,9 @@ #define AFF_CHARM 22 /**< Char is charmed */ #define AFF_BANDAGED 23 /**< Character was bandaged recently */ #define AFF_LISTEN 24 /**< Actively eavesdropping */ +#define AFF_MOUNTED 25 /**< Riding a mount */ /** Total number of affect flags */ -#define NUM_AFF_FLAGS 25 +#define NUM_AFF_FLAGS 26 /* Modes of connectedness: used by descriptor_data.state */ #define CON_PLAYING 0 /**< Playing - Nominal state */ @@ -1005,6 +1007,8 @@ struct char_special_data struct char_data *fighting; /**< Target of fight; else NULL */ struct char_data *hunting; /**< Target of NPC hunt; else NULL */ struct obj_data *furniture; /**< Object being sat on/in; else NULL */ + struct char_data *mount; /**< Mount being ridden; else NULL */ + struct char_data *rider; /**< Rider, if being mounted; else NULL */ struct char_data *next_in_furniture; /**< Next person sitting, else NULL */ byte position; /**< Standing, fighting, sleeping, etc. */ diff --git a/src/utils.h b/src/utils.h index 49a3b74..cc7bbab 100644 --- a/src/utils.h +++ b/src/utils.h @@ -196,6 +196,10 @@ void advance_level(struct char_data *ch); void char_from_furniture(struct char_data *ch); /** What ch is currently sitting on. */ #define SITTING(ch) ((ch)->char_specials.furniture) +/** Mount ch is currently riding. */ +#define MOUNT(ch) ((ch)->char_specials.mount) +/** Rider currently mounted on ch. */ +#define RIDDEN_BY(ch) ((ch)->char_specials.rider) /** Who is sitting next to ch, if anyone. */ #define NEXT_SITTING(ch) ((ch)->char_specials.next_in_furniture) /** Who is sitting on this obj */ From 4ff54bf429148e277d3ba28f2f52219f0eecf88f Mon Sep 17 00:00:00 2001 From: kinther Date: Tue, 30 Dec 2025 13:36:11 -0800 Subject: [PATCH 26/40] Look directional bug fix --- src/act.informative.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/act.informative.c b/src/act.informative.c index 19d3328..3de0139 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -962,8 +962,6 @@ static void look_in_direction(struct char_data *ch, int dir) for (distance = 0; distance < 3; distance++) { struct room_direction_data *exit = NULL; - send_to_char(ch, "%s\r\n", range_labels[distance]); - if (!blocked) { exit = W_EXIT(room, dir); @@ -978,10 +976,13 @@ static void look_in_direction(struct char_data *ch, int dir) } if (blocked || !VALID_ROOM_RNUM(room)) { - send_to_char(ch, "nothing\r\n"); - continue; + if (distance == 0) + send_to_char(ch, "nothing\r\n"); + break; } + send_to_char(ch, "%s\r\n", range_labels[distance]); + if (!look_list_direction_chars(ch, room)) send_to_char(ch, "nothing\r\n"); } From 1b7a53f9534e807d9114e35e26c334459444de90 Mon Sep 17 00:00:00 2001 From: kinther Date: Tue, 30 Dec 2025 18:07:00 -0800 Subject: [PATCH 27/40] Mount update 2 --- README.md | 5 +- src/act.h | 4 + src/act.informative.c | 3 + src/act.movement.c | 405 +++++++++++++++++++++++++++++++++++++++++- src/act.wizard.c | 3 + src/handler.c | 17 +- src/interpreter.c | 4 + src/players.c | 4 + src/structs.h | 1 + src/utils.c | 2 + src/utils.h | 2 + 11 files changed, 447 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index de12984..0f186fe 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,8 @@ Changes in v1.1.0-alpha: Features to be implemented in the next few releases: +* Height and weight normalized to species +* Stables will take mounts and provide tickets to get them out * Updated door code so that it can be closed/locked/saved with rsave code * SECTOR/ROOM type changes to make terrain movement easier or more difficult * Subclass selection to personalize character further @@ -73,7 +75,8 @@ Features to be implemented in the next few releases: * Wagons added to help with caravans * BUILDING object type created to allow enter/leave * Updated BUILDING object type so that it can be damaged and no longer enterable (but someone can leave at cost to health) -* Plantlife introduced +* Plantlife introduced, allowing a plant object to produce fruit or herbs every few hours/days +* Plantlife can be refreshed to spawn fruits/herbs more frequently by watering it * Updated lockpicking skill * Trap as a skill - one focused on city and one focused on desert * Poisons and antidotes diff --git a/src/act.h b/src/act.h index 38971b9..02d27f2 100644 --- a/src/act.h +++ b/src/act.h @@ -175,14 +175,18 @@ ACMD(do_gen_door); /* Functions without subcommands */ ACMD(do_enter); ACMD(do_follow); +ACMD(do_hitch); ACMD(do_leave); ACMD(do_mount); ACMD(do_move); +ACMD(do_pack); ACMD(do_rest); ACMD(do_dismount); ACMD(do_sit); ACMD(do_sleep); ACMD(do_stand); +ACMD(do_unhitch); +ACMD(do_unpack); ACMD(do_unfollow); ACMD(do_wake); /* Global variables from act.movement.c */ diff --git a/src/act.informative.c b/src/act.informative.c index 3de0139..22d256c 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -1435,6 +1435,9 @@ ACMD(do_score) send_to_char(ch, "Sdesc: %s\r\n", sdesc && *sdesc ? sdesc : "someone"); send_to_char(ch, "Ldesc: %s\r\n", *ldesc ? ldesc : "None"); + send_to_char(ch, "Weight: %d Height: %d\r\n", + GET_WEIGHT(ch), GET_HEIGHT(ch)); + send_to_char(ch, "HP: %d/%d Mana: %d/%d Stamina: %d/%d\r\n", GET_HIT(ch), GET_MAX_HIT(ch), diff --git a/src/act.movement.c b/src/act.movement.c index 036c5ab..295cae4 100644 --- a/src/act.movement.c +++ b/src/act.movement.c @@ -47,6 +47,10 @@ static const char *position_gerund(int pos); static void clear_mount_state(struct char_data *ch); static bool mount_skill_check(struct char_data *ch, int dc); static bool resolve_mounted_move(struct char_data *ch, struct char_data **mount); +static int count_hitched_mounts(struct char_data *ch); +static int max_hitched_mounts(struct char_data *ch); +static struct char_data *first_hitched_mount_in_room(struct char_data *ch); +static struct char_data *find_hitched_mount_for_pack(struct char_data *ch, struct obj_data *obj); /* simple function to determine if char can walk on water */ @@ -275,8 +279,11 @@ static void clear_mount_state(struct char_data *ch) return; mount = MOUNT(ch); - if (mount && RIDDEN_BY(mount) == ch) + if (mount && RIDDEN_BY(mount) == ch) { + int rider_weight = GET_WEIGHT(ch) + IS_CARRYING_W(ch); + IS_CARRYING_W(mount) = MAX(0, IS_CARRYING_W(mount) - rider_weight); RIDDEN_BY(mount) = NULL; + } MOUNT(ch) = NULL; REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_MOUNTED); } @@ -327,6 +334,74 @@ static bool resolve_mounted_move(struct char_data *ch, struct char_data **mount) *mount = mount_ch; return TRUE; } + +static int count_hitched_mounts(struct char_data *ch) +{ + struct follow_type *follow; + int count = 0; + + if (!ch) + return 0; + + for (follow = ch->followers; follow; follow = follow->next) { + if (HITCHED_TO(follow->follower) == ch && + MOB_FLAGGED(follow->follower, MOB_MOUNT)) + count++; + } + + return count; +} + +static int max_hitched_mounts(struct char_data *ch) +{ + int skill = GET_SKILL(ch, SKILL_ANIMAL_HANDLING); + + if (skill > 59) + return 2; + return 1; +} + +static struct char_data *first_hitched_mount_in_room(struct char_data *ch) +{ + struct follow_type *follow; + + if (!ch) + return NULL; + + for (follow = ch->followers; follow; follow = follow->next) { + if (HITCHED_TO(follow->follower) == ch && + MOB_FLAGGED(follow->follower, MOB_MOUNT) && + IN_ROOM(follow->follower) == IN_ROOM(ch)) + return follow->follower; + } + + return NULL; +} + +static struct char_data *find_hitched_mount_for_pack(struct char_data *ch, struct obj_data *obj) +{ + struct follow_type *follow; + + if (!ch || !obj) + return NULL; + + for (follow = ch->followers; follow; follow = follow->next) { + struct char_data *mount = follow->follower; + + if (HITCHED_TO(mount) != ch || !MOB_FLAGGED(mount, MOB_MOUNT)) + continue; + if (IN_ROOM(mount) != IN_ROOM(ch)) + continue; + if ((IS_CARRYING_N(mount) + 1) > CAN_CARRY_N(mount)) + continue; + if ((IS_CARRYING_W(mount) + GET_OBJ_WEIGHT(obj)) > CAN_CARRY_W(mount)) + continue; + + return mount; + } + + return NULL; +} /** Move a PC/NPC character from their current location to a new location. This * is the standard movement locomotion function that all normal walking * movement by characters should be sent through. This function also defines @@ -1022,10 +1097,64 @@ ACMD(do_stand) { char token[MAX_INPUT_LENGTH]; struct obj_data *furniture = NULL, *current_furniture = SITTING(ch); + struct char_data *mount = NULL; + char arg[MAX_INPUT_LENGTH]; bool has_target = FALSE, used_number = FALSE; int ordinal = 0; int orig_pos = GET_POS(ch); + if (*argument) { + one_argument(argument, arg); + if (*arg && !is_abbrev(arg, "at")) + mount = get_char_vis(ch, arg, NULL, FIND_CHAR_ROOM); + if (mount && MOB_FLAGGED(mount, MOB_MOUNT) && HITCHED_TO(mount) != ch) { + act("You don't have $N hitched.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + if (mount && HITCHED_TO(mount) == ch && MOB_FLAGGED(mount, MOB_MOUNT)) { + if (FIGHTING(mount)) { + act("$N is fighting right now.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + if (GET_POS(mount) == POS_RESTING) { + act("You get $N to stand up.", FALSE, ch, 0, mount, TO_CHAR); + act("$n gets $N to stand up.", TRUE, ch, 0, mount, TO_ROOM); + GET_POS(mount) = POS_STANDING; + clear_custom_ldesc(mount); + return; + } + if (GET_POS(mount) == POS_SLEEPING) { + act("$N has to wake up first.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + act("$N is already standing.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + } + + if (!*argument && AFF_FLAGGED(ch, AFF_MOUNTED) && MOUNT(ch)) { + mount = MOUNT(ch); + if (IN_ROOM(mount) != IN_ROOM(ch) || RIDDEN_BY(mount) != ch) { + clear_mount_state(ch); + send_to_char(ch, "You aren't mounted on anything.\r\n"); + return; + } + if (FIGHTING(mount)) { + send_to_char(ch, "Your mount is fighting right now.\r\n"); + return; + } + if (GET_POS(mount) != POS_SLEEPING) { + act("You get $N to rest and dismount.", FALSE, ch, 0, mount, TO_CHAR); + act("$n gets $N to rest and dismounts.", TRUE, ch, 0, mount, TO_ROOM); + GET_POS(mount) = POS_RESTING; + clear_custom_ldesc(mount); + } else { + act("$N is already asleep.", FALSE, ch, 0, mount, TO_CHAR); + } + clear_mount_state(ch); + return; + } + if (AFF_FLAGGED(ch, AFF_MOUNTED)) { send_to_char(ch, "You must dismount first.\r\n"); return; @@ -1267,9 +1396,64 @@ ACMD(do_rest) { char token[MAX_INPUT_LENGTH]; struct obj_data *furniture = NULL, *current_furniture = SITTING(ch); + struct char_data *mount = NULL; + char arg[MAX_INPUT_LENGTH]; bool has_target = FALSE, used_number = FALSE; int ordinal = 0; + if (*argument) { + one_argument(argument, arg); + if (*arg && !is_abbrev(arg, "at")) + mount = get_char_vis(ch, arg, NULL, FIND_CHAR_ROOM); + if (mount && MOB_FLAGGED(mount, MOB_MOUNT) && HITCHED_TO(mount) != ch) { + act("You don't have $N hitched.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + if (mount && HITCHED_TO(mount) == ch && MOB_FLAGGED(mount, MOB_MOUNT)) { + if (FIGHTING(mount)) { + act("$N is fighting right now.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + if (GET_POS(mount) == POS_RESTING) { + act("$N is already resting.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + if (GET_POS(mount) == POS_SLEEPING) { + act("$N is already asleep.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + act("You pull on $N's reins, forcing it to rest.", FALSE, ch, 0, mount, TO_CHAR); + act("$n pulls on $N's reins, forcing it to rest.", TRUE, ch, 0, mount, TO_ROOM); + GET_POS(mount) = POS_RESTING; + clear_custom_ldesc(mount); + return; + } + } + + if (!*argument && AFF_FLAGGED(ch, AFF_MOUNTED) && MOUNT(ch)) { + mount = MOUNT(ch); + if (IN_ROOM(mount) != IN_ROOM(ch) || RIDDEN_BY(mount) != ch) { + clear_mount_state(ch); + send_to_char(ch, "You aren't mounted on anything.\r\n"); + return; + } + if (FIGHTING(mount)) { + send_to_char(ch, "Your mount is fighting right now.\r\n"); + return; + } + if (GET_POS(mount) == POS_SLEEPING) { + act("$N is already asleep.", FALSE, ch, 0, mount, TO_CHAR); + clear_mount_state(ch); + return; + } + act("You pull on $N's reins, forcing it to rest.", FALSE, ch, 0, mount, TO_CHAR); + act("$n pulls on $N's reins, forcing it to rest and dismounts.", TRUE, ch, 0, mount, TO_ROOM); + GET_POS(mount) = POS_RESTING; + clear_custom_ldesc(mount); + clear_mount_state(ch); + return; + } + if (AFF_FLAGGED(ch, AFF_MOUNTED)) { send_to_char(ch, "You must dismount first.\r\n"); return; @@ -1621,14 +1805,25 @@ ACMD(do_mount) return; } + if (HITCHED_TO(mount) && HITCHED_TO(mount) != ch) { + act("$N is already hitched to someone else.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + if (RIDDEN_BY(mount)) { act("$N is already being ridden.", FALSE, ch, 0, mount, TO_CHAR); return; } + if ((GET_WEIGHT(ch) + IS_CARRYING_W(ch) + IS_CARRYING_W(mount)) > CAN_CARRY_W(mount)) { + act("$N can't carry that much weight.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + SET_BIT_AR(AFF_FLAGS(ch), AFF_MOUNTED); MOUNT(ch) = mount; RIDDEN_BY(mount) = ch; + IS_CARRYING_W(mount) += GET_WEIGHT(ch) + IS_CARRYING_W(ch); act("You mount $N.", FALSE, ch, 0, mount, TO_CHAR); act("$n mounts $N.", TRUE, ch, 0, mount, TO_ROOM); @@ -1649,6 +1844,214 @@ ACMD(do_dismount) clear_mount_state(ch); } +ACMD(do_hitch) +{ + char arg[MAX_INPUT_LENGTH]; + struct char_data *mount; + int max_hitched; + + one_argument(argument, arg); + + if (!*arg) { + send_to_char(ch, "Hitch what?\r\n"); + return; + } + + if (!(mount = get_char_vis(ch, arg, NULL, FIND_CHAR_ROOM))) { + send_to_char(ch, "%s", CONFIG_NOPERSON); + return; + } + + if (mount == ch) { + send_to_char(ch, "You can't hitch yourself.\r\n"); + return; + } + + if (!IS_NPC(mount) || !MOB_FLAGGED(mount, MOB_MOUNT)) { + send_to_char(ch, "You can't hitch %s!\r\n", get_char_sdesc(mount)); + return; + } + + if (RIDDEN_BY(mount) && RIDDEN_BY(mount) != ch) { + act("$N is already being ridden.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + + if (HITCHED_TO(mount) == ch) { + act("$N is already hitched to you.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + + if (HITCHED_TO(mount) && HITCHED_TO(mount) != ch) { + act("$N is already hitched to someone else.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + + if (mount->master && mount->master != ch) { + act("$N is already following someone else.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + + max_hitched = max_hitched_mounts(ch); + if (count_hitched_mounts(ch) >= max_hitched) { + send_to_char(ch, "You can't hitch any more mounts.\r\n"); + return; + } + + if (!mount->master) + add_follower(mount, ch); + + HITCHED_TO(mount) = ch; + act("You hitch $N to you.", FALSE, ch, 0, mount, TO_CHAR); + act("$n hitches $N to $m.", TRUE, ch, 0, mount, TO_ROOM); +} + +ACMD(do_unhitch) +{ + char arg[MAX_INPUT_LENGTH]; + struct char_data *mount; + + one_argument(argument, arg); + + if (!*arg) { + send_to_char(ch, "Unhitch what?\r\n"); + return; + } + + if (!(mount = get_char_vis(ch, arg, NULL, FIND_CHAR_ROOM))) { + send_to_char(ch, "%s", CONFIG_NOPERSON); + return; + } + + if (HITCHED_TO(mount) != ch || !MOB_FLAGGED(mount, MOB_MOUNT)) { + act("You don't have $N hitched.", FALSE, ch, 0, mount, TO_CHAR); + return; + } + + if (mount->master == ch) + stop_follower(mount); + else + HITCHED_TO(mount) = NULL; + + act("You unhitch $N.", FALSE, ch, 0, mount, TO_CHAR); + act("$n unhitches $N.", TRUE, ch, 0, mount, TO_ROOM); +} + +ACMD(do_pack) +{ + char arg[MAX_INPUT_LENGTH]; + struct char_data *mount; + struct obj_data *obj; + struct follow_type *follow; + bool found_mount = FALSE; + + one_argument(argument, arg); + + if (!*arg) { + for (follow = ch->followers; follow; follow = follow->next) { + bool found_item = FALSE; + + mount = follow->follower; + if (HITCHED_TO(mount) != ch || !MOB_FLAGGED(mount, MOB_MOUNT)) + continue; + if (IN_ROOM(mount) != IN_ROOM(ch)) + continue; + + found_mount = TRUE; + send_to_char(ch, "Packed on %s:\r\n", get_char_sdesc(mount)); + + for (obj = mount->carrying; obj; obj = obj->next_content) { + if (GET_OBJ_TYPE(obj) != ITEM_CONTAINER) + continue; + if (!CAN_SEE_OBJ(ch, obj)) + continue; + send_to_char(ch, " %s\r\n", obj->short_description ? obj->short_description : "something"); + found_item = TRUE; + } + + if (!found_item) + send_to_char(ch, " Nothing.\r\n"); + } + + if (!found_mount) + send_to_char(ch, "You don't have any mounts hitched.\r\n"); + return; + } + + if (!(obj = get_obj_in_list_vis(ch, arg, NULL, ch->carrying))) { + send_to_char(ch, "You don't seem to have that.\r\n"); + return; + } + + if (GET_OBJ_TYPE(obj) != ITEM_CONTAINER) { + send_to_char(ch, "You can only pack containers onto a mount.\r\n"); + return; + } + + mount = find_hitched_mount_for_pack(ch, obj); + if (!mount) { + if (!first_hitched_mount_in_room(ch)) + send_to_char(ch, "You don't have any mounts hitched here.\r\n"); + else + send_to_char(ch, "Your mount can't carry that much.\r\n"); + return; + } + + obj_from_char(obj); + obj_to_char(obj, mount); + + act("You pack $p onto $N.", FALSE, ch, obj, mount, TO_CHAR); + act("$n packs $p onto $N.", TRUE, ch, obj, mount, TO_ROOM); +} + +ACMD(do_unpack) +{ + char arg[MAX_INPUT_LENGTH]; + struct char_data *mount; + struct obj_data *obj; + struct follow_type *follow; + + one_argument(argument, arg); + + if (!*arg) { + send_to_char(ch, "Unpack what?\r\n"); + return; + } + + for (follow = ch->followers; follow; follow = follow->next) { + mount = follow->follower; + + if (HITCHED_TO(mount) != ch || !MOB_FLAGGED(mount, MOB_MOUNT)) + continue; + if (IN_ROOM(mount) != IN_ROOM(ch)) + continue; + + obj = get_obj_in_list_vis(ch, arg, NULL, mount->carrying); + if (!obj) + continue; + if (GET_OBJ_TYPE(obj) != ITEM_CONTAINER) + continue; + + if (IS_CARRYING_N(ch) >= CAN_CARRY_N(ch)) { + send_to_char(ch, "You can't carry any more items.\r\n"); + return; + } + if ((IS_CARRYING_W(ch) + GET_OBJ_WEIGHT(obj)) > CAN_CARRY_W(ch)) { + send_to_char(ch, "You can't carry that much weight.\r\n"); + return; + } + + obj_from_char(obj); + obj_to_char(obj, ch); + + act("You unpack $p from $N.", FALSE, ch, obj, mount, TO_CHAR); + act("$n unpacks $p from $N.", TRUE, ch, obj, mount, TO_ROOM); + return; + } + + send_to_char(ch, "You don't have that packed on a hitched mount.\r\n"); +} + ACMD(do_unfollow) { if (ch->master) { diff --git a/src/act.wizard.c b/src/act.wizard.c index 67d6b70..487d2fd 100644 --- a/src/act.wizard.c +++ b/src/act.wizard.c @@ -1829,6 +1829,9 @@ static void do_stat_character(struct char_data *ch, struct char_data *k) GET_STR(k), GET_INT(k), GET_WIS(k), GET_DEX(k), GET_CON(k), GET_CHA(k)); + stat_table_row_fmt(ch, "Size", "Weight %d, Height %d", + GET_WEIGHT(k), GET_HEIGHT(k)); + stat_table_row_fmt(ch, "Saving Throws", "Str %+d Dex %+d Con %+d Int %+d Wis %+d Cha %+d", get_save_mod(k, ABIL_STR), diff --git a/src/handler.c b/src/handler.c index ec6c3d1..814e43b 100644 --- a/src/handler.c +++ b/src/handler.c @@ -446,6 +446,8 @@ void obj_to_char(struct obj_data *object, struct char_data *ch) RoomSave_mark_dirty_room(__rs_room); IS_CARRYING_W(ch) += GET_OBJ_WEIGHT(object); IS_CARRYING_N(ch)++; + if (AFF_FLAGGED(ch, AFF_MOUNTED) && MOUNT(ch) && RIDDEN_BY(MOUNT(ch)) == ch) + IS_CARRYING_W(MOUNT(ch)) += GET_OBJ_WEIGHT(object); autoquest_trigger_check(ch, NULL, object, AQ_OBJ_FIND); @@ -487,6 +489,11 @@ void obj_from_char(struct obj_data *object) IS_CARRYING_W(object->carried_by) -= GET_OBJ_WEIGHT(object); IS_CARRYING_N(object->carried_by)--; + if (AFF_FLAGGED(object->carried_by, AFF_MOUNTED) && + MOUNT(object->carried_by) && + RIDDEN_BY(MOUNT(object->carried_by)) == object->carried_by) + IS_CARRYING_W(MOUNT(object->carried_by)) = + MAX(0, IS_CARRYING_W(MOUNT(object->carried_by)) - GET_OBJ_WEIGHT(object)); object->carried_by = NULL; object->next_content = NULL; if (__rs_room != NOWHERE) @@ -559,6 +566,8 @@ void equip_char(struct char_data *ch, struct obj_data *obj, int pos) obj->worn_by = ch; obj->worn_on = pos; IS_CARRYING_W(ch) += GET_OBJ_WEIGHT(obj); + if (AFF_FLAGGED(ch, AFF_MOUNTED) && MOUNT(ch) && RIDDEN_BY(MOUNT(ch)) == ch) + IS_CARRYING_W(MOUNT(ch)) += GET_OBJ_WEIGHT(obj); if (GET_OBJ_TYPE(obj) == ITEM_ARMOR) GET_AC(ch) -= apply_ac(ch, pos); @@ -592,6 +601,9 @@ struct obj_data *unequip_char(struct char_data *ch, int pos) obj->worn_by = NULL; obj->worn_on = -1; IS_CARRYING_W(ch) -= GET_OBJ_WEIGHT(obj); + if (AFF_FLAGGED(ch, AFF_MOUNTED) && MOUNT(ch) && RIDDEN_BY(MOUNT(ch)) == ch) + IS_CARRYING_W(MOUNT(ch)) = + MAX(0, IS_CARRYING_W(MOUNT(ch)) - GET_OBJ_WEIGHT(obj)); if (GET_OBJ_TYPE(obj) == ITEM_ARMOR) GET_AC(ch) += apply_ac(ch, pos); @@ -1005,8 +1017,11 @@ void extract_char_final(struct char_data *ch) if (AFF_FLAGGED(ch, AFF_MOUNTED) || MOUNT(ch)) { struct char_data *mount = MOUNT(ch); - if (mount && RIDDEN_BY(mount) == ch) + if (mount && RIDDEN_BY(mount) == ch) { + int rider_weight = GET_WEIGHT(ch) + IS_CARRYING_W(ch); + IS_CARRYING_W(mount) = MAX(0, IS_CARRYING_W(mount) - rider_weight); RIDDEN_BY(mount) = NULL; + } MOUNT(ch) = NULL; REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_MOUNTED); } diff --git a/src/interpreter.c b/src/interpreter.c index 99a938a..ec99df7 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -181,6 +181,7 @@ cpp_extern const struct command_info cmd_info[] = { { "hold" , "hold" , POS_RESTING , do_grab , 1, 0 }, { "holylight", "holy" , POS_DEAD , do_gen_tog , LVL_IMMORT, SCMD_HOLYLIGHT }, { "house" , "house" , POS_RESTING , do_house , 0, 0 }, + { "hitch" , "hitc" , POS_STANDING, do_hitch , 0, 0 }, { "inventory", "i" , POS_DEAD , do_inventory, 0, 0 }, { "idea" , "ide" , POS_DEAD , do_ibt , 0, SCMD_IDEA }, @@ -233,6 +234,7 @@ cpp_extern const struct command_info cmd_info[] = { { "ocopy" , "ocopy" , POS_DEAD , do_oasis_copy, LVL_GOD, CON_OEDIT }, { "put" , "p" , POS_RESTING , do_put , 0, 0 }, + { "pack" , "pac" , POS_RESTING , do_pack , 0, 0 }, { "peace" , "pe" , POS_DEAD , do_peace , LVL_BUILDER, 0 }, { "pemote" , "pem" , POS_SLEEPING, do_pemote , 0, SCMD_PEMOTE }, { "phemote" , "phem" , POS_SLEEPING, do_phemote , 0, SCMD_PHEMOTE }, @@ -329,7 +331,9 @@ cpp_extern const struct command_info cmd_info[] = { { "unlock" , "unlock" , POS_SITTING , do_gen_door , 0, SCMD_UNLOCK }, { "unban" , "unban" , POS_DEAD , do_unban , LVL_GRGOD, 0 }, { "unaffect" , "unaffect", POS_DEAD , do_wizutil , LVL_GOD, SCMD_UNAFFECT }, + { "unhitch" , "unh" , POS_STANDING, do_unhitch , 0, 0 }, { "unfollow" , "unf" , POS_RESTING , do_unfollow , 0, 0 }, + { "unpack" , "unpa" , POS_RESTING , do_unpack , 0, 0 }, { "uptime" , "uptime" , POS_DEAD , do_date , LVL_GOD, SCMD_UPTIME }, { "use" , "use" , POS_SITTING , do_use , 1, SCMD_USE }, { "users" , "users" , POS_DEAD , do_users , LVL_GOD, 0 }, diff --git a/src/players.c b/src/players.c index eace528..9fffa7c 100644 --- a/src/players.c +++ b/src/players.c @@ -551,6 +551,10 @@ int load_char(const char *name, struct char_data *ch) update_roleplay_age(ch); ch->player.time.birth = time(0) - get_total_played_seconds(ch); affect_total(ch); + MOUNT(ch) = NULL; + RIDDEN_BY(ch) = NULL; + HITCHED_TO(ch) = NULL; + REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_MOUNTED); /* initialization for imms */ if (GET_LEVEL(ch) >= LVL_IMMORT) { diff --git a/src/structs.h b/src/structs.h index ce16dcb..9b3318f 100644 --- a/src/structs.h +++ b/src/structs.h @@ -1009,6 +1009,7 @@ struct char_special_data struct obj_data *furniture; /**< Object being sat on/in; else NULL */ struct char_data *mount; /**< Mount being ridden; else NULL */ struct char_data *rider; /**< Rider, if being mounted; else NULL */ + struct char_data *hitched_to; /**< Person this mount is hitched to; else NULL */ struct char_data *next_in_furniture; /**< Next person sitting, else NULL */ byte position; /**< Standing, fighting, sleeping, etc. */ diff --git a/src/utils.c b/src/utils.c index 894c1e9..7f63726 100644 --- a/src/utils.c +++ b/src/utils.c @@ -654,6 +654,8 @@ void stop_follower(struct char_data *ch) } ch->master = NULL; + if (HITCHED_TO(ch)) + HITCHED_TO(ch) = NULL; REMOVE_BIT_AR(AFF_FLAGS(ch), AFF_CHARM); } diff --git a/src/utils.h b/src/utils.h index cc7bbab..0b5f12e 100644 --- a/src/utils.h +++ b/src/utils.h @@ -200,6 +200,8 @@ void char_from_furniture(struct char_data *ch); #define MOUNT(ch) ((ch)->char_specials.mount) /** Rider currently mounted on ch. */ #define RIDDEN_BY(ch) ((ch)->char_specials.rider) +/** Person ch is hitched to. */ +#define HITCHED_TO(ch) ((ch)->char_specials.hitched_to) /** Who is sitting next to ch, if anyone. */ #define NEXT_SITTING(ch) ((ch)->char_specials.next_in_furniture) /** Who is sitting on this obj */ From a765351be9e78caf259ccdcb8959b780b57c3117 Mon Sep 17 00:00:00 2001 From: kinther Date: Wed, 31 Dec 2025 08:06:03 -0800 Subject: [PATCH 28/40] Alignment update 2 --- src/act.informative.c | 3 -- src/class.c | 6 ---- src/constants.c | 1 - src/magic.c | 15 --------- src/spell_parser.c | 9 ------ src/spells.h | 73 +++++++++++++++++++++---------------------- src/structs.h | 47 ++++++++++++++-------------- 7 files changed, 58 insertions(+), 96 deletions(-) diff --git a/src/act.informative.c b/src/act.informative.c index 22d256c..f101e7b 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -236,9 +236,6 @@ static void show_obj_modifiers(struct obj_data *obj, struct char_data *ch) if (OBJ_FLAGGED(obj, ITEM_INVISIBLE)) send_to_char(ch, " (invisible)"); - if (OBJ_FLAGGED(obj, ITEM_BLESS) && AFF_FLAGGED(ch, AFF_DETECT_ALIGN)) - send_to_char(ch, " ..It glows blue!"); - if (OBJ_FLAGGED(obj, ITEM_MAGIC) && AFF_FLAGGED(ch, AFF_DETECT_MAGIC)) send_to_char(ch, " ..It glows yellow!"); diff --git a/src/class.c b/src/class.c index a801670..76d6724 100644 --- a/src/class.c +++ b/src/class.c @@ -404,7 +404,6 @@ static void apply_class_skills(int chclass, struct char_data *ch) apply_class_skill(chclass, ch, SPELL_CREATE_FOOD, 5, 90); apply_class_skill(chclass, ch, SPELL_CREATE_WATER, 5, 90); apply_class_skill(chclass, ch, SPELL_DETECT_POISON, 5, 90); - apply_class_skill(chclass, ch, SPELL_DETECT_ALIGN, 5, 90); apply_class_skill(chclass, ch, SPELL_CURE_BLIND, 5, 90); apply_class_skill(chclass, ch, SPELL_BLESS, 5, 90); apply_class_skill(chclass, ch, SPELL_DETECT_INVIS, 5, 90); @@ -420,8 +419,6 @@ static void apply_class_skills(int chclass, struct char_data *ch) apply_class_skill(chclass, ch, SPELL_WORD_OF_RECALL, 5, 90); apply_class_skill(chclass, ch, SPELL_DARKNESS, 5, 90); apply_class_skill(chclass, ch, SPELL_EARTHQUAKE, 5, 90); - apply_class_skill(chclass, ch, SPELL_DISPEL_EVIL, 5, 90); - apply_class_skill(chclass, ch, SPELL_DISPEL_GOOD, 5, 90); apply_class_skill(chclass, ch, SPELL_SANCTUARY, 5, 90); apply_class_skill(chclass, ch, SPELL_CALL_LIGHTNING, 5, 90); apply_class_skill(chclass, ch, SPELL_HEAL, 5, 90); @@ -778,7 +775,6 @@ void init_spell_levels(void) spell_level(SPELL_CREATE_FOOD, CLASS_CLERIC, 1); spell_level(SPELL_CREATE_WATER, CLASS_CLERIC, 1); spell_level(SPELL_DETECT_POISON, CLASS_CLERIC, 1); - spell_level(SPELL_DETECT_ALIGN, CLASS_CLERIC, 1); spell_level(SPELL_CURE_BLIND, CLASS_CLERIC, 1); spell_level(SPELL_BLESS, CLASS_CLERIC, 1); spell_level(SPELL_DETECT_INVIS, CLASS_CLERIC, 1); @@ -794,8 +790,6 @@ void init_spell_levels(void) spell_level(SPELL_WORD_OF_RECALL, CLASS_CLERIC, 1); spell_level(SPELL_DARKNESS, CLASS_CLERIC, 1); spell_level(SPELL_EARTHQUAKE, CLASS_CLERIC, 1); - spell_level(SPELL_DISPEL_EVIL, CLASS_CLERIC, 1); - spell_level(SPELL_DISPEL_GOOD, CLASS_CLERIC, 1); spell_level(SPELL_SANCTUARY, CLASS_CLERIC, 1); spell_level(SPELL_CALL_LIGHTNING, CLASS_CLERIC, 1); spell_level(SPELL_HEAL, CLASS_CLERIC, 1); diff --git a/src/constants.c b/src/constants.c index dd7a187..d3fcbc4 100644 --- a/src/constants.c +++ b/src/constants.c @@ -290,7 +290,6 @@ const char *affected_bits[] = "\0", /* DO NOT REMOVE!! */ "BLIND", "INVIS", - "DET-ALIGN", "DET-INVIS", "DET-MAGIC", "SENSE-LIFE", diff --git a/src/magic.c b/src/magic.c index 9ca8389..ef1ade0 100644 --- a/src/magic.c +++ b/src/magic.c @@ -235,14 +235,6 @@ int mag_damage(int level, struct char_data *ch, struct char_data *victim, break; /* Mostly clerics */ - case SPELL_DISPEL_EVIL: - dam = dice(6, 8) + 6; - break; - case SPELL_DISPEL_GOOD: - dam = dice(6, 8) + 6; - break; - - case SPELL_CALL_LIGHTNING: dam = dice(7, 8) + 7; break; @@ -384,13 +376,6 @@ void mag_affects(int level, struct char_data *ch, struct char_data *victim, to_vict = "You feel very uncomfortable."; break; - case SPELL_DETECT_ALIGN: - af[0].duration = 12 + level; - SET_BIT_AR(af[0].bitvector, AFF_DETECT_ALIGN); - accum_duration = TRUE; - to_vict = "Your eyes tingle."; - break; - case SPELL_DETECT_INVIS: af[0].duration = 12 + level; SET_BIT_AR(af[0].bitvector, AFF_DETECT_INVIS); diff --git a/src/spell_parser.c b/src/spell_parser.c index 6943ff9..a8a7d87 100644 --- a/src/spell_parser.c +++ b/src/spell_parser.c @@ -795,9 +795,6 @@ void mag_assign_spells(void) { spello(SPELL_DARKNESS, "darkness", 30, 5, 4, POS_STANDING, TAR_IGNORE, FALSE, MAG_ROOMS, NULL); - spello(SPELL_DETECT_ALIGN, "detect alignment", 20, 10, 2, POS_STANDING, - TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS, "You feel less aware."); - spello(SPELL_DETECT_INVIS, "detect invisibility", 20, 10, 2, POS_STANDING, TAR_CHAR_ROOM | TAR_SELF_ONLY, FALSE, MAG_AFFECTS, "Your eyes stop tingling."); @@ -810,12 +807,6 @@ void mag_assign_spells(void) { TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_ROOM, FALSE, MAG_MANUAL, "The detect poison wears off."); - spello(SPELL_DISPEL_EVIL, "dispel evil", 40, 25, 3, POS_FIGHTING, - TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); - - spello(SPELL_DISPEL_GOOD, "dispel good", 40, 25, 3, POS_FIGHTING, - TAR_CHAR_ROOM | TAR_FIGHT_VICT, TRUE, MAG_DAMAGE, NULL); - spello(SPELL_EARTHQUAKE, "earthquake", 40, 25, 3, POS_FIGHTING, TAR_IGNORE, TRUE, MAG_AREAS, NULL); diff --git a/src/spells.h b/src/spells.h index 3405aa0..83d345d 100644 --- a/src/spells.h +++ b/src/spells.h @@ -56,45 +56,42 @@ #define SPELL_CURE_CRITIC 15 /* Reserved Skill[] DO NOT CHANGE */ #define SPELL_CURE_LIGHT 16 /* Reserved Skill[] DO NOT CHANGE */ #define SPELL_CURSE 17 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_DETECT_ALIGN 18 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_DETECT_INVIS 19 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_DETECT_MAGIC 20 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_DETECT_POISON 21 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_DISPEL_EVIL 22 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_EARTHQUAKE 23 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_ENCHANT_WEAPON 24 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_ENERGY_DRAIN 25 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_FIREBALL 26 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_HARM 27 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_HEAL 28 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_INVISIBLE 29 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_LIGHTNING_BOLT 30 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_LOCATE_OBJECT 31 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_MAGIC_MISSILE 32 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_POISON 33 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_PROT_FROM_EVIL 34 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_REMOVE_CURSE 35 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_SANCTUARY 36 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_SHOCKING_GRASP 37 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_SLEEP 38 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_STRENGTH 39 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_SUMMON 40 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_VENTRILOQUATE 41 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_WORD_OF_RECALL 42 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_REMOVE_POISON 43 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_SENSE_LIFE 44 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_ANIMATE_DEAD 45 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_DISPEL_GOOD 46 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_GROUP_ARMOR 47 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_GROUP_HEAL 48 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_GROUP_RECALL 49 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_INFRAVISION 50 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_WATERWALK 51 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_IDENTIFY 52 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_FLY 53 /* Reserved Skill[] DO NOT CHANGE */ -#define SPELL_DARKNESS 54 +#define SPELL_DETECT_INVIS 18 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_DETECT_MAGIC 19 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_DETECT_POISON 20 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_EARTHQUAKE 21 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_ENCHANT_WEAPON 22 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_ENERGY_DRAIN 23 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_FIREBALL 24 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_HARM 25 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_HEAL 26 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_INVISIBLE 27 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_LIGHTNING_BOLT 28 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_LOCATE_OBJECT 29 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_MAGIC_MISSILE 30 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_POISON 31 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_PROT_FROM_EVIL 32 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_REMOVE_CURSE 33 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_SANCTUARY 34 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_SHOCKING_GRASP 35 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_SLEEP 36 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_STRENGTH 37 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_SUMMON 38 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_VENTRILOQUATE 39 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_WORD_OF_RECALL 40 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_REMOVE_POISON 41 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_SENSE_LIFE 42 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_ANIMATE_DEAD 43 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_GROUP_ARMOR 44 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_GROUP_HEAL 45 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_GROUP_RECALL 46 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_INFRAVISION 47 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_WATERWALK 48 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_IDENTIFY 49 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_FLY 50 /* Reserved Skill[] DO NOT CHANGE */ +#define SPELL_DARKNESS 51 /** Total Number of defined spells */ -#define NUM_SPELLS 54 +#define NUM_SPELLS 51 /* Insert new spells here, up to MAX_SPELLS */ #define MAX_SPELLS 130 diff --git a/src/structs.h b/src/structs.h index 9b3318f..713b4c5 100644 --- a/src/structs.h +++ b/src/structs.h @@ -312,31 +312,30 @@ #define AFF_DONTUSE 0 /**< DON'T USE! This allows 0 to mean "no bits set" in the database */ #define AFF_BLIND 1 /**< (R) Char is blind */ #define AFF_INVISIBLE 2 /**< Char is invisible */ -#define AFF_DETECT_ALIGN 3 /**< Char is sensitive to align */ -#define AFF_DETECT_INVIS 4 /**< Char can see invis chars */ -#define AFF_DETECT_MAGIC 5 /**< Char is sensitive to magic */ -#define AFF_SENSE_LIFE 6 /**< Char can sense hidden life */ -#define AFF_WATERWALK 7 /**< Char can walk on water */ -#define AFF_SANCTUARY 8 /**< Char protected by sanct */ -#define AFF_UNUSED 9 /**< (R) Char is grouped */ -#define AFF_CURSE 10 /**< Char is cursed */ -#define AFF_INFRAVISION 11 /**< Char can see in dark */ -#define AFF_POISON 12 /**< (R) Char is poisoned */ -#define AFF_RESERVED13 13 /**< Reserved (unused) */ -#define AFF_RESERVED14 14 /**< Reserved (unused) */ -#define AFF_SLEEP 15 /**< (R) Char magically asleep */ -#define AFF_NOTRACK 16 /**< Char can't be tracked */ -#define AFF_FLYING 17 /**< Char is flying */ -#define AFF_SCUBA 18 /**< Room for future expansion */ -#define AFF_SNEAK 19 /**< Char can move quietly */ -#define AFF_HIDE 20 /**< Char is hidden */ -#define AFF_SCAN 21 /**< Actively scanning for hidden threats */ -#define AFF_CHARM 22 /**< Char is charmed */ -#define AFF_BANDAGED 23 /**< Character was bandaged recently */ -#define AFF_LISTEN 24 /**< Actively eavesdropping */ -#define AFF_MOUNTED 25 /**< Riding a mount */ +#define AFF_DETECT_INVIS 3 /**< Char can see invis chars */ +#define AFF_DETECT_MAGIC 4 /**< Char is sensitive to magic */ +#define AFF_SENSE_LIFE 5 /**< Char can sense hidden life */ +#define AFF_WATERWALK 6 /**< Char can walk on water */ +#define AFF_SANCTUARY 7 /**< Char protected by sanct */ +#define AFF_UNUSED 8 /**< (R) Char is grouped */ +#define AFF_CURSE 9 /**< Char is cursed */ +#define AFF_INFRAVISION 10 /**< Char can see in dark */ +#define AFF_POISON 11 /**< (R) Char is poisoned */ +#define AFF_RESERVED13 12 /**< Reserved (unused) */ +#define AFF_RESERVED14 13 /**< Reserved (unused) */ +#define AFF_SLEEP 14 /**< (R) Char magically asleep */ +#define AFF_NOTRACK 15 /**< Char can't be tracked */ +#define AFF_FLYING 16 /**< Char is flying */ +#define AFF_SCUBA 17 /**< Room for future expansion */ +#define AFF_SNEAK 18 /**< Char can move quietly */ +#define AFF_HIDE 19 /**< Char is hidden */ +#define AFF_SCAN 20 /**< Actively scanning for hidden threats */ +#define AFF_CHARM 21 /**< Char is charmed */ +#define AFF_BANDAGED 22 /**< Character was bandaged recently */ +#define AFF_LISTEN 23 /**< Actively eavesdropping */ +#define AFF_MOUNTED 24 /**< Riding a mount */ /** Total number of affect flags */ -#define NUM_AFF_FLAGS 26 +#define NUM_AFF_FLAGS 25 /* Modes of connectedness: used by descriptor_data.state */ #define CON_PLAYING 0 /**< Playing - Nominal state */ From f8d9d31c1c0990be3e1c056e8bb226919bbe3faa Mon Sep 17 00:00:00 2001 From: kinther Date: Wed, 31 Dec 2025 08:27:33 -0800 Subject: [PATCH 29/40] Update audit command for melee weapons, add helpfile entry --- README.md | 2 +- lib/text/help/help.hlp | 38 +++++---- src/act.wizard.c | 184 ++++++++++++++++++++++++++++------------- 3 files changed, 148 insertions(+), 76 deletions(-) diff --git a/README.md b/README.md index 0f186fe..097b4c6 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Changes in v1.1.0-alpha: * Ability to change ldesc of PC/NPC's in some situations * Ability to look in certain directions to see what is 1-3 rooms away * 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 + * "audit armor" command for immortals (formerly "acaudit") * 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 * Removed alignment from game - no more GOOD/EVIL flags or restrictions on shops diff --git a/lib/text/help/help.hlp b/lib/text/help/help.hlp index 79f623e..371442d 100644 --- a/lib/text/help/help.hlp +++ b/lib/text/help/help.hlp @@ -315,29 +315,35 @@ Situational: cover (+2/+5), spells (Shield, Haste, etc.) See Also: SCORE #0 -AUDIT AC AUDIT-AC ACAUDIT ARMOR-AUDIT AUDIT-ARMOR IMMORTAL +AUDIT ARMOR AUDIT-ARMOR AUDIT AC AUDIT-AC ACAUDIT AUDIT MELEE AUDIT-MELEE IMMORTAL - Summary: Imm-only tool that scans all ITEM\_ARMOR prototypes and reports -per-piece fields against slot caps. Use this to catch outliers and quickly -rebalance items to the Light/Medium/Heavy targets. + Summary: Imm-only tool that scans armor and weapons for invalid config. Usage: -audit ac +audit armor|melee -If you omit the option, you'll be prompted with "Audit what?" - -What it does: +What auditing armor does: Scans prototypes for armor slots (head, body, legs, arms, hands, feet) and prints one line per item: -\[#VNUM] slot= ac=\ bulk= mag=+ flags= +[#VNUM] sl= ac= b= m= sd=<0/1> str= Markers: -OVER : value exceeds the slot’s hard cap (e.g., piece AC > slot max, or -magic > slot max) -WARN : value outside 0..3 (invalid for piece AC, bulk, or magic) -(STEALTHDISADV): flag is set (the piece imposes Stealth Disadvantage) +R! : value exceeds the slot’s hard cap (e.g., piece AC > slot max, or + magic > slot max) +Y? : value outside 0..3 (invalid for piece AC, bulk, or magic) +sd=1 : piece imposes Stealth Disadvantage + +What auditing melee weapons does: + +Scans melee weapon prototypes and reports attack type, damage (1d4/1d6/1d8/ +1d10/1d12), and weight. + +Melee markers: + +R! : attack type is missing/invalid or damage is not 1d4/1d6/1d8/1d10/1d12 +Y? : weight is 0 or less Notes: @@ -358,7 +364,7 @@ Medium : AC \~14–18 Heavy : AC \~16–20 See Also: ARMOR PIECES, BULK, SHIELDS, MAGIC CAPS, SCORE, OEDIT ARMOR -#32 +#2 ACRONYMS TERMINOLOGY VOCABULARY Here are some common terms used in building, and TBA zone: @@ -9822,7 +9828,7 @@ redit 34800 q y See Also: TBA-STAFF, TBA-ZONES -#32 +#2 TBA-ADVERTISING Mud Created: 2000 @@ -12568,7 +12574,7 @@ Examples: >; @ - shows all gods that are on and visible to you. - also shows if the gods who are visible to you are writing. >;# - sends text to everyone and above. - - ;#32 only God and above will see this. + - ;#2 only God and above will see this. See also: NOWIZ #2 diff --git a/src/act.wizard.c b/src/act.wizard.c index 487d2fd..bfc014f 100644 --- a/src/act.wizard.c +++ b/src/act.wizard.c @@ -6183,14 +6183,20 @@ ACMD(do_audit) { int found = 0, warned = 0; char arg[MAX_INPUT_LENGTH]; + bool do_armor = FALSE; + bool do_weapons = FALSE; one_argument(argument, arg); if (!*arg) { send_to_char(ch, "Audit what?\r\n"); return; } - if (!is_abbrev(arg, "ac")) { - send_to_char(ch, "Usage: audit ac\r\n"); + if (is_abbrev(arg, "armor")) + do_armor = TRUE; + else if (is_abbrev(arg, "melee")) + do_weapons = TRUE; + else { + send_to_char(ch, "Usage: audit armor | audit melee\r\n"); return; } @@ -6218,75 +6224,135 @@ ACMD(do_audit) len += (size_t)snprintf(out + len, cap - len, __VA_ARGS__); \ } while (0) - /* Header (short so it won’t wrap) */ - APPEND_FMT("\r\n\tY[Armor Audit]\tn ITEM_ARMOR scan\r\n"); - APPEND_FMT("Legend: \tR!\tn over-cap, \tY?\tn warn, S stealth-disadv\r\n"); + if (do_armor) { + /* Header (short so it won’t wrap) */ + APPEND_FMT("\r\n\tY[Armor Audit]\tn ITEM_ARMOR scan\r\n"); + APPEND_FMT("Legend: \tR!\tn over-cap, \tY?\tn warn, S stealth-disadv\r\n"); - for (obj_rnum r = 0; r <= top_of_objt; r++) { - struct obj_data *obj = &obj_proto[r]; - char namebuf[128] = {0}; - int idx, vnum, piece_ac, bulk, magic, stealth, strreq; + for (obj_rnum r = 0; r <= top_of_objt; r++) { + struct obj_data *obj = &obj_proto[r]; + char namebuf[128] = {0}; + int idx, vnum, piece_ac, bulk, magic, stealth, strreq; - if (GET_OBJ_TYPE(obj) != ITEM_ARMOR) - continue; + if (GET_OBJ_TYPE(obj) != ITEM_ARMOR) + continue; - /* Identify slot (skip shields here) */ - idx = armor_slot_index_from_wear(obj); - if (idx == -2) continue; /* shield handled in AC; skip */ - if (idx < 0) continue; /* not a supported armor slot */ + /* Identify slot (skip shields here) */ + idx = armor_slot_index_from_wear(obj); + if (idx == -2) continue; /* shield handled in AC; skip */ + if (idx < 0) continue; /* not a supported armor slot */ - vnum = GET_OBJ_VNUM(obj); - piece_ac = GET_OBJ_VAL(obj, VAL_ARMOR_PIECE_AC); - bulk = GET_OBJ_VAL(obj, VAL_ARMOR_BULK); - magic = GET_OBJ_VAL(obj, VAL_ARMOR_MAGIC_BONUS); - stealth = GET_OBJ_VAL(obj, VAL_ARMOR_STEALTH_DISADV); /* 1/0, yes or no */ - strreq = GET_OBJ_VAL(obj, VAL_ARMOR_STR_REQ); /* 0 or 13/15/16 typically */ + vnum = GET_OBJ_VNUM(obj); + piece_ac = GET_OBJ_VAL(obj, VAL_ARMOR_PIECE_AC); + bulk = GET_OBJ_VAL(obj, VAL_ARMOR_BULK); + magic = GET_OBJ_VAL(obj, VAL_ARMOR_MAGIC_BONUS); + stealth = GET_OBJ_VAL(obj, VAL_ARMOR_STEALTH_DISADV); /* 1/0, yes or no */ + strreq = GET_OBJ_VAL(obj, VAL_ARMOR_STR_REQ); /* 0 or 13/15/16 typically */ - /* Display name (trim to keep line width < ~78 cols) */ - if (obj->short_description) - snprintf(namebuf, sizeof(namebuf), "%s", obj->short_description); - else if (obj->name) - snprintf(namebuf, sizeof(namebuf), "%s", obj->name); - else - snprintf(namebuf, sizeof(namebuf), "object"); + /* Display name (trim to keep line width < ~78 cols) */ + if (obj->short_description) + snprintf(namebuf, sizeof(namebuf), "%s", obj->short_description); + else if (obj->name) + snprintf(namebuf, sizeof(namebuf), "%s", obj->name); + else + snprintf(namebuf, sizeof(namebuf), "object"); - /* Slot caps */ - const int max_piece_ac = armor_slots[idx].max_piece_ac; - const int max_magic = armor_slots[idx].max_magic; + /* Slot caps */ + const int max_piece_ac = armor_slots[idx].max_piece_ac; + const int max_magic = armor_slots[idx].max_magic; - /* Validations */ - bool over_ac = (piece_ac > max_piece_ac); - bool over_magic = (magic > max_magic); - bool bad_ac = (piece_ac < 0 || piece_ac > 3); - bool bad_bulk = (bulk < 0 || bulk > 3); - bool bad_magic = (magic < 0 || magic > 3); + /* Validations */ + bool over_ac = (piece_ac > max_piece_ac); + bool over_magic = (magic > max_magic); + bool bad_ac = (piece_ac < 0 || piece_ac > 3); + bool bad_bulk = (bulk < 0 || bulk > 3); + bool bad_magic = (magic < 0 || magic > 3); - found++; + found++; - /* Compact, non-wrapping row (~70 cols worst case) */ - APPEND_FMT("\tc[#%5d]\tn %-24.24s sl=%-5.5s ac=%2d%s b=%d%s m=%+d%s sd=%d str=%d\r\n", - vnum, - namebuf, - slot_name_from_index(idx), - piece_ac, over_ac ? " \tR!\tn" : (bad_ac ? " \tY?\tn" : ""), - bulk, bad_bulk ? " \tY?\tn" : "", - magic, over_magic ? " \tR!\tn" : (bad_magic? " \tY?\tn" : ""), - stealth, strreq); + /* Compact, non-wrapping row (~70 cols worst case) */ + APPEND_FMT("\tc[#%5d]\tn %-24.24s sl=%-5.5s ac=%2d%s b=%d%s m=%+d%s sd=%d str=%d\r\n", + vnum, + namebuf, + slot_name_from_index(idx), + piece_ac, over_ac ? " \tR!\tn" : (bad_ac ? " \tY?\tn" : ""), + bulk, bad_bulk ? " \tY?\tn" : "", + magic, over_magic ? " \tR!\tn" : (bad_magic? " \tY?\tn" : ""), + stealth, strreq); - if (over_ac || over_magic || bad_ac || bad_bulk || bad_magic) - warned++; + if (over_ac || over_magic || bad_ac || bad_bulk || bad_magic) + warned++; + } + + if (!found) { + free(out); + send_to_char(ch, "No ITEM_ARMOR prototypes found for the audited slots.\r\n"); + return; + } + + /* Footer */ + APPEND_FMT("\r\nScanned: %d items, %d with issues. Armor magic cap +%d (shield separate).\r\n", + found, warned, MAX_TOTAL_ARMOR_MAGIC); + } else if (do_weapons) { + APPEND_FMT("\r\n\tY[Weapon Audit]\tn ITEM_WEAPON scan\r\n"); + APPEND_FMT("Legend: \tR!\tn error, \tY?\tn warn, dmg=1d4/1d6/1d8/1d10/1d12\r\n"); + + for (obj_rnum r = 0; r <= top_of_objt; r++) { + struct obj_data *obj = &obj_proto[r]; + char namebuf[128] = {0}; + int vnum, ndice, sdice, atype, weight; + bool bad_type, bad_dmg, bad_weight; + const char *atype_name; + + if (GET_OBJ_TYPE(obj) != ITEM_WEAPON) + continue; + + vnum = GET_OBJ_VNUM(obj); + ndice = GET_OBJ_VAL(obj, 0); + sdice = GET_OBJ_VAL(obj, 1); + atype = GET_OBJ_VAL(obj, 2); + weight = GET_OBJ_WEIGHT(obj); + + /* Display name (trim to keep line width < ~78 cols) */ + if (obj->short_description) + snprintf(namebuf, sizeof(namebuf), "%s", obj->short_description); + else if (obj->name) + snprintf(namebuf, sizeof(namebuf), "%s", obj->name); + else + snprintf(namebuf, sizeof(namebuf), "object"); + + bad_type = (atype < 0 || atype >= NUM_ATTACK_TYPES); + bad_dmg = !(ndice == 1 && + (sdice == 4 || sdice == 6 || sdice == 8 || sdice == 10 || sdice == 12)); + bad_weight = (weight <= 0); + + if (bad_type) + atype_name = "invalid"; + else + atype_name = attack_hit_text[atype].singular; + + found++; + + APPEND_FMT("\tc[#%5d]\tn %-24.24s at=%-7.7s%s dmg=%dd%d%s wt=%d%s\r\n", + vnum, + namebuf, + atype_name, bad_type ? " \tR!\tn" : "", + ndice, sdice, bad_dmg ? " \tR!\tn" : "", + weight, bad_weight ? " \tY?\tn" : ""); + + if (bad_type || bad_dmg || bad_weight) + warned++; + } + + if (!found) { + free(out); + send_to_char(ch, "No ITEM_WEAPON prototypes found.\r\n"); + return; + } + + APPEND_FMT("\r\nScanned: %d items, %d with issues.\r\n", found, warned); } - if (!found) { - free(out); - send_to_char(ch, "No ITEM_ARMOR prototypes found for the audited slots.\r\n"); - return; - } - - /* Footer */ - APPEND_FMT("\r\nScanned: %d items, %d with issues. Armor magic cap +%d (shield separate).\r\n", - found, warned, MAX_TOTAL_ARMOR_MAGIC); - /* Page it (copy mode) and try to force 25-line pages */ if (ch->desc) { int old_len = 0; bool changed = false; From 57579be97b5d3c6c30dbbf2ee7019591094b6876 Mon Sep 17 00:00:00 2001 From: kinther Date: Wed, 31 Dec 2025 08:41:46 -0800 Subject: [PATCH 30/40] Add 'stat shop' command for immortals --- README.md | 7 +- src/act.wizard.c | 253 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 257 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 097b4c6..0ea781b 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Due to the sensitive nature of topics found in this setting, all characters and players are 18+. The game world is derived from several inspirational sources, most notably the former Armageddon MUD. -Roleplay is highly encouraged, but not enforced. +Roleplay is **highly** encouraged. Changes from stock tbaMUD 2025 to Cataclysm MUD v1.0.0-alpha: @@ -54,10 +54,10 @@ Changes in v1.1.0-alpha: * Renamed move to stamina in code to reflect how much energy is used for certain actions * Species have base hit/mana/stamina now, plus their class modifier rolls * Prioritized stats during character generation - * Ability to change ldesc of PC/NPC's in some situations + * Ability to change ldesc of PC/NPC's * Ability to look in certain directions to see what is 1-3 rooms away * PC's and NPC's can now have an age set between 18-65 - * "audit armor" command for immortals (formerly "acaudit") + * "audit armor" and "audit melee" commands for immortals (formerly "acaudit") to check non-compliant items * 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 * Removed alignment from game - no more GOOD/EVIL flags or restrictions on shops @@ -67,6 +67,7 @@ Changes in v1.1.0-alpha: Features to be implemented in the next few releases: * Height and weight normalized to species +* Stables allow for purchasing of mounts * Stables will take mounts and provide tickets to get them out * Updated door code so that it can be closed/locked/saved with rsave code * SECTOR/ROOM type changes to make terrain movement easier or more difficult diff --git a/src/act.wizard.c b/src/act.wizard.c index bfc014f..d36fe91 100644 --- a/src/act.wizard.c +++ b/src/act.wizard.c @@ -30,6 +30,7 @@ #include "genmob.h" #include "genolc.h" #include "genobj.h" +#include "genshp.h" #include "fight.h" #include "house.h" #include "modify.h" @@ -44,6 +45,7 @@ static void perform_immort_invis(struct char_data *ch, int level); static void do_stat_room(struct char_data *ch, struct room_data *rm); static void do_stat_object(struct char_data *ch, struct obj_data *j); static void do_stat_character(struct char_data *ch, struct char_data *k); +static void do_stat_shop(struct char_data *ch, shop_rnum shop_nr); static void stop_snooping(struct char_data *ch); static struct obj_data *find_inventory_coin(struct char_data *ch); static void remove_other_coins_from_list(struct obj_data *list, struct obj_data *keep); @@ -67,7 +69,12 @@ static const char *stat_border_line(void); static void stat_table_border(struct char_data *ch); static void stat_table_row(struct char_data *ch, const char *label, const char *value); static void stat_table_row_fmt(struct char_data *ch, const char *label, const char *fmt, ...) __attribute__((format(printf,3,4))); +static void stat_table_border_buf(char *buf, size_t buf_size, size_t *len); +static void stat_table_row_buf(char *buf, size_t buf_size, size_t *len, const char *label, const char *value); +static void stat_table_row_fmt_buf(char *buf, size_t buf_size, size_t *len, const char *label, const char *fmt, ...) __attribute__((format(printf,5,6))); static void stat_appendf(char *buf, size_t buf_size, size_t *len, const char *fmt, ...) __attribute__((format(printf,4,5))); +static void stat_append_list_item(char *buf, size_t buf_size, size_t *len, size_t *line_len, const char *item); +static void stat_format_notrade_classes(bitvector_t flags, char *out, size_t outsz); static void stat_format_script_triggers(struct script_data *sc, char *buf, size_t buf_size); static void stat_format_script_globals(struct script_data *sc, char *buf, size_t buf_size); static void stat_format_script_memory(struct script_memory *mem, char *buf, size_t buf_size); @@ -209,6 +216,60 @@ static void stat_table_row_fmt(struct char_data *ch, const char *label, const ch stat_table_row(ch, label, buf); } +static void stat_table_border_buf(char *buf, size_t buf_size, size_t *len) +{ + stat_appendf(buf, buf_size, len, "%s", stat_border_line()); +} + +static void stat_table_row_buf(char *buf, size_t buf_size, size_t *len, const char *label, const char *value) +{ + const char *text = (value && *value) ? value : ""; + bool printed = FALSE; + + while (*text) { + while (*text == '\r' || *text == '\n') + text++; + if (!*text) + break; + + char chunk[STAT_VALUE_WIDTH + 1]; + const char *next = stat_next_chunk(text, chunk, STAT_VALUE_WIDTH); + + if (!*chunk) { + text = next; + continue; + } + + stat_appendf(buf, buf_size, len, "| %-*s | %-*s |\r\n", + STAT_LABEL_WIDTH, + printed || !label ? "" : label, + STAT_VALUE_WIDTH, + chunk); + + printed = TRUE; + text = next; + } + + if (!printed) + stat_appendf(buf, buf_size, len, "| %-*s | %-*s |\r\n", + STAT_LABEL_WIDTH, + label ? label : "", + STAT_VALUE_WIDTH, + (value && *value) ? value : ""); +} + +static void stat_table_row_fmt_buf(char *buf, size_t buf_size, size_t *len, const char *label, const char *fmt, ...) +{ + char row[MAX_STRING_LENGTH]; + va_list args; + + va_start(args, fmt); + vsnprintf(row, sizeof(row), fmt, args); + va_end(args); + + stat_table_row_buf(buf, buf_size, len, label, row); +} + static void stat_appendf(char *buf, size_t buf_size, size_t *len, const char *fmt, ...) { if (*len >= buf_size) @@ -228,6 +289,52 @@ static void stat_appendf(char *buf, size_t buf_size, size_t *len, const char *fm *len += wrote; } +static void stat_append_list_item(char *buf, size_t buf_size, size_t *len, size_t *line_len, const char *item) +{ + size_t item_len = strlen(item); + + if (*line_len && *line_len + 2 + item_len > STAT_VALUE_WIDTH) { + stat_appendf(buf, buf_size, len, "\n"); + *line_len = 0; + } + + if (*line_len) { + stat_appendf(buf, buf_size, len, ", "); + *line_len += 2; + } + + stat_appendf(buf, buf_size, len, "%s", item); + *line_len += item_len; +} + +static void stat_format_notrade_classes(bitvector_t flags, char *out, size_t outsz) +{ + size_t len = 0; + int i, found = 0; + + if (!out || outsz == 0) + return; + + out[0] = '\0'; + + for (i = TRADE_CLASS_START; i < NUM_TRADERS; i++) { + if (IS_SET(flags, 1 << i)) { + int n = snprintf(out + len, outsz - len, "%s%s", found ? " " : "", trade_letters[i]); + + if (n < 0 || (size_t)n >= outsz - len) { + out[outsz - 1] = '\0'; + return; + } + + len += (size_t)n; + found = 1; + } + } + + if (!found) + strlcpy(out, "NOBITS", outsz); +} + static void stat_format_script_triggers(struct script_data *sc, char *buf, size_t buf_size) { size_t len = 0; @@ -1941,6 +2048,125 @@ static void do_stat_character(struct char_data *ch, struct char_data *k) stat_table_border(ch); } +static void do_stat_shop(struct char_data *ch, shop_rnum shop_nr) +{ + char entry[MAX_STRING_LENGTH]; + char list[MAX_STRING_LENGTH]; + char buf[MAX_STRING_LENGTH]; + char bits[MAX_STRING_LENGTH]; + char *out; + size_t out_size = MAX_STRING_LENGTH * 4; + size_t len = 0; + size_t line_len = 0; + size_t list_len = 0; + int i; + + CREATE(out, char, out_size); + out[0] = '\0'; + + stat_table_border_buf(out, out_size, &len); + stat_table_row_fmt_buf(out, out_size, &len, "Identifiers", "VNum #%d (RNum %d)", + SHOP_NUM(shop_nr), shop_nr); + + if (SHOP_KEEPER(shop_nr) == NOBODY) { + strlcpy(buf, "None", sizeof(buf)); + } else { + snprintf(buf, sizeof(buf), "[%d] %s", + mob_index[SHOP_KEEPER(shop_nr)].vnum, + mob_proto[SHOP_KEEPER(shop_nr)].player.short_descr ? + mob_proto[SHOP_KEEPER(shop_nr)].player.short_descr : ""); + } + stat_table_row_buf(out, out_size, &len, "Keeper", buf); + + stat_table_row_fmt_buf(out, out_size, &len, "Open/Close", + "Open1 %d Close1 %d, Open2 %d Close2 %d", + SHOP_OPEN1(shop_nr), SHOP_CLOSE1(shop_nr), + SHOP_OPEN2(shop_nr), SHOP_CLOSE2(shop_nr)); + + stat_table_row_fmt_buf(out, out_size, &len, "Rates", + "Sell %1.2f, Buy %1.2f", + SHOP_BUYPROFIT(shop_nr), SHOP_SELLPROFIT(shop_nr)); + + list[0] = '\0'; + line_len = 0; + list_len = 0; + for (i = 0; SHOP_ROOM(shop_nr, i) != NOWHERE; i++) { + room_rnum rnum = real_room(SHOP_ROOM(shop_nr, i)); + if (rnum != NOWHERE) + snprintf(entry, sizeof(entry), "#%d %s", + GET_ROOM_VNUM(rnum), world[rnum].name); + else + snprintf(entry, sizeof(entry), " (#%d)", SHOP_ROOM(shop_nr, i)); + stat_append_list_item(list, sizeof(list), &list_len, &line_len, entry); + } + if (!list_len) + strlcpy(list, "None", sizeof(list)); + stat_table_row_buf(out, out_size, &len, "Rooms", list); + + list[0] = '\0'; + list_len = 0; + line_len = 0; + for (i = 0; SHOP_PRODUCT(shop_nr, i) != NOTHING; i++) { + obj_rnum rnum = SHOP_PRODUCT(shop_nr, i); + if (rnum != NOTHING && rnum >= 0 && rnum <= top_of_objt) { + snprintf(entry, sizeof(entry), "%s (#%d)", + obj_proto[rnum].short_description ? obj_proto[rnum].short_description : "", + obj_index[rnum].vnum); + } else + snprintf(entry, sizeof(entry), ""); + stat_append_list_item(list, sizeof(list), &list_len, &line_len, entry); + } + if (!list_len) + strlcpy(list, "None", sizeof(list)); + stat_table_row_buf(out, out_size, &len, "Products", list); + + list[0] = '\0'; + list_len = 0; + line_len = 0; + for (i = 0; SHOP_BUYTYPE(shop_nr, i) != NOTHING; i++) { + const char *keyword = SHOP_BUYWORD(shop_nr, i) ? SHOP_BUYWORD(shop_nr, i) : "all"; + if (SHOP_BUYTYPE(shop_nr, i) >= 0 && SHOP_BUYTYPE(shop_nr, i) < NUM_ITEM_TYPES) { + snprintf(entry, sizeof(entry), "%s (#%d) [%s]", + item_types[SHOP_BUYTYPE(shop_nr, i)], SHOP_BUYTYPE(shop_nr, i), keyword); + } else + snprintf(entry, sizeof(entry), "Unknown (#%d) [%s]", SHOP_BUYTYPE(shop_nr, i), keyword); + stat_append_list_item(list, sizeof(list), &list_len, &line_len, entry); + } + if (!list_len) + strlcpy(list, "None", sizeof(list)); + stat_table_row_buf(out, out_size, &len, "Accept Types", list); + + stat_format_notrade_classes(SHOP_TRADE_WITH(shop_nr), buf, sizeof(buf)); + stat_table_row_buf(out, out_size, &len, "No Trade With", buf); + + sprintbit(SHOP_BITVECTOR(shop_nr), shop_bits, bits, sizeof(bits)); + stat_table_row_buf(out, out_size, &len, "Shop Flags", bits); + + stat_table_row_buf(out, out_size, &len, "Keeper No Item", + shop_index[shop_nr].no_such_item1 ? shop_index[shop_nr].no_such_item1 : "None"); + stat_table_row_buf(out, out_size, &len, "Player No Item", + shop_index[shop_nr].no_such_item2 ? shop_index[shop_nr].no_such_item2 : "None"); + stat_table_row_buf(out, out_size, &len, "Keeper No Cash", + shop_index[shop_nr].missing_cash1 ? shop_index[shop_nr].missing_cash1 : "None"); + stat_table_row_buf(out, out_size, &len, "Player No Cash", + shop_index[shop_nr].missing_cash2 ? shop_index[shop_nr].missing_cash2 : "None"); + stat_table_row_buf(out, out_size, &len, "Keeper No Buy", + shop_index[shop_nr].do_not_buy ? shop_index[shop_nr].do_not_buy : "None"); + stat_table_row_buf(out, out_size, &len, "Buy Success", + shop_index[shop_nr].message_buy ? shop_index[shop_nr].message_buy : "None"); + stat_table_row_buf(out, out_size, &len, "Sell Success", + shop_index[shop_nr].message_sell ? shop_index[shop_nr].message_sell : "None"); + + stat_table_border_buf(out, out_size, &len); + + if (ch->desc) + page_string(ch->desc, out, TRUE); + else + send_to_char(ch, "%s", out); + + free(out); +} + ACMD(do_stat) { char buf1[MAX_INPUT_LENGTH], buf2[MAX_INPUT_LENGTH]; @@ -2014,6 +2240,33 @@ ACMD(do_stat) else send_to_char(ch, "No such object around.\r\n"); } + } else if (is_abbrev(buf1, "shop")) { + shop_rnum shop_nr = NOWHERE; + if (!*buf2) { + int found = FALSE; + room_vnum rvnum = GET_ROOM_VNUM(IN_ROOM(ch)); + for (shop_nr = 0; shop_nr <= top_shop; shop_nr++) { + for (int j = 0; SHOP_ROOM(shop_nr, j) != NOWHERE; j++) { + if (SHOP_ROOM(shop_nr, j) == rvnum) { + found = TRUE; + break; + } + } + if (found) + break; + } + if (!found) { + send_to_char(ch, "This isn't a shop.\r\n"); + return; + } + } else { + shop_nr = real_shop(atoi(buf2)); + if (shop_nr == NOWHERE) { + send_to_char(ch, "That is not a valid shop.\r\n"); + return; + } + } + do_stat_shop(ch, shop_nr); } else if (is_abbrev(buf1, "zone")) { if (!*buf2) { print_zone(ch, zone_table[world[IN_ROOM(ch)].zone].number); From 43d966a6ea0406258138a3bcca45f8bc109e781d Mon Sep 17 00:00:00 2001 From: kinther Date: Wed, 31 Dec 2025 08:46:34 -0800 Subject: [PATCH 31/40] Fix minor grammatical error with furniture --- src/act.informative.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/act.informative.c b/src/act.informative.c index f101e7b..4e965e5 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -103,8 +103,11 @@ static void show_obj_to_char(struct obj_data *obj, struct char_data *ch, int mod found++; } if (found) { - send_to_char(ch, "You are %s upon %s.", GET_POS(ch) == POS_SITTING ? "sitting" : - "resting", obj->short_description); + const char *pos = (GET_POS(ch) == POS_STANDING ? "standing" : + (GET_POS(ch) == POS_SITTING ? "sitting" : + (GET_POS(ch) == POS_SLEEPING ? "sleeping" : "resting"))); + const char *prep = (GET_POS(ch) == POS_STANDING || GET_POS(ch) == POS_SITTING) ? "at" : "upon"; + send_to_char(ch, "You are %s %s %s.", pos, prep, obj->short_description); goto end; } } @@ -662,9 +665,13 @@ static void list_one_char(struct char_data *i, struct char_data *ch) send_to_char(ch, "%s", positions[(int) GET_POS(i)]); else { furniture = SITTING(i); - send_to_char(ch, " is %s upon %s.", (GET_POS(i) == POS_SLEEPING ? - "sleeping" : (GET_POS(i) == POS_RESTING ? "resting" : "sitting")), - OBJS(furniture, ch)); + { + const char *pos = (GET_POS(i) == POS_STANDING ? "standing" : + (GET_POS(i) == POS_SITTING ? "sitting" : + (GET_POS(i) == POS_SLEEPING ? "sleeping" : "resting"))); + const char *prep = (GET_POS(i) == POS_STANDING || GET_POS(i) == POS_SITTING) ? "at" : "upon"; + send_to_char(ch, " is %s %s %s.", pos, prep, OBJS(furniture, ch)); + } } } else { if (FIGHTING(i)) { @@ -768,10 +775,13 @@ static void build_current_ldesc(const struct char_data *ch, char *out, size_t ou snprintf(out, outsz, "%s%s", base, positions[(int) GET_POS(ch)]); } else { furniture = SITTING(ch); - snprintf(out, outsz, "%s is %s upon %s.", base, - (GET_POS(ch) == POS_SLEEPING ? "sleeping" : - (GET_POS(ch) == POS_RESTING ? "resting" : "sitting")), - OBJS(furniture, ch)); + { + const char *pos = (GET_POS(ch) == POS_STANDING ? "standing" : + (GET_POS(ch) == POS_SITTING ? "sitting" : + (GET_POS(ch) == POS_SLEEPING ? "sleeping" : "resting"))); + const char *prep = (GET_POS(ch) == POS_STANDING || GET_POS(ch) == POS_SITTING) ? "at" : "upon"; + snprintf(out, outsz, "%s is %s %s %s.", base, pos, prep, OBJS(furniture, ch)); + } } } else { if (FIGHTING(ch)) { @@ -1525,7 +1535,7 @@ ACMD(do_score) send_to_char(ch, "You are sitting.\r\n"); else { struct obj_data *furniture = SITTING(ch); - send_to_char(ch, "You are sitting upon %s.\r\n", furniture->short_description); + send_to_char(ch, "You are sitting at %s.\r\n", furniture->short_description); } break; case POS_FIGHTING: From 90abf0f214625e54906a9ec9e814c7c2a51c584e Mon Sep 17 00:00:00 2001 From: kinther Date: Wed, 31 Dec 2025 09:42:47 -0800 Subject: [PATCH 32/40] Add rcreate and rset commands for builders --- README.md | 2 + src/act.h | 1 + src/genwld.c | 1 + src/interpreter.c | 2 + src/rset.c | 1292 +++++++++++++++++++++++++++++++++++++++++++++ src/rset.h | 14 + 6 files changed, 1312 insertions(+) create mode 100644 src/rset.c create mode 100644 src/rset.h diff --git a/README.md b/README.md index 0ea781b..abdf8fa 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,8 @@ Changes in v1.1.0-alpha: * Removed alignment from game - no more GOOD/EVIL flags or restrictions on shops * Removed ANTI_ flags related to class restrictions on what objects they can use * Mounts added to help with long trips, and ability to use them as pack animals + * Introduced AGENTS.md file to ensure code quality + * Migration away from OLC with new commands "rcreate" and "rset" for builders to modify rooms Features to be implemented in the next few releases: diff --git a/src/act.h b/src/act.h index 02d27f2..5325627 100644 --- a/src/act.h +++ b/src/act.h @@ -19,6 +19,7 @@ #define _ACT_H_ #include "utils.h" /* for the ACMD macro */ +#include "rset.h" #ifndef MAX_EMOTE_TOKENS #define MAX_EMOTE_TOKENS 16 diff --git a/src/genwld.c b/src/genwld.c index f6f3396..6788cbd 100644 --- a/src/genwld.c +++ b/src/genwld.c @@ -463,6 +463,7 @@ int free_room_strings(struct room_data *room) free(room->description); if (room->ex_description) free_ex_descriptions(room->ex_description); + room->ex_description = NULL; if (room->forage) free_forage_list(room->forage); room->forage = NULL; diff --git a/src/interpreter.c b/src/interpreter.c index ec99df7..17f0301 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -273,6 +273,8 @@ cpp_extern const struct command_info cmd_info[] = { { "restore" , "resto" , POS_DEAD , do_restore , LVL_GOD, 0 }, { "return" , "retu" , POS_DEAD , do_return , 0, 0 }, { "redit" , "redit" , POS_DEAD , do_oasis_redit, LVL_BUILDER, 0 }, + { "rcreate" , "rcreate" , POS_DEAD , do_rcreate , LVL_BUILDER, 0 }, + { "rset" , "rset" , POS_DEAD , do_rset , LVL_BUILDER, 0 }, { "rlist" , "rlist" , POS_DEAD , do_oasis_list, LVL_BUILDER, SCMD_OASIS_RLIST }, { "rcopy" , "rcopy" , POS_DEAD , do_oasis_copy, LVL_GOD, CON_REDIT }, { "roomflags", "roomflags", POS_DEAD , do_gen_tog , LVL_IMMORT, SCMD_SHOWVNUMS }, diff --git a/src/rset.c b/src/rset.c new file mode 100644 index 0000000..01d2b01 --- /dev/null +++ b/src/rset.c @@ -0,0 +1,1292 @@ +/** +* @file rset.c +* Room creation/configuration and utility routines. +* +* This set of code was not originally part of the circlemud distribution. +*/ + +#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 "constants.h" +#include "genolc.h" +#include "genwld.h" +#include "genzon.h" +#include "oasis.h" +#include "improved-edit.h" +#include "modify.h" + +#include "rset.h" + +static void rset_show_usage(struct char_data *ch) +{ + send_to_char(ch, + "Usage:\r\n" + " rset show - show editable fields + current values\r\n" + " rset set - set a scalar field\r\n" + " rset add - add to a list field\r\n" + " rset del - remove from a list field\r\n" + " rset desc - edit long text (main description)\r\n" + " rset clear - clears all fields\r\n" + " rset validate - run validation checks\r\n" + "\r\n" + "Type:\r\n" + " rset set\r\n" + " rset add\r\n" + " rset del\r\n" + "\r\n" + "For command-specific options.\r\n"); +} + +static void rset_show_set_usage(struct char_data *ch) +{ + send_to_char(ch, + "Sets specific configuration to the room.\r\n" + "\r\n" + "Usage:\r\n" + " rset set name - add a room name\r\n" + " rset set sector - add terrain/sector type\r\n" + "\r\n" + "Examples:\r\n" + " rset set name \"A wind-scoured alley\"\r\n" + " rset set sector desert\r\n"); +} + +static void rset_show_set_sector_usage(struct char_data *ch) +{ + send_to_char(ch, + "Sets room sector type.\r\n" + "\r\n" + "Usage:\r\n" + " rset set sector \r\n" + "\r\n" + "Examples:\r\n" + " rset set sector desert\r\n" + "\r\n" + "Sectors:\r\n"); + column_list(ch, 0, sector_types, NUM_ROOM_SECTORS, FALSE); +} + +static void rset_show_add_usage(struct char_data *ch) +{ + send_to_char(ch, + "Adds specific configuration to the room.\r\n" + "\r\n" + "Usage:\r\n" + " rset add flags:\r\n" + " [flag ...]\r\n" + " rset add exit \r\n" + " rset add door \r\n" + " rset add key \r\n" + " rset add hidden \r\n" + " rset add forage \r\n" + " rset add edesc \r\n" + "\r\n" + "Examples:\r\n" + " rset add flags INDOORS QUITSAFE\r\n" + " rset add exit n 101\r\n" + " rset add door n door\r\n" + " rset add key n 201\r\n" + " rset add hidden n\r\n" + " rset add forage 301 15\r\n" + " rset add edesc mosaic A beautiful mosaic is here on the wall.\r\n"); +} + +static void rset_show_del_usage(struct char_data *ch) +{ + send_to_char(ch, + "Deletes specific configuration from the room.\r\n" + "\r\n" + "Usage:\r\n" + " rset del flags [flag ...]\r\n" + " rset del exit \r\n" + " rset del door \r\n" + " rset del key \r\n" + " rset del hidden \r\n" + " rset del forage \r\n" + " rset del edesc \r\n" + "\r\n" + "Examples:\r\n" + " rset del flags INDOORS QUITSAFE\r\n" + " rset del exit n\r\n" + " rset del door n\r\n" + " rset del key n\r\n" + " rset del hidden n\r\n" + " rset del forage 301\r\n" + " rset del edesc mosaic\r\n"); +} + +static void rset_show_clear_usage(struct char_data *ch) +{ + send_to_char(ch, + "Clears all configuration from a room to start over fresh.\r\n" + "\r\n" + "Usage:\r\n" + " rset clear\r\n" + "\r\n" + "Examples:\r\n" + " rset clear\r\n"); +} + +static void rset_show_validate_usage(struct char_data *ch) +{ + send_to_char(ch, + "Verifies your new room meets building standards and looks for any errors. If\r\n" + "correct, you can use the rsave command to finish building.\r\n" + "\r\n" + "Usage:\r\n" + " rset validate\r\n" + "\r\n" + "Examples:\r\n" + " rset validate\r\n"); +} + +static void rset_show_desc_usage(struct char_data *ch) +{ + send_to_char(ch, + "Enters text editor for editing the main description of the room.\r\n" + "\r\n" + "Usage:\r\n" + " rset desc\r\n"); +} + +static void rset_show_rcreate_usage(struct char_data *ch) +{ + send_to_char(ch, + "Creates a new unfinished room which can be entered and configured.\r\n" + "\r\n" + "Usage:\r\n" + " rcreate \r\n" + "\r\n" + "Examples:\r\n" + " rcreate 1001\r\n"); +} + +static void rset_show_add_flags_usage(struct char_data *ch) +{ + send_to_char(ch, + "Adds room flags.\r\n" + "\r\n" + "Usage:\r\n" + " rset add flags [flag ...]\r\n" + "\r\n" + "Examples:\r\n" + " rset add flags INDOORS QUITSAFE\r\n" + "\r\n" + "Flags:\r\n"); + column_list(ch, 0, room_bits, NUM_ROOM_FLAGS, FALSE); +} + +static void rset_show_del_flags_usage(struct char_data *ch) +{ + send_to_char(ch, + "Deletes room flags.\r\n" + "\r\n" + "Usage:\r\n" + " rset del flags [flag ...]\r\n" + "\r\n" + "Examples:\r\n" + " rset del flags INDOORS QUITSAFE\r\n" + "\r\n" + "Flags:\r\n"); + column_list(ch, 0, room_bits, NUM_ROOM_FLAGS, FALSE); +} + +static void rset_show_add_exit_usage(struct char_data *ch) +{ + send_to_char(ch, + "Adds an exit to the room.\r\n" + "\r\n" + "Usage:\r\n" + " rset add exit \r\n" + "\r\n" + "Examples:\r\n" + " rset add exit n 101\r\n"); +} + +static void rset_show_add_door_usage(struct char_data *ch) +{ + send_to_char(ch, + "Adds a door to an existing exit.\r\n" + "\r\n" + "Usage:\r\n" + " rset add door \r\n" + "\r\n" + "Examples:\r\n" + " rset add door n door\r\n"); +} + +static void rset_show_add_key_usage(struct char_data *ch) +{ + send_to_char(ch, + "Adds a key to an existing door.\r\n" + "\r\n" + "Usage:\r\n" + " rset add key \r\n" + "\r\n" + "Examples:\r\n" + " rset add key n 201\r\n"); +} + +static void rset_show_add_hidden_usage(struct char_data *ch) +{ + send_to_char(ch, + "Adds the hidden flag to an existing exit.\r\n" + "\r\n" + "Usage:\r\n" + " rset add hidden \r\n" + "\r\n" + "Examples:\r\n" + " rset add hidden n\r\n"); +} + +static void rset_show_add_forage_usage(struct char_data *ch) +{ + send_to_char(ch, + "Adds a forage entry to the room.\r\n" + "\r\n" + "Usage:\r\n" + " rset add forage \r\n" + "\r\n" + "Examples:\r\n" + " rset add forage 301 15\r\n"); +} + +static void rset_show_add_edesc_usage(struct char_data *ch) +{ + send_to_char(ch, + "Adds an extra description to the room.\r\n" + "\r\n" + "Usage:\r\n" + " rset add edesc \r\n" + "\r\n" + "Examples:\r\n" + " rset add edesc mosaic A beautiful mosaic is here on the wall.\r\n"); +} + +static void rset_show_del_exit_usage(struct char_data *ch) +{ + send_to_char(ch, + "Deletes an exit from the room.\r\n" + "\r\n" + "Usage:\r\n" + " rset del exit \r\n" + "\r\n" + "Examples:\r\n" + " rset del exit n\r\n"); +} + +static void rset_show_del_door_usage(struct char_data *ch) +{ + send_to_char(ch, + "Deletes a door from an existing exit.\r\n" + "\r\n" + "Usage:\r\n" + " rset del door \r\n" + "\r\n" + "Examples:\r\n" + " rset del door n\r\n"); +} + +static void rset_show_del_key_usage(struct char_data *ch) +{ + send_to_char(ch, + "Deletes a key from an existing door.\r\n" + "\r\n" + "Usage:\r\n" + " rset del key \r\n" + "\r\n" + "Examples:\r\n" + " rset del key n\r\n"); +} + +static void rset_show_del_hidden_usage(struct char_data *ch) +{ + send_to_char(ch, + "Deletes the hidden flag from an existing exit.\r\n" + "\r\n" + "Usage:\r\n" + " rset del hidden \r\n" + "\r\n" + "Examples:\r\n" + " rset del hidden n\r\n"); +} + +static void rset_show_del_forage_usage(struct char_data *ch) +{ + send_to_char(ch, + "Deletes a forage entry from the room.\r\n" + "\r\n" + "Usage:\r\n" + " rset del forage \r\n" + "\r\n" + "Examples:\r\n" + " rset del forage 301\r\n"); +} + +static void rset_show_del_edesc_usage(struct char_data *ch) +{ + send_to_char(ch, + "Deletes an extra description from the room.\r\n" + "\r\n" + "Usage:\r\n" + " rset del edesc \r\n" + "\r\n" + "Examples:\r\n" + " rset del edesc mosaic\r\n"); +} + +static int rset_find_room_flag(const char *arg) +{ + int i; + + for (i = 0; i < NUM_ROOM_FLAGS; i++) + if (is_abbrev(arg, room_bits[i])) + return i; + + return -1; +} + +static int rset_find_sector(const char *arg) +{ + int i; + + for (i = 0; i < NUM_ROOM_SECTORS; i++) + if (is_abbrev(arg, sector_types[i])) + return i; + + return -1; +} + +static int rset_find_dir(const char *arg) +{ + char dirbuf[MAX_INPUT_LENGTH]; + int dir; + + strlcpy(dirbuf, arg, sizeof(dirbuf)); + dir = search_block(dirbuf, dirs, FALSE); + if (dir == -1) { + strlcpy(dirbuf, arg, sizeof(dirbuf)); + dir = search_block(dirbuf, autoexits, FALSE); + } + + if (dir >= DIR_COUNT) + return -1; + + return dir; +} + +static void rset_mark_room_modified(room_rnum rnum) +{ + if (rnum == NOWHERE || rnum < 0 || rnum > top_of_world) + return; + + add_to_save_list(zone_table[world[rnum].zone].number, SL_WLD); +} + +static void rset_show_room(struct char_data *ch, struct room_data *room) +{ + char buf[MAX_STRING_LENGTH]; + char buf2[MAX_STRING_LENGTH]; + int i, count = 0; + + send_to_char(ch, "Room [%d]: %s\r\n", room->number, room->name ? room->name : ""); + send_to_char(ch, "Zone [%d]: %s\r\n", zone_table[room->zone].number, zone_table[room->zone].name); + + sprinttype(room->sector_type, sector_types, buf, sizeof(buf)); + send_to_char(ch, "Sector: %s\r\n", buf); + + sprintbitarray(room->room_flags, room_bits, RF_ARRAY_MAX, buf); + send_to_char(ch, "Flags: %s\r\n", buf); + + send_to_char(ch, "Description:\r\n%s", room->description ? room->description : " \r\n"); + + send_to_char(ch, "Exits:\r\n"); + for (i = 0; i < DIR_COUNT; i++) { + struct room_direction_data *exit = room->dir_option[i]; + room_rnum to_room; + const char *dir = dirs[i]; + char keybuf[32]; + + if (!exit) + continue; + + to_room = exit->to_room; + if (to_room == NOWHERE || to_room < 0 || to_room > top_of_world) + snprintf(buf2, sizeof(buf2), "NOWHERE"); + else + snprintf(buf2, sizeof(buf2), "%d", world[to_room].number); + + sprintbit(exit->exit_info, exit_bits, buf, sizeof(buf)); + if (IS_SET(exit->exit_info, EX_HIDDEN)) + strlcat(buf, "HIDDEN ", sizeof(buf)); + + if (exit->key == NOTHING) + strlcpy(keybuf, "None", sizeof(keybuf)); + else + snprintf(keybuf, sizeof(keybuf), "%d", exit->key); + + send_to_char(ch, " %-5s -> %s (door: %s, key: %s, flags: %s)\r\n", + dir, + buf2, + exit->keyword ? exit->keyword : "None", + keybuf, + buf); + count++; + } + if (!count) + send_to_char(ch, " None.\r\n"); + + send_to_char(ch, "Forage:\r\n"); + count = 0; + for (struct forage_entry *entry = room->forage; entry; entry = entry->next) { + obj_rnum rnum = real_object(entry->obj_vnum); + const char *sdesc = (rnum != NOTHING) ? obj_proto[rnum].short_description : "Unknown object"; + send_to_char(ch, " [%d] DC %d - %s\r\n", entry->obj_vnum, entry->dc, sdesc); + count++; + } + if (!count) + send_to_char(ch, " None.\r\n"); + + send_to_char(ch, "Extra Descs:\r\n"); + count = 0; + for (struct extra_descr_data *desc = room->ex_description; desc; desc = desc->next) { + send_to_char(ch, " %s\r\n", desc->keyword ? desc->keyword : ""); + count++; + } + if (!count) + send_to_char(ch, " None.\r\n"); +} + +static void rset_desc_edit(struct char_data *ch, struct room_data *room) +{ + char *oldtext = NULL; + + send_editor_help(ch->desc); + write_to_output(ch->desc, "Enter room description:\r\n\r\n"); + + if (room->description) { + write_to_output(ch->desc, "%s", room->description); + oldtext = strdup(room->description); + } + + string_write(ch->desc, &room->description, MAX_ROOM_DESC, 0, oldtext); + rset_mark_room_modified(IN_ROOM(ch)); +} + +static bool rset_room_has_flags(struct room_data *room) +{ + int i; + + for (i = 0; i < RF_ARRAY_MAX; i++) + if (room->room_flags[i]) + return TRUE; + + return FALSE; +} + +static void rset_validate_room(struct char_data *ch, struct room_data *room) +{ + int errors = 0; + int i; + + if (!room->name || !*room->name) { + send_to_char(ch, "Error: room name is not set.\r\n"); + errors++; + } + + if (!room->description || !*room->description) { + send_to_char(ch, "Error: room description is not set.\r\n"); + errors++; + } + + if (room->sector_type < 0 || room->sector_type >= NUM_ROOM_SECTORS) { + send_to_char(ch, "Error: sector type is invalid.\r\n"); + errors++; + } + + if (!rset_room_has_flags(room)) { + send_to_char(ch, "Error: at least one room flag should be set.\r\n"); + errors++; + } + + for (i = 0; i < DIR_COUNT; i++) { + struct room_direction_data *exit = room->dir_option[i]; + bool exit_valid; + + if (!exit) + continue; + + exit_valid = !(exit->to_room == NOWHERE || exit->to_room < 0 || exit->to_room > top_of_world); + + if (!exit_valid) { + send_to_char(ch, "Error: exit %s does not point to a valid room.\r\n", dirs[i]); + errors++; + } + + if (IS_SET(exit->exit_info, EX_ISDOOR) && !exit_valid) { + send_to_char(ch, "Error: door on %s has no valid exit.\r\n", dirs[i]); + errors++; + } + + if (exit->key != NOTHING) { + if (!IS_SET(exit->exit_info, EX_ISDOOR)) { + send_to_char(ch, "Error: key on %s is set without a door.\r\n", dirs[i]); + errors++; + } + if (real_object(exit->key) == NOTHING) { + send_to_char(ch, "Error: key vnum %d on %s does not exist.\r\n", exit->key, dirs[i]); + errors++; + } + } + + if (IS_SET(exit->exit_info, EX_HIDDEN) && !exit_valid) { + send_to_char(ch, "Error: hidden flag on %s has no valid exit.\r\n", dirs[i]); + errors++; + } + } + + for (struct forage_entry *entry = room->forage; entry; entry = entry->next) { + if (entry->obj_vnum <= 0 || real_object(entry->obj_vnum) == NOTHING) { + send_to_char(ch, "Error: forage object vnum %d is invalid.\r\n", entry->obj_vnum); + errors++; + } + if (entry->dc <= 0) { + send_to_char(ch, "Error: forage object vnum %d is missing a valid DC.\r\n", entry->obj_vnum); + errors++; + } + } + + for (struct extra_descr_data *desc = room->ex_description; desc; desc = desc->next) { + if (!desc->keyword || !*desc->keyword) { + send_to_char(ch, "Error: extra description is missing a keyword.\r\n"); + errors++; + } + if (!desc->description || !*desc->description) { + send_to_char(ch, "Error: extra description for %s is missing text.\r\n", + desc->keyword ? desc->keyword : ""); + errors++; + } + } + + if (!errors) + send_to_char(ch, "Room validates cleanly.\r\n"); + else + send_to_char(ch, "Validation failed: %d issue%s.\r\n", errors, errors == 1 ? "" : "s"); +} + +ACMD(do_rcreate) +{ + char arg[MAX_INPUT_LENGTH]; + char namebuf[MAX_INPUT_LENGTH]; + char descbuf[MAX_STRING_LENGTH]; + char timestr[64]; + struct room_data room; + room_vnum vnum; + room_rnum rnum; + zone_rnum znum; + time_t now; + + if (IS_NPC(ch) || ch->desc == NULL) { + send_to_char(ch, "rcreate is only usable by connected players.\r\n"); + return; + } + + argument = one_argument(argument, arg); + if (!*arg) { + rset_show_rcreate_usage(ch); + return; + } + + if (!is_number(arg)) { + rset_show_rcreate_usage(ch); + return; + } + + vnum = atoi(arg); + if (vnum <= 0) { + send_to_char(ch, "That is not a valid room vnum.\r\n"); + return; + } + + if (real_room(vnum) != NOWHERE) { + send_to_char(ch, "Room %d already exists.\r\n", vnum); + return; + } + + if ((znum = real_zone_by_thing(vnum)) == NOWHERE) { + send_to_char(ch, "That room number is not in a valid zone.\r\n"); + return; + } + + if (!can_edit_zone(ch, znum)) { + send_to_char(ch, "You do not have permission to modify that zone.\r\n"); + return; + } + + now = time(0); + strftime(timestr, sizeof(timestr), "%c", localtime(&now)); + snprintf(namebuf, sizeof(namebuf), "Unfinished room made by %s", GET_NAME(ch)); + snprintf(descbuf, sizeof(descbuf), + "This is an unfinished room created by %s on %s\r\n", + GET_NAME(ch), timestr); + + memset(&room, 0, sizeof(room)); + room.number = vnum; + room.zone = znum; + room.sector_type = SECT_INSIDE; + room.name = strdup(namebuf); + room.description = strdup(descbuf); + room.ex_description = NULL; + room.forage = NULL; + + rnum = add_room(&room); + + free(room.name); + free(room.description); + + if (rnum == NOWHERE) { + send_to_char(ch, "Room creation failed.\r\n"); + return; + } + + send_to_char(ch, "Room %d created.\r\n", vnum); +} + +ACMD(do_rset) +{ + char arg1[MAX_INPUT_LENGTH]; + char arg2[MAX_INPUT_LENGTH]; + char arg3[MAX_INPUT_LENGTH]; + struct room_data *room; + room_rnum rnum; + + if (IS_NPC(ch) || ch->desc == NULL) { + send_to_char(ch, "rset is only usable by connected players.\r\n"); + return; + } + + rnum = IN_ROOM(ch); + if (rnum == NOWHERE || rnum < 0 || rnum > top_of_world) { + send_to_char(ch, "You are not in a valid room.\r\n"); + return; + } + + if (!can_edit_zone(ch, world[rnum].zone)) { + send_to_char(ch, "You do not have permission to modify this zone.\r\n"); + return; + } + + room = &world[rnum]; + + argument = one_argument(argument, arg1); + if (!*arg1) { + rset_show_usage(ch); + return; + } + + if (is_abbrev(arg1, "show")) { + rset_show_room(ch, room); + return; + } + + if (is_abbrev(arg1, "set")) { + argument = one_argument(argument, arg2); + if (!*arg2) { + rset_show_set_usage(ch); + return; + } + + if (is_abbrev(arg2, "name")) { + skip_spaces(&argument); + if (!*argument) { + rset_show_set_usage(ch); + return; + } + genolc_checkstring(ch->desc, argument); + if (count_non_protocol_chars(argument) > MAX_ROOM_NAME / 2) { + send_to_char(ch, "Size limited to %d non-protocol characters.\r\n", MAX_ROOM_NAME / 2); + return; + } + if (room->name) + free(room->name); + argument[MAX_ROOM_NAME - 1] = '\0'; + room->name = str_udup(argument); + rset_mark_room_modified(rnum); + send_to_char(ch, "Room name set.\r\n"); + return; + } + + if (is_abbrev(arg2, "sector")) { + int sector; + + argument = one_argument(argument, arg3); + if (!*arg3) { + rset_show_set_sector_usage(ch); + return; + } + + if (is_number(arg3)) + sector = atoi(arg3) - 1; + else + sector = rset_find_sector(arg3); + + if (sector < 0 || sector >= NUM_ROOM_SECTORS) { + send_to_char(ch, "Invalid sector type.\r\n"); + return; + } + + room->sector_type = sector; + rset_mark_room_modified(rnum); + send_to_char(ch, "Sector type set.\r\n"); + return; + } + + { + int flag; + + flag = rset_find_room_flag(arg2); + if (flag >= 0) { + SET_BIT_AR(room->room_flags, flag); + rset_mark_room_modified(rnum); + send_to_char(ch, "Room flag set.\r\n"); + return; + } + } + + rset_show_set_usage(ch); + return; + } + + if (is_abbrev(arg1, "add")) { + argument = one_argument(argument, arg2); + if (!*arg2) { + rset_show_add_usage(ch); + return; + } + + if (is_abbrev(arg2, "flags")) { + bool any = FALSE; + + if (!*argument) { + rset_show_add_flags_usage(ch); + return; + } + + while (*argument) { + int flag; + + argument = one_argument(argument, arg3); + if (!*arg3) + break; + + flag = rset_find_room_flag(arg3); + if (flag < 0) { + send_to_char(ch, "Unknown room flag: %s\r\n", arg3); + continue; + } + + SET_BIT_AR(room->room_flags, flag); + any = TRUE; + } + + if (any) { + rset_mark_room_modified(rnum); + send_to_char(ch, "Room flags updated.\r\n"); + } + return; + } + + if (is_abbrev(arg2, "exit")) { + int dir; + room_rnum to_room; + + argument = one_argument(argument, arg3); + argument = one_argument(argument, arg1); + if (!*arg3 || !*arg1) { + rset_show_add_exit_usage(ch); + return; + } + + dir = rset_find_dir(arg3); + if (dir < 0) { + send_to_char(ch, "Invalid direction.\r\n"); + return; + } + + if (!is_number(arg1)) { + send_to_char(ch, "Room number must be numeric.\r\n"); + return; + } + + to_room = real_room(atoi(arg1)); + if (to_room == NOWHERE) { + send_to_char(ch, "That room does not exist.\r\n"); + return; + } + + if (!room->dir_option[dir]) { + CREATE(room->dir_option[dir], struct room_direction_data, 1); + room->dir_option[dir]->general_description = NULL; + room->dir_option[dir]->keyword = NULL; + room->dir_option[dir]->exit_info = 0; + room->dir_option[dir]->key = NOTHING; + } + + room->dir_option[dir]->to_room = to_room; + rset_mark_room_modified(rnum); + send_to_char(ch, "Exit %s set to room %d.\r\n", dirs[dir], world[to_room].number); + return; + } + + if (is_abbrev(arg2, "door")) { + int dir; + char *door_name; + + argument = one_argument(argument, arg3); + skip_spaces(&argument); + door_name = argument; + + if (!*arg3 || !*door_name) { + rset_show_add_door_usage(ch); + return; + } + + dir = rset_find_dir(arg3); + if (dir < 0) { + send_to_char(ch, "Invalid direction.\r\n"); + return; + } + + if (!room->dir_option[dir] || room->dir_option[dir]->to_room == NOWHERE) { + send_to_char(ch, "That exit does not exist.\r\n"); + return; + } + + genolc_checkstring(ch->desc, door_name); + if (room->dir_option[dir]->keyword) + free(room->dir_option[dir]->keyword); + room->dir_option[dir]->keyword = str_udup(door_name); + SET_BIT(room->dir_option[dir]->exit_info, EX_ISDOOR); + rset_mark_room_modified(rnum); + send_to_char(ch, "Door added to %s.\r\n", dirs[dir]); + return; + } + + if (is_abbrev(arg2, "key")) { + int dir; + int key_vnum; + + argument = one_argument(argument, arg3); + argument = one_argument(argument, arg1); + if (!*arg3 || !*arg1) { + rset_show_add_key_usage(ch); + return; + } + + dir = rset_find_dir(arg3); + if (dir < 0) { + send_to_char(ch, "Invalid direction.\r\n"); + return; + } + + if (!room->dir_option[dir] || room->dir_option[dir]->to_room == NOWHERE) { + send_to_char(ch, "That exit does not exist.\r\n"); + return; + } + + if (!IS_SET(room->dir_option[dir]->exit_info, EX_ISDOOR)) { + send_to_char(ch, "That exit has no door.\r\n"); + return; + } + + if (!is_number(arg1)) { + send_to_char(ch, "Key number must be numeric.\r\n"); + return; + } + + key_vnum = atoi(arg1); + if (real_object(key_vnum) == NOTHING) { + send_to_char(ch, "That key vnum does not exist.\r\n"); + return; + } + + room->dir_option[dir]->key = key_vnum; + rset_mark_room_modified(rnum); + send_to_char(ch, "Key set on %s.\r\n", dirs[dir]); + return; + } + + if (is_abbrev(arg2, "hidden")) { + int dir; + + argument = one_argument(argument, arg3); + if (!*arg3) { + rset_show_add_hidden_usage(ch); + return; + } + + dir = rset_find_dir(arg3); + if (dir < 0) { + send_to_char(ch, "Invalid direction.\r\n"); + return; + } + + if (!room->dir_option[dir] || room->dir_option[dir]->to_room == NOWHERE) { + send_to_char(ch, "That exit does not exist.\r\n"); + return; + } + + SET_BIT(room->dir_option[dir]->exit_info, EX_HIDDEN); + rset_mark_room_modified(rnum); + send_to_char(ch, "Hidden flag set on %s.\r\n", dirs[dir]); + return; + } + + if (is_abbrev(arg2, "forage")) { + int vnum, dc; + struct forage_entry *entry; + + argument = one_argument(argument, arg3); + argument = one_argument(argument, arg1); + if (!*arg3 || !*arg1) { + rset_show_add_forage_usage(ch); + return; + } + + if (!is_number(arg3) || !is_number(arg1)) { + send_to_char(ch, "Usage: rset add forage \r\n"); + return; + } + + vnum = atoi(arg3); + dc = atoi(arg1); + + if (vnum <= 0 || dc <= 0) { + send_to_char(ch, "Both vnum and DC must be positive.\r\n"); + return; + } + + if (real_object(vnum) == NOTHING) { + send_to_char(ch, "That object vnum does not exist.\r\n"); + return; + } + + CREATE(entry, struct forage_entry, 1); + entry->obj_vnum = vnum; + entry->dc = dc; + entry->next = room->forage; + room->forage = entry; + rset_mark_room_modified(rnum); + send_to_char(ch, "Forage entry added.\r\n"); + return; + } + + if (is_abbrev(arg2, "edesc")) { + struct extra_descr_data *desc; + char *keyword; + char *edesc; + + argument = one_argument(argument, arg3); + skip_spaces(&argument); + keyword = arg3; + edesc = argument; + + if (!*keyword || !*edesc) { + rset_show_add_edesc_usage(ch); + return; + } + + genolc_checkstring(ch->desc, edesc); + genolc_checkstring(ch->desc, keyword); + + CREATE(desc, struct extra_descr_data, 1); + desc->keyword = str_udup(keyword); + desc->description = str_udup(edesc); + desc->next = room->ex_description; + room->ex_description = desc; + rset_mark_room_modified(rnum); + send_to_char(ch, "Extra description added.\r\n"); + return; + } + + rset_show_add_usage(ch); + return; + } + + if (is_abbrev(arg1, "del")) { + argument = one_argument(argument, arg2); + if (!*arg2) { + rset_show_del_usage(ch); + return; + } + + if (is_abbrev(arg2, "flags")) { + bool any = FALSE; + + if (!*argument) { + rset_show_del_flags_usage(ch); + return; + } + + while (*argument) { + int flag; + + argument = one_argument(argument, arg3); + if (!*arg3) + break; + + flag = rset_find_room_flag(arg3); + if (flag < 0) { + send_to_char(ch, "Unknown room flag: %s\r\n", arg3); + continue; + } + + REMOVE_BIT_AR(room->room_flags, flag); + any = TRUE; + } + + if (any) { + rset_mark_room_modified(rnum); + send_to_char(ch, "Room flags updated.\r\n"); + } + return; + } + + if (is_abbrev(arg2, "exit")) { + int dir; + + argument = one_argument(argument, arg3); + if (!*arg3) { + rset_show_del_exit_usage(ch); + return; + } + + dir = rset_find_dir(arg3); + if (dir < 0) { + send_to_char(ch, "Invalid direction.\r\n"); + return; + } + + if (!room->dir_option[dir]) { + send_to_char(ch, "That exit does not exist.\r\n"); + return; + } + + if (room->dir_option[dir]->general_description) + free(room->dir_option[dir]->general_description); + if (room->dir_option[dir]->keyword) + free(room->dir_option[dir]->keyword); + free(room->dir_option[dir]); + room->dir_option[dir] = NULL; + rset_mark_room_modified(rnum); + send_to_char(ch, "Exit %s removed.\r\n", dirs[dir]); + return; + } + + if (is_abbrev(arg2, "door")) { + int dir; + + argument = one_argument(argument, arg3); + if (!*arg3) { + rset_show_del_door_usage(ch); + return; + } + + dir = rset_find_dir(arg3); + if (dir < 0) { + send_to_char(ch, "Invalid direction.\r\n"); + return; + } + + if (!room->dir_option[dir]) { + send_to_char(ch, "That exit does not exist.\r\n"); + return; + } + + if (room->dir_option[dir]->keyword) { + free(room->dir_option[dir]->keyword); + room->dir_option[dir]->keyword = NULL; + } + + REMOVE_BIT(room->dir_option[dir]->exit_info, EX_ISDOOR); + REMOVE_BIT(room->dir_option[dir]->exit_info, EX_CLOSED); + REMOVE_BIT(room->dir_option[dir]->exit_info, EX_LOCKED); + REMOVE_BIT(room->dir_option[dir]->exit_info, EX_PICKPROOF); + REMOVE_BIT(room->dir_option[dir]->exit_info, EX_HIDDEN); + rset_mark_room_modified(rnum); + send_to_char(ch, "Door removed from %s.\r\n", dirs[dir]); + return; + } + + if (is_abbrev(arg2, "key")) { + int dir; + + argument = one_argument(argument, arg3); + if (!*arg3) { + rset_show_del_key_usage(ch); + return; + } + + dir = rset_find_dir(arg3); + if (dir < 0) { + send_to_char(ch, "Invalid direction.\r\n"); + return; + } + + if (!room->dir_option[dir]) { + send_to_char(ch, "That exit does not exist.\r\n"); + return; + } + + room->dir_option[dir]->key = NOTHING; + rset_mark_room_modified(rnum); + send_to_char(ch, "Key removed from %s.\r\n", dirs[dir]); + return; + } + + if (is_abbrev(arg2, "hidden")) { + int dir; + + argument = one_argument(argument, arg3); + if (!*arg3) { + rset_show_del_hidden_usage(ch); + return; + } + + dir = rset_find_dir(arg3); + if (dir < 0) { + send_to_char(ch, "Invalid direction.\r\n"); + return; + } + + if (!room->dir_option[dir]) { + send_to_char(ch, "That exit does not exist.\r\n"); + return; + } + + REMOVE_BIT(room->dir_option[dir]->exit_info, EX_HIDDEN); + rset_mark_room_modified(rnum); + send_to_char(ch, "Hidden flag removed from %s.\r\n", dirs[dir]); + return; + } + + if (is_abbrev(arg2, "forage")) { + int vnum; + struct forage_entry *entry = room->forage; + struct forage_entry *prev = NULL; + + argument = one_argument(argument, arg3); + if (!*arg3) { + rset_show_del_forage_usage(ch); + return; + } + + if (!is_number(arg3)) { + send_to_char(ch, "Usage: rset del forage \r\n"); + return; + } + + vnum = atoi(arg3); + while (entry) { + if (entry->obj_vnum == vnum) + break; + prev = entry; + entry = entry->next; + } + + if (!entry) { + send_to_char(ch, "No forage entry found for vnum %d.\r\n", vnum); + return; + } + + if (prev) + prev->next = entry->next; + else + room->forage = entry->next; + free(entry); + rset_mark_room_modified(rnum); + send_to_char(ch, "Forage entry removed.\r\n"); + return; + } + + if (is_abbrev(arg2, "edesc")) { + struct extra_descr_data *desc = room->ex_description; + struct extra_descr_data *prev = NULL; + + argument = one_argument(argument, arg3); + if (!*arg3) { + rset_show_del_edesc_usage(ch); + return; + } + + while (desc) { + if (desc->keyword && isname(arg3, desc->keyword)) + break; + prev = desc; + desc = desc->next; + } + + if (!desc) { + send_to_char(ch, "No extra description found for %s.\r\n", arg3); + return; + } + + if (prev) + prev->next = desc->next; + else + room->ex_description = desc->next; + + if (desc->keyword) + free(desc->keyword); + if (desc->description) + free(desc->description); + free(desc); + rset_mark_room_modified(rnum); + send_to_char(ch, "Extra description removed.\r\n"); + return; + } + + rset_show_del_usage(ch); + return; + } + + if (is_abbrev(arg1, "desc")) { + rset_show_desc_usage(ch); + rset_desc_edit(ch, room); + return; + } + + if (is_abbrev(arg1, "clear")) { + if (*argument) { + rset_show_clear_usage(ch); + return; + } + + free_room_strings(room); + room->name = strdup("An unfinished room"); + room->description = strdup("You are in an unfinished room.\r\n"); + room->sector_type = SECT_INSIDE; + memset(room->room_flags, 0, sizeof(room->room_flags)); + rset_mark_room_modified(rnum); + send_to_char(ch, "Room cleared.\r\n"); + return; + } + + if (is_abbrev(arg1, "validate")) { + if (*argument) { + rset_show_validate_usage(ch); + return; + } + rset_validate_room(ch, room); + return; + } + + rset_show_usage(ch); +} diff --git a/src/rset.h b/src/rset.h new file mode 100644 index 0000000..131d33b --- /dev/null +++ b/src/rset.h @@ -0,0 +1,14 @@ +/** +* @file rset.h +* Room creation/configuration and utility headers. +* +* This set of code was not originally part of the circlemud distribution. +*/ + +#ifndef RSET_H +#define RSET_H + +ACMD(do_rset); +ACMD(do_rcreate); + +#endif From 691e15867e4031b0178dd90be55faca29a5659d2 Mon Sep 17 00:00:00 2001 From: kinther Date: Wed, 31 Dec 2025 09:55:40 -0800 Subject: [PATCH 33/40] Show door keywords when looking in a direction --- src/act.informative.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/act.informative.c b/src/act.informative.c index 4e965e5..4956ccb 100644 --- a/src/act.informative.c +++ b/src/act.informative.c @@ -961,10 +961,23 @@ static void look_in_direction(struct char_data *ch, int dir) { static const char *range_labels[] = { "[near]", "[far]", "[very far]" }; room_rnum room = IN_ROOM(ch); + struct room_direction_data *start_exit = W_EXIT(room, dir); + const char *door_name = NULL; int distance; bool blocked = FALSE; - send_to_char(ch, "You look to the %s and see:\r\n", dirs[dir]); + if (start_exit && start_exit->to_room != NOWHERE && + EXIT_FLAGGED(start_exit, EX_ISDOOR) && + (!EXIT_FLAGGED(start_exit, EX_HIDDEN) || PRF_FLAGGED(ch, PRF_HOLYLIGHT))) { + door_name = start_exit->keyword ? fname(start_exit->keyword) : "door"; + if (EXIT_FLAGGED(start_exit, EX_CLOSED)) { + send_to_char(ch, "You look to the %s and see the %s is closed.\r\n", dirs[dir], door_name); + return; + } + send_to_char(ch, "You look to the %s and see the %s is open:\r\n", dirs[dir], door_name); + } else { + send_to_char(ch, "You look to the %s and see:\r\n", dirs[dir]); + } for (distance = 0; distance < 3; distance++) { struct room_direction_data *exit = NULL; From aac7cee6dc029325830c2a849a26a12ee94ed550 Mon Sep 17 00:00:00 2001 From: kinther Date: Wed, 31 Dec 2025 14:35:19 -0800 Subject: [PATCH 34/40] Add ocreate and osave commands --- lib/world/obj/1.obj | 8 ++ src/Makefile.amiga | 6 +- src/Makefile.arc | 7 +- src/Makefile.bcc | 9 +- src/Makefile.bcc55 | 9 +- src/Makefile.lcc | 25 ++++- src/Makefile.msvc | 5 + src/Makefile.os2 | 6 +- src/Smakefile | 7 +- src/act.h | 2 +- src/interpreter.c | 2 + src/rset.h | 14 --- src/{rset.c => set.c} | 235 +++++++++++++++++++++++++++++++++++++++++- src/set.h | 14 +++ 14 files changed, 321 insertions(+), 28 deletions(-) delete mode 100644 src/rset.h rename src/{rset.c => set.c} (84%) create mode 100644 src/set.h diff --git a/lib/world/obj/1.obj b/lib/world/obj/1.obj index f284cd9..8a1b289 100644 --- a/lib/world/obj/1.obj +++ b/lib/world/obj/1.obj @@ -642,4 +642,12 @@ hide, reinforcing the foot from the ground below. 11 0 0 0 0 ah 0 0 0 0 0 0 0 0 0 0 0 1 40 0 0 0 +#168 +unfinished object~ +unfinished object made by Kinther~ +This is an unfinished object created by Kinther on Wed Dec 31 14:19:06 2025~ +~ +0 0 0 0 0 a 0 0 0 0 0 0 0 +0 0 0 0 +0 0 0 0 0 $~ diff --git a/src/Makefile.amiga b/src/Makefile.amiga index d4fe8f5..1ca73cc 100644 --- a/src/Makefile.amiga +++ b/src/Makefile.amiga @@ -20,7 +20,7 @@ PROFILE = CFLAGS = $(MYFLAGS) $(PROFILE) OBJFILES = comm.o act.comm.o act.informative.o act.movement.o act.item.o \ - act.offensive.o act.other.o act.social.o act.wizard.o ban.o boards.o \ + act.offensive.o act.other.o act.social.o act.wizard.o set.o ban.o boards.o \ castle.o class.o config.o constants.o db.o fight.o graph.o handler.o \ house.o interpreter.o limits.o magic.o mail.o mobact.o modify.o \ objsave.o shop.o spec_assign.o spec_procs.o spell_parser.o \ @@ -115,6 +115,10 @@ act.social.o: act.social.c conf.h sysdep.h structs.h utils.h comm.h \ act.wizard.o: act.wizard.c conf.h sysdep.h structs.h utils.h comm.h \ interpreter.h handler.h db.h spells.h house.h screen.h constants.h $(CC) -c $(CFLAGS) act.wizard.c +set.o: set.c conf.h sysdep.h structs.h utils.h comm.h \ + interpreter.h handler.h db.h constants.h genolc.h genwld.h genzon.h \ + oasis.h improved-edit.h modify.h genobj.h dg_scripts.h set.h + $(CC) -c $(CFLAGS) set.c ban.o: ban.c conf.h sysdep.h structs.h utils.h comm.h interpreter.h handler.h db.h $(CC) -c $(CFLAGS) ban.c boards.o: boards.c conf.h sysdep.h structs.h utils.h comm.h db.h boards.h \ diff --git a/src/Makefile.arc b/src/Makefile.arc index 29c1c61..6c68962 100644 --- a/src/Makefile.arc +++ b/src/Makefile.arc @@ -22,7 +22,7 @@ BINDIR = ^.bin CFLAGS = $(MYFLAGS) $(PROFILE) OBJFILES = o.comm act.o.comm act.o.informative act.o.movement act.o.item \ - act.o.offensive act.o.other act.o.social act.o.wizard o.ban o.boards \ + act.o.offensive act.o.other act.o.social act.o.wizard o.set o.ban o.boards \ o.castle o.class o.config o.constants o.db o.fight o.graph o.handler \ o.house o.interpreter o.limits o.magic o.mail o.mobact o.modify \ o.objsave o.random o.shop o.spec_assign o.spec_procs \ @@ -73,6 +73,11 @@ act.o.wizard: act.c.wizard h.conf h.sysdep h.structs \ h.utils h.comm h.interpreter h.handler \ h.db h.spells h.house h.screen h.constants $(CC) -c $(CFLAGS) act.c.wizard -o act.o.wizard +o.set: c.set h.conf h.sysdep h.structs \ + h.utils h.comm h.interpreter h.handler \ + h.db h.constants h.genobj h.genolc h.genwld h.genzon h.oasis \ + h.improved-edit h.modify h.dg_scripts h.set + $(CC) -c $(CFLAGS) c.set -o o.set o.ban: c.ban h.conf h.sysdep h.structs h.utils h.comm h.interpreter h.handler h.db $(CC) -c $(CFLAGS) c.ban o.boards: c.boards h.conf h.sysdep h.structs h.utils h.comm h.db h.boards \ diff --git a/src/Makefile.bcc b/src/Makefile.bcc index d5b6493..73b1fd1 100644 --- a/src/Makefile.bcc +++ b/src/Makefile.bcc @@ -49,6 +49,7 @@ Dep_circledexe = \ act.informative.obj\ act.offensive.obj\ act.other.obj\ + set.obj\ boards.obj\ ban.obj\ act.wizard.obj\ @@ -93,6 +94,7 @@ act.item.obj+ act.informative.obj+ act.offensive.obj+ act.other.obj+ +set.obj+ boards.obj+ ban.obj+ act.wizard.obj+ @@ -163,6 +165,11 @@ act.other.obj : act.other.c $(CompOptsAt_circledexe) $(CompInheritOptsAt_circledexe) -o$@ act.other.c | +set.obj : set.c + $(BCC32) -P- -c @&&| + $(CompOptsAt_circledexe) $(CompInheritOptsAt_circledexe) -o$@ set.c +| + boards.obj : boards.c $(BCC32) -P- -c @&&| $(CompOptsAt_circledexe) $(CompInheritOptsAt_circledexe) -o$@ boards.c @@ -339,5 +346,3 @@ BccW32.cfg : -WC -g0 | $@ - - diff --git a/src/Makefile.bcc55 b/src/Makefile.bcc55 index 9d16c19..4479b1b 100644 --- a/src/Makefile.bcc55 +++ b/src/Makefile.bcc55 @@ -50,6 +50,7 @@ Dep_circledexe = \ act.informative.obj\ act.offensive.obj\ act.other.obj\ + set.obj\ boards.obj\ ban.obj\ act.wizard.obj\ @@ -94,6 +95,7 @@ act.item.obj+ act.informative.obj+ act.offensive.obj+ act.other.obj+ +set.obj+ boards.obj+ ban.obj+ act.wizard.obj+ @@ -162,6 +164,11 @@ act.other.obj : act.other.c $(CompOptsAt_circledexe) $(CompInheritOptsAt_circledexe) -o$@ act.other.c | +set.obj : set.c + $(BCC32) -P- -c @&&| + $(CompOptsAt_circledexe) $(CompInheritOptsAt_circledexe) -o$@ set.c +| + boards.obj : boards.c $(BCC32) -P- -c @&&| $(CompOptsAt_circledexe) $(CompInheritOptsAt_circledexe) -o$@ boards.c @@ -339,5 +346,3 @@ BccW32.cfg : -WC -g0 | $@ - - diff --git a/src/Makefile.lcc b/src/Makefile.lcc index f2d4df8..a128ba6 100644 --- a/src/Makefile.lcc +++ b/src/Makefile.lcc @@ -48,6 +48,7 @@ OBJS=\ boards.obj \ ban.obj \ act.wizard.obj \ + set.obj \ act.social.obj \ act.other.obj \ act.offensive.obj \ @@ -494,6 +495,29 @@ ACT_WIZARD_C=\ act.wizard.obj: $(ACT_WIZARD_C) $(DISTDIR)\src\act.wizard.c $(CC) $(CFLAGS) $(DISTDIR)\src\act.wizard.c +# Build SET.C +SET_C=\ + $(DISTDIR)\src\sysdep.h\ + $(DISTDIR)\src\structs.h\ + $(DISTDIR)\src\utils.h\ + $(DISTDIR)\src\comm.h\ + $(DISTDIR)\src\interpreter.h\ + $(DISTDIR)\src\handler.h\ + $(DISTDIR)\src\db.h\ + $(DISTDIR)\src\constants.h\ + $(DISTDIR)\src\genobj.h\ + $(DISTDIR)\src\genolc.h\ + $(DISTDIR)\src\genwld.h\ + $(DISTDIR)\src\genzon.h\ + $(DISTDIR)\src\oasis.h\ + $(DISTDIR)\src\improved-edit.h\ + $(DISTDIR)\src\modify.h\ + $(DISTDIR)\src\dg_scripts.h\ + $(DISTDIR)\src\set.h\ + +set.obj: $(SET_C) $(DISTDIR)\src\set.c + $(CC) $(CFLAGS) $(DISTDIR)\src\set.c + # Build ACT.SOCIAL.C ACT_SOCIAL_C=\ $(DISTDIR)\src\sysdep.h\ @@ -598,4 +622,3 @@ ACT_COMM_C=\ act.comm.obj: $(ACT_COMM_C) $(DISTDIR)\src\act.comm.c $(CC) $(CFLAGS) $(DISTDIR)\src\act.comm.c - diff --git a/src/Makefile.msvc b/src/Makefile.msvc index cc06f68..60d54e9 100644 --- a/src/Makefile.msvc +++ b/src/Makefile.msvc @@ -37,6 +37,7 @@ MAKE = $(MAKE) /NOLOGO /S OBJFILES = comm.obj act.comm.obj act.informative.obj act.movement.obj act.item.obj \ asciimap.obj act.offensive.obj act.other.obj act.social.obj act.wizard.obj \ +set.obj \ ban.obj boards.obj castle.obj class.obj config.obj constants.obj db.obj \ dg_event.obj dg_scripts.obj dg_triggers.obj fight.obj genolc.obj graph.obj \ handler.obj house.obj ibt.obj interpreter.obj limits.obj lists.obj magic.obj \ @@ -83,6 +84,10 @@ act.social.obj: act.social.c conf.h sysdep.h structs.h utils.h comm.h \ act.wizard.obj: act.wizard.c conf.h sysdep.h structs.h utils.h comm.h \ interpreter.h handler.h db.h spells.h house.h screen.h constants.h $(CC) -c $(CFLAGS) act.wizard.c +set.obj: set.c conf.h sysdep.h structs.h utils.h comm.h \ + interpreter.h handler.h db.h constants.h genolc.h genwld.h genzon.h \ + oasis.h improved-edit.h modify.h genobj.h dg_scripts.h set.h + $(CC) -c $(CFLAGS) set.c ban.obj: ban.c conf.h sysdep.h structs.h utils.h comm.h interpreter.h handler.h db.h $(CC) -c $(CFLAGS) ban.c boards.obj: boards.c conf.h sysdep.h structs.h utils.h comm.h db.h boards.h \ diff --git a/src/Makefile.os2 b/src/Makefile.os2 index 765d057..c22f256 100644 --- a/src/Makefile.os2 +++ b/src/Makefile.os2 @@ -22,7 +22,7 @@ LIB = -lsocket CFLAGS = $(MYFLAGS) $(PROFILE) OBJFILES = comm.o act.comm.o act.informative.o act.movement.o act.item.o \ - act.offensive.o act.other.o act.social.o act.wizard.o ban.o boards.o \ + act.offensive.o act.other.o act.social.o act.wizard.o set.o ban.o boards.o \ castle.o class.o config.o constants.o db.o fight.o graph.o handler.o \ house.o interpreter.o limits.o magic.o mail.o mobact.o modify.o \ objsave.o shop.o spec_assign.o spec_procs.o spell_parser.o \ @@ -117,6 +117,10 @@ act.social.o: act.social.c conf.h sysdep.h structs.h utils.h comm.h \ act.wizard.o: act.wizard.c conf.h sysdep.h structs.h utils.h comm.h \ interpreter.h handler.h db.h spells.h house.h screen.h constants.h $(CC) -c $(CFLAGS) act.wizard.c +set.o: set.c conf.h sysdep.h structs.h utils.h comm.h \ + interpreter.h handler.h db.h constants.h genolc.h genwld.h genzon.h \ + oasis.h improved-edit.h modify.h genobj.h dg_scripts.h set.h + $(CC) -c $(CFLAGS) set.c ban.o: ban.c conf.h sysdep.h structs.h utils.h comm.h interpreter.h handler.h db.h $(CC) -c $(CFLAGS) ban.c boards.o: boards.c conf.h sysdep.h structs.h utils.h comm.h db.h boards.h \ diff --git a/src/Smakefile b/src/Smakefile index 1f62ca5..5635a98 100644 --- a/src/Smakefile +++ b/src/Smakefile @@ -18,7 +18,7 @@ CFLAGS = NOLINK $(MYFLAGS) $(PROFILE) MAKE = SMAKE OBJFILES = comm.o act.comm.o act.informative.o act.movement.o act.item.o \ - act.offensive.o act.other.o act.social.o act.wizard.o ban.o boards.o \ + act.offensive.o act.other.o act.social.o act.wizard.o set.o ban.o boards.o \ castle.o class.o config.o constants.o db.o fight.o graph.o handler.o \ house.o interpreter.o limits.o magic.o mail.o mobact.o modify.o \ objsave.o olc.o shop.o spec_assign.o spec_procs.o spell_parser.o \ @@ -109,6 +109,10 @@ act.social.o: act.social.c conf.h sysdep.h structs.h utils.h comm.h \ act.wizard.o: act.wizard.c conf.h sysdep.h structs.h utils.h comm.h \ interpreter.h handler.h db.h spells.h house.h screen.h $(CC) $(CFLAGS) act.wizard.c +set.o: set.c conf.h sysdep.h structs.h utils.h comm.h \ + interpreter.h handler.h db.h constants.h genolc.h genwld.h genzon.h \ + oasis.h improved-edit.h modify.h genobj.h dg_scripts.h set.h + $(CC) $(CFLAGS) set.c ban.o: ban.c conf.h sysdep.h structs.h utils.h comm.h interpreter.h handler.h db.h $(CC) $(CFLAGS) ban.c boards.o: boards.c conf.h sysdep.h structs.h utils.h comm.h db.h boards.h \ @@ -189,4 +193,3 @@ utils.o: utils.c conf.h sysdep.h structs.h utils.h comm.h screen.h spells.h \ weather.o: weather.c conf.h sysdep.h structs.h utils.h comm.h handler.h \ interpreter.h db.h $(CC) $(CFLAGS) weather.c - diff --git a/src/act.h b/src/act.h index 5325627..8f20741 100644 --- a/src/act.h +++ b/src/act.h @@ -19,7 +19,7 @@ #define _ACT_H_ #include "utils.h" /* for the ACMD macro */ -#include "rset.h" +#include "set.h" #ifndef MAX_EMOTE_TOKENS #define MAX_EMOTE_TOKENS 16 diff --git a/src/interpreter.c b/src/interpreter.c index 17f0301..d1f8244 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -229,7 +229,9 @@ cpp_extern const struct command_info cmd_info[] = { { "olc" , "olc" , POS_DEAD , do_show_save_list, LVL_BUILDER, 0 }, { "olist" , "olist" , POS_DEAD , do_oasis_list, LVL_BUILDER, SCMD_OASIS_OLIST }, { "oedit" , "oedit" , POS_DEAD , do_oasis_oedit, LVL_BUILDER, 0 }, + { "ocreate" , "ocreate" , POS_DEAD , do_ocreate , LVL_BUILDER, 0 }, { "ooc" , "oo" , POS_RESTING , do_ooc , 0, 0 }, + { "osave" , "osave" , POS_DEAD , do_osave , LVL_BUILDER, 0 }, { "oset" , "oset" , POS_DEAD , do_oset, LVL_BUILDER, 0 }, { "ocopy" , "ocopy" , POS_DEAD , do_oasis_copy, LVL_GOD, CON_OEDIT }, diff --git a/src/rset.h b/src/rset.h deleted file mode 100644 index 131d33b..0000000 --- a/src/rset.h +++ /dev/null @@ -1,14 +0,0 @@ -/** -* @file rset.h -* Room creation/configuration and utility headers. -* -* This set of code was not originally part of the circlemud distribution. -*/ - -#ifndef RSET_H -#define RSET_H - -ACMD(do_rset); -ACMD(do_rcreate); - -#endif diff --git a/src/rset.c b/src/set.c similarity index 84% rename from src/rset.c rename to src/set.c index 01d2b01..ff39a0a 100644 --- a/src/rset.c +++ b/src/set.c @@ -1,6 +1,6 @@ /** -* @file rset.c -* Room creation/configuration and utility routines. +* @file set.c +* Builder room/object creation and utility functions. * * This set of code was not originally part of the circlemud distribution. */ @@ -21,8 +21,10 @@ #include "oasis.h" #include "improved-edit.h" #include "modify.h" +#include "genobj.h" +#include "dg_scripts.h" -#include "rset.h" +#include "set.h" static void rset_show_usage(struct char_data *ch) { @@ -1290,3 +1292,230 @@ ACMD(do_rset) rset_show_usage(ch); } + +static struct obj_data *find_obj_vnum_nearby(struct char_data *ch, obj_vnum vnum) +{ + struct obj_data *obj; + + if (!ch || IN_ROOM(ch) == NOWHERE) + return NULL; + + for (obj = ch->carrying; obj; obj = obj->next_content) + if (CAN_SEE_OBJ(ch, obj) && GET_OBJ_VNUM(obj) == vnum) + return obj; + + for (obj = world[IN_ROOM(ch)].contents; obj; obj = obj->next_content) + if (CAN_SEE_OBJ(ch, obj) && GET_OBJ_VNUM(obj) == vnum) + return obj; + + return NULL; +} + +ACMD(do_ocreate) +{ + char arg[MAX_INPUT_LENGTH]; + char buf[MAX_STRING_LENGTH]; + char namebuf[MAX_NAME_LENGTH]; + char timestr[MAX_STRING_LENGTH]; + struct obj_data *newobj; + struct obj_data *obj; + obj_vnum vnum; + zone_rnum znum; + time_t ct; + + if (IS_NPC(ch) || ch->desc == NULL) { + send_to_char(ch, "ocreate is only usable by connected players.\r\n"); + return; + } + + one_argument(argument, arg); + + if (!*arg) { + send_to_char(ch, + "Creates a new unfinished object which can be configured.\r\n" + "\r\n" + "Usage:\r\n" + " ocreate \r\n" + "\r\n" + "Examples:\r\n" + " ocreate 1001\r\n"); + return; + } + + if (!is_number(arg)) { + send_to_char(ch, + "Creates a new unfinished object which can be configured.\r\n" + "\r\n" + "Usage:\r\n" + " ocreate \r\n" + "\r\n" + "Examples:\r\n" + " ocreate 1001\r\n"); + return; + } + + vnum = atoi(arg); + if (vnum < IDXTYPE_MIN || vnum > IDXTYPE_MAX) { + send_to_char(ch, "That object VNUM can't exist.\r\n"); + return; + } + + if (real_object(vnum) != NOTHING) { + send_to_char(ch, "Object %d already exists.\r\n", vnum); + return; + } + + znum = real_zone_by_thing(vnum); + if (znum == NOWHERE) { + send_to_char(ch, "Sorry, there is no zone for that number!\r\n"); + return; + } + + if (!can_edit_zone(ch, znum)) { + send_cannot_edit(ch, zone_table[znum].number); + return; + } + + CREATE(newobj, struct obj_data, 1); + clear_object(newobj); + + newobj->name = strdup("unfinished object"); + strlcpy(namebuf, GET_NAME(ch), sizeof(namebuf)); + snprintf(buf, sizeof(buf), "unfinished object made by %s", namebuf); + newobj->short_description = strdup(buf); + ct = time(0); + strftime(timestr, sizeof(timestr), "%c", localtime(&ct)); + snprintf(buf, sizeof(buf), + "This is an unfinished object created by %s on ", namebuf); + strlcat(buf, timestr, sizeof(buf)); + newobj->description = strdup(buf); + SET_BIT_AR(GET_OBJ_WEAR(newobj), ITEM_WEAR_TAKE); + + if (add_object(newobj, vnum) == NOTHING) { + free_object_strings(newobj); + free(newobj); + send_to_char(ch, "ocreate: failed to add object %d.\r\n", vnum); + return; + } + + if (in_save_list(zone_table[znum].number, SL_OBJ)) + remove_from_save_list(zone_table[znum].number, SL_OBJ); + + free_object_strings(newobj); + free(newobj); + + obj = read_object(vnum, VIRTUAL); + if (obj == NULL) { + send_to_char(ch, "ocreate: failed to instantiate object %d.\r\n", vnum); + return; + } + + obj_to_char(obj, ch); + send_to_char(ch, + "Object %d created (temporary). Use osave to write it to disk.\r\n", + vnum); +} + +ACMD(do_osave) +{ + char arg[MAX_INPUT_LENGTH]; + struct obj_data *obj; + struct obj_data *proto; + obj_rnum robj_num; + obj_vnum vnum; + zone_rnum znum; + + if (IS_NPC(ch) || ch->desc == NULL) { + send_to_char(ch, "osave is only usable by connected players.\r\n"); + return; + } + + one_argument(argument, arg); + + if (!*arg) { + send_to_char(ch, + "Saves an object and its current properties to disk, which will load upon next boot.\r\n" + "\r\n" + "Usage:\r\n" + " osave \r\n" + "\r\n" + "Examples:\r\n" + " osave 1001\r\n"); + return; + } + + if (!is_number(arg)) { + send_to_char(ch, + "Saves an object and its current properties to disk, which will load upon next boot.\r\n" + "\r\n" + "Usage:\r\n" + " osave \r\n" + "\r\n" + "Examples:\r\n" + " osave 1001\r\n"); + return; + } + + vnum = atoi(arg); + if (vnum < IDXTYPE_MIN || vnum > IDXTYPE_MAX) { + send_to_char(ch, "That object VNUM can't exist.\r\n"); + return; + } + + obj = find_obj_vnum_nearby(ch, vnum); + if (obj == NULL) { + send_to_char(ch, + "osave: object %d is not in your inventory or room.\r\n", vnum); + return; + } + + znum = real_zone_by_thing(vnum); + if (znum == NOWHERE) { + send_to_char(ch, "Sorry, there is no zone for that number!\r\n"); + return; + } + + if (!can_edit_zone(ch, znum)) { + send_cannot_edit(ch, zone_table[znum].number); + return; + } + + CREATE(proto, struct obj_data, 1); + clear_object(proto); + copy_object(proto, obj); + proto->in_room = NOWHERE; + proto->carried_by = NULL; + proto->worn_by = NULL; + proto->worn_on = NOWHERE; + proto->in_obj = NULL; + proto->contains = NULL; + proto->next_content = NULL; + proto->next = NULL; + proto->sitting_here = NULL; + proto->events = NULL; + proto->script = NULL; + proto->script_id = 0; + + if ((robj_num = add_object(proto, vnum)) == NOTHING) { + free_object_strings(proto); + free(proto); + send_to_char(ch, "osave: failed to update object %d.\r\n", vnum); + return; + } + + free_object_strings(proto); + free(proto); + + for (obj = object_list; obj; obj = obj->next) { + if (obj->item_number != robj_num) + continue; + if (SCRIPT(obj)) + extract_script(obj, OBJ_TRIGGER); + free_proto_script(obj, OBJ_TRIGGER); + copy_proto_script(&obj_proto[robj_num], obj, OBJ_TRIGGER); + assign_triggers(obj, OBJ_TRIGGER); + } + + save_objects(znum); + send_to_char(ch, "osave: object %d saved to disk.\r\n", vnum); +} diff --git a/src/set.h b/src/set.h new file mode 100644 index 0000000..bf3380a --- /dev/null +++ b/src/set.h @@ -0,0 +1,14 @@ +/** +* @file set.h +* Builder room/object creation and utility headers. +*/ + +#ifndef SET_H +#define SET_H + +ACMD(do_rset); +ACMD(do_rcreate); +ACMD(do_ocreate); +ACMD(do_osave); + +#endif From fa1a64a47ab5b96daeedc80002cf2243f28a4d2c Mon Sep 17 00:00:00 2001 From: kinther Date: Thu, 1 Jan 2026 09:05:00 -0800 Subject: [PATCH 35/40] Add oset command --- lib/text/help/help.hlp | 85 ++++ src/act.wizard.c | 47 -- src/set.c | 1059 +++++++++++++++++++++++++++++++++++++++- src/set.h | 1 + 4 files changed, 1135 insertions(+), 57 deletions(-) diff --git a/lib/text/help/help.hlp b/lib/text/help/help.hlp index 371442d..5c121b7 100644 --- a/lib/text/help/help.hlp +++ b/lib/text/help/help.hlp @@ -13447,4 +13447,89 @@ Amos sees: Gesturing to your empty mug, the bald, pudgy man waves you over with his right hand, pointing to an empty seat at his table. #0 +OVALS + + Ovals are object value slots (0-7). Use OSET ADD OVAL +to set them. Positions are 0-based. + +LIGHT: + 2 - hours_left + +SCROLL: + 0 - spell_level + 1 - spell1 + 2 - spell2 + 3 - spell3 + +POTION: + 0 - spell_level + 1 - spell1 + 2 - spell2 + 3 - spell3 + +WAND: + 0 - level + 1 - max_charges + 2 - remaining_charges + 3 - spell + +STAFF: + 0 - level + 1 - max_charges + 2 - remaining_charges + 3 - spell + +WEAPON: + 0 - dice_num + 1 - dice_size + 2 - weapon_type + 3 - message_type + +ARMOR: + 0 - piece_ac + 1 - bulk + 2 - magic_bonus + 3 - stealth_disadv + 4 - durability + 5 - str_requirement + +CONTAINER: + 0 - capacity + 1 - flags + 2 - key_vnum + 3 - corpse + +WORN: + 0 - closable + 1 - hooded + 2 - is_closed + 3 - capacity + 4 - hood_raised + +LIQ CONTAINER: + 0 - capacity + 1 - contains + 2 - liquid_type + 3 - poisoned + +FOUNTAIN: + 0 - capacity + 1 - contains + 2 - liquid_type + 3 - poisoned + +FOOD: + 0 - bites_capacity + 1 - bites_left + 2 - hours_full_per_bite + 3 - poisoned + +COINS: + 0 - coins + +FURNITURE: + 0 - max_seats + 1 - current_occupants + 2 - allowed_pos +#0 $~ diff --git a/src/act.wizard.c b/src/act.wizard.c index d36fe91..5578808 100644 --- a/src/act.wizard.c +++ b/src/act.wizard.c @@ -6350,53 +6350,6 @@ ACMD(do_recent) } -ACMD(do_oset) -{ - char arg[MAX_INPUT_LENGTH]; - char arg2[MAX_INPUT_LENGTH]; - const char usage[] = "Usage: \r\n" - "Options: alias, apply, longdesc, shortdesc\r\n" - "> oset