mthing->angle is a signed short, and if ANG45 * mthing->angle/45 < 0, the
result of the right shift is sign extended.
afaik, an being 16bit in the dos version of doom, you'd endup with a
negative array offset, which would just access values from adjacent arrays
(finetangent[] for finecosine[], and finecosine[] for finesine[]), and it
would result in a misplaced teleport fog in some circumstances (fog is not
in front of the player on respawn, hence "silent teleport"). so, this fix is
bug incompatible, but this only affects live multiplay.
to test:
% hget http://doomedsda.us/dm/ahfx7_2.zip | unzip -sv
extracting AHFX7_2.TXT
extracting AHFX7_2.LMP
% mv AHFX7_2.LMP ahfx7_2.lmp
% games/doom -playdemo ahfx7_2
[...]
doom 10553: suicide: sys: trap: fault read addr=0x400429e10 pc=0x205b45
KEY_F11 and KEY_F12 are not KEY_F1+11 and KEY_F1+12 as it is assumed in
runetokey(), which prevents these keystrokes from being used. rather than
change runetokey(), it seems better to just change the key definitions in
doomdef.h (the new values don't correspond to any other keys anyway).
F11 is the gamma correction key. to make gamma correction actually work,
i_video.c:I_SetPalette must also take into account usegamma (this was just
never ported). cf i_video.c:UploadNewPalette in source code release.
F12 is the spycam key. the spycam switches the renderview to a different player
during a coop game, or when watching a multiplayer demo. this feature only
changes the renderview; sounds, palette effects, status bar, etc. are still
from the first player's perspective.
a typo in st_stuff.c:ST_Responder prevents idclev (change level) cheat to work
in doom2 and final doom (gamemode == commercial): episode is set to 0, when
that's invalid, and ST_Responder just returns.
to test, while ingame type idclev, followed by:
. doom1: episode (1-3 or 1-4) then map number (1-9)
. doom2/final doom: map number (1-32)
incidentally, if the last digit typed is 1, the player's weapon will switch to
the fist, because of a different bug (basically kbdproc registering two events
when pressing a key, for 'c' and 'k' case).
this bug was introduced in the plan9 port, and since i_sound.c compiles with
no warning, it was never noticed. in effect, the statement between the
unterminated comment and the next is ignored. channelids[] is used in addsfx()
to avoid re-adding certain sounds if they are already playing. one of those is
sfx_sawful, and because of this bug, it is added again each tic during which
the player fires the chainsaw, rather than reset every tic.
compare firing the chainsaw continuously with and without the patch (without
hitting an enemy).
theres code that assumes one can dereference a char[] buffer on the stack
as a long (ghostscript gxblend.c), so make sure all automatics on the stack
are word aligned. this is not strictrly neccesary, but avoids some
trouble with unportable code.
buffers which still have requests queued on them are not free!
we cannot chanedev() a buffer while it has still requests queued on it
and we canot just queue our request (having different address) on the
buffer while there are other requests before it, otherwise we would
create artificial block dependency that can cause deadlock.
it is possible for another getbuf() on buffer b to come in
before undelayreq() calls givebuf() on a buffer again. then
givebuf() would find b already busy and abort().
instead, we now handle what getbuf() did in givebuf() and
consider the Buf* argument to givebuf() as a hint only for
the case when we have to actually flush/read a block from
disk.
when wunlock() was used by threads running within the same proc,
the wunlock() can deadlock as it keeps holding the RWLock.lock
spinlock while indirectly calling _threadrendezvous(). when
_threadrendezvous() switches to another thread in the same proc,
then that thread can hang at rlock()/wlock()/runlock() again
waiting for wunlock() to release the spinlock which will never
happen as lock() does not schedule threads.
wunlock() is changed to release the spinlock during rendezvous
wakeup of readers. note that this is a bit dangerous as more
readers might queue concurrently now which means that if
we cannot keep up with the wakeups, we might keep on waking
readers forever. that will be another patch for the future.
using "interrupt" ctl message directly doesnt work when the
process is doing libthread channel operations (threadrendezvous)
as it will just repeat a interrupted rendezvous(). threadint()
handles this for us.
threadint() is called to interrupt channel operation or a system call.
the kernel provides a new "interrupt" procctl message to interrupt a
process commited to or being in a blocking syscall, which is similar,
but not the same. the main difference is that "interrupt" condition
is not cleared before the process actually attempts to block. also
can be cleared with "nointerrupt" ctl message. see proc(3)
instead of ordering the source mount list, order the new destination
list which has the advantage that we do not need to wlock the source
namespace, so copying can be done in parallel and we do not need the
copy forward pointer in the Mount structure.
the Mhead back pointer in the Mount strcture was unused, removed.
there was a race between cunmount() and walk() on Mhead.from as Mhead.from was
unconditionally freed when we cunmount(), but findmount might have already
returned the Mhead in walk(). we have to ensure that Mhead.from is not freed
before the Mhead itself (now done in putmhead() once the reference count of the
Mhead drops to zero).
the Mhead struct contained two unused locks, removing.
no need to hold Pgrp.ns lock in closegrp() as nobody can get to it (refcount
droped to zero).
avoid cclose() and freemount() while holding Mhead.lock or Pgrp.ns locks as
it might block on a hung up fileserver.
remove the debug prints...
cleanup: use nil for pointers, remove redundant nil checks before putmhead().