forked from muspellsson/omega-ng
-
Notifications
You must be signed in to change notification settings - Fork 0
/
omega.bug
625 lines (517 loc) · 22.7 KB
/
omega.bug
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
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: <[email protected]>
Message-Id: <[email protected]>
Date: Mon, 06 Jan 1997 07:38:29 -0500
From: Sheldon Simms <[email protected]>
X-Mailer: Mozilla 2.0 (Macintosh; I; 68K)
Mime-Version: 1.0
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
--
W. Sheldon Simms III
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: <[email protected]>
Message-Id: <[email protected]>
Date: Mon, 06 Jan 1997 07:42:22 -0500
From: Sheldon Simms <[email protected]>
X-Mailer: Mozilla 2.0 (Macintosh; I; 68K)
Mime-Version: 1.0
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
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 [email protected]; Mon, 20 Jan 1997 09:31:03 -0500 (EST)
Message-Id: <[email protected]>
From: Kent Peterson <[email protected]>
Date: Mon, 20 Jan 97 09:30:48 EST
X-Mailer: UVa PCMail 1.9.0
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
[email protected] than to ask for permission.
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 <[email protected]>
Message-Id: <[email protected]>
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
Date: Thu, 13 Feb 1997 18:23:27 -0600 (CST)
In-Reply-To: <WQ7/[email protected]> 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