1Received: from future.atlcom.net by owl.csusm.edu (AIX 4.1/UCB 5.64/4.03) 2 id AA14118; Mon, 6 Jan 1997 04:24:45 -0800 3Received: from lpm2-10.atlcom.net by future.atlcom.net with SMTP (5.65/1.2-eef) 4 id AA20605; Mon, 6 Jan 97 07:33:45 -0500 5Return-Path: <sheldon@atlcom.net> 6Message-Id: <32D0F245.5510@atlcom.net> 7Date: Mon, 06 Jan 1997 07:38:29 -0500 8From: Sheldon Simms <sheldon@atlcom.net> 9X-Mailer: Mozilla 2.0 (Macintosh; I; 68K) 10Mime-Version: 1.0 11To: wtanksle@mailhost2.csusm.edu 12Subject: More Omega 13Content-Type: text/plain; charset=us-ascii 14Content-Transfer-Encoding: 7bit 15Status: 16X-Status: A 17 18Since I was looking through old mail... This is a message I sent 19to Erik Max Francis in late November 20 21I was trying to find out why I sometimes encoutered tangible (!m_statusp( m, 22INTANGIBLE )) monsters sitting on unrevealed secret passages. The way this 23looks to the player is that he sees a tangible monster, like a goblin, 24sitting there but when he tries to attack, Omega prints "Ouch!". 25 26The function m_unblocked() in util.c determines whether a monster can move 27onto a space. It explicitly disallows tangible monsters from moving onto a 28secret space unless they are smart, in which case they can "open" the secret 29door or passage, which then becomes non-secret. 30 31So I thought that tangible monsters might be getting put on secret walls 32when the level is populated. After tracking down the code, I found that the 33function findspace() (also in util.c) finds a space to put a new monster 34when the level is being populated. findspace() didn't care whether a space 35was secret, only whether the locchar was FLOOR, which it is for secret 36passages. So I figured (and still think) that modifying findspace() to 37disallow secret spaces has solved that problem. 38 39However, as I read findspace() I immediately thought about Laurence's 40comment about monsters having a party because the findspace was written, 41this was very likely to happen. Basically it picked a random space on the 42level and if that space wasn't ok, it started searching across and down for 43the first acceptable empty space. So if the uppermost room or corridor on a 44level was on (for example) row 16, with every row above that being filled 45with WALLs, 25% (16/64) of all the monsters on the level will be in the 46upper-left-most room or corridor - they're having a party! 47 48The reason I'm telling you all this is that I rewrote findspace() to 49eliminate the party effect. In my new findspace(), if the randomly chosen 50space is not ok, it searches either across or down (alternating each time a 51space is selected at random). If it finds no acceptable space in the row or 52column it searched, it tries another random space. Obviously it could try 53one random space after another, but I was wary of the possibility that such 54a loop might run for quite a while. 55 56Anyway, the code follows for inclusion in the official source, if you choose 57to use it: 58 59/* finds floor space on level with buildaux not equal to baux, 60sets x,y there. There must *be* floor space somewhere on level.... */ 61 62int spaceok( int i, int j, int baux ) 63{ 64 return (( Level->site[ i ][ j ].locchar == FLOOR ) && 65 ( Level->site[ i ][ j ].creature == NULL ) && 66 ( !loc_statusp( i, j, SECRET )) && 67 ( Level->site[ i ][ j ].buildaux != baux )); 68} 69 70void findspace( int *x, int *y, int baux ) 71{ 72 int i, j, tog = TRUE, done = FALSE; 73 74 do { 75 i = random_range( WIDTH ); 76 j = random_range( LENGTH ); 77 if ( spaceok( i, j, baux )) 78 { 79 done = TRUE; 80 } 81 else 82 { 83 if ( tog ) 84 { 85 tog = !tog; 86 while( 1 ) 87 { 88 i++; 89 if ( i >= WIDTH ) 90 break; 91 else if ( spaceok( i, j, baux )) 92 { 93 done = TRUE; 94 break; 95 } 96 } 97 } 98 else 99 { 100 tog = !tog; 101 while( 1 ) 102 { 103 j++; 104 if ( j >= LENGTH ) 105 break; 106 else if ( spaceok( i, j, baux )) 107 { 108 done = TRUE; 109 break; 110 } 111 } 112 } 113 } 114 } while ( !done ); 115 *x = i; 116 *y = j; 117} 118 119 120-- 121W. Sheldon Simms III 122sheldon@atlcom.net 123 124 125-- 126W. Sheldon Simms III 127sheldon@atlcom.net 128Received: from future.atlcom.net by owl.csusm.edu (AIX 4.1/UCB 5.64/4.03) 129 id AA07766; Mon, 6 Jan 1997 04:28:38 -0800 130Received: from lpm2-10.atlcom.net by future.atlcom.net with SMTP (5.65/1.2-eef) 131 id AA20687; Mon, 6 Jan 97 07:37:38 -0500 132Return-Path: <sheldon@atlcom.net> 133Message-Id: <32D0F32E.74F@atlcom.net> 134Date: Mon, 06 Jan 1997 07:42:22 -0500 135From: Sheldon Simms <sheldon@atlcom.net> 136X-Mailer: Mozilla 2.0 (Macintosh; I; 68K) 137Mime-Version: 1.0 138To: wtanksle@mailhost2.csusm.edu 139Subject: Still More Omega 140Content-Type: text/plain; charset=us-ascii 141Content-Transfer-Encoding: 7bit 142Status: 143X-Status: R 144 145here's another mail I sent to Max in November: 146 147 148 I just want to tell you about a few of the more dangerous bugs I have 149found in Omega. 150 1511) In inv.c, the function givemonster(), when grain is given to a 152 horse, the grain object is freed: 153 154 else 155 nprint1( "...and now seems satiated." ); 156 morewait(); 157 free( (char *)o ); 158 159 This is a bug because when givemonster() returns to give() in 160 command2.c, give() tries to access the object: 161 162 givemonster( m, obj ); 163 print2( "Given: " ); 164 nprint2( itemid( obj )); 165 166 This sometimes caused "bus error" crashes on my Mac. I have 167 simply commented out the free() statement for now. I'll probably 168 leave it that way and simply accept the memory leak. 169 1702) In guild1.c in the function l_arena(), after you kill your arena 171 opponent, the monster is freed: 172 173 print1( "Let the battle begin...." ); 174 175 time_clock( TRUE ); 176 while ( Current_Environment == E_ARENA ) 177 time_clock( FALSE ); 178 179 free(name); /* <- bad */ 180 free(corpse); /* <- bad */ 181 if (melee) /* <- bad */ 182 free(melee); /* <- bad */ 183 184 This is incorrect because the dead monster can be picked up and 185 carried out of the arena. The four lines marked "bad" should be 186 removed. 187 1883) The star-gem bug. This happens in save.c because the possessions of 189 hiscore_npc monsters are not saved. It is easily fixed by moving one 190 line in each of the functions save_monsters() and restore_monsters(). 191 In save_monsters(): 192 193 if ( tml->m->id != HISCORE_NPC ) 194 { 195 /* several lines snipped */ 196 197 /* ok &= save_itemlist( fd, tml->m->possessions ); <- move this */ 198 } /* else it'll be reloaded from the hiscore file on restore */ 199 ok &= save_itemlist( fd, tml->m->possessions ); /* <- to here */ 200 201 This change causes possessions to be saved for all monsters. The change 202 to restore_monsters() complements the change to save_monsters(): 203 204 if ( ml->m->id == HISCORE_NPC ) 205 { 206 /* stuff deleted */ 207 } 208 else 209 { 210 /* more stuff deleted */ 211 212 /* ml->m->possessions = restore_itemlist( fd ); <- move this */ 213 ml->m->meleestr = Monsters[ ml->m->id ].meleestr; 214 } 215 ml->m->possessions = restore_itemlist( fd ); /* <- to here */ 216 2174) There is also another bug that I haven't fixed yet. This involves 218 the time when you bash a statue and it glides into the floor leaving a 219 stairway down. When this happens on levels where there is not supposed 220 to be stairway down, taking the created stairway can cause problems. I 221 just encountered this problem on the 5th level of the astral plane (the 222 high astral plane). Trying to take the stairway down caused a crash. 223 224-- 225W. Sheldon Simms III 226sheldon@atlcom.net 227Received: from mail.Virginia.EDU by owl.csusm.edu (AIX 4.1/UCB 5.64/4.03) 228 id AA16322; Mon, 20 Jan 1997 06:20:52 -0800 229Received: from uva.pcmail.virginia.edu by mail.virginia.edu id aa25972; 230 20 Jan 97 9:31 EST 231Received: (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) 232Message-Id: <199701201431.JAA04707@uva.pcmail.virginia.edu> 233From: Kent Peterson <kmp2x@uva.pcmail.virginia.edu> 234Date: Mon, 20 Jan 97 09:30:48 EST 235X-Mailer: UVa PCMail 1.9.0 236To: wtanksle@mailhost2.csusm.edu 237Subject: Omega bugs 238Status: 239X-Status: R 240 241l_safe - siren goes off, need morewait afterwards 242 243send_to_jail - two of the release options have the x/y coords 244 reversed (subtle!) 245 246l_tavern - sleeping needs to change the date, drinking needs to 247 pass time 248 249l_library - cost of studying should be moved so as to apply only 250 to option e, not any of the others 251 2521) m_talk_druid - non-druid characters always have their alignment 253 *decreased* by neutralization? that's what seems to be 254 happening here ... 255 2562) m_sp_mb - manaburst explosion doesn't kill it, anything that 257 explodes itself should die by my lights. 258 2593) m_sp_dragonlord - dragonlord should be capitalized everywhere 260 2614) boots/spells of heroism should give immunity to fear 262 2635) l_void - need a morewait after "Death peers quizzically ..." etc 264 2656) l_escalator - need a morewait after stairs start moving 266 2677) m_simple_move - if blocked on straight line and both diagonals, 268 try moving randomly once 269 2708) casino closed for investigation - need to make this last the 271 entire day 272 2739) what is the difference between m_smart_move and m_normal_move? 274 A planned one? 275 27610) transcribe_monster_actions - when figuring attacks, when deciding 277 to attack center, it blocks instead 278 27911) void i_symbol - for loop cutting hp and for loop cutting items 280 should be 2 separate loops (?) 281 also, if you use the symbol twice on the same hour on 282 succeeding days, your god gets angry; there should be a 283 SymbolDay variable as well 284 (same with crystal ball) (and in i_enchantment) 285 (and i_helm) 286 28712) holy hand grenade (i_antioch) - count>3 / count<3 are the wrong 288 way around; should be count>3 for monster to have time to 289 throw it back 290 29113) Sceptre of High Magic - we need 2 HiMagic variables here, one for 292 the sceptre and one for the throneroom (same for the 293 throne's routine) 294 29514) berserk attacks while shadowformed - indefinitely 296 29715) i_perm_breathing fun - check p_drown to make sure it gives you 298 the normal chance to drop/bash/etc to survive 299 30016) surrendering to an undead guardsman 301 30217) saving in countryside is broken 303 30418) area effect (snowball) targeted on edge square (so that part of 305 the area is off the edge of the map) 306 30719) pressing escape while targetting staff (of disruption) is broken 308 30920) "Really. Well the police are being notified" - more always 310 appears, shouldn't 311 31221) killing a monster with riposte does not leave the normal treasure 313 pile that monsters carry; the * character gets printed, 314 but there's nothing there 315 31622) restoring from a save when near a monster often will make the 317 monster "sleep" for a dozen rounds while you whack away 318 safely at it 319 32023) Slowness - should be temporary (a dozen rounds/seconds/minutes). Right 321 now it's so crippling it's better to save/restore than go 322 through it. 323 (correction, it *is* temporary. tested it. it's just 324 way too long-lasting.) 325 32624) Shadow Form - should lose immunities at end (plain bug) 327 when the spell aborts, the various immunities should be 328 set to 0, rather than being decremented 329 (same thing with slowness?) 330 33125) breathing stat (powered armor etc) - when this 332 gets cursed or reversed, it ought to call the drown 333 function rather than simply killing you 334 33526) dispel - should also remove slowness and/or shadowform 336 33727) names for several temples should be reconciled between strategic 338 teleports and *roomname 339 34028) hint something about how azoth needs to be blessed 341 "They say blessings can really change an item's attitude." 342 34329) Encounters - fewer high-powered magical beasties on roads and plains; 344 wolves and lions are bad enough. Too easy to die while 345 traveling. 346 34730) Sacrificing - lower curve of required values; it's too hard to get 348 something worth giving as it stands (wands/staves should be 349 possible), especially at middle levels. Reasonable values would 350 be 200 gp at level 10, current values are more like 2-3 thousand 351 35231) Fire resistance - should be partial (depending on pluses), rather than 353 total (too easy to kill dragons & Elemental Lord of Fire) 354 (same with deflection - missile attacks become laughable, 355 should depend on plusses to shield, or total value of 356 spell cast - the longer the spell has to last, the more 357 effective it is?) 358 resistance to electricity/cold damage probably also 359 applies here; fire really stands out though 360 36132) DragonLord - should have a chance of waking up every round someone's in 362 the inner cave; it's too easy to steal repeatedly 363 Also, when games are saved and restored within the cave, the 364 portcullis should restore as down 365 36633) Prime Sorceror - should always be created with the Star Gem when in the 367 Circle plane, even if game saved/restored while in Astral 368 36934) Law/Chaos worship stones - these should depend a lot more on alignment; 370 as it stands it seems like even if you're very lawful the Star 371 View stone has pretty good chances of feeding you something 372 nasty; on the other hand, the reward shouldn't be as big (make 373 the stat increase random, 1-6?) 374 37535) Gym training - far too expensive; I *always* save/restore to make sure 376 the training pays off because I can't afford to throw away that 377 kind of money. A cost of 300-800 is more like it, or 378 maybe 1000 with half to 3/4 of your money back if your 379 ability doesn't improve. (or maybe the refund gets added 380 to your credit) 381 38236) 7 league boots - each time used, add 1 to fragility, when reaches 383 terminal, "your boots dissolve into dust with a soft sigh" 384 (right now they break the game - the countryside becomes 385 irrelevant) (esp. when combined with robbing the DragonLord) 386 38737) Gambling - should take time (~10 mins per game), and should be more 388 detailed (what the heck does it *do*, besides randomly rolling 389 electronic dice to see if you gain or lose money? what are the 390 rules of the game?) 391 39238) Tavern - have drinking take time (1 drink = 2-10 minutes, a round 393 = 10-30 minutes) - we need to be able to while away the 394 night hours 395 39639) Explorer's Club - needs to sell more stuff - maybe stimtabs/nutritabs/ 397 powtabs/immunotabs, for appropriate prices? (100/200/1000/50) 398 Also, the "listen for rumors" option could be expanded to 399 something more like a daytime tavern; you could have a 400 drink/snack and hear the rumors meanwhile (and have it take ~5 401 minutes) 402 40340) The mercenary legion should sell crossbows/longbows/arrows/bolts, 404 at 1/10 price to legion members - then they WOULD be the 405 "best equipped" (arrows and bolts especially, those are hard 406 to find) 407 40841) boots of leather/cloaks of wool ought to add 1 to defense, to 409 have a reason to use them aside from defense from 410 disintegration 411 412 413Kent Peterson It is easier to ask for forgiveness 414kmp2x@virginia.edu than to ask for permission. 415kent@dirac.physics.jmu.edu 416 Abortions should be safe, legal, early, and rare. 417Received: from Tree.EGR.UH.EDU by owl.csusm.edu (AIX 4.1/UCB 5.64/4.03) 418 id AA20516; Thu, 13 Feb 1997 16:12:26 -0800 419Received: from lonestar by tree.egr.uh.edu (NX5.67f2/NX3.0M) 420 id AA11355; Thu, 13 Feb 97 18:23:29 -0600 421From: David J Robertson <djr98665@tree.egr.uh.edu> 422Message-Id: <9702140023.AA11355@tree.egr.uh.edu> 423Received: by lonestar.egr.uh.edu (NX5.67e/NX3.0X) 424 id AA08345; Thu, 13 Feb 97 18:23:28 -0600 425Subject: Re: Omega: Bug reports 426To: wtanksle@mailhost2.csusm.edu 427Date: Thu, 13 Feb 1997 18:23:27 -0600 (CST) 428In-Reply-To: <WQ7/ygUEFd7V089yn@owl.csusm.edu> from "William Tanksley" at Feb 10, 97 06:49:42 pm 429X-Mailer: ELM [version 2.4 PL23] 430Content-Type: text 431Content-Length: 6580 432Status: RO 433X-Status: R 434 435> 436> David, thank you! That was a perfect bug report for me -- even gave the way 437> to fix it :). 438 439 No problem. 440> 441> I've got some good news of my own -- it just MIGHT take a little less time 442> to do this than I'd thought. Someone else had already started it :). 443> That's real good news; not only does it mean less work from me, but it also 444> means everyone gets the game sooner. 445 446 Cool! 447> 448> As for your suggestion -- I don't know. The first one (have "know all 449> spells" effects give MORE knowledge of already-known spells) makes sense, 450 451 Hmm, the only "know all spells" effect I know of is using the 452key that was lost. For this item, I agree that reducing the cost 453in addition might be too good. I was really talking about the 454extra spells you get from the guilds. They don't help the spell 455cost if you already know the spell they teach you. 456 457 Well, here is another bug/suggestion. Have fun. :) 458 459 460I was trying to track down a bug with ghost items/no items being 461left on a monsters death, and found it. The following is pseudo 462code for m_pulse in mon.c. 463 464m_pulse(m){ 465 gain a hit point every so often 466 if asleep, wake up if player is in range 467 if awake 468 if wandering 469 move around, then reset wandering if in range 470 else 471 do the monster mstrike 1/2 the time if more than 1 space away 472 (some) monsters move toward the player if more than 1 space away 473(1) hostile monsters attack the player if 1 space away 474(2)greedy monsters pick up stuff 475 do monsters special function (if in range) 476 } 477 478 Now the problem is in lines (1) and (2). During the attack the 479 player phase, the monster can be killed by a riposete. If this 480 happens, then the monster drops its stuff, and its hp are set to 481 -1. Then the code returns to m_pulse. The (dead) monster picks 482 up everything it dropped, including its corpse. Then the (dead) 483 monster does its special attack. Then, back in time_clock in 484 time.c, the monster is deallocated. However the stuff it picked 485 up is lost, since the code in time_clock assumes that the monster 486 dropped everything on death, leading to a memory leak. 487 488 When I was looking at the m_pulse, I also notice that the monsters 489 can do an awful lot in each melee round, with the worst situation 490 occuring when it is two spaces away. Then it can: 491 492 (1) do a ranged attack (1/2 the time) 493 (2) move next to you 494 (3) do a melee attack 495 (4) do its special attack (even if dead) 496 497 I think it would be good idea to change the flow code so that 498 if the monster does a ranged attack, it won't move (or maybe it 499 should only have a chance at moving). Then if the monster does 500 move, it shouldn't get a chance to do a melee attack. There 501 should be a random chance for the special attack to occur. 502 There should also be a hitpoint check placed on all monster 503 actions after the tacmonster function has a chance of being 504 called, to prevent the bugs I mentioned above. 505 506 I've enclosed a revised m_pulse function below (the original 507m_pulse follows it). 508 509/* Revised function */ 510/* consider one monster's action */ 511void m_pulse(m) 512struct monster *m; 513{ 514 int range = distance(m->x, m->y, Player.x,Player.y) 515 int STRIKE=FALSE; 516 pol prev; 517 518 if (Time % 10 == 0) 519 if (m->hp < Monsters[m->id].hp) 520 m->hp++; 521 522 if ((! m_statusp(m,AWAKE)) && (range <= m->wakeup)) { 523 m_status_set(m,AWAKE); 524 resetgamestatus(FAST_MOVE); 525 } 526 527 if (m_statusp(m,AWAKE)) { 528 if (m_statusp(m,WANDERING)) { 529 if (m_statusp(m,MOBILE)) m_random_move(m); 530 if (range <= m->sense && (m_statusp(m, HOSTILE) || 531 m_statusp(m, NEEDY))) 532 m_status_reset(m,WANDERING); 533 } 534 else /* not wandering */ { 535 if (m_statusp(m,HOSTILE)) 536 if ((range > 2) && (range < m->sense) && (random_range(2) == 1) 537 (los_p(m->x,m->y,Player.x,Player.y) && 538 (Player.status[INVISIBLE] == 0)) { 539 STRIKE=TRUE; 540 monster_strike(m); 541 } 542 543 if ((m_statusp(m,HOSTILE) || m_statusp(m,NEEDY)) 544 && (range > 1) && m_statusp(m,MOBILE)) && 545 (!STRIKE || (random_range(2) == 1)) 546 monster_move(m); 547 else 548 if (m_statusp(m,HOSTILE) && (range ==1)) { 549 resetgamestatus(FAST_MOVE); 550 tacmonster(m); 551 } 552 } 553 /* if monster is greedy, picks up treasure it finds */ 554 if (m_statusp(m,GREEDY) && (m->hp >0) ) 555 while (Level->site[m->x][m->y].things != NULL) { 556 m_pickup(m,Level->site[m->x][m->y].things->thing); 557 prev = Level->site[m->x][m->y].things; 558 Level->site[m->x][m->y].things = 559 Level->site[m->x][m->y].things->next; 560 free((char *) prev); 561 } 562 /* prevents monsters from casting spells from other side of dungeon */ 563 if ((range < max(5,m->level)) && (m->hp > 0) && 564 (random_range(2) == 1)) 565 monster_special(m); 566 } 567} 568 569 570/* Original Function */ 571/* consider one monster's action */ 572void m_pulse(m) 573struct monster *m; 574{ 575 int range = distance(m->x, m->y, Player.x,Player.y); 576 pol prev; 577 578 if (Time % 10 == 0) 579 if (m->hp < Monsters[m->id].hp) 580 m->hp++; 581 582 if ((! m_statusp(m,AWAKE)) && (range <= m->wakeup)) { 583 m_status_set(m,AWAKE); 584 resetgamestatus(FAST_MOVE); 585 } 586 587 if (m_statusp(m,AWAKE)) { 588 if (m_statusp(m,WANDERING)) { 589 if (m_statusp(m,MOBILE)) m_random_move(m); 590 if (range <= m->sense && (m_statusp(m, HOSTILE) || m_statusp(m, NEEDY))) 591 m_status_reset(m,WANDERING); 592 } 593 else /* not wandering */ { 594 if (m_statusp(m,HOSTILE)) { 595 if ((range > 2) && (range < m->sense) && (random_range(2) == 1)) 596 if (los_p(m->x,m->y,Player.x,Player.y) && 597 (Player.status[INVISIBLE] == 0)) monster_strike(m); 598 } 599 if ((m_statusp(m,HOSTILE) || m_statusp(m,NEEDY)) 600 && (range > 1) 601 && m_statusp(m,MOBILE)) { 602 monster_move(m); 603 604 } 605 if (m_statusp(m,HOSTILE) && (range ==1)) { 606 resetgamestatus(FAST_MOVE); 607 tacmonster(m); 608 } 609 } 610 /* if monster is greedy, picks up treasure it finds */ 611 if (m_statusp(m,GREEDY)) 612 while (Level->site[m->x][m->y].things != NULL) { 613 m_pickup(m,Level->site[m->x][m->y].things->thing); 614 prev = Level->site[m->x][m->y].things; 615 Level->site[m->x][m->y].things = 616 Level->site[m->x][m->y].things->next; 617 free((char *) prev); 618 } 619 /* prevents monsters from casting spells from other side of dungeon */ 620 if (range < max(5,m->level)) 621 monster_special(m); 622 } 623} 624 625David Robertson 626