Received: from future.atlcom.net by owl.csusm.edu (AIX 4.1/UCB 5.64/4.03) id AA14118; Mon, 6 Jan 1997 04:24:45 -0800 Received: from lpm2-10.atlcom.net by future.atlcom.net with SMTP (5.65/1.2-eef) id AA20605; Mon, 6 Jan 97 07:33:45 -0500 Return-Path: Message-Id: <32D0F245.5510@atlcom.net> Date: Mon, 06 Jan 1997 07:38:29 -0500 From: Sheldon Simms X-Mailer: Mozilla 2.0 (Macintosh; I; 68K) Mime-Version: 1.0 To: wtanksle@mailhost2.csusm.edu Subject: More Omega Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Status: X-Status: A Since I was looking through old mail... This is a message I sent to Erik Max Francis in late November I was trying to find out why I sometimes encoutered tangible (!m_statusp( m, INTANGIBLE )) monsters sitting on unrevealed secret passages. The way this looks to the player is that he sees a tangible monster, like a goblin, sitting there but when he tries to attack, Omega prints "Ouch!". The function m_unblocked() in util.c determines whether a monster can move onto a space. It explicitly disallows tangible monsters from moving onto a secret space unless they are smart, in which case they can "open" the secret door or passage, which then becomes non-secret. So I thought that tangible monsters might be getting put on secret walls when the level is populated. After tracking down the code, I found that the function findspace() (also in util.c) finds a space to put a new monster when the level is being populated. findspace() didn't care whether a space was secret, only whether the locchar was FLOOR, which it is for secret passages. So I figured (and still think) that modifying findspace() to disallow secret spaces has solved that problem. However, as I read findspace() I immediately thought about Laurence's comment about monsters having a party because the findspace was written, this was very likely to happen. Basically it picked a random space on the level and if that space wasn't ok, it started searching across and down for the first acceptable empty space. So if the uppermost room or corridor on a level was on (for example) row 16, with every row above that being filled with WALLs, 25% (16/64) of all the monsters on the level will be in the upper-left-most room or corridor - they're having a party! The reason I'm telling you all this is that I rewrote findspace() to eliminate the party effect. In my new findspace(), if the randomly chosen space is not ok, it searches either across or down (alternating each time a space is selected at random). If it finds no acceptable space in the row or column it searched, it tries another random space. Obviously it could try one random space after another, but I was wary of the possibility that such a loop might run for quite a while. Anyway, the code follows for inclusion in the official source, if you choose to use it: /* finds floor space on level with buildaux not equal to baux, sets x,y there. There must *be* floor space somewhere on level.... */ int spaceok( int i, int j, int baux ) { return (( Level->site[ i ][ j ].locchar == FLOOR ) && ( Level->site[ i ][ j ].creature == NULL ) && ( !loc_statusp( i, j, SECRET )) && ( Level->site[ i ][ j ].buildaux != baux )); } void findspace( int *x, int *y, int baux ) { int i, j, tog = TRUE, done = FALSE; do { i = random_range( WIDTH ); j = random_range( LENGTH ); if ( spaceok( i, j, baux )) { done = TRUE; } else { if ( tog ) { tog = !tog; while( 1 ) { i++; if ( i >= WIDTH ) break; else if ( spaceok( i, j, baux )) { done = TRUE; break; } } } else { tog = !tog; while( 1 ) { j++; if ( j >= LENGTH ) break; else if ( spaceok( i, j, baux )) { done = TRUE; break; } } } } } while ( !done ); *x = i; *y = j; } -- W. Sheldon Simms III sheldon@atlcom.net -- W. Sheldon Simms III sheldon@atlcom.net Received: from future.atlcom.net by owl.csusm.edu (AIX 4.1/UCB 5.64/4.03) id AA07766; Mon, 6 Jan 1997 04:28:38 -0800 Received: from lpm2-10.atlcom.net by future.atlcom.net with SMTP (5.65/1.2-eef) id AA20687; Mon, 6 Jan 97 07:37:38 -0500 Return-Path: Message-Id: <32D0F32E.74F@atlcom.net> Date: Mon, 06 Jan 1997 07:42:22 -0500 From: Sheldon Simms X-Mailer: Mozilla 2.0 (Macintosh; I; 68K) Mime-Version: 1.0 To: wtanksle@mailhost2.csusm.edu Subject: Still More Omega Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Status: X-Status: R here's another mail I sent to Max in November: I just want to tell you about a few of the more dangerous bugs I have found in Omega. 1) In inv.c, the function givemonster(), when grain is given to a horse, the grain object is freed: else nprint1( "...and now seems satiated." ); morewait(); free( (char *)o ); This is a bug because when givemonster() returns to give() in command2.c, give() tries to access the object: givemonster( m, obj ); print2( "Given: " ); nprint2( itemid( obj )); This sometimes caused "bus error" crashes on my Mac. I have simply commented out the free() statement for now. I'll probably leave it that way and simply accept the memory leak. 2) In guild1.c in the function l_arena(), after you kill your arena opponent, the monster is freed: print1( "Let the battle begin...." ); time_clock( TRUE ); while ( Current_Environment == E_ARENA ) time_clock( FALSE ); free(name); /* <- bad */ free(corpse); /* <- bad */ if (melee) /* <- bad */ free(melee); /* <- bad */ This is incorrect because the dead monster can be picked up and carried out of the arena. The four lines marked "bad" should be removed. 3) The star-gem bug. This happens in save.c because the possessions of hiscore_npc monsters are not saved. It is easily fixed by moving one line in each of the functions save_monsters() and restore_monsters(). In save_monsters(): if ( tml->m->id != HISCORE_NPC ) { /* several lines snipped */ /* ok &= save_itemlist( fd, tml->m->possessions ); <- move this */ } /* else it'll be reloaded from the hiscore file on restore */ ok &= save_itemlist( fd, tml->m->possessions ); /* <- to here */ This change causes possessions to be saved for all monsters. The change to restore_monsters() complements the change to save_monsters(): if ( ml->m->id == HISCORE_NPC ) { /* stuff deleted */ } else { /* more stuff deleted */ /* ml->m->possessions = restore_itemlist( fd ); <- move this */ ml->m->meleestr = Monsters[ ml->m->id ].meleestr; } ml->m->possessions = restore_itemlist( fd ); /* <- to here */ 4) There is also another bug that I haven't fixed yet. This involves the time when you bash a statue and it glides into the floor leaving a stairway down. When this happens on levels where there is not supposed to be stairway down, taking the created stairway can cause problems. I just encountered this problem on the 5th level of the astral plane (the high astral plane). Trying to take the stairway down caused a crash. -- W. Sheldon Simms III sheldon@atlcom.net Received: from mail.Virginia.EDU by owl.csusm.edu (AIX 4.1/UCB 5.64/4.03) id AA16322; Mon, 20 Jan 1997 06:20:52 -0800 Received: from uva.pcmail.virginia.edu by mail.virginia.edu id aa25972; 20 Jan 97 9:31 EST Received: (from root@localhost) by uva.pcmail.virginia.edu (8.7.6/8.6.6) id JAA04707 for wtanksle@owl.csusm.edu; Mon, 20 Jan 1997 09:31:03 -0500 (EST) Message-Id: <199701201431.JAA04707@uva.pcmail.virginia.edu> From: Kent Peterson Date: Mon, 20 Jan 97 09:30:48 EST X-Mailer: UVa PCMail 1.9.0 To: wtanksle@mailhost2.csusm.edu Subject: Omega bugs Status: X-Status: R l_safe - siren goes off, need morewait afterwards send_to_jail - two of the release options have the x/y coords reversed (subtle!) l_tavern - sleeping needs to change the date, drinking needs to pass time l_library - cost of studying should be moved so as to apply only to option e, not any of the others 1) m_talk_druid - non-druid characters always have their alignment *decreased* by neutralization? that's what seems to be happening here ... 2) m_sp_mb - manaburst explosion doesn't kill it, anything that explodes itself should die by my lights. 3) m_sp_dragonlord - dragonlord should be capitalized everywhere 4) boots/spells of heroism should give immunity to fear 5) l_void - need a morewait after "Death peers quizzically ..." etc 6) l_escalator - need a morewait after stairs start moving 7) m_simple_move - if blocked on straight line and both diagonals, try moving randomly once 8) casino closed for investigation - need to make this last the entire day 9) what is the difference between m_smart_move and m_normal_move? A planned one? 10) transcribe_monster_actions - when figuring attacks, when deciding to attack center, it blocks instead 11) void i_symbol - for loop cutting hp and for loop cutting items should be 2 separate loops (?) also, if you use the symbol twice on the same hour on succeeding days, your god gets angry; there should be a SymbolDay variable as well (same with crystal ball) (and in i_enchantment) (and i_helm) 12) holy hand grenade (i_antioch) - count>3 / count<3 are the wrong way around; should be count>3 for monster to have time to throw it back 13) Sceptre of High Magic - we need 2 HiMagic variables here, one for the sceptre and one for the throneroom (same for the throne's routine) 14) berserk attacks while shadowformed - indefinitely 15) i_perm_breathing fun - check p_drown to make sure it gives you the normal chance to drop/bash/etc to survive 16) surrendering to an undead guardsman 17) saving in countryside is broken 18) area effect (snowball) targeted on edge square (so that part of the area is off the edge of the map) 19) pressing escape while targetting staff (of disruption) is broken 20) "Really. Well the police are being notified" - more always appears, shouldn't 21) killing a monster with riposte does not leave the normal treasure pile that monsters carry; the * character gets printed, but there's nothing there 22) restoring from a save when near a monster often will make the monster "sleep" for a dozen rounds while you whack away safely at it 23) Slowness - should be temporary (a dozen rounds/seconds/minutes). Right now it's so crippling it's better to save/restore than go through it. (correction, it *is* temporary. tested it. it's just way too long-lasting.) 24) Shadow Form - should lose immunities at end (plain bug) when the spell aborts, the various immunities should be set to 0, rather than being decremented (same thing with slowness?) 25) breathing stat (powered armor etc) - when this gets cursed or reversed, it ought to call the drown function rather than simply killing you 26) dispel - should also remove slowness and/or shadowform 27) names for several temples should be reconciled between strategic teleports and *roomname 28) hint something about how azoth needs to be blessed "They say blessings can really change an item's attitude." 29) Encounters - fewer high-powered magical beasties on roads and plains; wolves and lions are bad enough. Too easy to die while traveling. 30) Sacrificing - lower curve of required values; it's too hard to get something worth giving as it stands (wands/staves should be possible), especially at middle levels. Reasonable values would be 200 gp at level 10, current values are more like 2-3 thousand 31) Fire resistance - should be partial (depending on pluses), rather than total (too easy to kill dragons & Elemental Lord of Fire) (same with deflection - missile attacks become laughable, should depend on plusses to shield, or total value of spell cast - the longer the spell has to last, the more effective it is?) resistance to electricity/cold damage probably also applies here; fire really stands out though 32) DragonLord - should have a chance of waking up every round someone's in the inner cave; it's too easy to steal repeatedly Also, when games are saved and restored within the cave, the portcullis should restore as down 33) Prime Sorceror - should always be created with the Star Gem when in the Circle plane, even if game saved/restored while in Astral 34) Law/Chaos worship stones - these should depend a lot more on alignment; as it stands it seems like even if you're very lawful the Star View stone has pretty good chances of feeding you something nasty; on the other hand, the reward shouldn't be as big (make the stat increase random, 1-6?) 35) Gym training - far too expensive; I *always* save/restore to make sure the training pays off because I can't afford to throw away that kind of money. A cost of 300-800 is more like it, or maybe 1000 with half to 3/4 of your money back if your ability doesn't improve. (or maybe the refund gets added to your credit) 36) 7 league boots - each time used, add 1 to fragility, when reaches terminal, "your boots dissolve into dust with a soft sigh" (right now they break the game - the countryside becomes irrelevant) (esp. when combined with robbing the DragonLord) 37) Gambling - should take time (~10 mins per game), and should be more detailed (what the heck does it *do*, besides randomly rolling electronic dice to see if you gain or lose money? what are the rules of the game?) 38) Tavern - have drinking take time (1 drink = 2-10 minutes, a round = 10-30 minutes) - we need to be able to while away the night hours 39) Explorer's Club - needs to sell more stuff - maybe stimtabs/nutritabs/ powtabs/immunotabs, for appropriate prices? (100/200/1000/50) Also, the "listen for rumors" option could be expanded to something more like a daytime tavern; you could have a drink/snack and hear the rumors meanwhile (and have it take ~5 minutes) 40) The mercenary legion should sell crossbows/longbows/arrows/bolts, at 1/10 price to legion members - then they WOULD be the "best equipped" (arrows and bolts especially, those are hard to find) 41) boots of leather/cloaks of wool ought to add 1 to defense, to have a reason to use them aside from defense from disintegration Kent Peterson It is easier to ask for forgiveness kmp2x@virginia.edu than to ask for permission. kent@dirac.physics.jmu.edu Abortions should be safe, legal, early, and rare. Received: from Tree.EGR.UH.EDU by owl.csusm.edu (AIX 4.1/UCB 5.64/4.03) id AA20516; Thu, 13 Feb 1997 16:12:26 -0800 Received: from lonestar by tree.egr.uh.edu (NX5.67f2/NX3.0M) id AA11355; Thu, 13 Feb 97 18:23:29 -0600 From: David J Robertson Message-Id: <9702140023.AA11355@tree.egr.uh.edu> Received: by lonestar.egr.uh.edu (NX5.67e/NX3.0X) id AA08345; Thu, 13 Feb 97 18:23:28 -0600 Subject: Re: Omega: Bug reports To: wtanksle@mailhost2.csusm.edu Date: Thu, 13 Feb 1997 18:23:27 -0600 (CST) In-Reply-To: from "William Tanksley" at Feb 10, 97 06:49:42 pm X-Mailer: ELM [version 2.4 PL23] Content-Type: text Content-Length: 6580 Status: RO X-Status: R > > David, thank you! That was a perfect bug report for me -- even gave the way > to fix it :). No problem. > > I've got some good news of my own -- it just MIGHT take a little less time > to do this than I'd thought. Someone else had already started it :). > That's real good news; not only does it mean less work from me, but it also > means everyone gets the game sooner. Cool! > > As for your suggestion -- I don't know. The first one (have "know all > spells" effects give MORE knowledge of already-known spells) makes sense, Hmm, the only "know all spells" effect I know of is using the key that was lost. For this item, I agree that reducing the cost in addition might be too good. I was really talking about the extra spells you get from the guilds. They don't help the spell cost if you already know the spell they teach you. Well, here is another bug/suggestion. Have fun. :) I was trying to track down a bug with ghost items/no items being left on a monsters death, and found it. The following is pseudo code for m_pulse in mon.c. m_pulse(m){ gain a hit point every so often if asleep, wake up if player is in range if awake if wandering move around, then reset wandering if in range else do the monster mstrike 1/2 the time if more than 1 space away (some) monsters move toward the player if more than 1 space away (1) hostile monsters attack the player if 1 space away (2)greedy monsters pick up stuff do monsters special function (if in range) } Now the problem is in lines (1) and (2). During the attack the player phase, the monster can be killed by a riposete. If this happens, then the monster drops its stuff, and its hp are set to -1. Then the code returns to m_pulse. The (dead) monster picks up everything it dropped, including its corpse. Then the (dead) monster does its special attack. Then, back in time_clock in time.c, the monster is deallocated. However the stuff it picked up is lost, since the code in time_clock assumes that the monster dropped everything on death, leading to a memory leak. When I was looking at the m_pulse, I also notice that the monsters can do an awful lot in each melee round, with the worst situation occuring when it is two spaces away. Then it can: (1) do a ranged attack (1/2 the time) (2) move next to you (3) do a melee attack (4) do its special attack (even if dead) I think it would be good idea to change the flow code so that if the monster does a ranged attack, it won't move (or maybe it should only have a chance at moving). Then if the monster does move, it shouldn't get a chance to do a melee attack. There should be a random chance for the special attack to occur. There should also be a hitpoint check placed on all monster actions after the tacmonster function has a chance of being called, to prevent the bugs I mentioned above. I've enclosed a revised m_pulse function below (the original m_pulse follows it). /* Revised function */ /* consider one monster's action */ void m_pulse(m) struct monster *m; { int range = distance(m->x, m->y, Player.x,Player.y) int STRIKE=FALSE; pol prev; if (Time % 10 == 0) if (m->hp < Monsters[m->id].hp) m->hp++; if ((! m_statusp(m,AWAKE)) && (range <= m->wakeup)) { m_status_set(m,AWAKE); resetgamestatus(FAST_MOVE); } if (m_statusp(m,AWAKE)) { if (m_statusp(m,WANDERING)) { if (m_statusp(m,MOBILE)) m_random_move(m); if (range <= m->sense && (m_statusp(m, HOSTILE) || m_statusp(m, NEEDY))) m_status_reset(m,WANDERING); } else /* not wandering */ { if (m_statusp(m,HOSTILE)) if ((range > 2) && (range < m->sense) && (random_range(2) == 1) (los_p(m->x,m->y,Player.x,Player.y) && (Player.status[INVISIBLE] == 0)) { STRIKE=TRUE; monster_strike(m); } if ((m_statusp(m,HOSTILE) || m_statusp(m,NEEDY)) && (range > 1) && m_statusp(m,MOBILE)) && (!STRIKE || (random_range(2) == 1)) monster_move(m); else if (m_statusp(m,HOSTILE) && (range ==1)) { resetgamestatus(FAST_MOVE); tacmonster(m); } } /* if monster is greedy, picks up treasure it finds */ if (m_statusp(m,GREEDY) && (m->hp >0) ) while (Level->site[m->x][m->y].things != NULL) { m_pickup(m,Level->site[m->x][m->y].things->thing); prev = Level->site[m->x][m->y].things; Level->site[m->x][m->y].things = Level->site[m->x][m->y].things->next; free((char *) prev); } /* prevents monsters from casting spells from other side of dungeon */ if ((range < max(5,m->level)) && (m->hp > 0) && (random_range(2) == 1)) monster_special(m); } } /* Original Function */ /* consider one monster's action */ void m_pulse(m) struct monster *m; { int range = distance(m->x, m->y, Player.x,Player.y); pol prev; if (Time % 10 == 0) if (m->hp < Monsters[m->id].hp) m->hp++; if ((! m_statusp(m,AWAKE)) && (range <= m->wakeup)) { m_status_set(m,AWAKE); resetgamestatus(FAST_MOVE); } if (m_statusp(m,AWAKE)) { if (m_statusp(m,WANDERING)) { if (m_statusp(m,MOBILE)) m_random_move(m); if (range <= m->sense && (m_statusp(m, HOSTILE) || m_statusp(m, NEEDY))) m_status_reset(m,WANDERING); } else /* not wandering */ { if (m_statusp(m,HOSTILE)) { if ((range > 2) && (range < m->sense) && (random_range(2) == 1)) if (los_p(m->x,m->y,Player.x,Player.y) && (Player.status[INVISIBLE] == 0)) monster_strike(m); } if ((m_statusp(m,HOSTILE) || m_statusp(m,NEEDY)) && (range > 1) && m_statusp(m,MOBILE)) { monster_move(m); } if (m_statusp(m,HOSTILE) && (range ==1)) { resetgamestatus(FAST_MOVE); tacmonster(m); } } /* if monster is greedy, picks up treasure it finds */ if (m_statusp(m,GREEDY)) while (Level->site[m->x][m->y].things != NULL) { m_pickup(m,Level->site[m->x][m->y].things->thing); prev = Level->site[m->x][m->y].things; Level->site[m->x][m->y].things = Level->site[m->x][m->y].things->next; free((char *) prev); } /* prevents monsters from casting spells from other side of dungeon */ if (range < max(5,m->level)) monster_special(m); } } David Robertson