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