The ThrowHead() and ThrowClientHead() functions are special. They
transform the entity given in `self` (mostly the caller itself) into a
ripped off head. They don't reset the entities clip mask, which may
cause problems in interactions with other entities. Fix that by reseting
the clip mask to `0`. `0` should be save, because that's the default and
and least SV_TestEntityPosition() handles `0` clip masks.
Suggested by @BjossiAlfreds.
If `ent->dmg` is `0` it's set to `2`:
```
if (!ent->dmg)
{
ent->dmg = 2;
}
```
This enforces func_rotate dealing at least `2` damage points per tick.
Vanilla Quake II had this code a few lines below:
```
if (ent->dmg)
{
ent->blocked = rotating_blocked;
}
```
The if clause is always true. PVS studio complained about that. By
mistake the whole block was removed, essentially preveting func_rotate
from freeing itself when blocked. This broke at least the 'Emulsifying
Flesh Press' in the fact2.bsp.
Closes#786.
Since `self->helth` is set after calling `master_start()`
`self->max_health is always 0. Found by @drakonorodny and
analyzed by @BjossiAlfreds. Closes#761.
There were complains that always generating footsteps is annoying,
because there will be footsteps while swimming or jumping. Refine
the cvar a little bit:
* `0`: No footsteps at all.
* `1`: Vanilla Quake II behavior.
* `2`: Always footsteps as long as the player has a ground entity.
* `3`: Always footsteps.
The changes the meaning of the values, `2` has become `3`.
Closes#738.
The commanders body entity is special, because it's spawned in god mode.
That's no problem in the baseq2 and addons campaigns. But it may break
some custom maps and prevents some hacks, one example is putting the
entity inside an killbox.
Submitted by Евгений T.
1: The Vanilla Quake II behaviour, footsteps are generated when the
player is faster than 255.
0: Footstep sounds are never generated.
2: Footstep sounds are always generated.
Defaults to `1`, cheat protected to `1`.
Closes#666.
In lab.bsp near the commanders head two parasites spawn in an hidden
place in the ceiling. On hard difficulty the box cracks open, exposing
the parasites. On medium skill it doesn't. Work around that by lowering
the monster count by 2.
Closes#668.
When coming down the river near the end on hard difficulty a gladiator
breaks out of a big metal crate to the left. On medium difficulty the
gladiator is spawned but never triggered. Work around this by lowering
the monstercount by one when skill is set to 1. This doesn't happen on
easy difficulty.
Closes#667.
$PROCESSOR_ARCHITECTURE seems to contain the architecture of the host,
but we need the architecture the current MinGW shell is targeting.
$MINGW_CHOST seems to be just that, and on my system it's either
i686-w64-mingw32 (mingw32.exe) or x86_64-w64-mingw32 (mingw64.exe)
(No idea what it looks like for Windows on ARM...)
As fixing this would otherwise break existing savegames, I bumped the
SAVEGAMEVER to "YQ2-4" and added a quirk for older savegameversions:
On Windows i386 savegames that contain "AMD64" instead of "i386" as
architecture are also accepted.
(For YQ2-1 this didn't seem necessary, apparently "i386" was hardcoded)
src/client/refresh/gl1/gl1_model.c:39:6: warning: type of ‘LoadSP2’ does not match original declaration [-Wlto-type-mismatch]
src/game/g_turret.c:29:6: warning: type of ‘infantry_die’ does not match original declaration [-Wlto-type-mismatch]
src/game/g_spawn.c:43:6: warning: type of ‘SP_info_player_intermission’ does not match original declaration [-Wlto-type-mismatch]
In coop it's often hard to get on the same elevator together, because
they're immediately triggered once the first player steps on it.
This cvar sets a delay (1 second by default) for the elevator to wait
before moving, so other players have some time to get on it.
If you like elevators/platforms that suck, just set it to `0` :-P
Currently only used in func_plat, if it turns out that other entities
are used for automatically triggered platforms, we'll have to adapt
those as well (I guess wait_and_change() is generally useful for that).
We're not bumping the savegame version because they should only break in
an uncommon corner case: *Coop* savegames created with clients including
this change will not work on older clients - SP savegames are not
affected and old savegames on new clients also still work.
In coop a weapon can be picked up only once. That's annoying, because in
coop ammunition is sparse and not getting the ammunition that comes with
a weapons make things worse. When `coop_pickup_weapons` is set to `1` a
weapon may be picked up if:
1) The player doesn't have the weapon in their inventory.
2) No other player has already picked it up.
Some projectiles like grenades or rockets are classified as enemies.
Their explosion spawn a sound entity, monsters should move to that. But
the projectile is destroyed when exploding, it's entity struct is set to
NULL. Therefor the self->enemy pointer is also NULL. The self->enemy
check was removed in bc5f5698. Work around this by pretending that the
enemy is already there.
This was reported by @Soldy, closesyquake2/xatrix#56.
C11 _Noreturn is only accepted on function declarations, not on function
pointers, so we can't use it on callbacks like game_import_t.error and
refimport_t.Sys_Error. Use a separate macro for those.
The problematic situation doesn't currently happen because the Makefile
hard-codes -std=gnu99, which disables C11 features; but removing
-std=gnu99 (resulting in the compiler's default, currently gnu11) causes
compilation failures with at least gcc 9.x.
Signed-off-by: Simon McVittie <smcv@debian.org>
In the vanilla code show_hostile was a qboolean what's clearly wrong.
For wome reasons I don't remember I changed it to an integer and added
the casts. This is problematic because show_hostile is derived from
level.time which is a float. The loss in precision broke some corner
cases like monsters becoming activated when they shouldn't.
Found, analyzed and reported by @BjossiAlfreds #525. Closes#525.
Pushing all entities slightly away from non-horizontal may let items to
slide to unreachable locations, or let monsters getting stuck.
This is part of yquake2/xatrix#50
Especially after savegame load not all slots in the edicts array may be
used. Check if the current entity has a classname string. This is
another part of #430.
It's unclear were this comes from, maybe it's a bug in the collision
detection. Because the collision detection is ununderstandable for
people without 'special brain type game programming' like me and even
bugfixes to it have a very high chance to break things, work around
it. Save current position, perform move, check if we're in the world
model. If we are revert to old position.
Debugged and work arounf suggested by @BjossiAlfreds. Fixes#443.
This is another code inconsistency, we must not clamp the current health
to the client max health (which apparently is always 100) but to the
current max health of the player entity.
Analyzed and fix suggest by @BjossiAlfreds, fixes#441.
This is another corner case. Parasites have a bbox height of 24,
walkmonster_start_go() hardcodes a viewheight of 25. Therefor most
traces in other functions like visible() overshoot the parasite.
Fix this by not overriding the monster viewheight.
Analyzed and fix suggested by @BjossiAlfreds. Closes issue #440.
This rather sophisticated command prints all entities of one or more
given classes and their coordinates. Possible classes are:
* ammo
* items
* keys
* monsters
* weapons
Classes can be combined into one command, e.g. `listentities ammo keys'
would print all ammunition and all keys. The special class `all` prints
all entities, regardless of their class.
The command is protected by `cheats 1`.
This is part of issue #430.
A command that teleports the player to abitrary locations was often
requested and may be helpfull for debugging, so finally add it. It works
like a normal teleporter: It moves the player to the requested location,
clears all movements, tells the server and clients that the entity just
teleported and telefrags everything that's in the target location.
The implementation does not verify if the requested location is save,
the player may teleport into the world model or even the void. But the
requested Z coordinate is elevated by 10 units to prevent the player
getting stuck in the floor.
The command is protected by sv_cheats.
This is part of issue #430.
44472722e added some sanity checks to the AI code. The checks in
ai_run() are likely wrong because the enemy entity might be already
NULL if we arrive their. By aborting early the code is unable to
determine a new enemy or return the monster to idle state, so the
monster will wait forever for an enemy that'll never come.
This happens only in monster vs. monster fights. Never in monster vs.
player, that game ends if the player dies.
In theory this change should be harmless, because if the enemy entity is
gone it won't generate sound targets now be visible. If the game crashes
by self->enemy being NULL we've got a problem elsewere.
This was reported by @BjossiAlfreds in #483. He also suggested the fix.
When searching for the player FinTarget() always goes after sound
targets and aborts as soon as it finds one. So if the player is
constantly generating sounds - for example firing the machine gun -
there's a high chance that monsters will only hear but never see
him. Work around this by adding a small timeout to player noises, make
sure that at least 3 frames passed since the last noise. This gives
monsters 2 frames to see the player.
This bug was present in the original code, this is a small gameplay
change.
The problem was analysed by @BjossiAlfreds in #436. He also suggested
the fix.
M_MoveFrame() calls first the AI functions that decide if a monster
should attack or not. After that the monsters think function is called
which walks through berserk_frames_stand[]. Even if the AI function found
an enemy and decided to attack, the monster is still standing for this
frame and berserker_fidget() is called. It may override the earlier
earlier decision, aborting the attack. Even worse this may let the
berserker stuck, because AI_STAND_GROUND may be cleared which prevents
further attacks.
This bug was present in the original code, so this is small gameplay
change. It's likely also present in both addons.
Reported and analyzed by @BjossiAlfreds in issue #433. He also suggested
the fix.
Otherwise the entities origin might be in the surface, which causes it
to be rendered in full black. This fix is a port from KMQuake2, reported
by @m-x-d. Closes#407.
This fixed bug #357 - the problem was that
client->resp.coop_respawn.weapon and .lastweapon (pointers to gitem)
were not properly initialized when loading a savegame.
Now those fields are saved (=> we had to bump the savegame version)
and for old savegames client->resp.coop_rewspawn is initialized
from client->pers, as a hack for backwards-compatibility.
In src/backends/unix/network.c:
* line 181: Assignment of function parameter has no effect outside the function. Did you forget dereferencing it?
* line 276: The scope of the variable 'tmp' can be reduced.
* line 665: The scope of the variable 'mcast_addr' can be reduced.
* line 665: The scope of the variable 'mcast_port' can be reduced.
* line 666: The scope of the variable 'error' can be reduced.
* line 775: The scope of the variable 'i' can be reduced.
In src/backends/windows/network.c:
* line 186: Assignment of function parameter has no effect outside the function. Did you forget dereferencing it?
* line 287: The scope of the variable 'tmp' can be reduced.
* line 707: The scope of the variable 'mcast_addr' can be reduced.
* line 707: The scope of the variable 'mcast_port' can be reduced.
* line 1049: The scope of the variable 'err' can be reduced.
* line 1163: The scope of the variable 'i' can be reduced.
In src/client/menu/menu.c
arrayIndexOutOfBounds:
* line 1921: Array 'creditsIndex[256]' accessed at index 256, which is out of bounds.
variableScope:
* line 332: The scope of the variable 'item' can be reduced.
* line 533: The scope of the variable 'x' can be reduced.
* line 533: The scope of the variable 'y' can be reduced.
* line 838: The scope of the variable 'b' can be reduced.
* line 864: The scope of the variable 'b' can be reduced.
* line 1910: The scope of the variable 'n' can be reduced.
* line 2199: The scope of the variable 'str' can be reduced.
* line 2812: The scope of the variable 'length' can be reduced.
* line 2813: The scope of the variable 'i' can be reduced.
* line 3838: The scope of the variable 'c' can be reduced.
* line 4112: The scope of the variable 'scratch' can be reduced.
* line 4181: The scope of the variable 'i' can be reduced.
* line 4345: The scope of the variable 's' can be reduced.
In src/game/player/hud.c
arrayIndexOutOfBounds:
* line 132: Array itemlist[43] accessed at index 255 which is out of bounds.
Itemlist assigned only once, and has only 43 items, better ignore unexisted items.
variableScope:
* line 82: The scope of the variable 'n' can be reduced.
* line 217: The scope of the variable 'x' can be reduced.
* line 217: The scope of the variable 'y' can be reduced.
* line 218: The scope of the variable 'cl' can be reduced.
* line 583: The scope of the variable 'cl' can be reduced.
This prevents gibs and debris being easily destroyed with the rocket
launcher but leaves enough room for the entities being destroyed by
elevators, doors and the like if necessary.
The gibs and debris per frame must be limited to prevent server mem
map overflows. Until now debris and gibs were handled the same, the
debris spawned by rockets and grenates could prevent the actual gibs
of the killed monster from spawning.
Before this change 20 entities were spawned at max. Now up tp 40
enties can be spawned. This needs some testings.
Fixes issue 323.
A long time ago in 2b4f223 I introduced a small logic change to the
handling of stacked entities. If two entities were standing on each
other the original code set the movement speed of the upper entity
to 0. It would be pushed or dragged by the lower entity. I changed
that in way that the upper entity got the same speed as the lower
entity. With that change it wasn't pushed or dragged but moving on
it's own. I hoped to fix some of the 'elevator hurts player or monster'
bugs.
That hope was wrong, at a later time we quirked all elevators that hurt
the player. Additionally the change lead to physics bugs if entities are
standing on high speed elevators (more than 200 units per seconds). So
revert it.
The actual fix was already committed as part of 69b6e5a. This is just a
little cleanup commit, mainly for documentation purposes.
This closes#320.
When killing the enforcer with one shot (instead of damaging him first
without killing, which will switch to the bloody skin), the skin wasn't
changed. Now it is.
1) Do not increment the frame rate returned by SDL by 1. Incrementing
is unnessecary, more or less up to date versions on Nvidias, AMDs
and Intels GPU driver on relevant platform return an value that's
either correct or rounded up to next integer. And SDL itself also
rounds up to the next integer. At least in current versions. In fact,
incrementing the value by one is harmfull, it messes our internal
timing up and leads to subtile miss predictions. Working around that
in frame.c would add another bunch of fragile magic... So just do
it correctly. If someone still has broken GPU drivers or SDL versions
that are rounding down the could set vid_displayrefreshrate.
2) The calculation of the 5% security margin to pfps in frame.c was
wrong. It didn't take into account that rfps can be slightly wrong
in the first place, e.g. 60 on an 59.95hz display. Correct it by
comparing against rfps including the margin and not the plain value.
On Unix platforms unicode is implemented through UTF-8 which is
transparent for applications. But on Windows a UTF-16 dialect is
used which needs alteration at application side. This wrapper is
another step to unicode support on Windows, now we can replace
fopen() by a function that converts our internal UTF-8 pathes to
Windows UTF-16 dialect.
This is a noop for Unix platforms. The Windows build is broken,
the compiler errors out in shared.h. This will be fixed in a
later commit.
Caveats:
* fopen() calls in 3rd party code (std_* and unzip) are not replaced.
This may become a problem. We need to check that.
* In the Unix specific code fopen() isn't replaced since it's not
necessayry.
Resurrect support for render / refresher loadable libraries and use them to implement an experimental OpenGL 3.2 renderer. Please note that the new renderer interface is somewhat different from the original one, old render libraries will NOT work!
there's a target_secret (with targetname "t117"), but no one triggers
it - that's why the help computer shows four secrets, but you can only
get three of them.
Now when you open the door in front of the hidden secret armor
(by shooting it), it'll trigger the target_secret and you can get all
four secrets.
fixes#182
When the monster was already killed by another monster or a coop player
some references may be NULL and the game was crashed. This was observed
by maraakte, who reported it in issue #164. I've just merged his fix
from q2dos.
teleport_time has nothing to do with teleports, it's just the time
since the last player sound. Rename it accordingly. This was suggest
by maraakate in issue #162.
In ai_checkattack() is a check against AI_SOUND_TARGET. If the player
made a noice and the the monster noticed this noise it's true. If
that noice was more than 5 seconds ago the monster forgets that event
and continues with it's search for the player. Otherwise it informs
the surrounding monsters that something interesting has happened and
then returns false. So the problem is: Even if the monster heard the
player and can see him, it aborts at this point.
Fix this by adding an additional visibility check. Do the sound
checking only if the player is not visible, otherwise just continue.
This was reported by shoober420 and debbuged by maraakate. This fix
was DanielGibons idea. This commit fixes issue #162.
I don't think that this has any visible effect, but it's saver than
assume that in multiplayer all clients enter the intermission at the
same time. This was reported by maraakate in yquake2 issue #160.
Until now autoexec.cfg was a special case. It was read several
times, whenever the 'game' cvar was altered or when the client was
restarted. But only if it was in the right directory in the right
position of the internal search path... Remove this altogether and
replace it by an ordinary 'exec autoexec.cfg' at startup.
This may break some mods that depend on an autoexec.cfg if the user has
his own version in ~/.yq2/. Such mods should use default.cfg instead.
This closes issue #163.
In baseq2 there's no need to force a certain damage texture on gunners
since there's only one. Also gunners can't wear the powershield so
there's no need to turn it of.
This was noticed by Maraakate.
This crash was found by DanielGibson, he even guessed the right fix
without having a usable coredump. ;) In boss1.bsp Macron is waiting for
the player, despawning as soon as the player moves to him. After that
the player needs to press 2 buttons, each button triggers 3 flyers. If
the player is fast enough, the first bunch of flyers may spawn before
macron is despawned. Now there's a small chance that a flyer decides to
attack macron... If Macron despwans at the the next frame, self->enemy
is set to NULL (Macron is gone) but nevertheless flyer_fire() is called.
The correct fix would be to call flyer_fire() before Macron despawns,
but that's hard to impossible. So take the easy route and check if
self->enemy is not NULL.
This bug was "fixed" by id with removing two lines in the ground entity
check. When cleaning up the game I added them back... I don't know if
it's really correct to just remove them, but let's try it. This fixes
issue #157.
The old implementation had two problems:
* OSTYPE and ARCH are systemwide defines, overriding them may break
the global libc headers. This is a theoretical problem, I've never
seen it in praxis.
* Not all system set ARCH correctly when building in a chroot env.
For example on Linux ARCH is set to x86_64 when building in an
i386 chroot. Now the user can do something like "make YQ2ARCH=i386"
to get things right.