********************UPDATE TO 1.4 BUG/FIX LIST******************* First update to the bug/fix list May 27th 99: --------------'LANGUAGE' COMMAND LOOKING IN WHOLE MUD From: Cronel pejro@sion.com So I was just idling, looking at code for the heck of it in act_comm.c, do_language, then noticed something strange. In do_language, when you try to learn a language, the code is supposed to look in the room for a teacher. Well, it actualy looks in the whole mud. I tested it. I loaded a mortal, transferred him to another mob (Domick) and had him type "lang learn elvish".. And the mud replied "Abbigail tells you ..(etc)". So it found Abbigail even though she's in the other room. Here's the culprit (around line 3081 in act_comm.c): for ( sch = ch->in_room->first_person; sch; sch = sch->next ) if ( IS_NPC(sch) && xIS_SET(sch->act, ACT_SCHOLAR) && knows_language( sch, ch->speaking, ch ) && knows_language( sch, lang_array[lang], sch ) && (!sch->speaking || knows_language( ch, sch->speaking, sch )) ) break; Notice the first, line, it's "sch->next" when it should be "sch = sch->next_in_room". That's it. --cronel ------------------------ALARM CLOCK From: Cronel pejro@sion.com Ok recently this player from Australia, I think, started triggering my ALARM thing, which is in comm.c. But he triggered it over and over and over, and so I was able to see that the ALARM anti-lag mechanism was not really working as it should because of a very minor detail. This ALARM thing is supposed to report the section of code where it found the lag (where the signal went off). This is why all over the new_descriptor() function there are statements like alarm_section = "accept"; But someone's fingers slipped and instead of showing this section it just concatenates the local buffer to itself so you end up with like ALARM CLOCK! In section ALARM CLOCK! In section ALARM (and so on) which is very funny to see as it happens, heh. Anyway to fix it just change this, in comm.c, line 427, in function caught_alarm(): sprintf(buf, "ALARM CLOCK! In section %s", buf ); into this: sprintf(buf, "ALARM CLOCK! In section %s", alarm_section ); Just a very small thingy, and I'm not even sure this alarm deal is actualy very useful. ------------------'COMMANDS' COMMAND GLITCH From: Jose Luis Sogorb jlalbatros@mx2.redestb.es When you type "commands" to see all commands available, those beggining with 'm' ( or 'p' as second letter) do not appear. In act_info.c (in do_commands function), it says: && (command->name[0] != 'm && command->name[1] != 'p') but I think it must be: && (command->name[0] != 'm' || command->name[1] != 'p') Tell me if I am right ;) -- From: Altrag altrag@realms.game.org He's right.. it (currently) says, if the first letter is NOT a 'm' AND the second letter is NOT a 'p'.. ie: !m && !p which reverses to mean (trust me, if you dont know yer boolean ops): m || p So we're skipping it if the first letter is an 'm' -or- the second letter is a 'p'. We want to be skipping if the first is a 'm' -and- the second is a 'p'. * Altrag (Altrag@game.org) * -- From: Cronel pejro@sion.com Right. Note that this leaves the following commands visible: mea (mpechoat) mer (mpeachoaround) mez (mpechozone) What I did was check the code string instead of the name, ie: strncmp("do_mp", 5..) --cronel In act_info.c change to look like these: if ( command->level < LEVEL_HERO && command->level <= get_trust( ch ) && (command->name[0] != 'm' || command->name[1] != 'p') if ( command->level < LEVEL_HERO && command->level <= get_trust( ch ) && !str_prefix(argument, command->name) && (command->name[0] != 'm' || command->name[1] != 'p') ---------------SMALL "CHECK_TOTAL_BANS" ANNOYANCE From: Cronel pejro@sion.com while this probably has nothing to do with phaedra's bans not working, i was looking at the ban code because of that and i discovered this little thing; there are two functions to check for bans, check_bans and check_total_bans. the first is used to check all types of bans but it takes a character; the second is used before the character name is known (when the descriptor is accepted) and of course it only checks level 65 site bans (no character, hence no level or class information). i wont bore everyone with how site bans are checked since everyone can see it in ban.c, suffice it to say that depending on the presence and position of wildcards in the host being banned, it calls str_cmp, str_suffix, str_preffix and strstr. well, as it so happens, while in check_bans everything is checked fine, in check_total_bans str_suffix is being called when str_prefix should be and viceversa. this will result in that level 65 site bans with wildcards only at end or start of the host string (not both) will not take effect until the player enters the character name and check_bans is called. as you see no biggie, just thought i'd report it. to fix it just: line 1102 of ban.c should be changed from if ( pban->suffix && !str_suffix( pban->name, new_host ) ) to: if ( pban->suffix && !str_prefix( pban->name, new_host ) ) and viceversa, line 1113 of ban.c should be changed from: if ( pban->prefix && !str_prefix( pban->name, new_host ) ) to: if ( pban->prefix && !str_suffix( pban->name, new_host ) ) thats all. --cronel --------------MENTALSTATE PROBLEM WHEN FIGHTING WIMPY MOBS From: gfinello@mail.karmanet.it I just discovered a problem in the 'damage' function, module fight.c: if ( dam > victim->max_hit / 4 ) { act( AT_HURT, "That really did HURT!", victim, 0, 0, TO_CHAR ); if ( number_bits(3) == 0 ) worsen_mental_state( ch, 1 ); } if ( victim->hit < victim->max_hit / 4 ) { act( AT_DANGER, "You wish that your wounds would stop BLEEDING so much!", victim, 0, 0, TO_CHAR ); if ( number_bits(2) == 0 ) worsen_mental_state( ch, 1 ); } The two worsen_mental_state calls should be called upon the victim... not the hitter. Otherwise YOUR mst will be screwed for hitting your opponent too hard, while it's supposed to be the other way around. Change them to: if ( dam > victim->max_hit / 4 ) { act( AT_HURT, "That really did HURT!", victim, 0, 0, TO_CHAR ); if ( number_bits(3) == 0 ) worsen_mental_state( victim, 1 ); } if ( victim->hit < victim->max_hit / 4 ) { act( AT_DANGER, "You wish that your wounds would stop BLEEDING so much!", victim, 0, 0, TO_CHAR ); if ( number_bits(2) == 0 ) worsen_mental_state( victim, 1 ); } ----------------------POISON WEAPON/DUAL-WIELD BUGS From: gfinello@mail.karmanet.it Searching through the code for the causes of a weird bug, I ended up finding another two. They are both related to the use of poisoned weapons. Like the "fights and mental state" bug I previously discovered, the negative effect of a poisoned weapon's successful hit is directed toward the wrong target too. Here is the code block. fight.c:damage if ( dam > 0 && dt > TYPE_HIT && !IS_AFFECTED( victim, AFF_POISON ) && is_wielding_poisoned( ch ) && !IS_SET( victim->immune, RIS_POISON ) && !saves_poison_death( ch->level, victim ) ) { AFFECT_DATA af; af.type = gsn_poison; af.duration = 20; af.location = APPLY_STR; af.modifier = -2; af.bitvector = meb(AFF_POISON); affect_join( victim, &af ); ch->mental_state = URANGE( 20, ch->mental_state + (IS_PKILL(ch) ? 1 : 2),100 ); } The last line should be changed to : victim->mental_state = URANGE( 20, victim->mental_state + (IS_PKILL(victim) ? 1 : 2), 100 ); -------- As for the second bug, look at the if's condition. It calls in the if_wielding_poisoned function and here is its code : bool is_wielding_poisoned( CHAR_DATA *ch ) { OBJ_DATA *obj; if ( (obj=get_eq_char(ch, WEAR_WIELD)) != NULL && IS_OBJ_STAT(obj, ITEM_POISONED) ) return TRUE; return FALSE; } This function returns TRUE only if ch is wearing a poisoned weapon in the "wear_wield" position. This means that if ch is wielding a normal weapon and dual-wielding the poisoned one, the poison effect of the second one will never kick in. Not even on a mob that will be hit only with the poisoned one (ie. piercing) because immune to the normal one's damage type (ie. slashing). If we swap the two weapons, BOTH will show poisonous capabilities, without the deteriorating effect on the normal one that poison would impose. The hit messages will depend on the "wear_wield" position too. Unfortunately for this bug I have not a quick solution, due to my lack of time right now (it has been a busy week). If you want to try it the problem is : one_hit(), that decides which one of the two weapons will be used, does not tell it to damage(), that handles of the venomous weapon effect, and dam_message(), that handles the hit messages. Only the damage type info (blasting, piercing etc.) is passed between them, so the last two are forced to obtain the weapon's poisoned status with is_wielding_poisoned(), that is probably older than the dual-wield skill. Dam_message() can be fixed quickly enough but damage() is called more often in all the codebase, so it requires more attention and testing to avoid solutions that will apparently work well, then crash in unforeseen situations. Good luck. -- From: Benjamin M. Walsh s0206237@monmouth.edu The function is_wielding_poisoned only checks the persons wielded weapon, if they are dualwielding it doesn't check the second weapon. You need to add a second if statement after the first: if ( (obj=get_eq_char(ch, DUAL_WEAR_WIELD)) != NULL && IS_OBJ_STAT(obj, ITEM_POISONED) ) return TRUE; -Zanthus --------------CRASH IN "RESET" COMMAND WHEN SWITCHED From: Cronel pejro@sion.com One of my builders noticed a bug in "reset"... It's very visible and very reproducible... do this: - goto any mob in the game - switch into the mob - type "reset" - kaboom...... Yes of course, Its the "I'll access pcdata without checking if the guy is switched" bug we all know ... :) The offending lines are: line 1053, reset.c: if ( !pArea ) pArea = ch->pcdata->area; line 1058, reset.c: else pArea = ch->pcdata->area; and line 1007, reset.c if ( pArea && pArea != ch->pcdata->area && pArea != ch->in_room->area ) My fix was to disallow use of the reset command while switched, but you may wanna fix it in other ways, such as having it find the area anyway like; pArea = !IS_NPC(ch) ? ch->pcdata->area : ((ch->desc && ch->desc->original) ? ch->desc->original->pcdata->area : NULL); etc.. --cronel ------------"RESET EDIT" HEADACHE From: MudPrince MudPrince@aol.com If a builder puts more than one object into a container, then types instazone, only the first object is reset into the container. When I try to fix this, by manually adding resets, I run into this I type: reset edit 47 put 102 201 It does exactly what I want it to, but instead of editing reset #47, it always edits reset #1. (First in the list) - From: Cronel pejro@sion.com It's in edit_reset, look: if ( !str_cmp(arg, "edit") ) { argument = one_argument(argument, arg); if ( !*arg || !is_number(arg) ) { send_to_char( "Usage: reset edit\n\r", ch ); return; } if ( !(pReset = find_reset(pArea, aRoom, num)) ) { send_to_char( "Reset not found.\n\r", ch ); return; } (more code for "reset edit (blah)" follows..) As you see it's obvious that the number string is parsed into "arg", and then it uses "num" to find the reset. But "num" is never initialized (to atoi(arg)), and since it's assigned 0 at the beginning of the function, "reset edit" will *always* edit the first reset no matter what. Amazing bug! Amazing in the sense that it's incredible no one has seen it yet, everyone must be using insta(zone/room). As it is obvious, all that you need to do is insert the line: num = atoi(arg); *before* the line: if ( !(pReset = find_reset(pArea, aRoom, num)) ) I checked other parts of the same function (delete, and other reset commands) and they are all ok as far as parsing the number goes. This one's the only one. --cronel -----------------------FUNKY 'E' RESETS From: Cronel pejro@sion.com A player went into a Thieves Alley room in Darkhaven (vnum 21063), and found he could "get ring" even though there was no visible ring in the room and also upon getting the ring from the ground, it was auto equipped to position finger ("worn on finger"). I went to investigate and found that the ring wasn't even visible to a 65 imm. Went into the code and voila, it was a bug in the reset code, of the 'E' reset. I don't think this was ever reported or noticed before, so here's how it goes; In that room, there are two resets. One of them is the thief that roams around Darkhaven (vnum 21052). The last one equips the ring (vnum 21055) to this thief (an E reset). However, the ring is prototype, and the thief is not. In an E reset the object is first loaded, then given to the mob with a call to obj_to_char() and then equipped to the mob with a call to equip_char(). However, obj_to_char refuses to give a proto item to a non proto mob. The call fails. Then equip_char is called without checking if the previous call succeeded; equip_char() doesn't check that the object being eqipped is actualy in the inventory of the character, and sets the object and the char as if everything was ok. One of the things that it does is set the obj->wear_loc to the given wear location (finger in this case). This explains both the object being invisible in the room and the auto-equipping of the object when you get it. So in short what this will produce is that if there is a reset of a proto item being equipped to a non-proto mob, the object will be left lying on the ground with all sorts of weird side effects. And we got first an area bug, fixable by removing the proto flag from object vnum 21055, and second a code bug, that I would fix by; around line 1382 of reset.c (case 'E' of reset_area()), modify it like this (to fix the reset bug): obj->level = URANGE(0, obj->level, LEVEL_AVATAR); obj = obj_to_char(obj, mob); if ( pReset->command == 'E' ) { if( obj->carried_by != mob ) { bug( "'E' reset: can't give object %d to mob %d.", obj->pIndexData->vnum, mob->pIndexData->vnum ); break; } equip_char(mob, obj, pReset->arg3); } lastobj = obj; break; and around line 1322 of handler.c, at the beginning of equip_char() add this (to catch other instances besides the reset bug): if( obj->carried_by != ch ) { bug( "equip_char: obj not being carried by ch!" ); return; } --cronel --------------------DREADED 95 SKILL TRASHING BUG From: Kilth DruidDarky@aol.com The 95's are out to get me! Well.. after having a bug reported, i looked into the skills: feed, steal, ect.. After looking at the reported problems.. such as BP needed to use the feed skill? I looked at the Mana: and it read 95.. suddenly.. I was surrounded by 95's. Round, Mana, Slot.. those had 95's.. all the max learns for it were at 95.. I see a pattern repeating in the skills table, but not everything is set to 95. What exactly causes this little problem? Thanks. Kilth -- From: "Rustry" rustry@dxcc.com Look at the following 1.4 code: struct skill_type { char * name; /* Name of skill */ sh_int skill_level[MAX_CLASS]; /* Level needed by class */ sh_int skill_adept[MAX_CLASS]; /* Max attainable % in this skill*/ sh_int race_level[MAX_CLASS]; /* Racial abilities: level */ sh_int race_adept[MAX_CLASS]; /* Racial abilities: adept */ Should not race_level and race_adept be dimensioned at MAX_RACE? With all the chat about adding races and classes on this list in the past month or so, how come nobody has picked up on this? Or am I REALLY missing something here???? Thanks, Rustry -- From: Cronel pejro@sion.com A little while ago someone posted a msg asking for help cause they were getting the dreaded "skill trashing" bug wich is associated with adding classes (trashes skills with the value 95 all over the place). The fix for this was discovered inadvertently by Rustry back in november! He found a bug, didn't know it was this bug. Like a day later Altrag realized it and sent a short post. The bug consists in that, inside the "skill_type" structure, the new "race_level" and "race_adept" arrays (which make racial skills happen) are dimensioned by MAX_CLASS, not by MAX_RACE. And throughout the code they are accessed as if they had MAX_RACE items. So if you have more races than you have classes, some part of the skill will be trashed. The bigger your ( MAX_RACE-MAX_CLASS ) is, the more that will get trashed. In stock code I think there's 15 races and 9 classes so you will get at least the next 3 or 4 members of the skill trashed. The catch, I think, is that this is overwritten *before* the code reads the skill from the skills.dat file (this happens in fread_skill(), tables.c). So for some fields you may not notice that they were trashed at all; most notably the code, which is *allways* read or set to something, so I don't know if this bug could account for people's "code" being set to some invalid hex address instead of its proper do_kick or whatever... But yes it could account for skills like vampire skills which don't have mana, and get their mana set to 95, if you have enough races added, etc.... Anyway all you have to do is go to mud.h, search for this: struct skill_type { char * name; /* Name of skill */ sh_int skill_level[MAX_CLASS]; /* Level needed by class */ sh_int skill_adept[MAX_CLASS]; /* Max attainable % in this skill */ sh_int race_level[MAX_CLASS]; /* Racial abilities: level */ sh_int race_adept[MAX_CLASS]; /* Racial abilities: adept */ and change it to this: struct skill_type { char * name; /* Name of skill */ sh_int skill_level[MAX_CLASS]; /* Level needed by class */ sh_int skill_adept[MAX_CLASS]; /* Max attainable % in this skill */ sh_int race_level[MAX_RACE]; /* Racial abilities: level */ sh_int race_adept[MAX_RACE]; /* Racial abilities: adept */ Then make clean, make. --cronel -------------------SLIST FULL OF MOB PROGRAM LINES From: Mud Admin mudadmin@rocketmail.com Ok, I was in room 21014, typed slist, and saw the following on slist: SPELL SKILL LIST ------------------ Level 1 Skill: aggressive style Current: 100 Max: 95 MinPos: answer $r, an intrepid Ranger ... endif if class($r) == augurer mpat hvak2 mpfor hvak2 answer $r, a novitiate Augurer ... endif mpechoat $r ...Please leave north to experience the Darkhaven Academy. mpechoat $r ...You may now "save" to make your character permanent. endif Skill: cook Current: 100 Max: 95 MinPos: fighting (defensive) Skill: kick Current: 100 Max: 85 MinPos: fighting (berserk) Anyone know how to fix this bug? Thanks. -- From: Cronel pejro@sion.com What triggers this are skills with invalid values in their "minpos". So surprisingly enough, it's related to the preexisting bug I posted earlier, which trashed skills, "minpos" being one of the fields it trashed even in stock SMAUG versions (without any modification to races or classes). However, the bug only exists in 1.4, not in 1.02a. It's this, in do_slist, act_info.c, there is a switch that sprintf's a string to "buf", about the minpos of the skill being listed. If it's POS_STANDING, it prints "standing" to the buffer, and so on. However, this switch doesn't have a default case, meaning that if the minpos is set incorrectly, it will never set "buf" to anything, leaving it with its original value. Later on, thus "buf" is output to the player. The "original value" of a buffer like "buf", which is a non-static local buffer, can be virtualy anything. Whatever is on the stack at the point where the function is called will become the value of the buffer. I've checked and found that the "comlist" of all progs is actualy copied to another local buffer, in the function "mprog_driver" in mud_prog.c, so it's totaly possible that the contents of that "hvak" mud prog are there on the stack when do_slist is called. Also, this "original value" will be visible only for the first skill with an incorrect minpos. As soon as a skill with a correct minpos is found, "buf" is filled with the string corresponding to it, so the next incorrect skill will be showing that value (seemingly correct, but not really). So as you see this explains all the "symptoms". I went into skills.dat and voila, the "agressive style" skill has an invalid minpos (a value of 195 in the file, which is loaded as 95 when the mud is run... definitely invalid, and obviously trashed by the 95 bug). So everything checks out. What I'd recommend is a) fixing the other bug that trashes skills and b) adding a default case to the switch so even if there are trashed minpos for other reasons, the buffer is filled with something and it's exposed with a bug() line. For b) just look for this code in act_info.c, inside do_slist: switch (skill_table[sn]->minimum_position) { case POS_DEAD: sprintf(buf, "any"); break; and change it into this switch (skill_table[sn]->minimum_position) { default: sprintf(buf, "Invalid"); bug( "do_slist: skill with invalid minpos, skill=%s", skill_table[sn]->name ); break; case POS_DEAD: sprintf(buf, "any"); break; -- From: me Zylara After fixing these two bugs, your slist -in the academy- will give you a long Log: [*****] BUG report. Since most of the weapon and language skills will be messed up you will need to go into ../dist/system/skills.dat and reset the minpos on any skills that are reporting invalid ones. --------MAX_WHERE_NAME--------setrace hp_regen/mana_regen From: Ron Kinney minex@dod.hpi.net I was examining some of the parameters for the races when I came upon hp_regen and mana_regen. These are unimplemented in SMAUG 1.4, but the code does read/write to the race file. I thus decided to go ahead and implement it myself. However, I want to make the stats store a percentage value (ie, 50, 100, 200, etc). set_race human hp_regen 100 set_race human save -->This causes the mud to crash. BUT set_race human mana_regen 100 set_race human save -->This does NOT cause the mud to crash. The two pieces of code look almost identical. Does anyone else's mud have this problem? I can't seem to figure out what is causing the crash. Minex --- From: Cronel pejro@sion.com This is an off-by-one error that produces a stray pointer, which is the reason we only see it now (stray pointer = erratic). It's somewhat related to the old where_names bug in a uhm conjectural way... Here's the scoop. The actual bug is in line 1627 of tables.c, in this for (function write_race_file): for ( i = 0; i <= MAX_WHERE_NAME; i++ ) fprintf( fpout, "WhereName %s~\n", race->where_name[i] ); The race->where_name[] array is actualy MAX_WHERE_NAME items long. As you see it accesses from 0 to MAX_WHERE_NAME, because of the "<=" (should be "<") so it's basicaly an off-by-one error. It tries to access one more element than there really is. So why hasn't this showed up before? Because there's something bellow the array (in memory); you guessed it, the "mana_regen" and "hp_regen" members. So what's happening is this. Whenever you save a race, it tries to access one more member of where_names, and finds mana_regen/hp_regen. Since these are 0 most of the time, and where_names is a pointer to char, they are interpreted as a pointer to char; it results as NULL. And this NULL is sent to fprintf, which prints it as "(null)". So if you've ever saved your races (and not modified mana_regen/hp_regen), go to your .race files and you'll see a line like: WhereName (null)~ But as Minex said, if you modify hp_regen or mana_regen it crashes, or doesn't... What happens is simply that the now non-zero hp_regen/max_regen get interpreted as a pointer to char. So fprintf() sees it as a non-NULL pointer, and tries to write the string there... So as in all stray pointer bugs, Anything Can Happen (TM), it can point to an invalid memory location (and it crashes) or it points somewhere valid (and it prints trash to the file, as I've seen happen). The easy fix is simply to change the "<=" into a "<". Also see around 1806, there's a would-be bug in the opposite direction (while loading the race); if ( wear < MAX_WHERE_NAME+1 ) { race->where_name[wear] = fread_string_nohash( fp ); ++wear; } else bug( "load_race_file: Too many where_names" ); The first line should be; if ( wear < MAX_WHERE_NAME ) I say this is the easy fix because it is my impression that whoever coded it got confused as to the number of elements in the arrays and the number of wear locations. This confusion stems from the fact that there is both a MAX_WHERE_NAME and a MAX_WEAR. So it's related to the old wear_names bug as reported on Zylara's bug list. So, to me, the real fix would be to completely get rid of MAX_WHERE_NAME, by making both the global array "where_names" and the "where_names" arrays inside the race structures be MAX_WEAR items long, and modify the three instances in tables.c where MAX_WHERE_NAME, change them to MAX_WEAR. Of course you don't *need* to do this because the actual bug is fixed by changing the "<=", but my point is that the MAX_WHERE_NAME/MAX_WEAR confusion is what caused the introduction of the bug in the first place (IMHO) so just delete it if you plan to finish coding the race edition or something related to it... --cronel --- From: Roger Libiez samson1@aviastar.net Be aware of one thing when fixing this also, if you've saved any race files, they'll all need to be fixed before you reboot the mud after compiling the bug fixes. Otherwise you'll end up with a bunch of errors in your logs as it tries to parse the now invalid extra Where_name entry. And those regen entries will likely also be worthless and need to be reset to something sane. I'm going over mine now, and it decided to stick some rather nasty values in there, some positive, some negative. And the where_name entries it chose to randomly grab are proving rather interesting :P ***********Not the end, but this editor won't hold any more???