Compare commits

...

158 commits

Author SHA1 Message Date
Yamagi
71d4b88ddf Update the CHANGELOG. 2025-04-02 11:21:53 +02:00
Yamagi
3ab00e4b92 Fix (potential) problematic use cases of qboolean.
xatrix had only one potential problematic use case, putting an int into
qboolean. It would have worked if qboolean is a bool, but better do it
right. No functional change intended.
2025-03-15 17:48:41 +01:00
Yamagi
7997219c85
Merge pull request #128 from BjossiAlfreds/door-use-fix
Fixed doors being unusable with NULL activator
2025-03-01 16:48:52 +01:00
Yamagi
358b497d16 Fix build with C23 by reusing the predefined bool type. 2025-03-01 12:46:03 +01:00
Yamagi
6cb21cfe13 Follow yquake2 and don't force a C standard in Makefile and CMakeLists.
This reverts 8932008.
2025-03-01 12:44:59 +01:00
BjossiAlfreds
e84a19865d Fixed doors being unusable with NULL activator 2025-02-24 15:54:16 +00:00
Yamagi
89320081fb Force C standard to gnu99 in cmake builds.
The Makefiles forces gnu99 since ages. Additionally gcc15 started to
default to C23 and our code doesn't (yet) build with it.
2025-02-22 11:43:34 +01:00
Yamagi
abca9f7e82 Add a Win64 workflow file. 2025-02-09 11:31:16 +01:00
Yamagi
5fc769f8cf Add a Linux/aarch64 workflow file. 2025-02-09 11:29:38 +01:00
Yamagi
fca183f43a Rename the Linux/x86_64 workflow file.
This is a preparation of an upcoming Linux/aarch64 build. While here
switch back to Ubuntu 22.04 as builder, we should use the same Ubuntu
version everywhere.
2025-02-09 11:29:33 +01:00
Yamagi
bc833a17e8 Update CI to use 4 CPUs on Linux and Windows. 2025-02-09 10:57:23 +01:00
Yamagi
830ad45774
Merge pull request #127 from protocultor/wpn_preview
Weapon preview for cycleweap
2024-12-21 09:52:40 +01:00
Jaime Moreira
61f1fdbbfd Weapon preview for cycleweap
'Pickup style' just like weapprev/weapnext, only works when cycleweap
is called with 3 or more parameters.
2024-12-04 19:07:39 -03:00
Yamagi
7cf6cad6ac Mark g_swap_speed as CVAR_ARCHIVE. 2024-09-21 09:52:43 +02:00
Yamagi
45a7d82156
Merge pull request #126 from BjossiAlfreds/spawntemp-leak-fix
Fixed spawntemp data leaking into mid-level spawned entities
2024-08-21 21:01:39 +02:00
BjossiAlfreds
982d100bb0 Fixed spawntemp data leaking into mid-level spawned entities 2024-08-12 16:31:51 +00:00
Yamagi
f9dd3be7e7 There's no need to run brew upgrade. 2024-08-12 18:22:28 +02:00
Yamagi
3fd777fb2e Add CI workflows for Linux, MacOS and Windows.
This is equivalent to the CI workflows added to the yquake2 main
repository. The workflows are triggered on commit, for new pull
requests and when the pull request branch is updated. The CI is
mostly for providing users with up to date test builds.
2024-08-12 17:50:33 +02:00
Yamagi
2e2cb4fc1f Modernize the README.
Convert to markdown and follow the same style as the yquake2 main
repository. Use it's resources were appropriate.
2024-08-12 17:47:45 +02:00
Yamagi
19014a3c85 Add g_monsterfootsteps to the CHANGELOG. 2024-07-22 17:59:55 +02:00
Yamagi
e2fcef5efc
Merge pull request #125 from 0lvin/master
Add Monster footsteps support #110
2024-07-22 17:59:09 +02:00
Denis Pauk
8a05565cfc Add Monster footsteps support #110 2024-07-21 13:31:42 +03:00
Yamagi
b26f8e590b Update CHANGELOG for 'Work around naggy help icons'. 2024-07-20 09:16:34 +02:00
Yamagi
b886ea5bac
Merge pull request #124 from BjossiAlfreds/helpmsg-always
Workarounds for naggy help icons
2024-07-20 09:14:27 +02:00
BjossiAlfreds
3c92e9a30f Workarounds for naggy help icons 2024-07-15 22:26:42 +00:00
Yamagi
145ed6ea89 Switch g_quick_weap to 1 by default.
It's a nice to have convenience feature that most players will never
notice. Die hard traditionalists can switch it off.
2024-07-15 21:46:53 +02:00
Yamagi
acad845a6f Fix description of g_quick_weap. 2024-07-15 21:44:45 +02:00
Yamagi
bea9dc85ff Update CHANGELOG for 2.12. 2024-07-13 16:27:20 +02:00
Yamagi
8baa9d35b0
Merge pull request #123 from protocultor/quick_weap
Faster "weapprev" and "weapnext" behavior
2023-12-17 11:56:27 +01:00
Jaime Moreira
95a40eef13 Preview of the coming weapon for weapprev/weapnext
The weapon you are changing to appears in the HUD, in "pickup" format.
Requires g_quick_weap == 1.
2023-12-16 17:53:25 -03:00
Jaime Moreira
15ac078a88 Faster "weapprev" and "weapnext" behavior
Allows to skip the "previous" or "next" weapon, by constantly tapping
the bound key (or scrolling the mouse wheel).
2023-12-07 23:45:46 -03:00
Yamagi
c3968e2534 s/Jaime Moreira/protocultor/g 2023-11-08 18:51:07 +01:00
Yamagi
b3654f4d27 Update CHANGELOG for rogue 2.11. 2023-11-04 14:27:24 +01:00
Yamagi
a9c73a4ebb Fix stuck monster in rmine1.bsp at 968 544 720.
Move it a little bit around so it's no longer stuck in the world model.
2023-11-04 14:27:24 +01:00
Yamagi
bd0019db85 Fix original bug, picking up the ammo pack reduces max fletchettes.
Flachettes have a base maximum of 200. Picking up the bandolier
increases it to 250. Picking up the ammo pack afterwards reset the
maximum to 200. Fix this by setting the maximum after picking up
the ammo pack to 300.
2023-11-04 14:27:24 +01:00
Yamagi
f0a8e88abc Port aimfix support for the super shotgun from yquake2. 2023-11-04 14:27:24 +01:00
Yamagi
db15317c90 Relicense rogue aka Ground Zero to GPL2.
This was made possible by id Software rereleasing the unaltered addon
sources codes under GPL2:

  https://github.com/id-Software/quake2-rerelease-dll/

All past contributors but one agreed with the relicensing:

* Adam Leskis - @lpmi-13
* Andrey Nazarov - @skullernet
* Angus Freudenberg - @afreuden
* @BjossiAlfreds
* @DanielGibson
* David Carlier - @devnexen
* Denis Pauk - @0lvin
* @De-Seppe
* Jaime Moreira - @protocultor
* Joshua Scoggins - @DrItanium
* Mitchell Richters - @mjr4077au
* @NeonKnightOA
* Scott - @Pickle
* @svdijk
* Yamagi

@Dremor8484 didn't give their permission, their commits were reverted:

* c083b7c
* 6de4a9c
* e2ac13d
* 5d767c6

Many thanks to all involved with this project!
2023-11-04 14:27:06 +01:00
Yamagi
3cb024b7b0 Revert "Add rmine1.ent, fixes a stuck monster."
This reverts commit c083b7c66c.

The author didn't give us permission to relicense the code to GPL2.
2023-11-04 11:05:47 +01:00
Yamagi
dfafc40af9 Revert "Update g_items.c"
This reverts commit 5d767c6b30.

The author didn't give us permission to relicense the code to GPL2.
2023-11-04 11:05:28 +01:00
Yamagi
56b0e0cdc2 Revert "Update weapon.c"
This reverts commit e2ac13dae4.

The author didn't give us permission to relicense the code to GPL2.
2023-11-04 11:05:15 +01:00
Yamagi
dd31f0377a Revert "Update weapon.c"
This reverts commit 6de4a9ce77.

The author didn't give us permission to relicense the code to GPL2.
2023-11-04 11:04:53 +01:00
Yamagi
c299a53a45
Merge pull request #121 from protocultor/limits
Added missing include, fixing compilation in Linux and MacOS
2023-09-15 20:20:59 +02:00
Jaime Moreira
8ea7bcd495 Added missing include for USHRT_MAX 2023-09-15 11:58:16 -03:00
Yamagi
1c52428172
Merge pull request #118 from protocultor/g_swap_speed_fix
Fix for g_swap_speed behaviour with extreme values
2023-09-14 21:26:57 +02:00
Yamagi
ae187b3c63
Merge pull request #115 from BjossiAlfreds/rhangar2-helpfix
Fixed nagging help message in rhangar2
2023-09-14 21:26:35 +02:00
Yamagi
10927dddaf
Merge pull request #120 from BjossiAlfreds/rbase1-fixes
Fix Entity used itself in rbase1 and other minor fixes
2023-09-14 21:20:17 +02:00
Yamagi
772e396fb5
Merge pull request #117 from BjossiAlfreds/turret-fixes
Fix minor AI glitches with turrets
2023-09-14 21:19:43 +02:00
Yamagi
8e6edc5ac6
Merge pull request #114 from BjossiAlfreds/rsewer1-fixes
Some fixes for rsewer1
2023-09-14 21:17:38 +02:00
BjossiAlfreds
cb66a3cc14 Fix Entity used itself in rbase1 and other minor fixes 2023-09-04 20:22:06 +00:00
Jaime Moreira
2469740598 Typos 2023-08-26 23:18:53 -04:00
Jaime Moreira
92a00c9f5d Fixed g_swap_speed behaviour with extreme values
When its value was between 0 and 1, rounded down to 0; did the same
when bigger than 65535. Both cases locked up the weapon animation.
2023-08-26 22:59:49 -04:00
BjossiAlfreds
631e27190d Upgraded old classnames in rhangar2 2023-08-24 13:12:57 +00:00
BjossiAlfreds
890b42a318 Some fixes for rsewer1 2023-08-24 13:09:45 +00:00
BjossiAlfreds
70c4c50951 Fix minor AI glitches with turrets 2023-08-22 20:14:47 +00:00
BjossiAlfreds
66100386e7 Fixed wrong/overlapping secret sound effect 2023-08-20 21:06:57 +00:00
BjossiAlfreds
84fdbe057b Fixed nagging help message in rhangar2 2023-08-20 18:55:08 +00:00
Yamagi
16eee95bb8
Merge pull request #112 from BjossiAlfreds/gunnergren
Fixed gunner grenade duck code running twice
2023-07-30 17:39:27 +02:00
BjossiAlfreds
452ad99821 Fixed gunner grenade duck code running twice 2023-07-24 21:42:18 +00:00
Yamagi
c78a7358d3
Merge pull request #109 from BjossiAlfreds/tdam-dir
T_Damage no longer modifies dir parameter
2023-07-16 09:49:16 +02:00
BjossiAlfreds
dd0f1a8a61 T_Damage no longer modifies dir parameter 2023-07-07 23:51:47 +00:00
Yamagi
391128e0ac
Merge pull request #108 from protocultor/g_swap_speed
Cheat to speed up "weapon change" animations
2023-07-01 16:21:50 +02:00
Jaime Moreira
8319109c9f Snappier "g_swap_speed" behaviour
Player is no longer forced to go through the last frame of activation
or deactivation of a weapon before changing its state.
2023-06-29 11:46:43 -04:00
Jaime Moreira
15c531c300 Cheat cvar "g_swap_speed" implemented
Allows to skip frames of "putting down weapon" and
"raising weapon" animations, speeding them up.
2023-06-28 16:25:09 -04:00
Yamagi
0742bc24d7
Merge pull request #107 from BjossiAlfreds/makronjmp
Fixes to makron jump sequence
2023-06-17 16:36:35 +02:00
BjossiAlfreds
46660b8902 Fixes to makron jump sequence 2023-06-07 13:40:50 +00:00
Yamagi
2ad53a679f
Merge pull request #106 from BjossiAlfreds/blind-rockets
Fixed wrong Tank muzzle flash
2023-06-05 20:49:51 +02:00
BjossiAlfreds
71b5f5cf95 Fixed wrong Tank muzzle flash 2023-06-02 13:21:54 +00:00
Yamagi
c8914dd482
Merge pull request #103 from BjossiAlfreds/intersight
Fixed monsters seeing players during intermissions
2023-05-13 15:30:54 +02:00
Yamagi
9d46ec85fd
Merge pull request #104 from BjossiAlfreds/makrondeath
Fixed ungibbable makron parts
2023-05-13 15:22:20 +02:00
BjossiAlfreds
306beceb0c Fixed ungibbable makron parts 2023-05-09 18:29:55 +00:00
Yamagi
352e81481a
Merge pull request #102 from BjossiAlfreds/gladrange
Fixed stand-ground gladiators not attacking at certain range
2023-05-08 18:09:02 +02:00
BjossiAlfreds
004ff57649 Fixed monsters seeing players during intermissions 2023-04-26 01:35:00 +00:00
BjossiAlfreds
4a9c7f897e Fixed stand-ground gladiators not attacking at certain range 2023-04-22 18:52:34 +00:00
Yamagi
f762ee6116
Merge pull request #101 from Dremor8484/patch-1
Update g_items.c
2023-03-25 17:16:31 +01:00
Dremor8484
5d767c6b30
Update g_items.c
ammopak usually increase the maximum ammo, even beyond the bandolier.
i suppose there is a bug with fletchette ammo.

fletchette starts with 200 max ammo, becomes 250 max ammo with bandolier and returns to 200 max ammo with ammopack.
on the contrary both cells and bullets start at 200, becomes 250 with bandolier and 300 with ammopack.
2023-03-20 15:47:12 +01:00
Yamagi
a9412c91b9 Fix copypasta, the Phalanx is exclusive to xatrix. 2022-12-08 14:41:18 +01:00
Yamagi
ff834f7a58 Update the CHANGELOG for 2.10. 2022-12-03 17:12:46 +01:00
Yamagi
fc0ffbcc91
Merge pull request #100 from Dremor8484/Dremor8484-rogue-doublebarrelshotgun-aimfix
Update weapon.c
2022-12-03 17:06:55 +01:00
Dremor8484
e2ac13dae4
Update weapon.c
the aimfix was working only on half of the attack, since the supershotgun shoots 2 times (half bullets left, half bullets right)

to carefully test it i tried to comment out 1 of the 2 shots while also keep yaw change to 0
in 1 case the bullets hit around the crossair, in the other case the bullets were not centered around the crossair.

i added the same fix to the shot that did not have it, and it worked.

i tested it out with yaw-5 and yaw+5 with both shots shooting at the same time and the bullets appeared to gather into 2 distinct clusters one left side of crossair, one right side of crossair like 2 eyes on the wall
2022-12-03 15:47:14 +01:00
Yamagi
9922dd88bb
Merge pull request #99 from devnexen/va_fmt_chg
va little signature change
2022-11-06 17:21:11 +01:00
David CARLIER
a4747d3d8d va little signature change 2022-11-05 10:27:06 +00:00
Yamagi
5ed36196b7
Merge pull request #94 from skullernet/master
Remove broken pusher delta yaw manipulation
2022-10-08 15:38:53 +02:00
Yamagi
0dda457eb5
Merge pull request #98 from BjossiAlfreds/collision
Prevent dead bodies from obstructing elevators and falling through them
2022-10-08 15:37:59 +02:00
Yamagi
fb2f6bd3b5
Merge pull request #97 from BjossiAlfreds/powercubes
Fix coop power cube related bugs
2022-10-08 15:37:42 +02:00
Yamagi
f15c5c57a2
Merge pull request #96 from BjossiAlfreds/splashes
Fix items already in water at level start playing splash sound
2022-10-08 15:37:27 +02:00
Yamagi
d64a15f535
Merge pull request #95 from BjossiAlfreds/flood
Prevented crash or memory corruption when flood_msgs is too high or too low
2022-10-08 15:37:16 +02:00
BjossiAlfreds
3bb2602f5b Prevent dead bodies from obstructing elevators and falling through them 2022-09-30 15:25:18 +00:00
BjossiAlfreds
eff7705812 Fix coop power cube related bugs 2022-09-24 14:33:38 +00:00
BjossiAlfreds
678eee9bc7 Fix items already in water at level start playing splash sound 2022-09-24 12:23:49 +00:00
BjossiAlfreds
2f76831f1c Prevented crash or memory corruption when flood_msgs is too high or too low 2022-09-24 01:49:35 +00:00
Andrey Nazarov
213b14e16a Remove broken pusher delta yaw manipulation.
This didn't work correctly for multiple reasons:

1. `deltayaw` was wrongly initialized for the pusher itself, rather than
for pushed client.

2. `delta_angles[YAW]` is a short, adding plain `amove[YAW]` to it is
wrong.

To support yaw angle rotation properly, delta_angles must be
interpolated on the client. But this is hardly practical as it would
introduce other bugs. Thus, simply remove delta yaw manipulation code
altogether.

Fixes infamous Q2 bug when player standing on a blocked lift gets turned
to wrong direction.
2022-09-09 21:55:04 +03:00
Yamagi
2246a943bf
Merge pull request #93 from protocultor/cycleweap_quick
Faster weapon switching with 'cycleweap'
2022-08-07 18:22:14 +02:00
Jaime Moreira
6b9331ea5f Faster weapon switching with 'cycleweap'
Allows to skip elements on the weapon list by tapping the same bound key
2022-08-01 14:35:42 -04:00
Yamagi
7bf2454901
Merge pull request #92 from Dremor8484/Dremor8484-rogue-doublebarrelshotgun-aimfix
Update weapon.c
2022-06-11 17:04:04 +02:00
Dremor8484
6de4a9ce77
Update weapon.c
rogue-doublebarrelshotgun-aimfix
2022-06-10 19:19:18 +02:00
Yamagi
15ffab8518 Fix of by one in Info_SetValueForKey(). Found by ASAN. 2022-05-28 11:35:08 +02:00
Yamagi
1ca53f3118 Update CHANGELOG for 2.09. 2022-05-28 11:35:08 +02:00
Yamagi
43a5a3fc23 Normalize arm64 to aarch64.
This ensures that we call ARM64 `aarch64` on all platform, which aren't
MacOS or Windows. And it fixes the bug, that `arm64` was normalized to
`arm`, making incompatible savegames between 32 bit and 64 bit ARM
loadable. Leading to crashes.
2022-05-20 12:55:51 +02:00
Yamagi
ca5e278670
Merge pull request #91 from devnexen/build_macos_arm_fix
Forcing proper native arch build on darwin mainly due to arm64
2022-05-20 12:48:33 +02:00
David CARLIER
e7642db54d Forcing proper native arch build on darwin mainly due to arm64 2022-05-14 16:30:01 +01:00
Yamagi
c083b7c66c Add rmine1.ent, fixes a stuck monster.
Found and submitted by @Dremor8484, closes #90.
2022-05-10 18:50:56 +02:00
Yamagi
72a6f98730
Merge pull request #89 from protocultor/prefweap
Added prefweap command to select weapon by priority
2022-04-13 11:50:57 +02:00
Jaime Moreira
20da96d0ab Added prefweap command to select weapon by priority 2022-04-11 09:53:13 -04:00
Yamagi
f63c952103 Fix door_go_up(), G_UseTargets() exiting early if no activator is given.
The problem in door_go_up() may prevent doors from crushing something
blocking them. The problem in G_UseTargets() may prevent targets from
getting killed or fired.

Pointed out by @maraakate.
2022-02-05 17:26:19 +01:00
Yamagi
7d1007ea1e Force an MASK_SHOT clip mask for thrown heads.
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 `MASK_SHOT`.

Suggested by @BjossiAlfreds.
2022-02-05 17:25:42 +01:00
Yamagi
ee6164cbce
Merge pull request #88 from BjossiAlfreds/playernoise
Fixed player_noise entity leak and improved stability surrounding player noises
2021-11-06 08:48:21 +01:00
BjossiAlfreds
2dd8c74dfd Fixed player_noise entity leak and improved stability surrounding player noises 2021-11-06 02:23:45 +00:00
Yamagi
d272c24706 Fix soldiers never showing their pain skins as long as they're alive.
Since `self->helth` is set after calling `master_start()`
`self->max_health is always 0. Found by @drakonorodny and
analyzed by @BjossiAlfreds.
2021-11-05 07:15:10 +01:00
Yamagi
8cba5293a0 Made the game able to handle entity overload better.
This is a port of yquake2 commit c3b57bc8.
2021-11-04 17:11:41 +01:00
Yamagi
fb1ebf960e
Merge pull request #87 from BjossiAlfreds/rsewer2-rware2
Updated mapfixes for rsewer2 and rware2
2021-10-26 08:43:34 +02:00
BjossiAlfreds
222438d738 Updated mapfixes for rsewer2 and rware2 2021-10-25 11:21:07 +00:00
Yamagi
f90991db4d
Merge pull request #84 from De-Seppe/master
Feature request : add cvar to disable machine gun recoil in single player #741 (rogue)
2021-09-28 18:33:06 +02:00
De-Seppe
ea57b889b6 Rename variable to conform to naming guidelines
Change the name of the cvar machinegun_norecoil to g_machinegun_norecoil to conform to the naming guidelines
2021-09-27 18:30:18 +02:00
De-Seppe
73beecec44 Add cvar machinegun_norecoil
Add cvar machinegun_norecoil
This cvar allows to disable machinegun recoil in single player.
The default value is the original Quake 2 behaviour.
2021-09-27 13:14:38 +02:00
Yamagi
19a6d805a9 Refine the g_footstep cvar.
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 yquake2/yquake2#738.
2021-08-25 18:39:09 +02:00
Yamagi
6cc225d670 Add a warning that the CMakeLists.txt is unmaintained. 2021-07-23 08:33:31 +02:00
Yamagi
6b6e536f79 Revert "Retire unmaintained CMakeLists.txt."
It turned out that there're some special cases not (yet) covered by the
Makefile. Crossbuilding in specialized chroot environments are one
example.
2021-07-23 08:30:59 +02:00
Yamagi
ab882a163f Retire unmaintained CMakeLists.txt.
I added the CMakeLists.txt 6 or 7 years ago so I could load the code
into Jetbrains Clion. I have moved to another editor years ago and the
cmake stuff is effectively unmaintained since then. We kept it around
in case that we'll do a MSVC port, but that's unlikely at this point.
Since bugreport and problems with the CMakeLists.txt keep coming up,
finally retire them. They can be resurrected from the git history if
we'll ever need them again.

Part of yquake2/yquake2#725.
2021-06-29 11:03:02 +02:00
Yamagi
397fdd77d5 Update the CHANGELOG for 2.08. 2021-06-14 16:29:07 +02:00
Yamagi
25b453f1b8
Merge pull request #83 from BjossiAlfreds/player-sounds
Fix for some player sound bugs
2021-04-30 11:51:40 +02:00
BjossiAlfreds
3bccc4bd79 Fix for some player sound bugs 2021-04-30 01:07:40 +00:00
Yamagi
98afa3a90d
Merge pull request #82 from BjossiAlfreds/shark-bbox
Shark bbox fix and added inuse check after entity thinking
2021-04-27 08:58:13 +02:00
BjossiAlfreds
d1ddda04ea Shark bbox fix and added inuse check after entity thinking 2021-04-18 01:27:18 +00:00
Yamagi
46362a3bb4
Merge pull request #81 from BjossiAlfreds/map-fixes
Map fixes for some rogue maps
2021-04-16 08:27:41 +02:00
BjossiAlfreds
cc6bf7dd5f killtarget monsters update killcounter correctly 2021-04-16 00:04:13 +00:00
BjossiAlfreds
e4a467e9c9 Added mapfixes for rammo1 2021-04-15 01:39:54 +00:00
BjossiAlfreds
503a8af5b2 Added mapfixes for rhangar2 and rware2 2021-04-15 01:02:21 +00:00
Yamagi
f0ebf1addc
Merge pull request #80 from devnexen/savegame_upd_to_match_yquake2
savegame to match more main repo
2021-04-13 12:58:31 +02:00
David CARLIER
a395fadf07 savegame to match more main repo 2021-04-12 21:35:20 +01:00
Yamagi
ce21ad2c16
Merge pull request #79 from devnexen/savegame_data_packing
game data packing representation of the headers
2021-04-08 11:00:03 +02:00
David Carlier
a000d06300 game data packing representation of the headers 2021-04-07 18:12:53 +01:00
Yamagi
9fd0bab374
Merge pull request #78 from BjossiAlfreds/bad-triggered
Console warning and fix triggered monsters with no targetname
2021-03-31 10:07:02 +02:00
BjossiAlfreds
a4fba01b97 Console warning and fix triggered monsters with no targetname 2021-03-28 17:00:26 +00:00
Yamagi
b0303c1098 Add a cvar g_footsteps to control the generation of footstep sound.
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`
2021-03-02 15:20:43 +01:00
Yamagi
f2c4d1b0b0
Merge pull request #75 from 0lvin/master
Fix function prototypes
2021-01-27 08:31:50 +01:00
Denis Pauk
0d2d20fc6e Fix function prototypes 2021-01-26 21:20:39 +02:00
Daniel Gibson
b92383eff9 Fix architecture detection on Windows in Makefile, bump SAVEGAMEVER
$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-5" and added a quirk for older savegameversions:
On Windows i386 savegames that contain "AMD64" instead of "i386" as
architecture are also accepted.
(For YQ2-2 this didn't seem necessary, apparently "i386" was hardcoded)
2021-01-14 03:05:15 +01:00
Yamagi
e8f8a1309c Fix P_ProjectSource() forward declaration.
This was reported in yquake2#631.
2020-12-09 15:29:14 +01:00
Yamagi
9dfd9de811 Implemented coop_elevator_delay cvar (for func_plat)
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.
2020-08-10 14:22:31 +02:00
Yamagi
6820b0cad1 Add coop_pickup_weapons, allow a weapon to be taken several times.
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.
2020-08-10 14:15:35 +02:00
Yamagi
cfd660abc3 Fix the Jork skin bug.
Submitted for baseq2 by @kondrak in yquake2#575.
2020-05-11 12:53:43 +02:00
Yamagi
221171831b
Merge pull request #73 from BjossiAlfreds/gunner-idle
Fix for gunner AI freeze bug
2020-05-11 11:41:44 +02:00
BjossiAlfreds
964895b760 Fix for gunner AI freeze bug 2020-05-08 22:14:44 +00:00
Yamagi
1cd49ad20b Fix Windows build, broken by the last changes. 2020-05-04 18:28:09 +02:00
Yamagi
d8ee6ce10f
Merge pull request #72 from mjr4077au/BuildFix
Fix CMakeLists.txt following changes to makefile.
2020-05-04 15:03:20 +02:00
Mitchell Richters
2cfdfee43d Fix CMakeLists.txt following changes to makefile. 2020-04-23 03:24:25 +10:00
Yamagi
73fd162dbe Bring Makefile on par with yquake2:
* Make CFLAGS and LDFLAGS overrideable
* Correct architecture and operating system detection.
* Enforce FPU mode.
* Implement DEBUG.
* Pass LDFLAGS after the objects.
* Rename OSTYPE and ARCH to YQ2OSTYPE and YQ2ARCH to avoid collisions.
2020-04-21 13:56:47 +02:00
Yamagi
09f9cf8f61
Merge pull request #71 from BjossiAlfreds/printf-leftover
Removed leftover printf debug prints
2020-04-21 12:53:34 +02:00
Yamagi
fc18bfa568
Merge pull request #70 from mjr4077au/Client_AimFixWithCVAR
Implement accurate-aiming CVAR in rogue game code.
2020-04-21 12:52:58 +02:00
BjossiAlfreds
0fc06c4fc9 Removed leftover printf debug prints 2020-04-21 00:44:13 +00:00
Mitchell Richters
95e432d604 Implement accurate-aiming CVAR in rogue game code. 2020-04-21 07:30:24 +10:00
Yamagi
e640c899c1
Merge pull request #68 from BjossiAlfreds/insta-powerups
Fix for some items playing wrong sound when instantly activated
2020-04-20 08:41:29 +02:00
Yamagi
03a7d77127
Merge pull request #67 from NeonKnightOA/turretfix
Fix: Turrets shooting faster while in melee range, which wasn't intended.
2020-04-20 08:41:10 +02:00
Yamagi
8dd1007284
Merge pull request #66 from NeonKnightOA/disguisefix
Fix: Disguise isn't traspassed between levels.
2020-04-20 08:40:11 +02:00
BjossiAlfreds
7e4fd68416 Fix for some items playing wrong sound when instantly activated 2020-04-11 00:46:48 +00:00
Yamagi
f0793d17f8 Change show_hostile from int to float and remove unnecessary casts.
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 in yquake2/yquake2#525.
2020-03-10 10:18:21 +01:00
NeonKnightOA
7bf7eff184 Fix: Turrets shooting faster while in melee range, which wasn't intended. 2020-02-15 20:01:30 -03:00
NeonKnightOA
a1786d614e Fix: Disguise isn't traspassed between levels. 2020-02-15 18:43:14 -03:00
69 changed files with 50393 additions and 2008 deletions

46
.github/workflows/linux_aarch64.yml vendored Normal file
View file

@ -0,0 +1,46 @@
name: Testbuild for Linux (aarch64)
run-name: testbuild_linux_aarch64
on:
push:
branches:
- 'master'
pull_request:
types:
- edited
- opened
- synchronize
concurrency:
# Cancel concurrent workflows for the same PR or commit hash.
group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}}
cancel-in-progress: true
jobs:
build_ubuntu_arm:
runs-on: ubuntu-22.04-arm
strategy:
fail-fast: false
matrix:
include:
- env: ubuntu
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Build
run: |
# Public runners come with 4 CPUs.
make -j4
- name: Create testbuild package
run: |
# Create release directory tree
mkdir -p publish/quake2-rogue-linux_aarch64-${{github.sha}}/misc/docs
# Copy release assets
cp -r release/* publish/quake2-rogue-linux_aarch64-${{github.sha}}/
# Copy misc assets
cp -r stuff/mapfixes publish/quake2-rogue-linux_aarch64-${{github.sha}}/misc
cp LICENSE publish/quake2-rogue-linux_aarch64-${{github.sha}}/misc/docs/LICENSE.txt
cp README.md publish/quake2-rogue-linux_aarch64-${{github.sha}}/misc/docs/README.txt
- name: Upload testbuild package
uses: actions/upload-artifact@v4
with:
name: quake2-rogue-linux_aarch64-${{github.sha}}
path: publish/
if-no-files-found: error

46
.github/workflows/linux_x86_64.yml vendored Normal file
View file

@ -0,0 +1,46 @@
name: Testbuild for Linux (x86_64)
run-name: testbuild_linux_x86_64
on:
push:
branches:
- 'master'
pull_request:
types:
- edited
- opened
- synchronize
concurrency:
# Cancel concurrent workflows for the same PR or commit hash.
group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}}
cancel-in-progress: true
jobs:
build_ubuntu_x86_64:
runs-on: ubuntu-22.04
strategy:
fail-fast: false
matrix:
include:
- env: ubuntu
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Build
run: |
# Public runners come with 4 CPUs.
make -j4
- name: Create testbuild package
run: |
# Create release directory tree
mkdir -p publish/quake2-rogue-linux_x86_64-${{github.sha}}/misc/docs
# Copy release assets
cp -r release/* publish/quake2-rogue-linux_x86_64-${{github.sha}}/
# Copy misc assets
cp -r stuff/mapfixes publish/quake2-rogue-linux_x86_64-${{github.sha}}/misc
cp LICENSE publish/quake2-rogue-linux_x86_64-${{github.sha}}/misc/docs/LICENSE.txt
cp README.md publish/quake2-rogue-linux_x86_64-${{github.sha}}/misc/docs/README.txt
- name: Upload testbuild package
uses: actions/upload-artifact@v4
with:
name: quake2-rogue-linux_x86_64-${{github.sha}}
path: publish/
if-no-files-found: error

50
.github/workflows/macos.yml vendored Normal file
View file

@ -0,0 +1,50 @@
name: Testbuild for MacOS
run-name: testbuild_macos
on:
push:
branches:
- 'master'
pull_request:
types:
- edited
- opened
- synchronize
concurrency:
# Cancel concurrent workflows for the same PR or commit hash.
group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}}
cancel-in-progress: true
jobs:
build_macos_aarch64:
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
include:
- env: macos
steps:
- name: Install build dependencies
run: |
brew update
brew install make
- name: Check out repository code
uses: actions/checkout@v4
- name: Build
run: |
# Public runners come with 3 CPUs.
gmake -j3
- name: Create testbuild package
run: |
# Create release directory tree
mkdir -p publish/quake2-rogue-macos-${{github.sha}}/misc/docs
# Copy release assets
cp -r release/* publish/quake2-rogue-macos-${{github.sha}}/
# Copy misc assets
cp -r stuff/mapfixes publish/quake2-rogue-macos-${{github.sha}}/misc
cp LICENSE publish/quake2-rogue-macos-${{github.sha}}/misc/docs/LICENSE.txt
cp README.md publish/quake2-rogue-macos-${{github.sha}}/misc/docs/README.txt
- name: Upload testbuild package
uses: actions/upload-artifact@v4
with:
name: quake2-rogue-macos-${{github.sha}}
path: publish/
if-no-files-found: error

57
.github/workflows/win32.yml vendored Normal file
View file

@ -0,0 +1,57 @@
name: Testbuild for Win32
run-name: testbuild_win32
on:
push:
branches:
- 'master'
pull_request:
types:
- edited
- opened
- synchronize
concurrency:
# Cancel concurrent workflows for the same PR or commit hash.
group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}}
cancel-in-progress: true
jobs:
build_mingw_x86_32:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- { sys: mingw32, env: i686 }
steps:
- uses: msys2/setup-msys2@v2
with:
msystem: ${{matrix.sys}}
update: true
install: >-
git
make
mingw-w64-${{matrix.env}}-gcc
mingw-w64-${{matrix.env}}-make
- name: Check out repository code
uses: actions/checkout@v4
- name: Build
shell: msys2 {0}
run: |
# Public runners come with 4 CPUs.
make -j4
- name: Create testbuild package
shell: msys2 {0}
run: |
# Create release directory tree
mkdir -p publish/quake2-rogue-win32-${{github.sha}}/misc/docs
# Copy release assets
cp -r release/* publish/quake2-rogue-win32-${{github.sha}}/
# Copy misc assets
cp -r stuff/mapfixes publish/quake2-rogue-win32-${{github.sha}}/misc
cp LICENSE publish/quake2-rogue-win32-${{github.sha}}/misc/docs/LICENSE.txt
cp README.md publish/quake2-rogue-win32-${{github.sha}}/misc/docs/README.txt
- name: Upload testbuild package
uses: actions/upload-artifact@v4
with:
name: quake2-rogue-win32-${{github.sha}}
path: publish/
if-no-files-found: error

57
.github/workflows/win64.yml vendored Normal file
View file

@ -0,0 +1,57 @@
name: Testbuild for Win64
run-name: testbuild_win64
on:
push:
branches:
- 'master'
pull_request:
types:
- edited
- opened
- synchronize
concurrency:
# Cancel concurrent workflows for the same PR or commit hash.
group: ${{github.workflow}}-${{github.event_name == 'pull_request' && github.head_ref || github.sha}}
cancel-in-progress: true
jobs:
build_mingw_x86_64:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
include:
- { sys: mingw64, env: x86_64 }
steps:
- uses: msys2/setup-msys2@v2
with:
msystem: ${{matrix.sys}}
update: true
install: >-
git
make
mingw-w64-${{matrix.env}}-gcc
mingw-w64-${{matrix.env}}-make
- name: Check out repository code
uses: actions/checkout@v4
- name: Build
shell: msys2 {0}
run: |
# Public runners come with 4 CPUs.
make -j4
- name: Create testbuild package
shell: msys2 {0}
run: |
# Create release directory tree
mkdir -p publish/quake2-rogue-win64-${{github.sha}}/misc/docs
# Copy release assets
cp -r release/* publish/quake2-rogue-win64-${{github.sha}}/
# Copy misc assets
cp -r stuff/mapfixes publish/quake2-rogue-win64-${{github.sha}}/misc
cp LICENSE publish/quake2-rogue-win64-${{github.sha}}/misc/docs/LICENSE.txt
cp README.md publish/quake2-rogue-win64-${{github.sha}}/misc/docs/README.txt
- name: Upload testbuild package
uses: actions/upload-artifact@v4
with:
name: quake2-rogue-win64-${{github.sha}}
path: publish/
if-no-files-found: error

View file

@ -1,3 +1,69 @@
Ground Zero 2.12 to 2.13
- Add weapon preview to the `cycleweap` command (by protocultor)
- Fix leaking temporary spawnflags into entities spawned mid-level. (by
BjossiAlfreds)
Ground Zero 2.11 to 2.12
- Implement `g_quick_weap`. If set to 1, both weapprev and weapnext
commands will count how many times they have been called, making
possible to skip weapons by quickly tapping one of these keys. (by
protocultor)
- Work around naggy help icons. (by BjossiAlfreds)
- Implement `g_monsterfootsteps` (by 0lvin)
Ground Zero 2.10 to 2.11
- Relicense under GPL2.
- Fix Entity used itself in rbase1 and other minor fixes. (by
BjossiAlfreds)
- Some fixes for rsewer1. (by BjossiAlfreds)
- Fix minor AI glitches with turrets (by BjossiAlfreds)
- Fixed nagging help message in rhangar2. (by BjossiAlfreds)
- Fixed gunner grenade duck code running twice. (by BjossiAlfreds)
- Fixed wrong Tank muzzle flash. (by BjossiAlfreds)
- Implement `g_swap_speed`. This allows to skip frames of "putting down
weapon" and "raising weapon" animations, speeding them up. (by
protocultor)
- Several fixes to makron (by BjossiAlfreds)
- Fixed stand-ground gladiators not attacking at certain range. (by
BjossiAlfreds)
- Fixed monsters seeing players during intermissions. (by BjossiAlfreds)
Ground Zero 2.09 to 2.10
- Implement faster weapon switching with the new 'cycleweap' command.
(by protocultor).
- Fixes pusher delta yaw manipulation. This fixes the infamous bug were
a player standing on a blocked elevator gets turned around (by
skuller).
- Fix several coop related bugs with the powercubes. (by BjossiAlfreds)
- A way better fix for dead bodies obstructing elevators or falling
through the worldmodel. (by BjossiAlfreds)
- Fix items already in water playing a splash sound at level start. (by
BjossiAlfreds)
Ground Zero 2.08 to 2.09
- Refine the 'g_footstep' cvar to match Quake II itself.
- Implement 'g_machinegun_norecoil'. The cvar is cheat protected. (by
De-Seppe)
- Update the entity files for rmine1, rsewer2 and rware2, fixing some
smaller map bugs. (by BjossiAlfreds and Dremor8484)
- Fix soldiers never showing their pain skins as long as they're alive.
(by BjossiAlfreds)
- Implement the 'prefweap' command to select a weapon by priority. (by
protocultor)
Ground Zero 2.07 to 2.08
- Fix wrong sound for some items when activated. (by BjossiAlfreds)
- Port the 'aimfix' cvar. (by Mitchell Richters)
- Port the 'coop_pickup_weapons' and 'coop_elevator_delay' cvars.
- Fix a long standing crash occuring when exploding projectiles like
grenates or rockets generate sound targets and a least one monster
starts moving to one of that targets.
- Add a cvar `g_footsteps` to control the generation of footstep sound.
- Move several hard coded map fixes to entity files. Add newly
discovered mapfixes to the entity files. (by BjossiAlfreds)
- Fix several subtile gameplay and entity handling bug. (by
BjossiAlfreds)
Ground Zero 2.06 to 2.07
- Several fixes for subtile bugs (by BjossiAlfreds)

View file

@ -1,5 +1,8 @@
cmake_minimum_required(VERSION 3.0)
# Print a message that using the Makefiles is recommended.
message(NOTICE: " The CMakeLists.txt is unmaintained. Use the Makefile if possible.")
# Enforce "Debug" as standard build type
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
@ -19,13 +22,13 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fno-strict-aliasing -fwrapv")
string(REPLACE "-O3" "-O2" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
# Operating system
add_definitions(-DOSTYPE="${CMAKE_SYSTEM_NAME}")
add_definitions(-DYQ2OSTYPE="${CMAKE_SYSTEM_NAME}")
# Architecture string
string(REGEX REPLACE "amd64" "x86_64" ARCH "${CMAKE_SYSTEM_PROCESSOR}")
string(REGEX REPLACE "i.86" "i386" ARCH "${ARCH}")
string(REGEX REPLACE "^arm.*" "arm" ARCH "${ARCH}")
add_definitions(-DARCH="${ARCH}")
string(REGEX REPLACE "amd64" "x86_64" YQ2_ARCH "${CMAKE_SYSTEM_PROCESSOR}")
string(REGEX REPLACE "i.86" "i386" YQ2_ARCH "${YQ2_ARCH}")
string(REGEX REPLACE "^arm.*" "arm" YQ2_ARCH "${YQ2_ARCH}")
add_definitions(-DYQ2ARCH="${YQ2_ARCH}")
# Linker Flags
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")

581
LICENSE
View file

@ -1,327 +1,340 @@
LIMITED PROGRAM SOURCE CODE LICENSE
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
This Limited Program Source Code License (the "Agreement") is between
Id Software, Inc., a Texas corporation, (hereinafter "Id Software")
and Licensee (as defined below) and is made effective beginning on
the date you, the Licensee, download the Code, as defined below,
(the "Effective Date"). BY DOWNLOADING THE CODE, AS DEFINED
BELOW, YOU, THE LICENSEE, AGREE TO ALL THE TERMS AND CONDITIONS OF
THIS AGREEMENT. YOU SHOULD READ THIS AGREEMENT CAREFULLY BEFORE
DOWNLOADING THE CODE. EVERY PERSON IN POSSESSION OF AN AUTHORIZED
COPY, AS DEFINED BELOW, OF THE CODE SHALL BE SUBJECT TO THE TERMS
AND CONDITIONS OF THIS AGREEMENT.
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
R E C I T A L S
Preamble
WHEREAS, Id Software is the owner and developer of the computer software
program source code accompanied by this Agreement (the "Code");
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
WHEREAS, Id Software desires to license certain limited non-exclusive
rights regarding the Code to Licensee; and
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
WHEREAS, Licensee desires to receive a limited license for such rights.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
T E R M S A N D C O N D I T I O N S
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
NOW, THEREFORE, for and in consideration of the mutual premises
contained herein and for other good and valuable consideration,
the receipt and sufficiency of which is hereby acknowledged, the
undersigned parties do hereby agree as follows:
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
1. Definitions. The parties hereto agree the following definitions
shall apply to this Agreement:
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
a. "Authorized Copy" shall mean a copy of the Code obtained by
Authorized Means, as defined below. A copy of the Code is not
an "Authorized Copy" unless it is accompanied by a copy of this
Agreement and obtained by Authorized Means. A Modified Copy,
as defined below, is not an Authorized Copy;
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
b. "Authorized Means" shall mean obtaining an Authorized Copy only
by downloading the Authorized Copy from Id Software's Internet web
site or from another web site authorized or approved by Id Software
for such purposes or by obtaining an Authorized Copy by electronic
means via the Internet;
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
c. "Code" shall mean the computer software program source code
which accompanies this Agreement and includes Code included within
any Modified Copy and which is the code that constitutes the
Authorized Copy;
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
d. "Game" shall mean QUAKE II;
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
e. "Licensee" shall mean you, the person who is in possession of
an Authorized Copy by Authorized Means; and
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
f. "Modified Copy" shall mean a copy of the Code first obtained
by Authorized Means which is subsequently modified by Licensee,
as provided in paragraph 2. below.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. Grant of Rights. Subject to the terms and provisions of this
Agreement, Id Software hereby grants to Licensee and Licensee hereby
accepts, a limited, world-wide (except as otherwise provided herein),
non-exclusive, non-transferable, and non-assignable license to: (i)
use the Authorized Copy and the Modified Copy, as defined above, for
the development by Licensee of extra levels operable with the Game (the
"Extra Levels"); (ii) incorporate all or a portion of the Authorized Copy
and the Modified Copy within the Extra Levels; (iii) distribute by way
of a sublicense limited by the terms of this Agreement, free of charge
and at no cost, the Authorized Copy and the Modified Copy to the extent
such Modified Copy and such Authorized Copy, or a portion thereof, is
included within the Extra Levels; (iv) distribute by way of a sublicense
limited by the terms of this Agreement, free of charge and at no cost, by
electronic transmission via the Internet only the Authorized Copy without
any alteration or modification along with a copy of this Agreement which
must always accompany the Authorized Copy; (v) modify the Authorized Copy
in order to create a Modified Copy, as defined above; and (vi) distribute
the Modified Copy by way of a sublicense limited by the terms of this
Agreement, free of charge and at no cost, by electronic transmission via
the Internet only. Each person or entity who/which receives a copy of
the Code shall be subject to the terms of this Agreement but, no rights
are granted to any person or entity who/which obtains, receives, or is
in possession of any copy of the Code by other than Authorized Means.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
3. Reservation of Rights and Prohibitions. Id Software expressly
reserves all rights not granted herein. Licensee shall not make any use
of the trademarks relating to the Game or Id Software (the "Trademarks").
Any use by Licensee of the Authorized Copy or the Modified Copy not
expressly permitted in paragraph 2. above is expressly prohibited and
any such unauthorized use shall constitute a material breach of this
Agreement by Licensee. Any use of the Code, whether included within
a Modified Copy or otherwise, and/or the Authorized Copy not permitted
in this Agreement shall constitute an infringement or violation of Id
Software's copyright in the Code. Licensee shall not copy, reproduce,
manufacture or distribute (free of charge or otherwise) the Authorized
Copy or the Modified Copy in any tangible media, including, without
limitation, a CD ROM. Licensee shall not commercially exploit by sale,
lease, rental or otherwise the Authorized Copy or the Modified Copy
whether included within Extra Levels or otherwise. Licensee shall not
commercially exploit by sale, lease, rental or otherwise any Extra Levels
developed by the use of the Code, whether in whole or in part. Licensee
is not receiving any rights hereunder regarding the Game, the Trademarks
or any audio-visual elements, artwork, sound, music, images, characters,
or other element of the Game. Licensee may modify the Authorized Copy in
order to create a Modified Copy, as noted above, but all sublicensees who
receive the Modified Copy shall not receive any rights to commercially
exploit or to make any other use of the Code included therein except the
right to use such Code for such sublicensee's personal entertainment. By
way of example and not exclusion, a sublicensee for the Modified Copy
shall not further modify the Code within the Modified Copy. Only the
Licensee who obtains the Code by Authorized Means shall be permitted to
modify such Code on the terms as described in this Agreement.
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
4. Additional Obligations. In addition to the obligations of Licensee
otherwise set forth in this Agreement, during the Term, and thereafter
where specified, Licensee agrees that:
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
a. Licensee will not attack or challenge the ownership by Id
Software of the Code, the Authorized Copy, the Game, the Trademarks,
or any copyright, patent or trademark or other intellectual property
right related thereto and Licensee will not attack or challenge
the validity of the license granted hereunder during the Term or
thereafter; and
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
b. Licensee will promptly inform Id Software of any unauthorized
use of the Code, the Authorized Copy, the Trademarks, or the Game,
or any portions thereof, and will reasonably assist Id Software
in the enforcement of all rights Id Software may have against such
unauthorized users.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
5. Ownership. Title to and all ownership rights in and to the Code,
whether included within the Modified Copy, the Authorized Copy or
otherwise, the Game, the Authorized Copy, and the Trademarks and the
copyrights, trade secrets, trademarks, patents and all other intellectual
property rights related thereto shall remain with Id Software which shall
have the exclusive right to protect the same by copyright or otherwise.
Licensee shall have no ownership rights in or to the Game, the Code,
the Authorized Copy or the Trademarks. Licensee acknowledges that
Licensee, by this Agreement, is only receiving a limited license to use
the Authorized Copy, as specified in paragraph 2. of this Agreement.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
6. Compliance with Applicable Laws. In exercising Licensee's
limited rights hereunder, Licensee shall comply with all applicable
laws, [including, without limitation, 22 U.S.C., section 2778 and 22
U.S.C. C.F.R. Parts 120-130 (1995)] regulations, ordinances and statutes,
including, but not limited to, the import/export laws and regulations
of the United States and its governmental and regulatory agencies
(including, without limitation, the Bureau of Export Administration
and the U.S. Department of Commerce) and all applicable international
treaties and laws.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
7. Term and Termination.
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
a. The term of this Agreement and the license granted herein
begins on the Effective Date and shall expire, without notice,
on a date one (1) calendar year from the Effective Date (the "Term").
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
b. Either party may terminate this Agreement, for any reason or
no reason, on thirty (30) days written notice to the other party.
Termination will be effective on the thirtieth (30th) day following
delivery of the notice of termination. Notwithstanding anything
to the contrary herein, this Agreement shall immediately terminate,
without the requirement of any notice from Id Software to Licensee,
upon the occurrence of any of the following "Terminating Events":
(i) if Licensee files a petition in bankruptcy; (ii) if Licensee
makes an assignment for the benefit of creditors; (iii) if any
bankruptcy proceeding or assignment for benefit of creditors is
commenced against Licensee and not dismissed within sixty (60)
days after the date of its commencement; (iv) the insolvency of
Licensee; or (v) a breach, whether material or otherwise, of this
Agreement by Licensee. Upon the occurrence of a Terminating Event,
this Agreement and any and all rights hereunder shall terminate
without prejudice to any rights or claims Id Software may have,
and all rights granted hereunder shall revert, without notice,
to and be vested in Id Software.
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
c. Termination or expiration of this Agreement shall not create
any liability against Id Software and shall not relieve Licensee
from any liability which arises prior to termination or expiration.
Upon expiration or earlier termination of this Agreement, Licensee
shall have no further right to exercise the rights licensed hereunder
or otherwise acquired in relation to this Agreement.
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
8. Licensee's Warranties. Licensee warrants and represents that:
(i) Licensee has full legal rights and authority to enter into and
become bound by the terms of this Agreement; (ii) Licensee has full
legal rights and authority to perform Licensee?s obligations hereunder;
(iii) Licensee will comply, at all times during the Term, with all
applicable laws, as set forth hereinabove; (iv) all modifications which
Licensee performs on the Code in order to create the Modified Copy and
all non-Id Software property included within Extra Levels shall not
infringe against or misappropriate any third party rights, including,
without limitation, copyrights and trade secrets; and (v) the use or
non-use of all modifications which Licensee performs on the Code in order
to create the Modified Copy and all non-Id Software property included
within Extra Levels shall not infringe against or misappropriate any third
party rights, including, without limitation, copyrights and trade secrets.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
9. Indemnification. Licensee hereby agrees to indemnify, hold
harmless and defend Id Software and Id Software's predecessors,
successors, assigns, officers, directors, shareholders, employees,
agents, representatives, licensees (but not including Licensee),
sublicensees, distributors, attorneys and accountants (collectively,
the "Id Related Parties") from and against any and all "Claims", which
shall mean all damages, claims, losses, causes of action, liabilities,
lawsuits, judgments and expenses (including, without limitation,
reasonable attorneys' fees and expenses) arising from, relating to or in
connection with (i) a breach of this Agreement by Licensee and/or (ii)
Licensee's use or non-use of the Code, whether the Authorized Copy or
whether a portion of the Code as may be included within the Modified
Copy or within Extra Levels. Id Software agrees to notify Licensee
of any such Claims within a reasonable time after Id Software learns
of same. Licensee, at its own expense, shall defend Id Software and the
Id Related Parties from and against any and all Claims. Id Software and
the Id Related Parties reserve the right to participate in any defense
of the Claims with counsel of their choice, and at their own expense.
In the event Licensee fails to provide a defense, then Licensee shall be
responsible for paying the attorneys' fees and expenses incurred by Id
Software and the Id Related Parties regarding the defense of the Claims.
Id Software and the Id Related Parties, as applicable, agree to reasonably
assist in the defense of the Claims. No settlement by Licensee of any
Claims shall be valid unless Licensee receives the prior written consent
of Id Software and the Id Related Parties, as applicable, to any such
settlement, with consent may be withheld in Id Software's and the Id
Related Parties' sole discretion.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
10. Limitation of Liability. UNDER NO CIRCUMSTANCES SHALL ID SOFTWARE
BE LIABLE TO LICENSEE FOR ACTUAL, SPECIAL, INCIDENTAL, CONSEQUENTIAL
OR PUNITIVE DAMAGES OR ANY OTHER DAMAGES, WHETHER OR NOT ID SOFTWARE
RECEIVES NOTICE OF ANY SUCH DAMAGES.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
11. Disclaimer of Warranties. ID SOFTWARE EXPRESSLY DISCLAIMS ALL
WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE, WITH REGARD TO THE CODE, THE AUTHORIZED COPY AND OTHERWISE.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
12. Goodwill. Licensee recognizes the great value of the goodwill
associated with the Game and the Trademarks, and acknowledges that such
goodwill, now existing and hereafter created, exclusively belongs to Id
Software and that the Trademarks have acquired a secondary meaning in
the mind of the public.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
13. Remedies. In the event of a breach of this Agreement by Id Software,
Licensee's sole remedy shall be to terminate this Agreement by delivering
written notice of termination to Id Software. In the event of a breach
by Licensee of this Agreement, Id Software may pursue the remedies to
which Id Software is entitled under applicable law and this Agreement.
Licensee agrees that Licensee's unauthorized use of the Authorized
Copy would immediately and irreparably damage Id Software, and in the
event of such threatened or actual unauthorized use, Id Software shall
be entitled to an injunctive order appropriately restraining and/or
prohibiting such unauthorized use without the necessity of Id Software
posting bond or other security. Pursuit of any remedy by Id Software
shall not constitute a waiver of any other right or remedy of Id Software
under this Agreement or under applicable law.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
14. Choice of Law, Venue and Service of Process. This Agreement shall
be construed in accordance with the laws of the State of Texas and
applicable United States federal law and all claims and/or lawsuits
in connection with this Agreement must be brought in Dallas County,
Texas where exclusive venue shall lie. Licensee hereby agrees that
service of process by certified mail to the address set forth below,
with return receipt requested, shall constitute valid service of process
upon Licensee. If for any reason Licensee has moved or cannot be validly
served, then Licensee appoints the Secretary of State of the state of
Texas to accept service of process on Licensee's behalf.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
15. Delivery of Notices. Unless otherwise directed in writing by
the parties, all notices given hereunder shall be sent to the last
known address of addressee. All notices, requests, consents and other
communications under this Agreement shall be in writing and shall be
deemed to have been delivered on the date personally delivered or on the
date deposited in the United States Postal Service, postage prepaid, by
certified mail, return receipt requested, or telegraphed and confirmed,
or delivered by electronic facsimile and confirmed. Any notice to Id
Software shall also be sent to its counsel: D. Wade Cloud, Jr., Hiersche,
Martens, Hayward, Drakeley & Urbach, P.C., 15303 Dallas Parkway, Suite
700, LB 17, Dallas, Texas 75248.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
16. No Partnership, Etc. This Agreement does not constitute and shall
not be construed as constituting a partnership or joint venture between
Id Software and Licensee. Neither party shall have any right to obligate
or bind the other party in any manner whatsoever, and nothing herein
contained shall give, or is intended to give, any rights of any kind to
any third persons.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
17. Entire agreement. This Agreement constitutes the entire
understanding between Licensee and Id Software regarding the subject
matter hereof. Each and every clause of this Agreement is severable from
the whole and shall survive unless the entire Agreement is declared
unenforceable. No prior or present agreements or representations
between the parties hereto regarding the subject matter hereof shall be
binding upon the parties hereto unless incorporated in this Agreement.
No modification or change in this Agreement shall be valid or binding
upon the parties hereto unless in writing and executed by the parties
to be bound thereby.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
18. Assignment. This Agreement shall bind and inure to the benefit of
Id Software, its successors and assigns, and Id Software may assign its
rights hereunder, in Id Software's sole discretion. This Agreement
is personal to Licensee, and Licensee shall not assign, transfer,
convey nor franchise its rights granted hereunder. As provided above,
Licensee may sublicense Licensee's limited rights herein by transferring
the Authorized Copy by Authorized Means. As noted, each sublicensee
in possession of a copy of the Authorized Copy shall be subject to the
terms and conditions of this Agreement.
NO WARRANTY
19. Survival. The following provisions shall survive the expiration
or earlier termination of this Agreement: paragraphs 5., 8., 9., 10.,
11., 12., 13., 14., 15., 16., 17., 19., 20.a. and 20.b.
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
20. Miscellaneous.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
a. All captions in this Agreement are intended solely for the
convenience of the parties, and none shall effect the meaning or
construction of any provision.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
b. The terms and conditions of this Agreement have been negotiated
fully and freely among the parties. Accordingly, the preparation
of this Agreement by counsel for a given party will not be material
to the construction hereof, and the terms of this Agreement shall
not be strictly construed against such party.
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
BY DOWNLOADING THE CODE, AS DEFINED ABOVE, YOU, THE LICENSEE, AGREE TO
ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
February 12, 1998
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

156
Makefile
View file

@ -6,8 +6,8 @@
# #
# Dependencies: #
# - None, but you need a Quake II to play. #
# While in theorie every client should work #
# Yamagi Quake II ist recommended. #
# While in theory every client should work #
# Yamagi Quake II is recommended. #
# #
# Platforms: #
# - FreeBSD #
@ -19,33 +19,45 @@
# Detect the OS
ifdef SystemRoot
OSTYPE := Windows
YQ2_OSTYPE ?= Windows
else
OSTYPE := $(shell uname -s)
YQ2_OSTYPE ?= $(shell uname -s)
endif
# Special case for MinGW
ifneq (,$(findstring MINGW,$(OSTYPE)))
OSTYPE := Windows
endif
# On Windows / MinGW $(CC) is undefined by default.
ifeq ($(OSTYPE),Windows)
CC := gcc
ifneq (,$(findstring MINGW,$(YQ2_OSTYPE)))
YQ2_OSTYPE := Windows
endif
# Detect the architecture
ifeq ($(OSTYPE), Windows)
ifeq ($(YQ2_OSTYPE), Windows)
ifdef MINGW_CHOST
ifeq ($(MINGW_CHOST), x86_64-w64-mingw32)
YQ2_ARCH ?= x86_64
else # i686-w64-mingw32
YQ2_ARCH ?= i386
endif
else # windows, but MINGW_CHOST not defined
ifdef PROCESSOR_ARCHITEW6432
# 64 bit Windows
ARCH := $(PROCESSOR_ARCHITEW6432)
YQ2_ARCH ?= $(PROCESSOR_ARCHITEW6432)
else
# 32 bit Windows
ARCH := $(PROCESSOR_ARCHITECTURE)
YQ2_ARCH ?= $(PROCESSOR_ARCHITECTURE)
endif
endif # windows but MINGW_CHOST not defined
else
# Normalize some abiguous ARCH strings
ARCH := $(shell uname -m | sed -e 's/i.86/i386/' -e 's/amd64/x86_64/' -e 's/^arm.*/arm/')
ifneq ($(YQ2_OSTYPE), Darwin)
# Normalize some abiguous YQ2_ARCH strings
YQ2_ARCH ?= $(shell uname -m | sed -e 's/i.86/i386/' -e 's/amd64/x86_64/' -e 's/arm64/aarch64/' -e 's/^arm.*/arm/')
else
YQ2_ARCH ?= $(shell uname -m)
endif
endif
# On Windows / MinGW $(CC) is undefined by default.
ifeq ($(YQ2_OSTYPE),Windows)
CC ?= gcc
endif
# Detect the compiler
@ -61,30 +73,32 @@ endif
# ----------
# Base CFLAGS.
#
# -O2 are enough optimizations.
#
# -fno-strict-aliasing since the source doesn't comply
# with strict aliasing rules and it's next to impossible
# to get it there...
#
# -fomit-frame-pointer since the framepointer is mostly
# useless for debugging Quake II and slows things down.
#
# -g to build allways with debug symbols. Please do not
# change this, since it's our only chance to debug this
# crap when random crashes happen!
#
# -fPIC for position independend code.
#
# -MMD to generate header dependencies.
ifeq ($(OSTYPE), Darwin)
CFLAGS := -O2 -fno-strict-aliasing -fomit-frame-pointer \
-Wall -pipe -g -fwrapv -arch i386 -arch x86_64
# Base CFLAGS. These may be overridden by the environment.
# Highest supported optimizations are -O2, higher levels
# will likely break this crappy code.
ifdef DEBUG
CFLAGS ?= -O0 -g -Wall -pipe
else
CFLAGS := -std=gnu99 -O2 -fno-strict-aliasing -fomit-frame-pointer \
-Wall -pipe -g -MMD -fwrapv
CFLAGS ?= -O2 -Wall -pipe -fomit-frame-pointer
endif
# Always needed are:
# -fno-strict-aliasing since the source doesn't comply
# with strict aliasing rules and it's next to impossible
# to get it there...
# -fwrapv for defined integer wrapping. MSVC6 did this
# and the game code requires it.
override CFLAGS += -fno-strict-aliasing -fwrapv
# -MMD to generate header dependencies. Unsupported by
# the Clang shipped with OS X.
ifneq ($(YQ2_OSTYPE), Darwin)
override CFLAGS += -MMD
endif
# OS X architecture.
ifeq ($(YQ2_OSTYPE), Darwin)
override CFLAGS += -arch $(YQ2_ARCH)
endif
# ----------
@ -106,17 +120,47 @@ endif
# ----------
# Defines the operating system and architecture
CFLAGS += -DOSTYPE=\"$(OSTYPE)\" -DARCH=\"$(ARCH)\"
override CFLAGS += -DYQ2OSTYPE=\"$(YQ2_OSTYPE)\" -DYQ2ARCH=\"$(YQ2_ARCH)\"
# ----------
# For reproduceable builds, look here for details:
# https://reproducible-builds.org/specs/source-date-epoch/
ifdef SOURCE_DATE_EPOCH
CFLAGS += -DBUILD_DATE=\"$(shell date --utc --date="@${SOURCE_DATE_EPOCH}" +"%b %_d %Y" | sed -e 's/ /\\ /g')\"
endif
# ----------
# Using the default x87 float math on 32bit x86 causes rounding trouble
# -ffloat-store could work around that, but the better solution is to
# just enforce SSE - every x86 CPU since Pentium3 supports that
# and this should even improve the performance on old CPUs
ifeq ($(YQ2_ARCH), i386)
override CFLAGS += -msse -mfpmath=sse
endif
# Force SSE math on x86_64. All sane compilers should do this
# anyway, just to protect us from broken Linux distros.
ifeq ($(YQ2_ARCH), x86_64)
override CFLAGS += -mfpmath=sse
endif
# ----------
# Base LDFLAGS.
ifeq ($(OSTYPE), Darwin)
LDFLAGS := -shared -arch i386 -arch x86_64
else ifeq ($(OSTYPE), Windows)
LDFLAGS := -shared -static-libgcc
LDFLAGS ?=
# It's a shared library.
override LDFLAGS += -shared
# Required libaries
ifeq ($(YQ2_OSTYPE), Darwin)
override LDFLAGS += -arch $(YQ2_ARCH)
else ifeq ($(YQ2_OSTYPE), Windows)
override LDFLAGS += -static-libgcc
else
LDFLAGS := -shared -lm
override LDFLAGS += -lm
endif
# ----------
@ -136,12 +180,12 @@ Q := @
endif
# ----------
# Phony targets
.PHONY : all clean rogue
# ----------
# Cleanup
clean:
@echo "===> CLEAN"
@ -150,12 +194,12 @@ clean:
# ----------
# The rogue game
ifeq ($(OSTYPE), Windows)
ifeq ($(YQ2_OSTYPE), Windows)
rogue:
@echo "===> Building game.dll"
${Q}mkdir -p release
$(MAKE) release/game.dll
else ifeq ($(OSTYPE), Darwin)
else ifeq ($(YQ2_OSTYPE), Darwin)
rogue:
@echo "===> Building game.dylib"
${Q}mkdir -p release
@ -238,11 +282,11 @@ ROGUE_OBJS_ = \
src/savegame/savegame.o \
src/shared/flash.o \
src/shared/rand.o \
src/shared/shared.o
src/shared/shared.o
# ----------
# Rewrite pathes to our object directory
# Rewrite paths to our object directory
ROGUE_OBJS = $(patsubst %,build/%,$(ROGUE_OBJS_))
# ----------
@ -257,18 +301,18 @@ ROGUE_DEPS= $(ROGUE_OBJS:.o=.d)
# ----------
ifeq ($(OSTYPE), Windows)
ifeq ($(YQ2_OSTYPE), Windows)
release/game.dll : $(ROGUE_OBJS)
@echo "===> LD $@"
${Q}$(CC) $(LDFLAGS) -o $@ $(ROGUE_OBJS)
else ifeq ($(OSTYPE), Darwin)
${Q}$(CC) -o $@ $(ROGUE_OBJS) $(LDFLAGS)
else ifeq ($(YQ2_OSTYPE), Darwin)
release/game.dylib : $(ROGUE_OBJS)
@echo "===> LD $@"
${Q}$(CC) $(LDFLAGS) -o $@ $(ROGUE_OBJS)
${Q}$(CC) -o $@ $(ROGUE_OBJS) $(LDFLAGS)
else
release/game.so : $(ROGUE_OBJS)
@echo "===> LD $@"
${Q}$(CC) $(LDFLAGS) -o $@ $(ROGUE_OBJS)
${Q}$(CC) -o $@ $(ROGUE_OBJS) $(LDFLAGS)
endif
# ----------

41
README
View file

@ -1,41 +0,0 @@
This is a bugfixed version of id Software's Quake II missionpack
"Ground Zero", developed by Rogue Software. Hundreds of bugs were
fixed, this version should run much more stable than the old
SDK version. While compatible with any Quake II client that uses
the original unaltered mod API, the "Yamagi Quake II Client" is
highly recommended to play the addon. For more information visit
http://www.yamagi.org/quake2.
Installation for FreeBSD, Linux and OpenBSD:
--------------------------------------------
1. Type "make" or "gmake" to compile the game.so.
2. Create a subdirectory rogue/ in your quake2 directory.
3. Copy pak0.pak and videos/ from the "Ground Zero" CD to
the newly created directory rogue/.
4. Copy release/game.so to rogue/.
5. Start the game with "./quake2 +set game rogue"
Installation for OS X:
----------------------
1. Create a subdirectory rogue/ in your quake2 directory.
2. Copy pak0.pak and videos/ from the "Ground Zero" CD to
the newly created directory rogue/.
3. Copy game.dynlib from the zip-archive to rogue/.
4. Start the game with "quake2 +set game rogue"
If you want to compile 'rogue' for OS X from source, please take a
look at the "Installation" section of the README of the Yamagi Quake II
client. In the same file the integration into an app-bundle is
explained.
Installation for Windows:
-------------------------
1. Create a subdirectory rogue\ in your quake2 directory.
2. Copy pak0.pak and videos\ from the "Ground Zero" CD to
the newly created directory rogue\.
3. Copy game.dll from the zip-archive to rogue/.
4. Start the game with "quake2.exe +set game rogue"
If you want to compile 'rogue' for Windows from source, please take a
look at the "Installation" section of the README of the Yamagi Quake II
client. There's descripted how to setup the build environment.

67
README.md Normal file
View file

@ -0,0 +1,67 @@
# Ground Zero for Yamagi Quake II
Ground Zero for Yamagi Quake II is a bugfixed version of the second
official missionpack released for Quake II. It's based upon the Quake
II SDK source code and licensed under GPL version 2:
* [LICENSE](https://github.com/yquake2/rogue/blob/master/LICENSE)
Hundreds of bugs were fixed and some convenience features added. The
missionpack is intended to be used with Yamagi Quake II, but it's also
fully backward compatible with the last Quake II pointrelease 3.20 and
may work with other source ports.
Officially supported operating systems are:
* FreeBSD
* Linux
* Windows
Beside theses Ground Zero for Yamagi Quake II has community support
for MacOS and most other unixoid operating systems, including NetBSD,
OpenBSD and Solaris.
## Development
Ground Zero for Yamagi Quake II is a community driven project and
lives from community involvement. Please report bugs in our issue
tracker:
* [Issue Tracker](https://github.com/yquake2/rogue/issues)
We are always open to code contributions, no matter if they are small
bugfixes or bigger features. However, Yamagi Quake II is a conservative
project with big focus on stability and backward compatibility. We don't
accept breaking changes. When in doubt please open an issue and ask if a
contribution in welcome before putting too much work into it. Open a
pull request to submit code:
* [Pull Requests](https://github.com/yquake2/rogue/pulls)
Also have a look at our contributors guide:
* [Contributors Guide](https://github.com/yquake2/yquake2/blob/master/doc/080_contributing.md)
## Documentation
Yamagi Quake II has rather extensive documentation covering all relevant
areas from installation and configuration to package building. Have a
look at the documentation index:
* [Documentation Index](https://github.com/yquake2/yquake2/blob/master/doc/010_index.md)
## Releases
Ground Zero for Yamagi Quake II releases at an irregular schedule. The
official releases with source code tarballs and prebuild Windows
binaries can be found at the homepage:
* [Homepage](https://www.yamagi.org/quake2/)
Our CI builds **unsupported** Linux, MacOS and Windows binaries at every
commit. The artifacts can be found here:
* [Github Actions](https://github.com/yquake2/rogue/actions)

View file

@ -503,7 +503,7 @@ FoundTarget(edict_t *self)
level.sight_entity->light_level = 128;
}
self->show_hostile = (int)level.time + 1; /* wake up other monsters */
self->show_hostile = level.time + 1; /* wake up other monsters */
VectorCopy(self->enemy->s.origin, self->monsterinfo.last_sighting);
self->monsterinfo.trail_time = level.time;
@ -616,15 +616,11 @@ FindTarget(edict_t *self)
else
{
client = level.sight_client;
if (!client)
{
return false; /* no clients to get mad at */
}
}
/* if the entity went away, forget it */
if (!client->inuse)
if (!client || !client->inuse ||
(client->client && level.intermissiontime))
{
return false;
}
@ -692,7 +688,7 @@ FindTarget(edict_t *self)
if (r == RANGE_NEAR)
{
if ((client->show_hostile < (int)level.time) && !infront(self, client))
if ((client->show_hostile < level.time) && !infront(self, client))
{
return false;
}
@ -1151,11 +1147,38 @@ ai_run_slide(edict_t *self, float distance)
* or do something else used by
* ai_run and ai_stand
*/
static qboolean
hesDeadJim(const edict_t *self)
{
const edict_t *enemy = self->enemy;
if (!enemy || !enemy->inuse)
{
return true;
}
if (self->monsterinfo.aiflags & AI_MEDIC)
{
return (enemy->health > 0);
}
if (enemy->client && level.intermissiontime)
{
return true;
}
if (self->monsterinfo.aiflags & AI_BRUTAL)
{
return (enemy->health <= -80);
}
return (enemy->health <= 0);
}
qboolean
ai_checkattack(edict_t *self, float dist)
{
vec3_t temp;
qboolean hesDeadJim;
qboolean retval;
if (!self)
@ -1199,7 +1222,7 @@ ai_checkattack(edict_t *self, float dist)
}
else
{
self->show_hostile = (int)level.time + 1;
self->show_hostile = level.time + 1;
return false;
}
}
@ -1208,41 +1231,10 @@ ai_checkattack(edict_t *self, float dist)
enemy_vis = false;
/* see if the enemy is dead */
hesDeadJim = false;
if ((!self->enemy) || (!self->enemy->inuse))
if (hesDeadJim(self))
{
hesDeadJim = true;
}
else if (self->monsterinfo.aiflags & AI_MEDIC)
{
if (self->enemy->health > 0)
{
hesDeadJim = true;
}
}
else
{
if (self->monsterinfo.aiflags & AI_BRUTAL)
{
if (self->enemy->health <= -80)
{
hesDeadJim = true;
}
}
else
{
if (self->enemy->health <= 0)
{
hesDeadJim = true;
}
}
}
if (hesDeadJim)
{
self->monsterinfo.aiflags &= ~AI_MEDIC;
self->enemy = NULL;
self->monsterinfo.aiflags &= ~AI_MEDIC;
if (self->oldenemy && (self->oldenemy->health > 0))
{
@ -1279,7 +1271,7 @@ ai_checkattack(edict_t *self, float dist)
}
}
self->show_hostile = (int)level.time + 1; /* wake up other monsters */
self->show_hostile = level.time + 1; /* wake up other monsters */
/* check knowledge of enemy */
enemy_vis = visible(self, self->enemy);
@ -1596,8 +1588,15 @@ ai_run(edict_t *self, float dist)
return;
}
tempgoal = G_SpawnOptional();
if (!tempgoal)
{
M_MoveToGoal(self, dist);
return;
}
save = self->goalentity;
tempgoal = G_Spawn();
self->goalentity = tempgoal;
new = false;

View file

@ -728,12 +728,20 @@ Cmd_WeapPrev_f(edict_t *ent)
cl = ent->client;
if (!cl->pers.weapon)
if (g_quick_weap->value && cl->newweapon)
{
it = cl->newweapon;
}
else if (cl->pers.weapon)
{
it = cl->pers.weapon;
}
else
{
return;
}
selected_weapon = ITEM_INDEX(cl->pers.weapon);
selected_weapon = ITEM_INDEX(it);
/* scan for the next valid one */
for (i = 1; i <= MAX_ITEMS; i++)
@ -748,12 +756,7 @@ Cmd_WeapPrev_f(edict_t *ent)
it = &itemlist[index];
if (!it->use)
{
continue;
}
if (!(it->flags & IT_WEAPON))
if (!it->use || !(it->flags & IT_WEAPON))
{
continue;
}
@ -763,6 +766,12 @@ Cmd_WeapPrev_f(edict_t *ent)
/* prevent scrolling through ALL weapons */
if (cl->newweapon == it)
{
if (g_quick_weap->value)
{
cl->ps.stats[STAT_PICKUP_ICON] = gi.imageindex(cl->newweapon->icon);
cl->ps.stats[STAT_PICKUP_STRING] = CS_ITEMS + ITEM_INDEX(cl->newweapon);
cl->pickup_msg_time = level.time + 0.9f;
}
return;
}
}
@ -783,14 +792,22 @@ Cmd_WeapNext_f(edict_t *ent)
cl = ent->client;
if (!cl->pers.weapon)
if (g_quick_weap->value && cl->newweapon)
{
it = cl->newweapon;
}
else if (cl->pers.weapon)
{
it = cl->pers.weapon;
}
else
{
return;
}
selected_weapon = ITEM_INDEX(cl->pers.weapon);
selected_weapon = ITEM_INDEX(it);
/* scan for the next valid one */
/* scan for the next valid one */
for (i = 1; i <= MAX_ITEMS; i++)
{
/* prevent scrolling through ALL weapons */
@ -803,12 +820,7 @@ Cmd_WeapNext_f(edict_t *ent)
it = &itemlist[index];
if (!it->use)
{
continue;
}
if (!(it->flags & IT_WEAPON))
if (!it->use || !(it->flags & IT_WEAPON))
{
continue;
}
@ -818,6 +830,12 @@ Cmd_WeapNext_f(edict_t *ent)
/* prevent scrolling through ALL weapons */
if (cl->newweapon == it)
{
if (g_quick_weap->value)
{
cl->ps.stats[STAT_PICKUP_ICON] = gi.imageindex(cl->newweapon->icon);
cl->ps.stats[STAT_PICKUP_STRING] = CS_ITEMS + ITEM_INDEX(cl->newweapon);
cl->pickup_msg_time = level.time + 0.9f;
}
return;
}
}
@ -1073,14 +1091,81 @@ Cmd_Wave_f(edict_t *ent)
}
}
static qboolean
flooded(edict_t *ent)
{
gclient_t *cl;
int i;
int num_msgs;
int mx;
if (!ent)
{
return false;
}
if (!deathmatch->value && !coop->value)
{
return false;
}
num_msgs = flood_msgs->value;
if (num_msgs <= 0)
{
return false;
}
cl = ent->client;
mx = sizeof(cl->flood_when) / sizeof(cl->flood_when[0]);
if (num_msgs > mx)
{
gi.dprintf("flood_msgs lowered to max: 10\n");
num_msgs = mx;
gi.cvar_forceset("flood_msgs", "10");
}
if (level.time < cl->flood_locktill)
{
gi.cprintf(ent, PRINT_HIGH, "You can't talk for %d more seconds\n",
(int)(cl->flood_locktill - level.time));
return true;
}
i = (cl->flood_whenhead - num_msgs) + 1;
if (i < 0)
{
i += mx;
}
if (cl->flood_when[i] &&
(level.time - cl->flood_when[i]) < flood_persecond->value)
{
cl->flood_locktill = level.time + flood_waitdelay->value;
gi.cprintf(ent, PRINT_CHAT,
"Flood protection: You can't talk for %d seconds.\n",
(int)flood_waitdelay->value);
return true;
}
cl->flood_whenhead = (cl->flood_whenhead + 1) % mx;
cl->flood_when[cl->flood_whenhead] = level.time;
return false;
}
void
Cmd_Say_f(edict_t *ent, qboolean team, qboolean arg0)
{
int i, j;
int j;
edict_t *other;
char *p;
char text[2048];
gclient_t *cl;
if (!ent)
{
@ -1092,6 +1177,11 @@ Cmd_Say_f(edict_t *ent, qboolean team, qboolean arg0)
return;
}
if (flooded(ent))
{
return;
}
if (!((int)(dmflags->value) & (DF_MODELTEAMS | DF_SKINTEAMS)))
{
team = false;
@ -1133,39 +1223,6 @@ Cmd_Say_f(edict_t *ent, qboolean team, qboolean arg0)
strcat(text, "\n");
if (flood_msgs->value)
{
cl = ent->client;
if (level.time < cl->flood_locktill)
{
gi.cprintf(ent, PRINT_HIGH, "You can't talk for %d more seconds\n",
(int)(cl->flood_locktill - level.time));
return;
}
i = cl->flood_whenhead - flood_msgs->value + 1;
if (i < 0)
{
i = (sizeof(cl->flood_when) / sizeof(cl->flood_when[0])) + i;
}
if (cl->flood_when[i] &&
(level.time - cl->flood_when[i] < flood_persecond->value))
{
cl->flood_locktill = level.time + flood_waitdelay->value;
gi.cprintf(ent, PRINT_CHAT,
"Flood protection: You can't talk for %d seconds.\n",
(int)flood_waitdelay->value);
return;
}
cl->flood_whenhead = (cl->flood_whenhead + 1) % (sizeof(cl->flood_when) /
sizeof(cl->flood_when[0]));
cl->flood_when[cl->flood_whenhead] = level.time;
}
if (dedicated->value)
{
gi.cprintf(NULL, PRINT_CHAT, "%s", text);
@ -1470,6 +1527,7 @@ cycle_weapon(edict_t *ent)
int i;
int start;
int num_weaps;
const char *weapname = NULL;
if (!ent)
{
@ -1486,11 +1544,20 @@ cycle_weapon(edict_t *ent)
num_weaps = gi.argc();
/* find where we want to start the search for the next eligible weapon */
if (cl->pers.weapon)
if (cl->newweapon)
{
weapname = cl->newweapon->classname;
}
else if (cl->pers.weapon)
{
weapname = cl->pers.weapon->classname;
}
if (weapname)
{
for (i = 1; i < num_weaps; i++)
{
if (Q_stricmp(cl->pers.weapon->classname, gi.argv(i)) == 0)
if (Q_stricmp(weapname, gi.argv(i)) == 0)
{
break;
}
@ -1570,6 +1637,120 @@ cycle_weapon(edict_t *ent)
void
Cmd_CycleWeap_f(edict_t *ent)
{
gitem_t *weap;
gclient_t *cl;
int num_weaps;
if (!ent)
{
return;
}
num_weaps = gi.argc();
if (num_weaps <= 1)
{
gi.cprintf(ent, PRINT_HIGH, "Usage: cycleweap classname1 classname2 .. classnameN\n");
return;
}
weap = cycle_weapon(ent);
if (!weap) return;
cl = ent->client;
if (cl->pers.inventory[ITEM_INDEX(weap)] <= 0)
{
gi.cprintf(ent, PRINT_HIGH, "Out of item: %s\n", weap->pickup_name);
return;
}
weap->use(ent, weap);
if (num_weaps > 3 && cl->newweapon == weap)
{
cl->ps.stats[STAT_PICKUP_ICON] = gi.imageindex(weap->icon);
cl->ps.stats[STAT_PICKUP_STRING] = CS_ITEMS + ITEM_INDEX(weap);
cl->pickup_msg_time = level.time + 0.7f;
}
}
static gitem_t *
preferred_weapon(edict_t *ent)
{
gclient_t *cl;
gitem_t *noammo_fallback;
gitem_t *noweap_fallback;
gitem_t *weap;
gitem_t *ammo;
int i;
int num_weaps;
if (!ent)
{
return NULL;
}
cl = ent->client;
if (!cl)
{
return NULL;
}
num_weaps = gi.argc();
noammo_fallback = NULL;
noweap_fallback = NULL;
/* find the first eligible weapon in the list we can switch to */
for (i = 1; i < num_weaps; i++)
{
weap = FindItemByClassname(gi.argv(i));
if (weap && (weap->flags & IT_WEAPON) && weap->use)
{
if (cl->pers.inventory[ITEM_INDEX(weap)] > 0)
{
if (weap->ammo)
{
ammo = FindItem(weap->ammo);
if (ammo)
{
if (cl->pers.inventory[ITEM_INDEX(ammo)] >= get_ammo_usage(weap))
{
return weap;
}
if (!noammo_fallback)
{
noammo_fallback = weap;
}
}
}
else
{
return weap;
}
}
else if (!noweap_fallback)
{
noweap_fallback = weap;
}
}
}
/* if no weapon was found, the fallbacks will be used for
printing the appropriate error message to the console
*/
if (noammo_fallback)
{
return noammo_fallback;
}
return noweap_fallback;
}
void
Cmd_PrefWeap_f(edict_t *ent)
{
gitem_t *weap;
@ -1580,11 +1761,11 @@ Cmd_CycleWeap_f(edict_t *ent)
if (gi.argc() <= 1)
{
gi.cprintf(ent, PRINT_HIGH, "Usage: cycleweap classname1 classname2 .. classnameN\n");
gi.cprintf(ent, PRINT_HIGH, "Usage: prefweap classname1 classname2 .. classnameN\n");
return;
}
weap = cycle_weapon(ent);
weap = preferred_weapon(ent);
if (weap)
{
if (ent->client->pers.inventory[ITEM_INDEX(weap)] <= 0)
@ -1758,6 +1939,10 @@ ClientCommand(edict_t *ent)
{
Cmd_CycleWeap_f(ent);
}
else if (Q_stricmp(cmd, "prefweap") == 0)
{
Cmd_PrefWeap_f(ent);
}
else /* anything that doesn't match a command will be a chat */
{
Cmd_Say_f(ent, false, true);

View file

@ -128,11 +128,6 @@ Killed(edict_t *targ, edict_t *inflictor, edict_t *attacker,
return;
}
if (targ->health < -999)
{
targ->health = -999;
}
/* Reset AI flag for being ducked. This fixes a corner case
were the monster is ressurected by a medic and get's stuck
in the next frame for mmove_t not matching the AI state. */
@ -629,6 +624,24 @@ CheckTeamDamage(edict_t *targ, edict_t *attacker)
return false;
}
static void
apply_knockback(edict_t *targ, vec3_t dir, float knockback, float scale)
{
vec3_t kvel;
float mass;
if (!knockback)
{
return;
}
mass = (targ->mass < 50) ? 50.0f : (float)targ->mass;
VectorNormalize2(dir, kvel);
VectorScale(kvel, scale * (knockback / mass), kvel);
VectorAdd(targ->velocity, kvel, targ->velocity);
}
void
T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir,
vec3_t point, vec3_t normal, int damage, int knockback, int dflags,
@ -731,8 +744,6 @@ T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir,
te_sparks = TE_SPARKS;
}
VectorNormalize(dir);
/* bonus damage for suprising a monster */
if (!(dflags & DAMAGE_RADIUS) && (targ->svflags & SVF_MONSTER) &&
(attacker->client) && (!targ->enemy) && (targ->health > 0))
@ -746,37 +757,14 @@ T_Damage(edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir,
}
/* figure momentum add */
if (!(dflags & DAMAGE_NO_KNOCKBACK))
if (!(dflags & DAMAGE_NO_KNOCKBACK) &&
(targ->movetype != MOVETYPE_NONE) &&
(targ->movetype != MOVETYPE_BOUNCE) &&
(targ->movetype != MOVETYPE_PUSH) &&
(targ->movetype != MOVETYPE_STOP))
{
if ((knockback) && (targ->movetype != MOVETYPE_NONE) &&
(targ->movetype != MOVETYPE_BOUNCE) &&
(targ->movetype != MOVETYPE_PUSH) &&
(targ->movetype != MOVETYPE_STOP))
{
vec3_t kvel;
float mass;
if (targ->mass < 50)
{
mass = 50;
}
else
{
mass = targ->mass;
}
if (targ->client && (attacker == targ))
{
/* the rocket jump hack... */
VectorScale(dir, 1600.0 * (float)knockback / mass, kvel);
}
else
{
VectorScale(dir, 500.0 * (float)knockback / mass, kvel);
}
VectorAdd(targ->velocity, kvel, targ->velocity);
}
apply_knockback (targ, dir, knockback,
((client && attacker == targ) ? 1600.0f : 500.0f));
}
take = damage;

View file

@ -664,6 +664,39 @@ Use_Plat(edict_t *ent, edict_t *other, edict_t *activator /* unused */)
plat_go_down(ent);
}
void
wait_and_change_think(edict_t* ent)
{
void (*afterwaitfunc)(edict_t *) = ent->moveinfo.endfunc;
ent->moveinfo.endfunc = NULL;
afterwaitfunc(ent);
}
/*
* In coop mode, this waits for coop_elevator_delay seconds
* before calling afterwaitfunc(ent); otherwise it just calls
* afterwaitfunc(ent);
*/
static void
wait_and_change(edict_t* ent, void (*afterwaitfunc)(edict_t *))
{
float waittime = coop_elevator_delay->value;
if (coop->value && waittime > 0.0f)
{
if(ent->nextthink == 0)
{
ent->moveinfo.endfunc = afterwaitfunc;
ent->think = wait_and_change_think;
ent->nextthink = level.time + waittime;
}
}
else
{
afterwaitfunc(ent);
}
}
void
Touch_Plat_Center(edict_t *ent, edict_t *other, cplane_t *plane /* unsed */,
csurface_t *surf /* unused */)
@ -687,7 +720,7 @@ Touch_Plat_Center(edict_t *ent, edict_t *other, cplane_t *plane /* unsed */,
if (ent->moveinfo.state == STATE_BOTTOM)
{
plat_go_up(ent);
wait_and_change(ent, plat_go_up);
}
else if (ent->moveinfo.state == STATE_TOP)
{
@ -2068,7 +2101,7 @@ door_go_down(edict_t *self)
void
door_go_up(edict_t *self, edict_t *activator)
{
if (!self || !activator)
if (!self)
{
return;
}
@ -2233,7 +2266,7 @@ door_use(edict_t *self, edict_t *other /* unused */, edict_t *activator)
edict_t *ent;
vec3_t center;
if (!self || !activator)
if (!self)
{
return;
}
@ -3410,13 +3443,22 @@ trigger_elevator_use(edict_t *self, edict_t *other,
edict_t *activator /* unused */)
{
edict_t *target;
edict_t *train;
if (!self || !other)
{
return;
}
if (self->movetarget->nextthink)
train = self->movetarget;
if (!train || !train->inuse ||
!train->classname || strcmp(train->classname, "func_train") != 0)
{
return;
}
if (train->nextthink)
{
return;
}
@ -3436,8 +3478,8 @@ trigger_elevator_use(edict_t *self, edict_t *other,
return;
}
self->movetarget->target_ent = target;
train_resume(self->movetarget);
train->target_ent = target;
train_resume(train);
}
void

View file

@ -219,27 +219,6 @@ Pickup_Powerup(edict_t *ent, edict_t *other)
{
SetRespawn(ent, ent->item->quantity);
}
if (((int)dmflags->value & DF_INSTANT_ITEMS) ||
((ent->item->use == Use_Quad) &&
(ent->spawnflags & DROPPED_PLAYER_ITEM)))
{
if ((ent->item->use == Use_Quad) &&
(ent->spawnflags & DROPPED_PLAYER_ITEM))
{
quad_drop_timeout_hack =
(ent->nextthink - level.time) / FRAMETIME;
}
if (ent->item->use)
{
ent->item->use(other, ent->item);
}
else
{
gi.dprintf("Powerup has no use function!\n");
}
}
}
return true;
@ -426,9 +405,9 @@ Pickup_Pack(edict_t *ent, edict_t *other)
other->client->pers.max_slugs = 100;
}
if (other->client->pers.max_flechettes < 200)
if (other->client->pers.max_flechettes < 300)
{
other->client->pers.max_flechettes = 200;
other->client->pers.max_flechettes = 300;
}
if (g_disruptor->value)
@ -788,18 +767,6 @@ Pickup_Sphere(edict_t *ent, edict_t *other)
{
SetRespawn(ent, ent->item->quantity);
}
if (((int)dmflags->value & DF_INSTANT_ITEMS))
{
if (ent->item->use)
{
ent->item->use(other, ent->item);
}
else
{
gi.dprintf("Powerup has no use function!\n");
}
}
}
return true;
@ -1051,7 +1018,6 @@ Add_Ammo(edict_t *ent, gitem_t *item, int count)
if (item->tag == AMMO_BULLETS)
{
printf("1\n");
max = ent->client->pers.max_bullets;
}
else if (item->tag == AMMO_SHELLS)
@ -1088,7 +1054,6 @@ Add_Ammo(edict_t *ent, gitem_t *item, int count)
}
else if (item->tag == AMMO_DISRUPTOR)
{
printf("2\n");
max = ent->client->pers.max_rounds;
}
else
@ -1591,6 +1556,33 @@ Touch_Item(edict_t *ent, edict_t *other, cplane_t *plane /* unused */, csurface_
{
gi.sound(other, CHAN_ITEM, gi.soundindex(ent->item->pickup_sound), 1, ATTN_NORM, 0);
}
/* activate item instantly if appropriate */
/* moved down here so activation sounds override the pickup sound */
if (deathmatch->value)
{
if ((((int)dmflags->value & DF_INSTANT_ITEMS) &&
(ent->item->flags & IT_INSTANT_USE)) ||
((ent->item->use == Use_Quad) &&
(ent->spawnflags & DROPPED_PLAYER_ITEM)))
{
if ((ent->item->use == Use_Quad) &&
(ent->spawnflags & DROPPED_PLAYER_ITEM))
{
quad_drop_timeout_hack =
(ent->nextthink - level.time) / FRAMETIME;
}
if (ent->item->use)
{
ent->item->use(other, ent->item);
}
else
{
gi.dprintf("Powerup has no use function!\n");
}
}
}
}
if (!(ent->spawnflags & ITEM_TARGETS_USED))
@ -2098,7 +2090,7 @@ SpawnItem(edict_t *ent, gitem_t *item)
PrecacheItem(item);
if (coop->value && (strcmp(ent->classname, "key_power_cube") == 0))
if (coop->value && !(ent->spawnflags & ITEM_NO_TOUCH) && (strcmp(ent->classname, "key_power_cube") == 0))
{
ent->spawnflags |= (1 << (8 + level.power_cubes));
level.power_cubes++;
@ -2859,7 +2851,7 @@ gitem_t itemlist[] = {
2,
60,
NULL,
IT_POWERUP,
IT_POWERUP|IT_INSTANT_USE,
0,
NULL,
0,
@ -2881,7 +2873,7 @@ gitem_t itemlist[] = {
2,
300,
NULL,
IT_POWERUP,
IT_POWERUP | IT_INSTANT_USE,
0,
NULL,
0,
@ -2903,7 +2895,7 @@ gitem_t itemlist[] = {
2,
60,
NULL,
IT_POWERUP,
IT_POWERUP | IT_INSTANT_USE,
0,
NULL,
0,
@ -2925,7 +2917,7 @@ gitem_t itemlist[] = {
2,
60,
NULL,
IT_STAY_COOP | IT_POWERUP,
IT_STAY_COOP | IT_POWERUP | IT_INSTANT_USE,
0,
NULL,
0,
@ -2947,7 +2939,7 @@ gitem_t itemlist[] = {
2,
60,
NULL,
IT_STAY_COOP | IT_POWERUP,
IT_STAY_COOP | IT_POWERUP | IT_INSTANT_USE,
0,
NULL,
0,
@ -3059,7 +3051,7 @@ gitem_t itemlist[] = {
2,
60,
NULL,
IT_POWERUP,
IT_POWERUP | IT_INSTANT_USE,
0,
NULL,
0,
@ -3081,7 +3073,7 @@ gitem_t itemlist[] = {
2,
60,
NULL,
IT_POWERUP,
IT_POWERUP | IT_INSTANT_USE,
0,
NULL,
0,
@ -3124,7 +3116,7 @@ gitem_t itemlist[] = {
2,
60,
NULL,
IT_POWERUP,
IT_POWERUP | IT_INSTANT_USE,
0,
NULL,
0,
@ -3146,7 +3138,7 @@ gitem_t itemlist[] = {
2,
120,
NULL,
IT_POWERUP,
IT_POWERUP | IT_INSTANT_USE,
0,
NULL,
0,
@ -3168,7 +3160,7 @@ gitem_t itemlist[] = {
2,
60,
NULL,
IT_POWERUP,
IT_POWERUP | IT_INSTANT_USE,
0,
NULL,
0,

View file

@ -23,6 +23,8 @@ edict_t *g_edicts;
cvar_t *deathmatch;
cvar_t *coop;
cvar_t *coop_baseq2; /* treat spawnflags according to baseq2 rules */
cvar_t *coop_elevator_delay;
cvar_t *coop_pickup_weapons;
cvar_t *dmflags;
cvar_t *skill;
cvar_t *fraglimit;
@ -35,6 +37,9 @@ cvar_t *maxspectators;
cvar_t *maxentities;
cvar_t *g_select_empty;
cvar_t *dedicated;
cvar_t *g_footsteps;
cvar_t *g_monsterfootsteps;
cvar_t *g_fix_triggered;
cvar_t *filterban;
@ -70,6 +75,11 @@ cvar_t *randomrespawn;
cvar_t *g_disruptor;
cvar_t *aimfix;
cvar_t *g_machinegun_norecoil;
cvar_t *g_quick_weap;
cvar_t *g_swap_speed;
void SpawnEntities(char *mapname, char *entities, char *spawnpoint);
void ClientThink(edict_t *ent, usercmd_t *cmd);
qboolean ClientConnect(edict_t *ent, char *userinfo);

View file

@ -178,14 +178,19 @@ ThrowGib(edict_t *self, char *gibname, int damage, int type)
return;
}
gibsthisframe++;
if (gibsthisframe > MAX_GIBS)
{
return;
}
gib = G_Spawn();
gib = G_SpawnOptional();
if (!gib)
{
return;
}
gibsthisframe++;
VectorScale(self->size, 0.5, size);
VectorAdd(self->absmin, size, origin);
@ -195,6 +200,7 @@ ThrowGib(edict_t *self, char *gibname, int damage, int type)
gi.setmodel(gib, gibname);
gib->solid = SOLID_BBOX;
gib->svflags = SVF_DEADMONSTER;
gib->s.effects |= EF_GIB;
gib->flags |= FL_NO_KNOCKBACK;
gib->takedamage = DAMAGE_YES;
@ -255,6 +261,10 @@ ThrowHead(edict_t *self, char *gibname, int damage, int type)
self->targetname = NULL;
self->die = gib_die;
// The entity still has the monsters clipmaks.
// Reset it to MASK_SHOT to be on the save side.
self->clipmask = MASK_SHOT;
if (type == GIB_ORGANIC)
{
self->movetype = MOVETYPE_TOSS;
@ -313,6 +323,10 @@ ThrowClientHead(edict_t *self, int damage)
self->s.sound = 0;
self->flags |= FL_NO_KNOCKBACK;
// The entity still has the monsters clipmaks.
// Reset it to MASK_SHOT to be on the save side.
self->clipmask = MASK_SHOT;
self->movetype = MOVETYPE_BOUNCE;
VelocityForDamage(damage, vd);
VectorAdd(self->velocity, vd, self->velocity);
@ -353,14 +367,20 @@ ThrowDebris(edict_t *self, char *modelname, float speed, vec3_t origin)
return;
}
debristhisframe++;
if (debristhisframe > MAX_DEBRIS)
{
return;
}
chunk = G_Spawn();
chunk = G_SpawnOptional();
if (!chunk)
{
return;
}
debristhisframe++;
VectorCopy(origin, chunk->s.origin);
gi.setmodel(chunk, modelname);
v[0] = 100 * crandom();
@ -677,7 +697,7 @@ SP_info_null(edict_t *self)
/*
* QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4)
*
* Used as a positional target for lightning.
* Used as a positional target for lighting.
*/
void
SP_info_notnull(edict_t *self)

View file

@ -872,6 +872,16 @@ monster_start(edict_t *self)
self->spawnflags |= 1;
}
if ((self->spawnflags & 2) && !self->targetname)
{
if (g_fix_triggered->value)
{
self->spawnflags &= ~2;
}
gi.dprintf ("triggered %s at %s has no targetname\n", self->classname, vtos (self->s.origin));
}
if ((!(self->monsterinfo.aiflags & AI_GOOD_GUY)) &&
(!(self->monsterinfo.aiflags & AI_DO_NOT_COUNT)))
{

View file

@ -1746,3 +1746,48 @@ monster_jump_finished(edict_t *self)
return false;
}
qboolean
blind_rocket_ok (edict_t *self, vec3_t start, vec3_t right, vec3_t target, float ofs,
vec3_t dir)
{
trace_t tr;
vec3_t vec;
if (!self)
{
return false;
}
tr = gi.trace(start, vec3_origin, vec3_origin, target, self, MASK_SHOT);
/* since all traces have the same start point this only needs one check */
if (tr.startsolid)
{
return false;
}
if (!tr.allsolid && (tr.fraction >= 0.5f))
{
return true;
}
VectorMA(target, -ofs, right, vec);
VectorSubtract(vec, start, dir);
VectorNormalize(dir);
tr = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
if (!tr.allsolid && (tr.fraction >= 0.5f))
{
return true;
}
VectorMA(target, ofs, right, vec);
VectorSubtract(vec, start, dir);
VectorNormalize(dir);
tr = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
return !tr.allsolid && (tr.fraction >= 0.5f);
}

View file

@ -19,7 +19,6 @@ typedef struct
edict_t *ent;
vec3_t origin;
vec3_t angles;
float deltayaw;
} pushed_t;
pushed_t pushed[MAX_EDICTS], *pushed_p;
@ -53,7 +52,10 @@ SV_TestEntityPosition(edict_t *ent)
return NULL;
}
if (ent->clipmask)
/* dead bodies are supposed to not be solid so lets
ensure they only collide with BSP during pushmoves
*/
if (ent->clipmask && !(ent->svflags & SVF_DEADMONSTER))
{
mask = ent->clipmask;
}
@ -518,6 +520,17 @@ retry:
trace = gi.trace(start, ent->mins, ent->maxs, end, ent, mask);
/* startsolid treats different-content volumes
as continuous, like the bbox of a monster/player
and the floor of an elevator. So do another trace
that only collides with BSP so that we make a best
effort to keep these entities inside non-solid space
*/
if (trace.startsolid && (mask & ~MASK_SOLID))
{
trace = gi.trace (start, ent->mins, ent->maxs, end, ent, MASK_SOLID);
}
VectorCopy(trace.endpos, ent->s.origin);
gi.linkentity(ent);
@ -606,12 +619,6 @@ SV_Push(edict_t *pusher, vec3_t move, vec3_t amove)
pushed_p->ent = pusher;
VectorCopy(pusher->s.origin, pushed_p->origin);
VectorCopy(pusher->s.angles, pushed_p->angles);
if (pusher->client)
{
pushed_p->deltayaw = pusher->client->ps.pmove.delta_angles[YAW];
}
pushed_p++;
/* move the pusher to it's final position */
@ -679,11 +686,6 @@ SV_Push(edict_t *pusher, vec3_t move, vec3_t amove)
/* try moving the contacted entity */
VectorAdd(check->s.origin, move, check->s.origin);
if (check->client)
{
check->client->ps.pmove.delta_angles[YAW] += amove[YAW];
}
/* figure movement due to the pusher's amove */
VectorSubtract(check->s.origin, pusher->s.origin, org);
org2[0] = DotProduct(org, forward);
@ -732,11 +734,6 @@ SV_Push(edict_t *pusher, vec3_t move, vec3_t amove)
VectorCopy(p->origin, p->ent->s.origin);
VectorCopy(p->angles, p->ent->s.angles);
if (p->ent->client)
{
p->ent->client->ps.pmove.delta_angles[YAW] = p->deltayaw;
}
gi.linkentity(p->ent);
}
@ -893,6 +890,12 @@ SV_Physics_Toss(edict_t *ent)
/* regular thinking */
SV_RunThink(ent);
/* entities are very often freed during thinking */
if (!ent->inuse)
{
return;
}
/* if not a team captain, so movement will be handled elsewhere */
if (ent->flags & FL_TEAMSLAVE)
{
@ -984,7 +987,11 @@ SV_Physics_Toss(edict_t *ent)
if (!wasinwater && isinwater)
{
gi.positioned_sound(old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
/* don't play splash sound for entities already in water on level start */
if (level.framenum > 3)
{
gi.positioned_sound(old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
}
}
else if (wasinwater && !isinwater)
{

View file

@ -897,6 +897,9 @@ SpawnEntities(const char *mapname, char *entities, const char *spawnpoint)
ent->s.renderfx |= RF_IR_VISIBLE;
}
/* in case the last entity in the entstring has spawntemp fields */
memset(&st, 0, sizeof(st));
gi.dprintf("%i entities inhibited.\n", inhibit);
G_FindTeams();

View file

@ -158,11 +158,11 @@ SV_FilterPacket(char *from)
{
if ((in & ipfilters[i].mask) == ipfilters[i].compare)
{
return (int)filterban->value;
return (filterban->value != 0);
}
}
return (int)!filterban->value;
return (filterban->value == 0);
}
void

View file

@ -7,6 +7,9 @@
#include "header/local.h"
#define TARGET_HELP_PRIMARY 1
#define TARGET_HELP_THINK_DELAY 0.3f
#define LASER_ON 0x0001
#define LASER_RED 0x0002
#define LASER_GREEN 0x0004
@ -153,6 +156,50 @@ SP_target_speaker(edict_t *ent)
/* ========================================================== */
static void
Target_Help_Apply(const char *msg, int is_primary)
{
char *curr;
size_t sz;
if (!msg)
{
return;
}
if (is_primary)
{
curr = game.helpmessage1;
sz = sizeof(game.helpmessage1);
}
else
{
curr = game.helpmessage2;
sz = sizeof(game.helpmessage2);
}
if (strcmp(curr, msg) == 0)
{
return;
}
Q_strlcpy(curr, msg, sz - 1);
game.helpchanged++;
}
void
Target_Help_Think(edict_t *ent)
{
if (!ent)
{
return;
}
Target_Help_Apply(ent->message, ent->spawnflags & TARGET_HELP_PRIMARY);
ent->think = NULL;
}
void
Use_Target_Help(edict_t *ent, edict_t *other /* unused */, edict_t *activator /* unused */)
{
@ -161,16 +208,18 @@ Use_Target_Help(edict_t *ent, edict_t *other /* unused */, edict_t *activator /*
return;
}
if (ent->spawnflags & 1)
if (level.time > TARGET_HELP_THINK_DELAY)
{
strncpy(game.helpmessage1, ent->message, sizeof(game.helpmessage2) - 1);
Target_Help_Apply(ent->message, ent->spawnflags & TARGET_HELP_PRIMARY);
}
else
{
strncpy(game.helpmessage2, ent->message, sizeof(game.helpmessage1) - 1);
/* The game is still pre-loading so delay the help message a bit,
otherwise its changes to game structure will leak past save loads
*/
ent->think = Target_Help_Think;
ent->nextthink = TARGET_HELP_THINK_DELAY;
}
game.helpchanged++;
}
/*

View file

@ -8,7 +8,7 @@
#include "header/local.h"
qboolean FindTarget(edict_t *self);
void infantry_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage);
void infantry_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
void infantry_stand(edict_t *self);
void monster_use(edict_t *self, edict_t *other, edict_t *activator);
void SpawnTargetingSystem(edict_t *turret);
@ -419,7 +419,7 @@ turret_driver_die(edict_t *self, edict_t *inflictor, edict_t *attacker,
self->target_ent->owner = NULL;
self->target_ent->teammaster->owner = NULL;
infantry_die(self, inflictor, attacker, damage);
infantry_die(self, inflictor, attacker, damage, point);
}
void

View file

@ -270,7 +270,7 @@ G_UseTargets(edict_t *ent, edict_t *activator)
edict_t *t;
edict_t *master;
if (!ent || !activator)
if (!ent)
{
return;
}
@ -292,7 +292,7 @@ G_UseTargets(edict_t *ent, edict_t *activator)
}
/* print the message */
if ((ent->message) && !(activator->svflags & SVF_MONSTER))
if (activator && (ent->message) && !(activator->svflags & SVF_MONSTER))
{
gi.centerprintf(activator, "%s", ent->message);
@ -330,6 +330,13 @@ G_UseTargets(edict_t *ent, edict_t *activator)
}
}
/* correct killcounter if a living monster gets killtargeted */
if ((t->monsterinfo.checkattack || strcmp (t->classname, "turret_driver") == 0) &&
!(t->monsterinfo.aiflags & (AI_GOOD_GUY|AI_DO_NOT_COUNT)) && t->deadflag != DEAD_DEAD)
{
level.killed_monsters++;
}
G_FreeEdict(t);
if (!ent->inuse)
@ -662,40 +669,66 @@ G_InitEdict(edict_t *e)
}
/*
* Either finds a free edict, or allocates a new one.
* Try to avoid reusing an entity that was recently freed,
* because it can cause the client to think the entity
* morphed into something else instead of being removed
* and recreated, which can cause interpolated angles and
* bad trails.
* Either finds a free edict, or allocates a
* new one. Try to avoid reusing an entity
* that was recently freed, because it can
* cause the client to think the entity
* morphed into something else instead of
* being removed and recreated, which can
* cause interpolated angles and bad trails.
*/
edict_t *
G_Spawn(void)
#define POLICY_DEFAULT 0
#define POLICY_DESPERATE 1
static edict_t *
G_FindFreeEdict(int policy)
{
int i;
edict_t *e;
e = &g_edicts[(int)maxclients->value + 1];
for (i = maxclients->value + 1; i < globals.num_edicts; i++, e++)
for (e = g_edicts + game.maxclients + 1 ; e < &g_edicts[globals.num_edicts] ; e++)
{
/* the first couple seconds of server time can involve a lot of
freeing and allocating, so relax the replacement policy */
if (!e->inuse &&
((e->freetime < 2) || (level.time - e->freetime > 0.5)))
freeing and allocating, so relax the replacement policy
*/
if (!e->inuse && (policy == POLICY_DESPERATE || e->freetime < 2.0f || (level.time - e->freetime) > 0.5f))
{
G_InitEdict(e);
G_InitEdict (e);
return e;
}
}
if (i == game.maxentities)
return NULL;
}
edict_t *
G_SpawnOptional(void)
{
edict_t *e = G_FindFreeEdict (POLICY_DEFAULT);
if (e)
{
gi.error("ED_Alloc: no free edicts");
return e;
}
globals.num_edicts++;
G_InitEdict(e);
if (globals.num_edicts >= game.maxentities)
{
return G_FindFreeEdict (POLICY_DESPERATE);
}
e = &g_edicts[globals.num_edicts++];
G_InitEdict (e);
return e;
}
edict_t *
G_Spawn(void)
{
edict_t *e = G_SpawnOptional();
if (!e)
gi.error ("ED_Alloc: no free edicts");
return e;
}

View file

@ -981,7 +981,14 @@ bfg_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
gi.sound(self, CHAN_VOICE, gi.soundindex("weapons/bfg__x1b.wav"), 1, ATTN_NORM, 0);
self->solid = SOLID_NOT;
self->touch = NULL;
VectorMA(self->s.origin, -1 * FRAMETIME, self->velocity, self->s.origin);
/* move it back a bit from walls so the effects aren't cut off */
if (!other->takedamage)
{
VectorNormalize(self->velocity);
VectorMA(self->s.origin, -40.0f, self->velocity, self->s.origin);
}
VectorClear(self->velocity);
self->s.modelindex = gi.modelindex("sprites/s_bfg3.sp2");
self->s.frame = 0;
@ -991,6 +998,8 @@ bfg_touch(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
self->nextthink = level.time + FRAMETIME;
self->enemy = other;
gi.linkentity(self);
gi.WriteByte(svc_temp_entity);
gi.WriteByte(TE_BFG_BIGEXPLOSION);
gi.WritePosition(self->s.origin);

View file

@ -60,6 +60,7 @@
#define FL_TEAMSLAVE 0x00000400 /* not the first on the team */
#define FL_NO_KNOCKBACK 0x00000800
#define FL_POWER_ARMOR 0x00001000 /* power armor (if any) is active */
#define FL_COOP_TAKEN 0x00002000 /* Another client has already taken it */
#define FL_RESPAWN 0x80000000 /* used for item respawning */
#define FL_MECHANICAL 0x00002000 /* entity is mechanical, use sparks not blood */
@ -232,6 +233,7 @@ typedef struct
#define IT_POWERUP 0x00000020
#define IT_MELEE 0x00000040
#define IT_NOT_GIVEABLE 0x00000080 /* item can not be given */
#define IT_INSTANT_USE 0x000000100 /* item is insta-used on pickup if dmflag is set */
/* gitem_t->weapmodel for weapons indicates model index */
#define WEAP_BLASTER 1
@ -583,6 +585,8 @@ extern cvar_t *maxentities;
extern cvar_t *deathmatch;
extern cvar_t *coop;
extern cvar_t *coop_baseq2; /* treat spawnflags according to baseq2 rules */
extern cvar_t *coop_elevator_delay;
extern cvar_t *coop_pickup_weapons;
extern cvar_t *dmflags;
extern cvar_t *skill;
extern cvar_t *fraglimit;
@ -591,6 +595,9 @@ extern cvar_t *password;
extern cvar_t *spectator_password;
extern cvar_t *g_select_empty;
extern cvar_t *dedicated;
extern cvar_t *g_footsteps;
extern cvar_t *g_monsterfootsteps;
extern cvar_t *g_fix_triggered;
extern cvar_t *filterban;
@ -627,6 +634,11 @@ extern cvar_t *randomrespawn;
extern cvar_t *g_disruptor;
extern cvar_t *aimfix;
extern cvar_t *g_machinegun_norecoil;
extern cvar_t *g_quick_weap;
extern cvar_t *g_swap_speed;
/* this is for the count of monsters */
#define ENT_SLOTS_LEFT \
(ent->monsterinfo.monster_slots - \
@ -713,6 +725,7 @@ void G_UseTargets(edict_t *ent, edict_t *activator);
void G_SetMovedir(vec3_t angles, vec3_t movedir);
void G_InitEdict(edict_t *e);
edict_t *G_SpawnOptional(void);
edict_t *G_Spawn(void);
void G_FreeEdict(edict_t *e);
@ -955,6 +968,8 @@ edict_t *PickCoopTarget(edict_t *self);
int CountPlayers(void);
void monster_jump_start(edict_t *self);
qboolean monster_jump_finished(edict_t *self);
qboolean blind_rocket_ok (edict_t *self, vec3_t start, vec3_t right,
vec3_t target, float ofs, vec3_t dir);
/* g_sphere.c */
void Defender_Launch(edict_t *self);
@ -1238,8 +1253,8 @@ struct edict_s
int max_health;
int gib_health;
int deadflag;
int show_hostile;
float show_hostile;
float powerarmor_time;
char *map; /* target_changelevel */
@ -1249,7 +1264,7 @@ struct edict_s
int dmg;
int radius_dmg;
float dmg_radius;
int sounds; /* make this a spawntemp var? */
int sounds; /* now also used for player death sound aggregation */
int count;
edict_t *chain;

View file

@ -18,8 +18,21 @@
#include <stdlib.h>
#include <time.h>
typedef unsigned char byte;
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L // C23 or newer
typedef bool qboolean;
#else
#ifdef true
#undef true
#endif
#ifdef false
#undef false
#endif
typedef enum {false, true} qboolean;
#endif
typedef unsigned char byte;
#ifndef NULL
#define NULL ((void *)0)
@ -204,7 +217,7 @@ float BigFloat(float l);
float LittleFloat(float l);
void Swap_Init(void);
char *va(char *format, ...);
char *va(const char *format, ...);
/* ============================================= */

View file

@ -1,4 +1,23 @@
/* =======================================================================
/*
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* The berserker.
*
@ -15,8 +34,35 @@ static int sound_punch;
static int sound_sight;
static int sound_search;
static int sound_step;
static int sound_step2;
void berserk_fidget(edict_t *self);
void
berserk_footstep(edict_t *self)
{
if (!g_monsterfootsteps->value)
return;
// Lazy loading for savegame compatibility.
if (sound_step == 0 || sound_step2 == 0)
{
sound_step = gi.soundindex("berserk/step1.wav");
sound_step2 = gi.soundindex("berserk/step2.wav");
}
if (randk() % 2 == 0)
{
gi.sound(self, CHAN_BODY, sound_step, 1, ATTN_NORM, 0);
}
else
{
gi.sound(self, CHAN_BODY, sound_step2, 1, ATTN_NORM, 0);
}
}
void
berserk_sight(edict_t *self, edict_t *other)
{
@ -39,7 +85,7 @@ berserk_search(edict_t *self)
gi.sound(self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
}
mframe_t berserk_frames_stand[] = {
static mframe_t berserk_frames_stand[] = {
{ai_stand, 0, berserk_fidget},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -47,11 +93,12 @@ mframe_t berserk_frames_stand[] = {
{ai_stand, 0, NULL}
};
mmove_t berserk_move_stand = {
mmove_t berserk_move_stand =
{
FRAME_stand1,
FRAME_stand5,
berserk_frames_stand,
NULL
FRAME_stand5,
berserk_frames_stand,
NULL
};
void
@ -65,7 +112,7 @@ berserk_stand(edict_t *self)
self->monsterinfo.currentmove = &berserk_move_stand;
}
mframe_t berserk_frames_stand_fidget[] = {
static mframe_t berserk_frames_stand_fidget[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -88,7 +135,8 @@ mframe_t berserk_frames_stand_fidget[] = {
{ai_stand, 0, NULL}
};
mmove_t berserk_move_stand_fidget = {
mmove_t berserk_move_stand_fidget =
{
FRAME_standb1,
FRAME_standb20,
berserk_frames_stand_fidget,
@ -122,26 +170,27 @@ berserk_fidget(edict_t *self)
gi.sound(self, CHAN_WEAPON, sound_idle, 1, ATTN_IDLE, 0);
}
mframe_t berserk_frames_walk[] = {
static mframe_t berserk_frames_walk[] = {
{ai_walk, 9.1, NULL},
{ai_walk, 6.3, NULL},
{ai_walk, 4.9, NULL},
{ai_walk, 6.7, NULL},
{ai_walk, 6.7, berserk_footstep},
{ai_walk, 6.0, NULL},
{ai_walk, 8.2, NULL},
{ai_walk, 7.2, NULL},
{ai_walk, 6.1, NULL},
{ai_walk, 4.9, NULL},
{ai_walk, 4.9, berserk_footstep},
{ai_walk, 4.7, NULL},
{ai_walk, 4.7, NULL},
{ai_walk, 4.8, NULL}
};
mmove_t berserk_move_walk = {
mmove_t berserk_move_walk =
{
FRAME_walkc1,
FRAME_walkc11,
berserk_frames_walk,
NULL
FRAME_walkc11,
berserk_frames_walk,
NULL
};
void
@ -155,20 +204,21 @@ berserk_walk(edict_t *self)
self->monsterinfo.currentmove = &berserk_move_walk;
}
mframe_t berserk_frames_run1[] = {
static mframe_t berserk_frames_run1[] = {
{ai_run, 21, NULL},
{ai_run, 11, NULL},
{ai_run, 11, berserk_footstep},
{ai_run, 21, NULL},
{ai_run, 25, monster_done_dodge},
{ai_run, 18, NULL},
{ai_run, 18, berserk_footstep},
{ai_run, 19, NULL}
};
mmove_t berserk_move_run1 = {
mmove_t berserk_move_run1 =
{
FRAME_run1,
FRAME_run6,
berserk_frames_run1,
NULL
FRAME_run6,
berserk_frames_run1,
NULL
};
void
@ -214,7 +264,7 @@ berserk_swing(edict_t *self)
gi.sound(self, CHAN_WEAPON, sound_punch, 1, ATTN_NORM, 0);
}
mframe_t berserk_frames_attack_spike[] = {
static mframe_t berserk_frames_attack_spike[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, berserk_swing},
@ -225,11 +275,12 @@ mframe_t berserk_frames_attack_spike[] = {
{ai_charge, 0, NULL}
};
mmove_t berserk_move_attack_spike = {
mmove_t berserk_move_attack_spike =
{
FRAME_att_c1,
FRAME_att_c8,
berserk_frames_attack_spike,
berserk_run
FRAME_att_c8,
berserk_frames_attack_spike,
berserk_run
};
void
@ -246,10 +297,10 @@ berserk_attack_club(edict_t *self)
fire_hit(self, aim, (5 + (rand() % 6)), 400);
}
mframe_t berserk_frames_attack_club[] = {
{ai_charge, 0, NULL},
static mframe_t berserk_frames_attack_club[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, berserk_footstep},
{ai_charge, 0, NULL},
{ai_charge, 0, berserk_swing},
{ai_charge, 0, NULL},
@ -261,11 +312,12 @@ mframe_t berserk_frames_attack_club[] = {
{ai_charge, 0, NULL}
};
mmove_t berserk_move_attack_club = {
mmove_t berserk_move_attack_club =
{
FRAME_att_c9,
FRAME_att_c20,
berserk_frames_attack_club,
berserk_run
FRAME_att_c20,
berserk_frames_attack_club,
berserk_run
};
void
@ -273,28 +325,29 @@ berserk_strike(edict_t *self)
{
}
mframe_t berserk_frames_attack_strike[] = {
{ai_move, 0, NULL},
static mframe_t berserk_frames_attack_strike[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, berserk_footstep},
{ai_move, 0, berserk_swing},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, berserk_strike},
{ai_move, 0, NULL},
{ai_move, 0, berserk_footstep},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 9.7, NULL},
{ai_move, 13.6, NULL}
{ai_move, 13.6, berserk_footstep}
};
mmove_t berserk_move_attack_strike = {
mmove_t berserk_move_attack_strike =
{
FRAME_att_c21,
FRAME_att_c34,
berserk_frames_attack_strike,
berserk_run
FRAME_att_c34,
berserk_frames_attack_strike,
berserk_run
};
void
@ -317,21 +370,22 @@ berserk_melee(edict_t *self)
}
}
mframe_t berserk_frames_pain1[] = {
static mframe_t berserk_frames_pain1[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL}
};
mmove_t berserk_move_pain1 = {
mmove_t berserk_move_pain1 =
{
FRAME_painc1,
FRAME_painc4,
berserk_frames_pain1,
berserk_run
FRAME_painc4,
berserk_frames_pain1,
berserk_run
};
mframe_t berserk_frames_pain2[] = {
static mframe_t berserk_frames_pain2[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -354,15 +408,17 @@ mframe_t berserk_frames_pain2[] = {
{ai_move, 0, NULL}
};
mmove_t berserk_move_pain2 = {
mmove_t berserk_move_pain2 =
{
FRAME_painb1,
FRAME_painb20,
berserk_frames_pain2,
berserk_run
FRAME_painb20,
berserk_frames_pain2,
berserk_run
};
void
berserk_pain(edict_t *self, edict_t *other /* unused */, float kick, int damage)
berserk_pain(edict_t *self, edict_t *other /* unused */,
float kick /* unused */, int damage)
{
if (!self)
{
@ -415,7 +471,7 @@ berserk_dead(edict_t *self)
gi.linkentity(self);
}
mframe_t berserk_frames_death1[] = {
static mframe_t berserk_frames_death1[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -431,14 +487,15 @@ mframe_t berserk_frames_death1[] = {
{ai_move, 0, NULL}
};
mmove_t berserk_move_death1 = {
mmove_t berserk_move_death1 =
{
FRAME_death1,
FRAME_death13,
berserk_frames_death1,
berserk_dead
FRAME_death13,
berserk_frames_death1,
berserk_dead
};
mframe_t berserk_frames_death2[] = {
static mframe_t berserk_frames_death2[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -449,16 +506,17 @@ mframe_t berserk_frames_death2[] = {
{ai_move, 0, NULL}
};
mmove_t berserk_move_death2 = {
mmove_t berserk_move_death2 =
{
FRAME_deathc1,
FRAME_deathc8,
berserk_frames_death2,
berserk_dead
berserk_frames_death2,
berserk_dead
};
void
berserk_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* unused */,
int damage, vec3_t point)
int damage, vec3_t point /* unused */)
{
int n;
@ -473,15 +531,18 @@ berserk_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /*
for (n = 0; n < 2; n++)
{
ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
ThrowGib(self, "models/objects/gibs/bone/tris.md2",
damage, GIB_ORGANIC);
}
for (n = 0; n < 4; n++)
{
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2",
damage, GIB_ORGANIC);
}
ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
ThrowHead(self, "models/objects/gibs/head2/tris.md2",
damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
@ -562,7 +623,7 @@ berserk_jump_wait_land(edict_t *self)
}
}
mframe_t berserk_frames_jump[] = {
static mframe_t berserk_frames_jump[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -581,7 +642,7 @@ mmove_t berserk_move_jump = {
berserk_run
};
mframe_t berserk_frames_jump2[] = {
static mframe_t berserk_frames_jump2[] = {
{ai_move, -8, NULL},
{ai_move, -4, NULL},
{ai_move, -4, NULL},
@ -674,6 +735,11 @@ SP_monster_berserk(edict_t *self)
return;
}
// Force recaching at next footstep to ensure
// that the sound indices are correct.
sound_step = 0;
sound_step2 = 0;
/* pre-caches */
sound_pain = gi.soundindex("berserk/berpain2.wav");
sound_die = gi.soundindex("berserk/berdeth2.wav");

View file

@ -99,7 +99,7 @@ Boss2PredictiveRocket(edict_t *self)
VectorSubtract(vec, start, dir);
VectorNormalize(dir);
monster_fire_rocket(self, start, dir, 50, BOSS2_ROCKET_SPEED, MZ2_BOSS2_ROCKET_4);
}
}
void
Boss2Rocket(edict_t *self)
@ -159,7 +159,7 @@ Boss2Rocket(edict_t *self)
VectorMA(dir, -0.4, right, dir);
VectorNormalize(dir);
monster_fire_rocket(self, start, dir, 50, 500, MZ2_BOSS2_ROCKET_4);
}
}
void
boss2_firebullet_right(edict_t *self)
@ -222,7 +222,7 @@ Boss2MachineGun(edict_t *self)
boss2_firebullet_right(self);
}
mframe_t boss2_frames_stand[] = {
static mframe_t boss2_frames_stand[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -253,7 +253,7 @@ mmove_t boss2_move_stand = {
NULL
};
mframe_t boss2_frames_fidget[] = {
static mframe_t boss2_frames_fidget[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -293,7 +293,7 @@ mmove_t boss2_move_fidget = {
NULL
};
mframe_t boss2_frames_walk[] = {
static mframe_t boss2_frames_walk[] = {
{ai_walk, 10, NULL},
{ai_walk, 10, NULL},
{ai_walk, 10, NULL},
@ -323,7 +323,7 @@ mmove_t boss2_move_walk = {
NULL
};
mframe_t boss2_frames_run[] = {
static mframe_t boss2_frames_run[] = {
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL},
@ -353,7 +353,7 @@ mmove_t boss2_move_run = {
NULL
};
mframe_t boss2_frames_attack_pre_mg[] = {
static mframe_t boss2_frames_attack_pre_mg[] = {
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
@ -373,7 +373,7 @@ mmove_t boss2_move_attack_pre_mg = {
};
/* Loop this */
mframe_t boss2_frames_attack_mg[] = {
static mframe_t boss2_frames_attack_mg[] = {
{ai_charge, 2, Boss2MachineGun},
{ai_charge, 2, Boss2MachineGun},
{ai_charge, 2, Boss2MachineGun},
@ -389,7 +389,7 @@ mmove_t boss2_move_attack_mg = {
NULL
};
mframe_t boss2_frames_attack_post_mg[] = {
static mframe_t boss2_frames_attack_post_mg[] = {
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
@ -404,7 +404,7 @@ mmove_t boss2_move_attack_post_mg = {
boss2_run
};
mframe_t boss2_frames_attack_rocket[] = {
static mframe_t boss2_frames_attack_rocket[] = {
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
@ -434,7 +434,7 @@ mmove_t boss2_move_attack_rocket = {FRAME_attack20,
boss2_run
};
mframe_t boss2_frames_pain_heavy[] = {
static mframe_t boss2_frames_pain_heavy[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -462,7 +462,7 @@ mmove_t boss2_move_pain_heavy = {
boss2_run
};
mframe_t boss2_frames_pain_light[] = {
static mframe_t boss2_frames_pain_light[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -476,7 +476,7 @@ mmove_t boss2_move_pain_light = {
boss2_run
};
mframe_t boss2_frames_death[] = {
static mframe_t boss2_frames_death[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},

View file

@ -65,7 +65,7 @@ jorg_search(edict_t *self)
}
/* stand */
mframe_t jorg_frames_stand[] = {
static mframe_t jorg_frames_stand[] = {
{ai_stand, 0, jorg_idle},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -181,7 +181,7 @@ jorg_stand(edict_t *self)
self->monsterinfo.currentmove = &jorg_move_stand;
}
mframe_t jorg_frames_run[] = {
static mframe_t jorg_frames_run[] = {
{ai_run, 17, jorg_step_left},
{ai_run, 0, NULL},
{ai_run, 0, NULL},
@ -206,7 +206,7 @@ mmove_t jorg_move_run = {
};
/* walk */
mframe_t jorg_frames_start_walk[] = {
static mframe_t jorg_frames_start_walk[] = {
{ai_walk, 5, NULL},
{ai_walk, 6, NULL},
{ai_walk, 7, NULL},
@ -221,7 +221,7 @@ mmove_t jorg_move_start_walk = {
NULL
};
mframe_t jorg_frames_walk[] = {
static mframe_t jorg_frames_walk[] = {
{ai_walk, 17, NULL},
{ai_walk, 0, NULL},
{ai_walk, 0, NULL},
@ -245,7 +245,7 @@ mmove_t jorg_move_walk = {
NULL
};
mframe_t jorg_frames_end_walk[] = {
static mframe_t jorg_frames_end_walk[] = {
{ai_walk, 11, NULL},
{ai_walk, 0, NULL},
{ai_walk, 0, NULL},
@ -290,7 +290,7 @@ jorg_run(edict_t *self)
}
}
mframe_t jorg_frames_pain3[] = {
static mframe_t jorg_frames_pain3[] = {
{ai_move, -28, NULL},
{ai_move, -6, NULL},
{ai_move, -3, jorg_step_left},
@ -325,7 +325,7 @@ mmove_t jorg_move_pain3 = {
jorg_run
};
mframe_t jorg_frames_pain2[] = {
static mframe_t jorg_frames_pain2[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL}
@ -338,7 +338,7 @@ mmove_t jorg_move_pain2 = {
jorg_run
};
mframe_t jorg_frames_pain1[] = {
static mframe_t jorg_frames_pain1[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL}
@ -351,7 +351,7 @@ mmove_t jorg_move_pain1 = {
jorg_run
};
mframe_t jorg_frames_death1[] = {
static mframe_t jorg_frames_death1[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -411,7 +411,7 @@ mmove_t jorg_move_death = {
jorg_dead
};
mframe_t jorg_frames_attack2[] = {
static mframe_t jorg_frames_attack2[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -434,7 +434,7 @@ mmove_t jorg_move_attack2 = {
jorg_run
};
mframe_t jorg_frames_start_attack1[] = {
static mframe_t jorg_frames_start_attack1[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -452,7 +452,7 @@ mmove_t jorg_move_start_attack1 = {
jorg_attack1
};
mframe_t jorg_frames_attack1[] = {
static mframe_t jorg_frames_attack1[] = {
{ai_charge, 0, jorg_firebullet},
{ai_charge, 0, jorg_firebullet},
{ai_charge, 0, jorg_firebullet},
@ -468,7 +468,7 @@ mmove_t jorg_move_attack1 = {
jorg_reattack1
};
mframe_t jorg_frames_end_attack1[] = {
static mframe_t jorg_frames_end_attack1[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -875,8 +875,8 @@ SP_monster_jorg(edict_t *self)
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex("models/monsters/boss3/rider/tris.md2");
self->s.modelindex2 = gi.modelindex("models/monsters/boss3/jorg/tris.md2");
self->s.modelindex = gi.modelindex("models/monsters/boss3/jorg/tris.md2");
self->s.modelindex2 = gi.modelindex("models/monsters/boss3/rider/tris.md2");
VectorSet(self->mins, -80, -80, 0);
VectorSet(self->maxs, 80, 80, 140);

View file

@ -60,7 +60,7 @@ makron_taunt(edict_t *self)
}
/* stand */
mframe_t makron_frames_stand[] = {
static mframe_t makron_frames_stand[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -141,7 +141,7 @@ makron_stand(edict_t *self)
self->monsterinfo.currentmove = &makron_move_stand;
}
mframe_t makron_frames_run[] = {
static mframe_t makron_frames_run[] = {
{ai_run, 3, makron_step_left},
{ai_run, 12, NULL},
{ai_run, 8, NULL},
@ -227,19 +227,6 @@ makron_prerailgun(edict_t *self)
gi.sound(self, CHAN_WEAPON, sound_prerailgun, 1, ATTN_NORM, 0);
}
mframe_t makron_frames_walk[] = {
{ai_walk, 3, makron_step_left},
{ai_walk, 12, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, makron_step_right},
{ai_walk, 6, NULL},
{ai_walk, 12, NULL},
{ai_walk, 9, NULL},
{ai_walk, 6, NULL},
{ai_walk, 12, NULL}
};
mmove_t makron_move_walk = {
FRAME_walk204,
FRAME_walk213,
@ -276,7 +263,7 @@ makron_run(edict_t *self)
}
}
mframe_t makron_frames_pain6[] = {
static mframe_t makron_frames_pain6[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -313,7 +300,7 @@ mmove_t makron_move_pain6 = {
makron_run
};
mframe_t makron_frames_pain5[] = {
static mframe_t makron_frames_pain5[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -327,7 +314,7 @@ mmove_t makron_move_pain5 = {
makron_run
};
mframe_t makron_frames_pain4[] = {
static mframe_t makron_frames_pain4[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -341,7 +328,7 @@ mmove_t makron_move_pain4 = {
makron_run
};
mframe_t makron_frames_death2[] = {
static mframe_t makron_frames_death2[] = {
{ai_move, -15, NULL},
{ai_move, 3, NULL},
{ai_move, -12, NULL},
@ -446,7 +433,7 @@ mmove_t makron_move_death2 = {
makron_dead
};
mframe_t makron_frames_death3[] = {
static mframe_t makron_frames_death3[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -476,7 +463,7 @@ mmove_t makron_move_death3 = {
NULL
};
mframe_t makron_frames_sight[] = {
static mframe_t makron_frames_sight[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -524,7 +511,7 @@ makronBFG(edict_t *self)
monster_fire_bfg(self, start, dir, 50, 300, 100, 300, MZ2_MAKRON_BFG);
}
mframe_t makron_frames_attack3[] = {
static mframe_t makron_frames_attack3[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -542,7 +529,7 @@ mmove_t makron_move_attack3 = {
makron_run
};
mframe_t makron_frames_attack4[] = {
static mframe_t makron_frames_attack4[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -578,7 +565,7 @@ mmove_t makron_move_attack4 = {
makron_run
};
mframe_t makron_frames_attack5[] = {
static mframe_t makron_frames_attack5[] = {
{ai_charge, 0, makron_prerailgun},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -757,12 +744,6 @@ makron_pain(edict_t *self, edict_t *other /* unused */, float kick, int damage)
void
makron_sight(edict_t *self, edict_t *other /* unused */)
{
if (!self)
{
return;
}
self->monsterinfo.currentmove = &makron_move_sight;
}
void
@ -799,7 +780,14 @@ makron_torso_think(edict_t *self)
return;
}
if (self->owner && self->owner->inuse && self->owner->deadflag != DEAD_DEAD)
/* detach from the makron if the legs are gone completely */
if (self->owner && (!self->owner->inuse || (self->owner->health <= self->owner->gib_health)))
{
self->owner = NULL;
}
/* if the makron is revived the torso was put back on him */
if (self->owner && self->owner->deadflag != DEAD_DEAD)
{
G_FreeEdict(self);
return;
@ -824,24 +812,84 @@ makron_torso_think(edict_t *self)
self->nextthink = level.time + FRAMETIME;
}
void
makron_torso(edict_t *ent)
static void
makron_torso_origin(edict_t *self, edict_t *torso)
{
if (!ent)
vec3_t v;
trace_t tr;
AngleVectors(self->s.angles, v, NULL, NULL);
VectorMA(self->s.origin, -84.0f, v, v);
tr = gi.trace(self->s.origin, torso->mins, torso->maxs, v, self, MASK_SOLID);
VectorCopy (tr.endpos, torso->s.origin);
}
void
makron_torso_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* unused */,
int damage /* unused */, vec3_t point /* unused */)
{
int n;
if (self->health > self->gib_health)
{
return;
}
ent->movetype = MOVETYPE_NONE;
ent->solid = SOLID_NOT;
VectorSet(ent->mins, -8, -8, 0);
VectorSet(ent->maxs, 8, 8, 8);
ent->s.frame = FRAME_death301;
ent->s.modelindex = gi.modelindex("models/monsters/boss3/rider/tris.md2");
ent->think = makron_torso_think;
ent->nextthink = level.time + 2 * FRAMETIME;
ent->s.sound = gi.soundindex("makron/spine.wav");
gi.linkentity(ent);
gi.sound(self, CHAN_VOICE, gi.soundindex( "misc/udeath.wav"), 1, ATTN_NORM, 0);
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2",
damage, GIB_ORGANIC);
for (n = 0; n < 4; n++)
{
ThrowGib(self, "models/objects/gibs/sm_metal/tris.md2",
damage, GIB_METALLIC);
}
G_FreeEdict(self);
}
void
makron_torso(edict_t *self)
{
edict_t *torso;
if (!self)
{
return;
}
torso = G_SpawnOptional();
if (!torso)
{
return;
}
VectorCopy(self->s.angles, torso->s.angles);
VectorSet(torso->mins, -24, -24, 0);
VectorSet(torso->maxs, 24, 24, 16);
makron_torso_origin(self, torso);
torso->gib_health = -800;
torso->takedamage = DAMAGE_YES;
torso->die = makron_torso_die;
torso->deadflag = DEAD_DEAD;
torso->owner = self;
torso->movetype = MOVETYPE_TOSS;
torso->solid = SOLID_BBOX;
torso->svflags = SVF_MONSTER|SVF_DEADMONSTER;
torso->clipmask = MASK_MONSTERSOLID;
torso->s.frame = FRAME_death301;
torso->s.modelindex = gi.modelindex("models/monsters/boss3/rider/tris.md2");
torso->think = makron_torso_think;
torso->nextthink = level.time + 2 * FRAMETIME;
torso->s.sound = gi.soundindex("makron/spine.wav");
gi.linkentity(torso);
}
/* death */
@ -853,8 +901,8 @@ makron_dead(edict_t *self)
return;
}
VectorSet(self->mins, -60, -60, 0);
VectorSet(self->maxs, 60, 60, 72);
VectorSet(self->mins, -48, -48, 0);
VectorSet(self->maxs, 48, 48, 24);
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
self->nextthink = 0;
@ -865,7 +913,6 @@ void
makron_die(edict_t *self, edict_t *inflictor /* update */, edict_t *attacker /* update */,
int damage, vec3_t point /* update */)
{
edict_t *tempent;
int n;
if (!self)
@ -905,12 +952,11 @@ makron_die(edict_t *self, edict_t *inflictor /* update */, edict_t *attacker /*
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
tempent = G_Spawn();
VectorCopy(self->s.origin, tempent->s.origin);
VectorCopy(self->s.angles, tempent->s.angles);
tempent->s.origin[1] -= 84;
tempent->owner = self;
makron_torso(tempent);
makron_torso(self);
/* lower bbox since the torso is gone */
self->maxs[2] = 64;
gi.linkentity (self);
self->monsterinfo.currentmove = &makron_move_death2;
}
@ -1098,29 +1144,72 @@ void
MakronSpawn(edict_t *self)
{
vec3_t vec;
edict_t *player;
edict_t *enemy;
edict_t *oldenemy;
if (!self)
{
return;
}
/* spawning can mess with enemy state so clear it temporarily */
enemy = self->enemy;
self->enemy = NULL;
oldenemy = self->oldenemy;
self->oldenemy = NULL;
SP_monster_makron(self);
/* jump at player */
player = level.sight_client;
if (!player)
if (self->think)
{
return;
self->think(self);
}
VectorSubtract(player->s.origin, self->s.origin, vec);
self->s.angles[YAW] = vectoyaw(vec);
VectorNormalize(vec);
VectorMA(vec3_origin, 400, vec, self->velocity);
self->velocity[2] = 200;
/* and re-link enemy state now that he's spawned */
if (enemy && enemy->inuse && enemy->deadflag != DEAD_DEAD)
{
self->enemy = enemy;
}
if (oldenemy && oldenemy->inuse && oldenemy->deadflag != DEAD_DEAD)
{
self->oldenemy = oldenemy;
}
if (!self->enemy)
{
self->enemy = self->oldenemy;
self->oldenemy = NULL;
}
enemy = self->enemy;
if (enemy)
{
FoundTarget(self);
VectorCopy(self->pos1, self->monsterinfo.last_sighting);
}
if (enemy && visible(self, enemy))
{
VectorSubtract(enemy->s.origin, self->s.origin, vec);
self->s.angles[YAW] = vectoyaw(vec);
VectorNormalize(vec);
}
else
AngleVectors(self->s.angles, vec, NULL, NULL);
VectorScale(vec, 400, self->velocity);
/* the jump frames are fixed length so best to normalize the up speed */
self->velocity[2] = 200.0f * (sv_gravity->value / 800.0f);
self->groundentity = NULL;
self->s.origin[2] += 1;
gi.linkentity(self);
self->pain_debounce_time = level.time + 1;
self->monsterinfo.currentmove = &makron_move_sight;
}
/*
@ -1142,4 +1231,9 @@ MakronToss(edict_t *self)
ent->think = MakronSpawn;
ent->target = self->target;
VectorCopy(self->s.origin, ent->s.origin);
VectorCopy(self->s.angles, ent->s.angles);
VectorCopy(self->monsterinfo.last_sighting, ent->pos1);
ent->enemy = self->enemy;
ent->oldenemy = self->oldenemy;
}

View file

@ -1,4 +1,23 @@
/* =======================================================================
/*
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* Brain.
*
@ -23,9 +42,37 @@ static int sound_melee1;
static int sound_melee2;
static int sound_melee3;
static int sound_step;
static int sound_step2;
void brain_run(edict_t *self);
void brain_dead(edict_t *self);
void
brain_footstep(edict_t *self)
{
if (!g_monsterfootsteps->value)
return;
// Lazy loading for savegame compatibility.
if (sound_step == 0 || sound_step2 == 0)
{
sound_step = gi.soundindex("brain/step1.wav");
sound_step2 = gi.soundindex("brain/step2.wav");
}
if (randk() % 2 == 0)
{
gi.sound(self, CHAN_BODY, sound_step, 1, ATTN_NORM, 0);
}
else
{
gi.sound(self, CHAN_BODY, sound_step2, 1, ATTN_NORM, 0);
}
}
void
brain_sight(edict_t *self, edict_t *other /* unused */)
{
@ -49,7 +96,8 @@ brain_search(edict_t *self)
}
/* STAND */
mframe_t brain_frames_stand[] = {
static mframe_t brain_frames_stand[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -84,11 +132,12 @@ mframe_t brain_frames_stand[] = {
{ai_stand, 0, NULL}
};
mmove_t brain_move_stand = {
mmove_t brain_move_stand =
{
FRAME_stand01,
FRAME_stand30,
brain_frames_stand,
NULL
FRAME_stand30,
brain_frames_stand,
NULL
};
void
@ -103,7 +152,8 @@ brain_stand(edict_t *self)
}
/* IDLE */
mframe_t brain_frames_idle[] = {
static mframe_t brain_frames_idle[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -138,11 +188,12 @@ mframe_t brain_frames_idle[] = {
{ai_stand, 0, NULL}
};
mmove_t brain_move_idle = {
mmove_t brain_move_idle =
{
FRAME_stand31,
FRAME_stand60,
brain_frames_idle,
brain_stand
FRAME_stand60,
brain_frames_idle,
brain_stand
};
void
@ -158,25 +209,27 @@ brain_idle(edict_t *self)
}
/* WALK */
mframe_t brain_frames_walk1[] = {
static mframe_t brain_frames_walk1[] = {
{ai_walk, 7, NULL},
{ai_walk, 2, NULL},
{ai_walk, 3, NULL},
{ai_walk, 3, NULL},
{ai_walk, 3, brain_footstep},
{ai_walk, 1, NULL},
{ai_walk, 0, NULL},
{ai_walk, 0, NULL},
{ai_walk, 9, NULL},
{ai_walk, -4, NULL},
{ai_walk, -1, NULL},
{ai_walk, -1, brain_footstep},
{ai_walk, 2, NULL}
};
mmove_t brain_move_walk1 = {
mmove_t brain_move_walk1 =
{
FRAME_walk101,
FRAME_walk111,
brain_frames_walk1,
NULL
brain_frames_walk1,
NULL
};
void
@ -190,7 +243,7 @@ brain_walk(edict_t *self)
self->monsterinfo.currentmove = &brain_move_walk1;
}
mframe_t brain_frames_defense[] = {
static mframe_t brain_frames_defense[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -202,14 +255,15 @@ mframe_t brain_frames_defense[] = {
{ai_move, 0, NULL}
};
mmove_t brain_move_defense = {
mmove_t brain_move_defense =
{
FRAME_defens01,
FRAME_defens08,
brain_frames_defense,
NULL
FRAME_defens08,
brain_frames_defense,
NULL
};
mframe_t brain_frames_pain3[] = {
static mframe_t brain_frames_pain3[] = {
{ai_move, -2, NULL},
{ai_move, 2, NULL},
{ai_move, 1, NULL},
@ -218,14 +272,15 @@ mframe_t brain_frames_pain3[] = {
{ai_move, -4, NULL}
};
mmove_t brain_move_pain3 = {
mmove_t brain_move_pain3 =
{
FRAME_pain301,
FRAME_pain306,
brain_frames_pain3,
brain_run
FRAME_pain306,
brain_frames_pain3,
brain_run
};
mframe_t brain_frames_pain2[] = {
static mframe_t brain_frames_pain2[] = {
{ai_move, -2, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -236,17 +291,18 @@ mframe_t brain_frames_pain2[] = {
{ai_move, -2, NULL}
};
mmove_t brain_move_pain2 = {
mmove_t brain_move_pain2 =
{
FRAME_pain201,
FRAME_pain208,
brain_frames_pain2,
brain_run
};
mframe_t brain_frames_pain1[] = {
static mframe_t brain_frames_pain1[] = {
{ai_move, -6, NULL},
{ai_move, -2, NULL},
{ai_move, -6, NULL},
{ai_move, -6, brain_footstep},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -263,36 +319,38 @@ mframe_t brain_frames_pain1[] = {
{ai_move, 1, NULL},
{ai_move, 7, NULL},
{ai_move, 0, NULL},
{ai_move, 3, NULL},
{ai_move, 3, brain_footstep},
{ai_move, -1, NULL}
};
mmove_t brain_move_pain1 = {
mmove_t brain_move_pain1 =
{
FRAME_pain101,
FRAME_pain121,
brain_frames_pain1,
brain_run
FRAME_pain121,
brain_frames_pain1,
brain_run
};
mframe_t brain_frames_duck[] = {
static mframe_t brain_frames_duck[] = {
{ai_move, 0, NULL},
{ai_move, -2, monster_duck_down},
{ai_move, 17, monster_duck_hold},
{ai_move, -3, NULL},
{ai_move, -3, brain_footstep},
{ai_move, -1, monster_duck_up},
{ai_move, -5, NULL},
{ai_move, -6, NULL},
{ai_move, -6, NULL}
{ai_move, -6, brain_footstep}
};
mmove_t brain_move_duck = {
mmove_t brain_move_duck =
{
FRAME_duck01,
FRAME_duck08,
brain_frames_duck,
brain_run
};
mframe_t brain_frames_death2[] = {
static mframe_t brain_frames_death2[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -300,14 +358,15 @@ mframe_t brain_frames_death2[] = {
{ai_move, 0, NULL}
};
mmove_t brain_move_death2 = {
mmove_t brain_move_death2 =
{
FRAME_death201,
FRAME_death205,
brain_frames_death2,
brain_dead
brain_dead
};
mframe_t brain_frames_death1[] = {
static mframe_t brain_frames_death1[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, -2, NULL},
@ -328,7 +387,8 @@ mframe_t brain_frames_death1[] = {
{ai_move, 0, NULL}
};
mmove_t brain_move_death1 = {
mmove_t brain_move_death1 =
{
FRAME_death101,
FRAME_death118,
brain_frames_death1,
@ -336,6 +396,7 @@ mmove_t brain_move_death1 = {
};
/* MELEE */
void
brain_swing_right(edict_t *self)
{
@ -379,13 +440,13 @@ brain_swing_left(edict_t *self)
void
brain_hit_left(edict_t *self)
{
vec3_t aim;
if (!self)
{
return;
}
vec3_t aim;
VectorSet(aim, MELEE_DISTANCE, self->mins[0], 8);
if (fire_hit(self, aim, (15 + (rand() % 5)), 40))
@ -394,11 +455,11 @@ brain_hit_left(edict_t *self)
}
}
mframe_t brain_frames_attack1[] = {
static mframe_t brain_frames_attack1[] = {
{ai_charge, 8, NULL},
{ai_charge, 3, NULL},
{ai_charge, 5, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, brain_footstep},
{ai_charge, -3, brain_swing_right},
{ai_charge, 0, NULL},
{ai_charge, -5, NULL},
@ -412,14 +473,15 @@ mframe_t brain_frames_attack1[] = {
{ai_charge, -1, NULL},
{ai_charge, -3, NULL},
{ai_charge, 2, NULL},
{ai_charge, -11, NULL}
{ai_charge, -11, brain_footstep}
};
mmove_t brain_move_attack1 = {
mmove_t brain_move_attack1 =
{
FRAME_attak101,
FRAME_attak118,
brain_frames_attack1,
brain_run
FRAME_attak118,
brain_frames_attack1,
brain_run
};
void
@ -472,7 +534,7 @@ brain_chest_closed(edict_t *self)
}
}
mframe_t brain_frames_attack2[] = {
static mframe_t brain_frames_attack2[] = {
{ai_charge, 5, NULL},
{ai_charge, -4, NULL},
{ai_charge, -4, NULL},
@ -492,11 +554,12 @@ mframe_t brain_frames_attack2[] = {
{ai_charge, -6, NULL}
};
mmove_t brain_move_attack2 = {
mmove_t brain_move_attack2 =
{
FRAME_attak201,
FRAME_attak217,
brain_frames_attack2,
brain_run
FRAME_attak217,
brain_frames_attack2,
brain_run
};
void
@ -518,23 +581,25 @@ brain_melee(edict_t *self)
}
/* RUN */
mframe_t brain_frames_run[] = {
static mframe_t brain_frames_run[] = {
{ai_run, 9, NULL},
{ai_run, 2, NULL},
{ai_run, 3, NULL},
{ai_run, 3, NULL},
{ai_run, 3, brain_footstep},
{ai_run, 1, NULL},
{ai_run, 0, NULL},
{ai_run, 0, NULL},
{ai_run, 10, NULL},
{ai_run, -4, NULL},
{ai_run, -1, NULL},
{ai_run, -1, brain_footstep},
{ai_run, 2, NULL}
};
mmove_t brain_move_run = {
mmove_t brain_move_run =
{
FRAME_walk101,
FRAME_walk111,
FRAME_walk111,
brain_frames_run,
NULL
};
@ -560,8 +625,8 @@ brain_run(edict_t *self)
}
void
brain_pain(edict_t *self, edict_t *other /* unused */, float kick /* unused */,
int damage /* unused */)
brain_pain(edict_t *self, edict_t *other /* unused */,
float kick /* unused */, int damage /* unused */)
{
float r;
@ -645,19 +710,23 @@ brain_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* u
/* check for gib */
if (self->health <= self->gib_health)
{
gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"),
1, ATTN_NORM, 0);
for (n = 0; n < 2; n++)
{
ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
ThrowGib(self, "models/objects/gibs/bone/tris.md2",
damage, GIB_ORGANIC);
}
for (n = 0; n < 4; n++)
{
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2",
damage, GIB_ORGANIC);
}
ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
ThrowHead(self, "models/objects/gibs/head2/tris.md2",
damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
@ -725,6 +794,11 @@ SP_monster_brain(edict_t *self)
return;
}
// Force recaching at next footstep to ensure
// that the sound indices are correct.
sound_step = 0;
sound_step2 = 0;
sound_chest_open = gi.soundindex("brain/brnatck1.wav");
sound_tentacles_extend = gi.soundindex("brain/brnatck2.wav");
sound_tentacles_retract = gi.soundindex("brain/brnatck3.wav");

View file

@ -634,7 +634,7 @@ carrier_start_spawn(edict_t *self)
CarrierMachineGun(self);
}
mframe_t carrier_frames_stand[] = {
static mframe_t carrier_frames_stand[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -657,7 +657,7 @@ mmove_t carrier_move_stand = {
NULL
};
mframe_t carrier_frames_walk[] = {
static mframe_t carrier_frames_walk[] = {
{ai_walk, 4, NULL},
{ai_walk, 4, NULL},
{ai_walk, 4, NULL},
@ -680,7 +680,7 @@ mmove_t carrier_move_walk = {
NULL
};
mframe_t carrier_frames_run[] = {
static mframe_t carrier_frames_run[] = {
{ai_run, 6, CarrierCoopCheck},
{ai_run, 6, CarrierCoopCheck},
{ai_run, 6, CarrierCoopCheck},
@ -703,7 +703,7 @@ mmove_t carrier_move_run = {
NULL
};
mframe_t carrier_frames_attack_pre_mg[] = {
static mframe_t carrier_frames_attack_pre_mg[] = {
{ai_charge, 4, CarrierCoopCheck},
{ai_charge, 4, CarrierCoopCheck},
{ai_charge, 4, CarrierCoopCheck},
@ -722,7 +722,7 @@ mmove_t carrier_move_attack_pre_mg = {
};
/* Loop this */
mframe_t carrier_frames_attack_mg[] = {
static mframe_t carrier_frames_attack_mg[] = {
{ai_charge, -2, CarrierMachineGun},
{ai_charge, -2, CarrierMachineGun},
{ai_charge, -2, carrier_reattack_mg}
@ -735,7 +735,7 @@ mmove_t carrier_move_attack_mg = {
NULL
};
mframe_t carrier_frames_attack_post_mg[] = {
static mframe_t carrier_frames_attack_post_mg[] = {
{ai_charge, 4, CarrierCoopCheck},
{ai_charge, 4, CarrierCoopCheck},
{ai_charge, 4, CarrierCoopCheck},
@ -749,7 +749,7 @@ mmove_t carrier_move_attack_post_mg = {
carrier_run
};
mframe_t carrier_frames_attack_pre_gren[] = {
static mframe_t carrier_frames_attack_pre_gren[] = {
{ai_charge, 4, CarrierCoopCheck},
{ai_charge, 4, CarrierCoopCheck},
{ai_charge, 4, CarrierCoopCheck},
@ -765,7 +765,7 @@ mmove_t carrier_move_attack_pre_gren = {
NULL
};
mframe_t carrier_frames_attack_gren[] = {
static mframe_t carrier_frames_attack_gren[] = {
{ai_charge, -15, CarrierGrenade},
{ai_charge, 4, CarrierCoopCheck},
{ai_charge, 4, CarrierCoopCheck},
@ -779,7 +779,7 @@ mmove_t carrier_move_attack_gren = {
NULL
};
mframe_t carrier_frames_attack_post_gren[] = {
static mframe_t carrier_frames_attack_post_gren[] = {
{ai_charge, 4, CarrierCoopCheck},
{ai_charge, 4, CarrierCoopCheck},
{ai_charge, 4, CarrierCoopCheck},
@ -795,7 +795,7 @@ mmove_t carrier_move_attack_post_gren = {
carrier_run
};
mframe_t carrier_frames_attack_rocket[] = {
static mframe_t carrier_frames_attack_rocket[] = {
{ai_charge, 15, CarrierRocket}
};
@ -844,7 +844,7 @@ CarrierSaveLoc(edict_t *self)
self->pos1[2] += self->enemy->viewheight;
}
mframe_t carrier_frames_attack_rail[] = {
static mframe_t carrier_frames_attack_rail[] = {
{ai_charge, 2, CarrierCoopCheck},
{ai_charge, 2, CarrierSaveLoc},
{ai_charge, 2, CarrierCoopCheck},
@ -863,7 +863,7 @@ mmove_t carrier_move_attack_rail = {
carrier_run
};
mframe_t carrier_frames_spawn[] = {
static mframe_t carrier_frames_spawn[] = {
{ai_charge, -2, CarrierMachineGun},
{ai_charge, -2, CarrierMachineGun},
{ai_charge, -2, CarrierMachineGun},
@ -891,7 +891,7 @@ mmove_t carrier_move_spawn = {
NULL
};
mframe_t carrier_frames_pain_heavy[] = {
static mframe_t carrier_frames_pain_heavy[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -911,7 +911,7 @@ mmove_t carrier_move_pain_heavy = {
carrier_run
};
mframe_t carrier_frames_pain_light[] = {
static mframe_t carrier_frames_pain_light[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -925,7 +925,7 @@ mmove_t carrier_move_pain_light = {
carrier_run
};
mframe_t carrier_frames_death[] = {
static mframe_t carrier_frames_death[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},

View file

@ -1,4 +1,23 @@
/* =======================================================================
/*
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* Iron Maiden.
*
@ -34,6 +53,34 @@ static int sound_pain3;
static int sound_sight;
static int sound_search;
static int sound_step;
static int sound_step2;
void
chick_footstep(edict_t *self)
{
if (!g_monsterfootsteps->value)
return;
// Lazy loading for savegame compatibility.
if (sound_step == 0 || sound_step2 == 0)
{
sound_step = gi.soundindex("bitch/step1.wav");
sound_step2 = gi.soundindex("bitch/step2.wav");
}
if (randk() % 2 == 0)
{
gi.sound(self, CHAN_BODY, sound_step, 1, ATTN_NORM, 0);
}
else
{
gi.sound(self, CHAN_BODY, sound_step2, 1, ATTN_NORM, 0);
}
}
void
ChickMoan(edict_t *self)
{
@ -52,7 +99,7 @@ ChickMoan(edict_t *self)
}
}
mframe_t chick_frames_fidget[] = {
static mframe_t chick_frames_fidget[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -85,7 +132,8 @@ mframe_t chick_frames_fidget[] = {
{ai_stand, 0, NULL}
};
mmove_t chick_move_fidget = {
mmove_t chick_move_fidget =
{
FRAME_stand201,
FRAME_stand230,
chick_frames_fidget,
@ -111,7 +159,7 @@ chick_fidget(edict_t *self)
}
}
mframe_t chick_frames_stand[] = {
static mframe_t chick_frames_stand[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -144,7 +192,8 @@ mframe_t chick_frames_stand[] = {
{ai_stand, 0, chick_fidget},
};
mmove_t chick_move_stand = {
mmove_t chick_move_stand =
{
FRAME_stand101,
FRAME_stand130,
chick_frames_stand,
@ -162,7 +211,7 @@ chick_stand(edict_t *self)
self->monsterinfo.currentmove = &chick_move_stand;
}
mframe_t chick_frames_start_run[] = {
static mframe_t chick_frames_start_run[] = {
{ai_run, 1, NULL},
{ai_run, 0, NULL},
{ai_run, 0, NULL},
@ -175,47 +224,50 @@ mframe_t chick_frames_start_run[] = {
{ai_run, 3, NULL}
};
mmove_t chick_move_start_run = {
mmove_t chick_move_start_run =
{
FRAME_walk01,
FRAME_walk10,
chick_frames_start_run,
chick_run
};
mframe_t chick_frames_run[] = {
static mframe_t chick_frames_run[] = {
{ai_run, 6, NULL},
{ai_run, 8, NULL},
{ai_run, 8, chick_footstep},
{ai_run, 13, NULL},
{ai_run, 5, NULL},
{ai_run, 7, NULL},
{ai_run, 4, NULL},
{ai_run, 11, NULL},
{ai_run, 11, chick_footstep},
{ai_run, 5, NULL},
{ai_run, 9, NULL},
{ai_run, 7, NULL}
};
mmove_t chick_move_run = {
mmove_t chick_move_run =
{
FRAME_walk11,
FRAME_walk20,
chick_frames_run,
NULL
};
mframe_t chick_frames_walk[] = {
static mframe_t chick_frames_walk[] = {
{ai_walk, 6, NULL},
{ai_walk, 8, NULL},
{ai_walk, 8, chick_footstep},
{ai_walk, 13, NULL},
{ai_walk, 5, NULL},
{ai_walk, 7, NULL},
{ai_walk, 4, NULL},
{ai_walk, 11, NULL},
{ai_walk, 11, chick_footstep},
{ai_walk, 5, NULL},
{ai_walk, 9, NULL},
{ai_walk, 7, NULL}
};
mmove_t chick_move_walk = {
mmove_t chick_move_walk =
{
FRAME_walk11,
FRAME_walk20,
chick_frames_walk,
@ -260,7 +312,7 @@ chick_run(edict_t *self)
}
}
mframe_t chick_frames_pain1[] = {
static mframe_t chick_frames_pain1[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -268,28 +320,31 @@ mframe_t chick_frames_pain1[] = {
{ai_move, 0, NULL}
};
mmove_t chick_move_pain1 = {
mmove_t chick_move_pain1 =
{
FRAME_pain101,
FRAME_pain105,
chick_frames_pain1, chick_run
};
mframe_t chick_frames_pain2[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL}
};
mmove_t chick_move_pain2 = {
FRAME_pain201,
FRAME_pain205,
chick_frames_pain2,
chick_frames_pain1,
chick_run
};
mframe_t chick_frames_pain3[] = {
static mframe_t chick_frames_pain2[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL}
};
mmove_t chick_move_pain2 =
{
FRAME_pain201,
FRAME_pain205,
chick_frames_pain2,
chick_run
};
static mframe_t chick_frames_pain3[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, -6, NULL},
@ -313,15 +368,17 @@ mframe_t chick_frames_pain3[] = {
{ai_move, 2, NULL}
};
mmove_t chick_move_pain3 = {
mmove_t chick_move_pain3 =
{
FRAME_pain301,
FRAME_pain321,
chick_frames_pain3,
chick_frames_pain3,
chick_run
};
void
chick_pain(edict_t *self, edict_t *other /* other */, float kick /* other */, int damage)
chick_pain(edict_t *self, edict_t *other /* unused */,
float kick /* unused */, int damage)
{
float r;
@ -403,24 +460,24 @@ chick_dead(edict_t *self)
gi.linkentity(self);
}
mframe_t chick_frames_death2[] = {
static mframe_t chick_frames_death2[] = {
{ai_move, -6, NULL},
{ai_move, 0, NULL},
{ai_move, -1, NULL},
{ai_move, -5, NULL},
{ai_move, -5, chick_footstep},
{ai_move, 0, NULL},
{ai_move, -1, NULL},
{ai_move, -2, NULL},
{ai_move, 1, NULL},
{ai_move, 10, NULL},
{ai_move, 2, NULL},
{ai_move, 3, NULL},
{ai_move, 3, chick_footstep},
{ai_move, 1, NULL},
{ai_move, 2, NULL},
{ai_move, 0, NULL},
{ai_move, 3, NULL},
{ai_move, 3, NULL},
{ai_move, 1, NULL},
{ai_move, 1, chick_footstep},
{ai_move, -3, NULL},
{ai_move, -5, NULL},
{ai_move, 4, NULL},
@ -429,14 +486,15 @@ mframe_t chick_frames_death2[] = {
{ai_move, 1, NULL}
};
mmove_t chick_move_death2 = {
mmove_t chick_move_death2 =
{
FRAME_death201,
FRAME_death223,
chick_frames_death2,
chick_dead
};
mframe_t chick_frames_death1[] = {
static mframe_t chick_frames_death1[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, -7, NULL},
@ -451,16 +509,18 @@ mframe_t chick_frames_death1[] = {
{ai_move, 0, NULL}
};
mmove_t chick_move_death1 = {
mmove_t chick_move_death1 =
{
FRAME_death101,
FRAME_death112,
chick_frames_death1,
chick_dead
FRAME_death112,
chick_frames_death1,
chick_dead
};
void
chick_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* unused */,
int damage, vec3_t point /* unused */)
chick_die(edict_t *self, edict_t *inflictor /* unused */,
edict_t *attacker /* unused */, int damage,
vec3_t point /*unused */)
{
int n;
@ -472,20 +532,23 @@ chick_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* u
/* check for gib */
if (self->health <= self->gib_health)
{
gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"),
1, ATTN_NORM, 0);
for (n = 0; n < 2; n++)
{
ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage,
GIB_ORGANIC);
ThrowGib(self, "models/objects/gibs/bone/tris.md2",
damage, GIB_ORGANIC);
}
for (n = 0; n < 4; n++)
{
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2",
damage, GIB_ORGANIC);
}
ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
ThrowHead(self, "models/objects/gibs/head2/tris.md2",
damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
@ -513,7 +576,7 @@ chick_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* u
}
}
mframe_t chick_frames_duck[] = {
static mframe_t chick_frames_duck[] = {
{ai_move, 0, monster_duck_down},
{ai_move, 1, NULL},
{ai_move, 4, monster_duck_hold},
@ -625,58 +688,26 @@ ChickRocket(edict_t *self)
VectorNormalize(dir);
trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
if (blindfire)
{
/* blindfire has different fail criteria for the trace */
if (!(trace.startsolid || trace.allsolid || (trace.fraction < 0.5)))
if (!blind_rocket_ok(self, start, right, target, 10.0f, dir))
{
monster_fire_rocket(self, start, dir, 50,
rocketSpeed, MZ2_CHICK_ROCKET_1);
}
else
{
VectorCopy(target, vec);
VectorMA(vec, -10, right, vec);
VectorSubtract(vec, start, dir);
VectorNormalize(dir);
trace = gi.trace(start, vec3_origin, vec3_origin, vec,
self, MASK_SHOT);
if (!(trace.startsolid || trace.allsolid || (trace.fraction < 0.5)))
{
monster_fire_rocket(self, start, dir, 50, rocketSpeed, MZ2_CHICK_ROCKET_1);
}
else
{
/* ok, that failed. try to the right */
VectorCopy(target, vec);
VectorMA(vec, 10, right, vec);
VectorSubtract(vec, start, dir);
VectorNormalize(dir);
trace = gi.trace(start, vec3_origin, vec3_origin, vec,
self, MASK_SHOT);
if (!(trace.startsolid || trace.allsolid || (trace.fraction < 0.5)))
{
monster_fire_rocket(self, start, dir, 50, rocketSpeed, MZ2_CHICK_ROCKET_1);
}
}
return;
}
}
else
{
trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
if ((trace.ent == self->enemy) || (trace.ent == world))
if (((trace.ent != self->enemy) && (trace.ent != world)) ||
((trace.fraction <= 0.5f) && !trace.ent->client))
{
if ((trace.fraction > 0.5) || (trace.ent && trace.ent->client))
{
monster_fire_rocket(self, start, dir, 50, rocketSpeed, MZ2_CHICK_ROCKET_1);
}
return;
}
}
monster_fire_rocket(self, start, dir, 50, rocketSpeed, MZ2_CHICK_ROCKET_1);
}
void
@ -701,7 +732,7 @@ ChickReload(edict_t *self)
gi.sound(self, CHAN_VOICE, sound_missile_reload, 1, ATTN_NORM, 0);
}
mframe_t chick_frames_start_attack1[] = {
static mframe_t chick_frames_start_attack1[] = {
{ai_charge, 0, Chick_PreAttack1},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -710,57 +741,60 @@ mframe_t chick_frames_start_attack1[] = {
{ai_charge, -3, NULL},
{ai_charge, 3, NULL},
{ai_charge, 5, NULL},
{ai_charge, 7, NULL},
{ai_charge, 7, chick_footstep},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, chick_attack1}
};
mmove_t chick_move_start_attack1 = {
mmove_t chick_move_start_attack1 =
{
FRAME_attak101,
FRAME_attak113,
chick_frames_start_attack1,
NULL
FRAME_attak113,
chick_frames_start_attack1,
NULL
};
mframe_t chick_frames_attack1[] = {
static mframe_t chick_frames_attack1[] = {
{ai_charge, 19, ChickRocket},
{ai_charge, -6, NULL},
{ai_charge, -5, NULL},
{ai_charge, -5, chick_footstep},
{ai_charge, -2, NULL},
{ai_charge, -7, NULL},
{ai_charge, -7, chick_footstep},
{ai_charge, 0, NULL},
{ai_charge, 1, NULL},
{ai_charge, 10, ChickReload},
{ai_charge, 4, NULL},
{ai_charge, 5, NULL},
{ai_charge, 5, chick_footstep},
{ai_charge, 6, NULL},
{ai_charge, 6, NULL},
{ai_charge, 4, NULL},
{ai_charge, 4, chick_footstep},
{ai_charge, 3, chick_rerocket}
};
mmove_t chick_move_attack1 = {
mmove_t chick_move_attack1 =
{
FRAME_attak114,
FRAME_attak127,
chick_frames_attack1,
NULL
FRAME_attak127,
chick_frames_attack1,
NULL
};
mframe_t chick_frames_end_attack1[] = {
static mframe_t chick_frames_end_attack1[] = {
{ai_charge, -3, NULL},
{ai_charge, 0, NULL},
{ai_charge, -6, NULL},
{ai_charge, -4, NULL},
{ai_charge, -2, NULL}
{ai_charge, -2, chick_footstep}
};
mmove_t chick_move_end_attack1 = {
mmove_t chick_move_end_attack1 =
{
FRAME_attak128,
FRAME_attak132,
chick_frames_end_attack1,
chick_run
chick_run
};
void
@ -807,7 +841,7 @@ chick_attack1(edict_t *self)
self->monsterinfo.currentmove = &chick_move_attack1;
}
mframe_t chick_frames_slash[] = {
static mframe_t chick_frames_slash[] = {
{ai_charge, 1, NULL},
{ai_charge, 7, ChickSlash},
{ai_charge, -7, NULL},
@ -819,24 +853,26 @@ mframe_t chick_frames_slash[] = {
{ai_charge, -2, chick_reslash}
};
mmove_t chick_move_slash = {
mmove_t chick_move_slash =
{
FRAME_attak204,
FRAME_attak212,
chick_frames_slash,
NULL
FRAME_attak212,
chick_frames_slash,
NULL
};
mframe_t chick_frames_end_slash[] = {
static mframe_t chick_frames_end_slash[] = {
{ai_charge, -6, NULL},
{ai_charge, -1, NULL},
{ai_charge, -6, NULL},
{ai_charge, 0, NULL}
{ai_charge, 0, chick_footstep}
};
mmove_t chick_move_end_slash = {
mmove_t chick_move_end_slash =
{
FRAME_attak213,
FRAME_attak216,
chick_frames_end_slash,
chick_frames_end_slash,
chick_run
};
@ -879,17 +915,18 @@ chick_slash(edict_t *self)
self->monsterinfo.currentmove = &chick_move_slash;
}
mframe_t chick_frames_start_slash[] = {
static mframe_t chick_frames_start_slash[] = {
{ai_charge, 1, NULL},
{ai_charge, 8, NULL},
{ai_charge, 3, NULL}
{ai_charge, 3, chick_footstep}
};
mmove_t chick_move_start_slash = {
mmove_t chick_move_start_slash =
{
FRAME_attak201,
FRAME_attak203,
chick_frames_start_slash,
chick_slash
chick_slash
};
void
@ -1064,6 +1101,11 @@ SP_monster_chick(edict_t *self)
return;
}
// Force recaching at next footstep to ensure
// that the sound indices are correct.
sound_step = 0;
sound_step2 = 0;
sound_missile_prelaunch = gi.soundindex("chick/chkatck1.wav");
sound_missile_launch = gi.soundindex("chick/chkatck2.wav");
sound_melee_swing = gi.soundindex("chick/chkatck3.wav");

View file

@ -21,7 +21,7 @@ static int sound_sight;
void flipper_stand(edict_t *self);
mframe_t flipper_frames_stand[] = {
static mframe_t flipper_frames_stand[] = {
{ai_stand, 0, NULL}
};
@ -43,7 +43,7 @@ flipper_stand(edict_t *self)
self->monsterinfo.currentmove = &flipper_move_stand;
}
mframe_t flipper_frames_run[] = {
static mframe_t flipper_frames_run[] = {
{ai_run, FLIPPER_RUN_SPEED, NULL}, /* 6 */
{ai_run, FLIPPER_RUN_SPEED, NULL},
{ai_run, FLIPPER_RUN_SPEED, NULL},
@ -90,7 +90,7 @@ flipper_run_loop(edict_t *self)
self->monsterinfo.currentmove = &flipper_move_run_loop;
}
mframe_t flipper_frames_run_start[] = {
static mframe_t flipper_frames_run_start[] = {
{ai_run, 8, NULL},
{ai_run, 8, NULL},
{ai_run, 8, NULL},
@ -118,7 +118,7 @@ flipper_run(edict_t *self)
}
/* Standard Swimming */
mframe_t flipper_frames_walk[] = {
static mframe_t flipper_frames_walk[] = {
{ai_walk, 4, NULL},
{ai_walk, 4, NULL},
{ai_walk, 4, NULL},
@ -163,7 +163,7 @@ flipper_walk(edict_t *self)
self->monsterinfo.currentmove = &flipper_move_walk;
}
mframe_t flipper_frames_start_run[] = {
static mframe_t flipper_frames_start_run[] = {
{ai_run, 8, NULL},
{ai_run, 8, NULL},
{ai_run, 8, NULL},
@ -189,7 +189,7 @@ flipper_start_run(edict_t *self)
self->monsterinfo.currentmove = &flipper_move_start_run;
}
mframe_t flipper_frames_pain2[] = {
static mframe_t flipper_frames_pain2[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -204,7 +204,7 @@ mmove_t flipper_move_pain2 = {
flipper_run
};
mframe_t flipper_frames_pain1[] = {
static mframe_t flipper_frames_pain1[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -244,7 +244,7 @@ flipper_preattack(edict_t *self)
gi.sound(self, CHAN_WEAPON, sound_chomp, 1, ATTN_NORM, 0);
}
mframe_t flipper_frames_attack[] = {
static mframe_t flipper_frames_attack[] = {
{ai_charge, 0, flipper_preattack},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -329,20 +329,31 @@ flipper_pain(edict_t *self, edict_t *other /* unused */, float kick, int damage)
void
flipper_dead(edict_t *self)
{
vec3_t p;
trace_t tr;
if (!self)
{
return;
}
VectorSet(self->mins, -16, -16, -24);
VectorSet(self->maxs, 16, 16, -8);
/* original dead bbox was wrong - and make sure the bbox adjustment stays in solidity */
p[0] = self->s.origin[0];
p[1] = self->s.origin[1];
p[2] = self->s.origin[2] - 8;
tr = gi.trace(self->s.origin, self->mins, self->maxs, p, self, self->clipmask);
self->mins[2] = tr.endpos[2] - self->s.origin[2];
self->movetype = MOVETYPE_TOSS;
self->svflags |= SVF_DEADMONSTER;
self->nextthink = 0;
gi.linkentity(self);
}
mframe_t flipper_frames_death[] = {
static mframe_t flipper_frames_death[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},

View file

@ -79,7 +79,7 @@ floater_fire_blaster(edict_t *self)
monster_fire_blaster(self, start, dir, 1, 1000, MZ2_FLOAT_BLASTER_1, effect);
}
mframe_t floater_frames_stand1[] = {
static mframe_t floater_frames_stand1[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -141,7 +141,7 @@ mmove_t floater_move_stand1 = {
NULL
};
mframe_t floater_frames_stand2[] = {
static mframe_t floater_frames_stand2[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -221,7 +221,7 @@ floater_stand(edict_t *self)
}
}
mframe_t floater_frames_activate[] = {
static mframe_t floater_frames_activate[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -261,7 +261,7 @@ mmove_t floater_move_activate = {
NULL
};
mframe_t floater_frames_attack1[] = {
static mframe_t floater_frames_attack1[] = {
{ai_charge, 0, NULL}, /* Blaster attack */
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -286,7 +286,7 @@ mmove_t floater_move_attack1 = {
};
/* circle strafe frames */
mframe_t floater_frames_attack1a[] = {
static mframe_t floater_frames_attack1a[] = {
{ai_charge, 10, NULL}, // Blaster attack
{ai_charge, 10, NULL},
{ai_charge, 10, NULL},
@ -310,7 +310,7 @@ mmove_t floater_move_attack1a = {
floater_run
};
mframe_t floater_frames_attack2[] = {
static mframe_t floater_frames_attack2[] = {
{ai_charge, 0, NULL}, /* Claws */
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -345,7 +345,7 @@ mmove_t floater_move_attack2 = {
floater_run
};
mframe_t floater_frames_attack3[] = {
static mframe_t floater_frames_attack3[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -389,7 +389,7 @@ mmove_t floater_move_attack3 = {
floater_run
};
mframe_t floater_frames_death[] = {
static mframe_t floater_frames_death[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -412,7 +412,7 @@ mmove_t floater_move_death = {
floater_dead
};
mframe_t floater_frames_pain1[] = {
static mframe_t floater_frames_pain1[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -429,7 +429,7 @@ mmove_t floater_move_pain1 = {
floater_run
};
mframe_t floater_frames_pain2[] = {
static mframe_t floater_frames_pain2[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -447,7 +447,7 @@ mmove_t floater_move_pain2 = {
floater_run
};
mframe_t floater_frames_pain3[] = {
static mframe_t floater_frames_pain3[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -469,7 +469,7 @@ mmove_t floater_move_pain3 = {
floater_run
};
mframe_t floater_frames_walk[] = {
static mframe_t floater_frames_walk[] = {
{ai_walk, 5, NULL},
{ai_walk, 5, NULL},
{ai_walk, 5, NULL},
@ -531,7 +531,7 @@ mmove_t floater_move_walk = {
NULL
};
mframe_t floater_frames_run[] = {
static mframe_t floater_frames_run[] = {
{ai_run, 13, NULL},
{ai_run, 13, NULL},
{ai_run, 13, NULL},

View file

@ -65,7 +65,7 @@ flyer_pop_blades(edict_t *self)
gi.sound(self, CHAN_VOICE, sound_sproing, 1, ATTN_NORM, 0);
}
mframe_t flyer_frames_stand[] = {
static mframe_t flyer_frames_stand[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -120,7 +120,7 @@ mmove_t flyer_move_stand = {
NULL
};
mframe_t flyer_frames_walk[] = {
static mframe_t flyer_frames_walk[] = {
{ai_walk, 5, NULL},
{ai_walk, 5, NULL},
{ai_walk, 5, NULL},
@ -175,7 +175,7 @@ mmove_t flyer_move_walk = {
NULL
};
mframe_t flyer_frames_run[] = {
static mframe_t flyer_frames_run[] = {
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL},
@ -230,7 +230,7 @@ mmove_t flyer_move_run = {
NULL
};
mframe_t flyer_frames_kamizake[] = {
static mframe_t flyer_frames_kamizake[] = {
{ai_charge, 40, flyer_kamikaze_check},
{ai_charge, 40, flyer_kamikaze_check},
{ai_charge, 40, flyer_kamikaze_check},
@ -373,7 +373,7 @@ flyer_kamikaze_check(edict_t *self)
}
}
mframe_t flyer_frames_start[] = {
static mframe_t flyer_frames_start[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -389,7 +389,7 @@ mmove_t flyer_move_start = {
NULL
};
mframe_t flyer_frames_stop[] = {
static mframe_t flyer_frames_stop[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -428,7 +428,7 @@ flyer_start(edict_t *self)
self->monsterinfo.currentmove = &flyer_move_start;
}
mframe_t flyer_frames_rollright[] = {
static mframe_t flyer_frames_rollright[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -447,7 +447,7 @@ mmove_t flyer_move_rollright = {
NULL
};
mframe_t flyer_frames_rollleft[] = {
static mframe_t flyer_frames_rollleft[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -466,7 +466,7 @@ mmove_t flyer_move_rollleft = {
NULL
};
mframe_t flyer_frames_pain3[] = {
static mframe_t flyer_frames_pain3[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -480,7 +480,7 @@ mmove_t flyer_move_pain3 = {
flyer_run
};
mframe_t flyer_frames_pain2[] = {
static mframe_t flyer_frames_pain2[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -494,7 +494,7 @@ mmove_t flyer_move_pain2 = {
flyer_run
};
mframe_t flyer_frames_pain1[] = {
static mframe_t flyer_frames_pain1[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -513,7 +513,7 @@ mmove_t flyer_move_pain1 = {
flyer_run
};
mframe_t flyer_frames_defense[] = {
static mframe_t flyer_frames_defense[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL}, /* Hold this frame */
@ -529,7 +529,7 @@ mmove_t flyer_move_defense = {
NULL
};
mframe_t flyer_frames_bankright[] = {
static mframe_t flyer_frames_bankright[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -546,7 +546,7 @@ mmove_t flyer_move_bankright = {
NULL
};
mframe_t flyer_frames_bankleft[] = {
static mframe_t flyer_frames_bankleft[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -626,7 +626,7 @@ flyer_fireright(edict_t *self)
flyer_fire(self, MZ2_FLYER_BLASTER_2);
}
mframe_t flyer_frames_attack2[] = {
static mframe_t flyer_frames_attack2[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -654,7 +654,7 @@ mmove_t flyer_move_attack2 = {
};
/* circle strafe frames */
mframe_t flyer_frames_attack3[] = {
static mframe_t flyer_frames_attack3[] = {
{ai_charge, 10, NULL},
{ai_charge, 10, NULL},
{ai_charge, 10, NULL},
@ -711,7 +711,7 @@ flyer_slash_right(edict_t *self)
gi.sound(self, CHAN_WEAPON, sound_slash, 1, ATTN_NORM, 0);
}
mframe_t flyer_frames_start_melee[] = {
static mframe_t flyer_frames_start_melee[] = {
{ai_charge, 0, flyer_pop_blades},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -727,7 +727,7 @@ mmove_t flyer_move_start_melee = {
flyer_loop_melee
};
mframe_t flyer_frames_end_melee[] = {
static mframe_t flyer_frames_end_melee[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL}
@ -740,7 +740,7 @@ mmove_t flyer_move_end_melee = {
flyer_run
};
mframe_t flyer_frames_loop_melee[] = {
static mframe_t flyer_frames_loop_melee[] = {
{ai_charge, 0, NULL}, /* Loop Start */
{ai_charge, 0, NULL},
{ai_charge, 0, flyer_slash_left}, /* Left Wing Strike */

View file

@ -1,4 +1,23 @@
/* =======================================================================
/*
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* Gladiator.
*
@ -19,6 +38,33 @@ static int sound_idle;
static int sound_search;
static int sound_sight;
static int sound_step;
static int sound_step2;
void
gladiator_footstep(edict_t *self)
{
if (!g_monsterfootsteps->value)
return;
// Lazy loading for savegame compatibility.
if (sound_step == 0 || sound_step2 == 0)
{
sound_step = gi.soundindex("gladiator/step1.wav");
sound_step2 = gi.soundindex("gladiator/step2.wav");
}
if (randk() % 2 == 0)
{
gi.sound(self, CHAN_BODY, sound_step, 1, ATTN_NORM, 0);
}
else
{
gi.sound(self, CHAN_BODY, sound_step2, 1, ATTN_NORM, 0);
}
}
void
gladiator_idle(edict_t *self)
{
@ -63,7 +109,7 @@ gladiator_cleaver_swing(edict_t *self)
gi.sound(self, CHAN_WEAPON, sound_cleaver_swing, 1, ATTN_NORM, 0);
}
mframe_t gladiator_frames_stand[] = {
static mframe_t gladiator_frames_stand[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -73,11 +119,12 @@ mframe_t gladiator_frames_stand[] = {
{ai_stand, 0, NULL}
};
mmove_t gladiator_move_stand = {
mmove_t gladiator_move_stand =
{
FRAME_stand1,
FRAME_stand7,
gladiator_frames_stand,
NULL
FRAME_stand7,
gladiator_frames_stand,
NULL
};
void
@ -91,12 +138,12 @@ gladiator_stand(edict_t *self)
self->monsterinfo.currentmove = &gladiator_move_stand;
}
mframe_t gladiator_frames_walk[] = {
static mframe_t gladiator_frames_walk[] = {
{ai_walk, 15, NULL},
{ai_walk, 7, NULL},
{ai_walk, 6, NULL},
{ai_walk, 5, NULL},
{ai_walk, 2, NULL},
{ai_walk, 2, gladiator_footstep},
{ai_walk, 0, NULL},
{ai_walk, 2, NULL},
{ai_walk, 8, NULL},
@ -104,17 +151,18 @@ mframe_t gladiator_frames_walk[] = {
{ai_walk, 8, NULL},
{ai_walk, 5, NULL},
{ai_walk, 5, NULL},
{ai_walk, 2, NULL},
{ai_walk, 2, gladiator_footstep},
{ai_walk, 2, NULL},
{ai_walk, 1, NULL},
{ai_walk, 8, NULL}
};
mmove_t gladiator_move_walk = {
mmove_t gladiator_move_walk =
{
FRAME_walk1,
FRAME_walk16,
gladiator_frames_walk,
NULL
FRAME_walk16,
gladiator_frames_walk,
NULL
};
void
@ -128,20 +176,21 @@ gladiator_walk(edict_t *self)
self->monsterinfo.currentmove = &gladiator_move_walk;
}
mframe_t gladiator_frames_run[] = {
static mframe_t gladiator_frames_run[] = {
{ai_run, 23, NULL},
{ai_run, 14, NULL},
{ai_run, 14, NULL},
{ai_run, 14, gladiator_footstep},
{ai_run, 21, NULL},
{ai_run, 12, NULL},
{ai_run, 13, NULL}
{ai_run, 13, gladiator_footstep}
};
mmove_t gladiator_move_run = {
mmove_t gladiator_move_run =
{
FRAME_run1,
FRAME_run6,
gladiator_frames_run,
NULL
FRAME_run6,
gladiator_frames_run,
NULL
};
void
@ -184,7 +233,7 @@ GaldiatorMelee(edict_t *self)
}
}
mframe_t gladiator_frames_attack_melee[] = {
static mframe_t gladiator_frames_attack_melee[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -204,11 +253,12 @@ mframe_t gladiator_frames_attack_melee[] = {
{ai_charge, 0, NULL}
};
mmove_t gladiator_move_attack_melee = {
mmove_t gladiator_move_attack_melee =
{
FRAME_melee1,
FRAME_melee17,
gladiator_frames_attack_melee,
gladiator_run
FRAME_melee17,
gladiator_frames_attack_melee,
gladiator_run
};
void
@ -245,7 +295,7 @@ GladiatorGun(edict_t *self)
monster_fire_railgun(self, start, dir, 50, 100, MZ2_GLADIATOR_RAILGUN_1);
}
mframe_t gladiator_frames_attack_gun[] = {
static mframe_t gladiator_frames_attack_gun[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -257,11 +307,12 @@ mframe_t gladiator_frames_attack_gun[] = {
{ai_charge, 0, NULL}
};
mmove_t gladiator_move_attack_gun = {
mmove_t gladiator_move_attack_gun =
{
FRAME_attack1,
FRAME_attack9,
gladiator_frames_attack_gun,
gladiator_run
FRAME_attack9,
gladiator_frames_attack_gun,
gladiator_run
};
void
@ -275,13 +326,19 @@ gladiator_attack(edict_t *self)
return;
}
/* a small safe zone */
VectorSubtract(self->s.origin, self->enemy->s.origin, v);
range = VectorLength(v);
if (range <= (MELEE_DISTANCE + 32))
/* a small safe zone
but not for stand-ground ones since players can
abuse it by standing still inside this range
*/
if (!(self->monsterinfo.aiflags & AI_STAND_GROUND))
{
return;
VectorSubtract(self->s.origin, self->enemy->s.origin, v);
range = VectorLength(v);
if (range <= (MELEE_DISTANCE + 32))
{
return;
}
}
/* charge up the railgun */
@ -291,7 +348,7 @@ gladiator_attack(edict_t *self)
self->monsterinfo.currentmove = &gladiator_move_attack_gun;
}
mframe_t gladiator_frames_pain[] = {
static mframe_t gladiator_frames_pain[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -300,14 +357,15 @@ mframe_t gladiator_frames_pain[] = {
{ai_move, 0, NULL}
};
mmove_t gladiator_move_pain = {
mmove_t gladiator_move_pain =
{
FRAME_pain1,
FRAME_pain6,
gladiator_frames_pain,
gladiator_run
FRAME_pain6,
gladiator_frames_pain,
gladiator_run
};
mframe_t gladiator_frames_pain_air[] = {
static mframe_t gladiator_frames_pain_air[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -317,15 +375,17 @@ mframe_t gladiator_frames_pain_air[] = {
{ai_move, 0, NULL}
};
mmove_t gladiator_move_pain_air = {
mmove_t gladiator_move_pain_air =
{
FRAME_painup1,
FRAME_painup7,
gladiator_frames_pain_air,
gladiator_run
FRAME_painup7,
gladiator_frames_pain_air,
gladiator_run
};
void
gladiator_pain(edict_t *self, edict_t *other /* unused */, float kick, int damage)
gladiator_pain(edict_t *self, edict_t *other /* unused */,
float kick /* unused */, int damage)
{
if (!self)
{
@ -390,7 +450,7 @@ gladiator_dead(edict_t *self)
gi.linkentity(self);
}
mframe_t gladiator_frames_death[] = {
static mframe_t gladiator_frames_death[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -415,16 +475,18 @@ mframe_t gladiator_frames_death[] = {
{ai_move, 0, NULL}
};
mmove_t gladiator_move_death = {
mmove_t gladiator_move_death =
{
FRAME_death1,
FRAME_death22,
gladiator_frames_death,
gladiator_dead
FRAME_death22,
gladiator_frames_death,
gladiator_dead
};
void
gladiator_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* unused */,
int damage, vec3_t point /* unused */)
gladiator_die(edict_t *self, edict_t *inflictor /* unused */,
edict_t *attacker /* unused */, int damage /*unused */,
vec3_t point)
{
int n;
@ -436,19 +498,23 @@ gladiator_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker
/* check for gib */
if (self->health <= self->gib_health)
{
gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
gi.sound(self, CHAN_VOICE, gi.soundindex(
"misc/udeath.wav"), 1, ATTN_NORM, 0);
for (n = 0; n < 2; n++)
{
ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
ThrowGib(self, "models/objects/gibs/bone/tris.md2",
damage, GIB_ORGANIC);
}
for (n = 0; n < 4; n++)
{
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2",
damage, GIB_ORGANIC);
}
ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
ThrowHead(self, "models/objects/gibs/head2/tris.md2",
damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
@ -499,6 +565,11 @@ SP_monster_gladiator(edict_t *self)
return;
}
// Force recaching at next footstep to ensure
// that the sound indices are correct.
sound_step = 0;
sound_step2 = 0;
sound_pain1 = gi.soundindex("gladiator/pain.wav");
sound_pain2 = gi.soundindex("gladiator/gldpain2.wav");
sound_die = gi.soundindex("gladiator/glddeth2.wav");

View file

@ -1,4 +1,23 @@
/* =======================================================================
/*
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* Gunner.
*
@ -16,6 +35,9 @@ static int sound_open;
static int sound_search;
static int sound_sight;
static int sound_step;
static int sound_step2;
qboolean visible(edict_t *self, edict_t *other);
void GunnerGrenade(edict_t *self);
void GunnerFire(edict_t *self);
@ -24,6 +46,30 @@ void gunner_refire_chain(edict_t *self);
void gunner_stand(edict_t *self);
void
gunner_footstep(edict_t *self)
{
if (!g_monsterfootsteps->value)
return;
// Lazy loading for savegame compatibility.
if (sound_step == 0 || sound_step2 == 0)
{
sound_step = gi.soundindex("gunner/step1.wav");
sound_step2 = gi.soundindex("gunner/step2.wav");
}
if (randk() % 2 == 0)
{
gi.sound(self, CHAN_BODY, sound_step, 1, ATTN_NORM, 0);
}
else
{
gi.sound(self, CHAN_BODY, sound_step2, 1, ATTN_NORM, 0);
}
}
void
gunner_idlesound(edict_t *self)
{
@ -57,7 +103,7 @@ gunner_search(edict_t *self)
gi.sound(self, CHAN_VOICE, sound_search, 1, ATTN_NORM, 0);
}
mframe_t gunner_frames_fidget[] = {
static mframe_t gunner_frames_fidget[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -113,10 +159,11 @@ mframe_t gunner_frames_fidget[] = {
{ai_stand, 0, NULL}
};
mmove_t gunner_move_fidget = {
mmove_t gunner_move_fidget =
{
FRAME_stand31,
FRAME_stand70,
gunner_frames_fidget,
gunner_frames_fidget,
gunner_stand
};
@ -128,6 +175,11 @@ gunner_fidget(edict_t *self)
return;
}
if (self->enemy)
{
return;
}
if (self->monsterinfo.aiflags & AI_STAND_GROUND)
{
return;
@ -139,7 +191,7 @@ gunner_fidget(edict_t *self)
}
}
mframe_t gunner_frames_stand[] = {
static mframe_t gunner_frames_stand[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -174,11 +226,12 @@ mframe_t gunner_frames_stand[] = {
{ai_stand, 0, gunner_fidget}
};
mmove_t gunner_move_stand = {
mmove_t gunner_move_stand =
{
FRAME_stand01,
FRAME_stand30,
gunner_frames_stand,
NULL
FRAME_stand30,
gunner_frames_stand,
NULL
};
void
@ -192,27 +245,28 @@ gunner_stand(edict_t *self)
self->monsterinfo.currentmove = &gunner_move_stand;
}
mframe_t gunner_frames_walk[] = {
{ai_walk, 0, NULL},
static mframe_t gunner_frames_walk[] = {
{ai_walk, 0, gunner_footstep},
{ai_walk, 3, NULL},
{ai_walk, 4, NULL},
{ai_walk, 5, NULL},
{ai_walk, 7, NULL},
{ai_walk, 2, NULL},
{ai_walk, 2, gunner_footstep},
{ai_walk, 6, NULL},
{ai_walk, 4, NULL},
{ai_walk, 2, NULL},
{ai_walk, 7, NULL},
{ai_walk, 5, NULL},
{ai_walk, 7, NULL},
{ai_walk, 4, NULL}
{ai_walk, 4, gunner_footstep}
};
mmove_t gunner_move_walk = {
mmove_t gunner_move_walk =
{
FRAME_walk07,
FRAME_walk19,
gunner_frames_walk,
NULL
FRAME_walk19,
gunner_frames_walk,
NULL
};
void
@ -226,22 +280,23 @@ gunner_walk(edict_t *self)
self->monsterinfo.currentmove = &gunner_move_walk;
}
mframe_t gunner_frames_run[] = {
static mframe_t gunner_frames_run[] = {
{ai_run, 26, NULL},
{ai_run, 9, NULL},
{ai_run, 9, gunner_footstep},
{ai_run, 9, NULL},
{ai_run, 9, monster_done_dodge},
{ai_run, 15, NULL},
{ai_run, 10, NULL},
{ai_run, 10, gunner_footstep},
{ai_run, 13, NULL},
{ai_run, 6, NULL}
};
mmove_t gunner_move_run = {
mmove_t gunner_move_run =
{
FRAME_run01,
FRAME_run08,
gunner_frames_run,
NULL
gunner_frames_run,
NULL
};
void
@ -264,20 +319,21 @@ gunner_run(edict_t *self)
}
}
mframe_t gunner_frames_runandshoot[] = {
static mframe_t gunner_frames_runandshoot[] = {
{ai_run, 32, NULL},
{ai_run, 15, NULL},
{ai_run, 15, gunner_footstep},
{ai_run, 10, NULL},
{ai_run, 18, NULL},
{ai_run, 8, NULL},
{ai_run, 8, gunner_footstep},
{ai_run, 20, NULL}
};
mmove_t gunner_move_runandshoot = {
mmove_t gunner_move_runandshoot =
{
FRAME_runs01,
FRAME_runs06,
FRAME_runs06,
gunner_frames_runandshoot,
NULL
NULL
};
void
@ -291,7 +347,7 @@ gunner_runandshoot(edict_t *self)
self->monsterinfo.currentmove = &gunner_move_runandshoot;
}
mframe_t gunner_frames_pain3[] = {
static mframe_t gunner_frames_pain3[] = {
{ai_move, -3, NULL},
{ai_move, 1, NULL},
{ai_move, 1, NULL},
@ -299,35 +355,37 @@ mframe_t gunner_frames_pain3[] = {
{ai_move, 1, NULL}
};
mmove_t gunner_move_pain3 = {
mmove_t gunner_move_pain3 =
{
FRAME_pain301,
FRAME_pain305,
gunner_frames_pain3,
gunner_run
FRAME_pain305,
gunner_frames_pain3,
gunner_run
};
mframe_t gunner_frames_pain2[] = {
static mframe_t gunner_frames_pain2[] = {
{ai_move, -2, NULL},
{ai_move, 11, NULL},
{ai_move, 6, NULL},
{ai_move, 6, gunner_footstep},
{ai_move, 2, NULL},
{ai_move, -1, NULL},
{ai_move, -7, NULL},
{ai_move, -2, NULL},
{ai_move, -7, NULL}
{ai_move, -7, gunner_footstep}
};
mmove_t gunner_move_pain2 = {
mmove_t gunner_move_pain2 =
{
FRAME_pain201,
FRAME_pain208,
gunner_frames_pain2,
gunner_run
FRAME_pain208,
gunner_frames_pain2,
gunner_run
};
mframe_t gunner_frames_pain1[] = {
static mframe_t gunner_frames_pain1[] = {
{ai_move, 2, NULL},
{ai_move, 0, NULL},
{ai_move, -5, NULL},
{ai_move, -5, gunner_footstep},
{ai_move, 3, NULL},
{ai_move, -1, NULL},
{ai_move, 0, NULL},
@ -337,23 +395,25 @@ mframe_t gunner_frames_pain1[] = {
{ai_move, 1, NULL},
{ai_move, 1, NULL},
{ai_move, 2, NULL},
{ai_move, 1, NULL},
{ai_move, 1, gunner_footstep},
{ai_move, 0, NULL},
{ai_move, -2, NULL},
{ai_move, -2, NULL},
{ai_move, 0, NULL},
{ai_move, 0, gunner_footstep},
{ai_move, 0, NULL}
};
mmove_t gunner_move_pain1 = {
mmove_t gunner_move_pain1 =
{
FRAME_pain101,
FRAME_pain118,
gunner_frames_pain1,
gunner_run
FRAME_pain118,
gunner_frames_pain1,
gunner_run
};
void
gunner_pain(edict_t *self, edict_t *other /* unused */, float kick, int damage)
gunner_pain(edict_t *self, edict_t *other /* unused */,
float kick /* unused */, int damage)
{
if (!self)
{
@ -430,7 +490,7 @@ gunner_dead(edict_t *self)
gi.linkentity(self);
}
mframe_t gunner_frames_death[] = {
static mframe_t gunner_frames_death[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -444,16 +504,18 @@ mframe_t gunner_frames_death[] = {
{ai_move, 0, NULL}
};
mmove_t gunner_move_death = {
mmove_t gunner_move_death =
{
FRAME_death01,
FRAME_death11,
gunner_frames_death,
gunner_dead
FRAME_death11,
gunner_frames_death,
gunner_dead
};
void
gunner_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* unused */,
int damage, vec3_t point /* unused */)
gunner_die(edict_t *self, edict_t *inflictor /* unused */,
edict_t *attacker /* unused */, int damage /* unused */,
vec3_t point)
{
int n;
@ -469,15 +531,18 @@ gunner_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /*
for (n = 0; n < 2; n++)
{
ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
ThrowGib(self, "models/objects/gibs/bone/tris.md2",
damage, GIB_ORGANIC);
}
for (n = 0; n < 4; n++)
{
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2",
damage, GIB_ORGANIC);
}
ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
ThrowHead(self, "models/objects/gibs/head2/tris.md2",
damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
@ -504,14 +569,6 @@ gunner_duck_down(edict_t *self)
self->monsterinfo.aiflags |= AI_DUCKED;
if (skill->value >= SKILL_HARD)
{
if (random() > 0.5)
{
GunnerGrenade(self);
}
}
self->maxs[2] = self->monsterinfo.base_height - 32;
self->takedamage = DAMAGE_YES;
@ -523,8 +580,23 @@ gunner_duck_down(edict_t *self)
gi.linkentity(self);
}
mframe_t gunner_frames_duck[] = {
{ai_move, 1, gunner_duck_down},
static void
gunner_duck_down_think(edict_t *self)
{
gunner_duck_down(self);
/* rogue code calls duck_down twice, so move this here */
if (skill->value >= SKILL_HARD)
{
if (random() > 0.5)
{
GunnerGrenade(self);
}
}
}
static mframe_t gunner_frames_duck[] = {
{ai_move, 1, gunner_duck_down_think},
{ai_move, 1, NULL},
{ai_move, 1, monster_duck_hold},
{ai_move, 0, NULL},
@ -534,11 +606,12 @@ mframe_t gunner_frames_duck[] = {
{ai_move, -1, NULL}
};
mmove_t gunner_move_duck = {
mmove_t gunner_move_duck =
{
FRAME_duck01,
FRAME_duck08,
gunner_frames_duck,
gunner_run
FRAME_duck08,
gunner_frames_duck,
gunner_run
};
/* gunner dodge moved below so I know about attack sequences */
@ -758,9 +831,9 @@ GunnerGrenade(edict_t *self)
monster_fire_grenade(self, start, aim, 50, 600, flash_number);
}
mframe_t gunner_frames_attack_chain[] = {
static mframe_t gunner_frames_attack_chain[] = {
{ai_charge, 0, gunner_opengun},
{ai_charge, 0, NULL},
{ai_charge, 0, gunner_footstep},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -768,14 +841,15 @@ mframe_t gunner_frames_attack_chain[] = {
{ai_charge, 0, NULL}
};
mmove_t gunner_move_attack_chain = {
mmove_t gunner_move_attack_chain =
{
FRAME_attak209,
FRAME_attak215,
gunner_frames_attack_chain,
gunner_fire_chain
FRAME_attak215,
gunner_frames_attack_chain,
gunner_fire_chain
};
mframe_t gunner_frames_fire_chain[] = {
static mframe_t gunner_frames_fire_chain[] = {
{ai_charge, 0, GunnerFire},
{ai_charge, 0, GunnerFire},
{ai_charge, 0, GunnerFire},
@ -786,28 +860,30 @@ mframe_t gunner_frames_fire_chain[] = {
{ai_charge, 0, GunnerFire}
};
mmove_t gunner_move_fire_chain = {
mmove_t gunner_move_fire_chain =
{
FRAME_attak216,
FRAME_attak223,
gunner_frames_fire_chain,
gunner_refire_chain
FRAME_attak223,
gunner_frames_fire_chain,
gunner_refire_chain
};
mframe_t gunner_frames_endfire_chain[] = {
static mframe_t gunner_frames_endfire_chain[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL}
{ai_charge, 0, gunner_footstep}
};
mmove_t gunner_move_endfire_chain = {
mmove_t gunner_move_endfire_chain =
{
FRAME_attak224,
FRAME_attak230,
gunner_frames_endfire_chain,
gunner_run
FRAME_attak230,
gunner_frames_endfire_chain,
gunner_run
};
void
@ -828,7 +904,7 @@ gunner_blind_check(edict_t *self)
}
}
mframe_t gunner_frames_attack_grenade[] = {
static mframe_t gunner_frames_attack_grenade[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -852,11 +928,12 @@ mframe_t gunner_frames_attack_grenade[] = {
{ai_charge, 0, NULL}
};
mmove_t gunner_move_attack_grenade = {
mmove_t gunner_move_attack_grenade =
{
FRAME_attak101,
FRAME_attak121,
gunner_frames_attack_grenade,
gunner_run
gunner_frames_attack_grenade,
gunner_run
};
void
@ -1028,7 +1105,7 @@ gunner_jump_wait_land(edict_t *self)
}
}
mframe_t gunner_frames_jump[] = {
static mframe_t gunner_frames_jump[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -1048,7 +1125,7 @@ mmove_t gunner_move_jump = {
gunner_run
};
mframe_t gunner_frames_jump2[] = {
static mframe_t gunner_frames_jump2[] = {
{ai_move, -8, NULL},
{ai_move, -4, NULL},
{ai_move, -4, NULL},
@ -1211,6 +1288,11 @@ SP_monster_gunner(edict_t *self)
return;
}
// Force recaching at next footstep to ensure
// that the sound indices are correct.
sound_step = 0;
sound_step2 = 0;
sound_death = gi.soundindex("gunner/death1.wav");
sound_pain = gi.soundindex("gunner/gunpain2.wav");
sound_pain2 = gi.soundindex("gunner/gunpain1.wav");

View file

@ -85,7 +85,7 @@ hover_search(edict_t *self)
}
}
mframe_t hover_frames_stand[] = {
static mframe_t hover_frames_stand[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -125,7 +125,7 @@ mmove_t hover_move_stand = {
NULL
};
mframe_t hover_frames_pain3[] = {
static mframe_t hover_frames_pain3[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -144,7 +144,7 @@ mmove_t hover_move_pain3 = {
hover_run
};
mframe_t hover_frames_pain2[] = {
static mframe_t hover_frames_pain2[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -166,7 +166,7 @@ mmove_t hover_move_pain2 = {
hover_run
};
mframe_t hover_frames_pain1[] = {
static mframe_t hover_frames_pain1[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 2, NULL},
@ -204,7 +204,7 @@ mmove_t hover_move_pain1 = {
hover_run
};
mframe_t hover_frames_walk[] = {
static mframe_t hover_frames_walk[] = {
{ai_walk, 4, NULL},
{ai_walk, 4, NULL},
{ai_walk, 4, NULL},
@ -249,7 +249,7 @@ mmove_t hover_move_walk = {
NULL
};
mframe_t hover_frames_run[] = {
static mframe_t hover_frames_run[] = {
{ai_run, 10, NULL},
{ai_run, 10, NULL},
{ai_run, 10, NULL},
@ -294,7 +294,7 @@ mmove_t hover_move_run = {
NULL
};
mframe_t hover_frames_death1[] = {
static mframe_t hover_frames_death1[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -315,7 +315,7 @@ mmove_t hover_move_death1 = {
hover_dead
};
mframe_t hover_frames_start_attack[] = {
static mframe_t hover_frames_start_attack[] = {
{ai_charge, 1, NULL},
{ai_charge, 1, NULL},
{ai_charge, 1, NULL}
@ -328,7 +328,7 @@ mmove_t hover_move_start_attack = {
hover_attack
};
mframe_t hover_frames_attack1[] = {
static mframe_t hover_frames_attack1[] = {
{ai_charge, -10, hover_fire_blaster},
{ai_charge, -10, hover_fire_blaster},
{ai_charge, 0, hover_reattack},
@ -341,7 +341,7 @@ mmove_t hover_move_attack1 = {
NULL
};
mframe_t hover_frames_end_attack[] = {
static mframe_t hover_frames_end_attack[] = {
{ai_charge, 1, NULL},
{ai_charge, 1, NULL}
};
@ -353,7 +353,7 @@ mmove_t hover_move_end_attack = {
hover_run
};
mframe_t hover_frames_start_attack2[] = {
static mframe_t hover_frames_start_attack2[] = {
{ai_charge, 15, NULL},
{ai_charge, 15, NULL},
{ai_charge, 15, NULL}
@ -366,7 +366,7 @@ mmove_t hover_move_start_attack2 = {
hover_attack
};
mframe_t hover_frames_attack2[] = {
static mframe_t hover_frames_attack2[] = {
{ai_charge, 10, hover_fire_blaster},
{ai_charge, 10, hover_fire_blaster},
{ai_charge, 10, hover_reattack},
@ -379,7 +379,7 @@ mmove_t hover_move_attack2 = {
NULL
};
mframe_t hover_frames_end_attack2[] = {
static mframe_t hover_frames_end_attack2[] = {
{ai_charge, 15, NULL},
{ai_charge, 15, NULL}
};

View file

@ -1,4 +1,23 @@
/* =======================================================================
/*
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* Infantry.
*
@ -23,7 +42,34 @@ static int sound_sight;
static int sound_search;
static int sound_idle;
mframe_t infantry_frames_stand[] = {
static int sound_step;
static int sound_step2;
void
infantry_footstep(edict_t *self)
{
if (!g_monsterfootsteps->value)
return;
// Lazy loading for savegame compatibility.
if (sound_step == 0 || sound_step2 == 0)
{
sound_step = gi.soundindex("infantry/step1.wav");
sound_step2 = gi.soundindex("infantry/step2.wav");
}
if (randk() % 2 == 0)
{
gi.sound(self, CHAN_BODY, sound_step, 1, ATTN_NORM, 0);
}
else
{
gi.sound(self, CHAN_BODY, sound_step2, 1, ATTN_NORM, 0);
}
}
static mframe_t infantry_frames_stand[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -48,9 +94,10 @@ mframe_t infantry_frames_stand[] = {
{ai_stand, 0, NULL}
};
mmove_t infantry_move_stand = {
mmove_t infantry_move_stand =
{
FRAME_stand50,
FRAME_stand71,
FRAME_stand71,
infantry_frames_stand,
NULL
};
@ -66,13 +113,13 @@ infantry_stand(edict_t *self)
self->monsterinfo.currentmove = &infantry_move_stand;
}
mframe_t infantry_frames_fidget[] = {
static mframe_t infantry_frames_fidget[] = {
{ai_stand, 1, NULL},
{ai_stand, 0, NULL},
{ai_stand, 1, NULL},
{ai_stand, 3, NULL},
{ai_stand, 6, NULL},
{ai_stand, 3, NULL},
{ai_stand, 3, infantry_footstep},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -114,15 +161,16 @@ mframe_t infantry_frames_fidget[] = {
{ai_stand, -3, NULL},
{ai_stand, -2, NULL},
{ai_stand, -3, NULL},
{ai_stand, -3, NULL},
{ai_stand, -3, infantry_footstep},
{ai_stand, -2, NULL}
};
mmove_t infantry_move_fidget = {
mmove_t infantry_move_fidget =
{
FRAME_stand01,
FRAME_stand49,
infantry_frames_fidget,
infantry_stand
FRAME_stand49,
infantry_frames_fidget,
infantry_stand
};
void
@ -137,14 +185,14 @@ infantry_fidget(edict_t *self)
gi.sound(self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
}
mframe_t infantry_frames_walk[] = {
{ai_walk, 5, NULL},
static mframe_t infantry_frames_walk[] = {
{ai_walk, 5, infantry_footstep},
{ai_walk, 4, NULL},
{ai_walk, 4, NULL},
{ai_walk, 5, NULL},
{ai_walk, 4, NULL},
{ai_walk, 5, NULL},
{ai_walk, 6, NULL},
{ai_walk, 6, infantry_footstep},
{ai_walk, 4, NULL},
{ai_walk, 4, NULL},
{ai_walk, 4, NULL},
@ -152,10 +200,11 @@ mframe_t infantry_frames_walk[] = {
{ai_walk, 5, NULL}
};
mmove_t infantry_move_walk = {
mmove_t infantry_move_walk =
{
FRAME_walk03,
FRAME_walk14,
infantry_frames_walk,
FRAME_walk14,
infantry_frames_walk,
NULL
};
@ -170,28 +219,29 @@ infantry_walk(edict_t *self)
self->monsterinfo.currentmove = &infantry_move_walk;
}
mframe_t infantry_frames_run[] = {
static mframe_t infantry_frames_run[] = {
{ai_run, 10, NULL},
{ai_run, 20, NULL},
{ai_run, 20, infantry_footstep},
{ai_run, 5, NULL},
{ai_run, 7, monster_done_dodge},
{ai_run, 30, NULL},
{ai_run, 35, NULL},
{ai_run, 35, infantry_footstep},
{ai_run, 2, NULL},
{ai_run, 6, NULL}
};
mmove_t infantry_move_run = {
mmove_t infantry_move_run =
{
FRAME_run01,
FRAME_run08,
infantry_frames_run,
FRAME_run08,
infantry_frames_run,
NULL
};
void
infantry_run(edict_t *self)
{
if (!self)
if (!self)
{
return;
}
@ -208,48 +258,51 @@ infantry_run(edict_t *self)
}
}
mframe_t infantry_frames_pain1[] = {
static mframe_t infantry_frames_pain1[] = {
{ai_move, -3, NULL},
{ai_move, -2, NULL},
{ai_move, -1, NULL},
{ai_move, -2, NULL},
{ai_move, -1, NULL},
{ai_move, -1, infantry_footstep},
{ai_move, 1, NULL},
{ai_move, -1, NULL},
{ai_move, 1, NULL},
{ai_move, 6, NULL},
{ai_move, 2, NULL}
{ai_move, 2, infantry_footstep}
};
mmove_t infantry_move_pain1 = {
mmove_t infantry_move_pain1 =
{
FRAME_pain101,
FRAME_pain110,
infantry_frames_pain1,
infantry_run
};
mframe_t infantry_frames_pain2[] = {
static mframe_t infantry_frames_pain2[] = {
{ai_move, -3, NULL},
{ai_move, -3, NULL},
{ai_move, 0, NULL},
{ai_move, -1, NULL},
{ai_move, -2, NULL},
{ai_move, -2, infantry_footstep},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 2, NULL},
{ai_move, 5, NULL},
{ai_move, 2, NULL}
{ai_move, 2, infantry_footstep}
};
mmove_t infantry_move_pain2 = {
mmove_t infantry_move_pain2 =
{
FRAME_pain201,
FRAME_pain210,
infantry_frames_pain2,
infantry_run
FRAME_pain210,
infantry_frames_pain2,
infantry_run
};
void
infantry_pain(edict_t *self, edict_t *other /* unused */, float kick, int damage)
infantry_pain(edict_t *self, edict_t *other /* unused */,
float kick /* unused */, int damage)
{
int n;
@ -394,16 +447,16 @@ infantry_dead(edict_t *self)
M_FlyCheck(self);
}
mframe_t infantry_frames_death1[] = {
static mframe_t infantry_frames_death1[] = {
{ai_move, -4, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, -1, NULL},
{ai_move, -4, NULL},
{ai_move, -4, infantry_footstep},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, -1, NULL},
{ai_move, -1, infantry_footstep},
{ai_move, 3, NULL},
{ai_move, 1, NULL},
{ai_move, 1, NULL},
@ -417,22 +470,23 @@ mframe_t infantry_frames_death1[] = {
{ai_move, -3, NULL}
};
mmove_t infantry_move_death1 = {
mmove_t infantry_move_death1 =
{
FRAME_death101,
FRAME_death120,
infantry_frames_death1,
infantry_dead
FRAME_death120,
infantry_frames_death1,
infantry_dead
};
/* Off with his head */
mframe_t infantry_frames_death2[] = {
static mframe_t infantry_frames_death2[] = {
{ai_move, 0, NULL},
{ai_move, 1, NULL},
{ai_move, 5, NULL},
{ai_move, -1, NULL},
{ai_move, 0, NULL},
{ai_move, 1, NULL},
{ai_move, 1, NULL},
{ai_move, 1, infantry_footstep},
{ai_move, 1, infantry_footstep},
{ai_move, 4, NULL},
{ai_move, 3, NULL},
{ai_move, 0, NULL},
@ -453,14 +507,15 @@ mframe_t infantry_frames_death2[] = {
{ai_move, 0, NULL}
};
mmove_t infantry_move_death2 = {
mmove_t infantry_move_death2 =
{
FRAME_death201,
FRAME_death225,
FRAME_death225,
infantry_frames_death2,
infantry_dead
};
mframe_t infantry_frames_death3[] = {
static mframe_t infantry_frames_death3[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -472,7 +527,8 @@ mframe_t infantry_frames_death3[] = {
{ai_move, 0, NULL}
};
mmove_t infantry_move_death3 = {
mmove_t infantry_move_death3 =
{
FRAME_death301,
FRAME_death309,
infantry_frames_death3,
@ -480,8 +536,9 @@ mmove_t infantry_move_death3 = {
};
void
infantry_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* unused */,
int damage, vec3_t point /* unused */)
infantry_die(edict_t *self, edict_t *inflictor /* unused */,
edict_t *attacker /* unused */, int damage,
vec3_t point /* unused */)
{
int n;
@ -497,15 +554,18 @@ infantry_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /
for (n = 0; n < 2; n++)
{
ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
ThrowGib(self, "models/objects/gibs/bone/tris.md2",
damage, GIB_ORGANIC);
}
for (n = 0; n < 4; n++)
{
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2",
damage, GIB_ORGANIC);
}
ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
ThrowHead(self, "models/objects/gibs/head2/tris.md2",
damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
@ -539,12 +599,12 @@ infantry_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /
}
}
mframe_t infantry_frames_duck[] = {
static mframe_t infantry_frames_duck[] = {
{ai_move, -2, monster_duck_down},
{ai_move, -5, monster_duck_hold},
{ai_move, 3, NULL},
{ai_move, 4, monster_duck_up},
{ai_move, 0, NULL}
{ai_move, 0, infantry_footstep}
};
mmove_t infantry_move_duck = {
@ -599,7 +659,7 @@ infantry_fire_prep(edict_t *self)
self->monsterinfo.pausetime = level.time + n * FRAMETIME;
}
mframe_t infantry_frames_attack1[] = {
static mframe_t infantry_frames_attack1[] = {
{ai_charge, -3, NULL}, /* 101 */
{ai_charge, -2, NULL}, /* 102 */
{ai_charge, -1, infantry_fire_prep}, /* 103 */
@ -653,11 +713,11 @@ infantry_smack(edict_t *self)
}
}
mframe_t infantry_frames_attack2[] = {
static mframe_t infantry_frames_attack2[] = {
{ai_charge, 3, NULL},
{ai_charge, 6, NULL},
{ai_charge, 0, infantry_swing},
{ai_charge, 8, NULL},
{ai_charge, 8, infantry_footstep},
{ai_charge, 5, NULL},
{ai_charge, 8, infantry_smack},
{ai_charge, 6, NULL},
@ -748,7 +808,7 @@ infantry_jump_wait_land(edict_t *self)
}
}
mframe_t infantry_frames_jump[] = {
static mframe_t infantry_frames_jump[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -768,7 +828,7 @@ mmove_t infantry_move_jump = {
infantry_run
};
mframe_t infantry_frames_jump2[] = {
static mframe_t infantry_frames_jump2[] = {
{ai_move, -8, NULL},
{ai_move, -4, NULL},
{ai_move, -4, NULL},
@ -928,6 +988,11 @@ SP_monster_infantry(edict_t *self)
return;
}
// Force recaching at next footstep to ensure
// that the sound indices are correct.
sound_step = 0;
sound_step2 = 0;
sound_pain1 = gi.soundindex("infantry/infpain1.wav");
sound_pain2 = gi.soundindex("infantry/infpain2.wav");
sound_die1 = gi.soundindex("infantry/infdeth1.wav");

View file

@ -1,4 +1,23 @@
/* =======================================================================
/*
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* The insane earth soldiers.
*
@ -15,6 +34,11 @@ static int sound_shake;
static int sound_moan;
static int sound_scream[8];
static int sound_step;
static int sound_step2;
static int sound_step3;
static int sound_step4;
void insane_stand(edict_t *self);
void insane_dead(edict_t *self);
void insane_cross(edict_t *self);
@ -24,6 +48,43 @@ void insane_checkdown(edict_t *self);
void insane_checkup(edict_t *self);
void insane_onground(edict_t *self);
void
insane_footstep(edict_t *self)
{
if (!g_monsterfootsteps->value)
return;
// Lazy loading for savegame compatibility.
if (sound_step == 0 || sound_step2 == 0 || sound_step3 == 0 || sound_step4 == 0)
{
sound_step = gi.soundindex("player/step1.wav");
sound_step2 = gi.soundindex("player/step2.wav");
sound_step3 = gi.soundindex("player/step3.wav");
sound_step4 = gi.soundindex("player/step4.wav");
}
int i;
i = randk() % 4;
if (i == 0)
{
gi.sound(self, CHAN_BODY, sound_step, 0.7, ATTN_NORM, 0);
}
else if (i == 1)
{
gi.sound(self, CHAN_BODY, sound_step2, 0.7, ATTN_NORM, 0);
}
else if (i == 2)
{
gi.sound(self, CHAN_BODY, sound_step3, 0.7, ATTN_NORM, 0);
}
else if (i == 3)
{
gi.sound(self, CHAN_BODY, sound_step4, 0.7, ATTN_NORM, 0);
}
}
void
insane_fist(edict_t *self)
{
@ -80,7 +141,7 @@ insane_scream(edict_t *self)
gi.sound(self, CHAN_VOICE, sound_scream[rand() % 8], 1, ATTN_IDLE, 0);
}
mframe_t insane_frames_stand_normal[] = {
static mframe_t insane_frames_stand_normal[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -89,14 +150,15 @@ mframe_t insane_frames_stand_normal[] = {
{ai_stand, 0, insane_checkdown}
};
mmove_t insane_move_stand_normal = {
mmove_t insane_move_stand_normal =
{
FRAME_stand60,
FRAME_stand65,
FRAME_stand65,
insane_frames_stand_normal,
insane_stand
};
mframe_t insane_frames_stand_insane[] = {
static mframe_t insane_frames_stand_insane[] = {
{ai_stand, 0, insane_shake},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -129,14 +191,15 @@ mframe_t insane_frames_stand_insane[] = {
{ai_stand, 0, insane_checkdown}
};
mmove_t insane_move_stand_insane = {
mmove_t insane_move_stand_insane =
{
FRAME_stand65,
FRAME_stand94,
insane_frames_stand_insane,
insane_frames_stand_insane,
insane_stand
};
mframe_t insane_frames_uptodown[] = {
static mframe_t insane_frames_uptodown[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -182,43 +245,45 @@ mframe_t insane_frames_uptodown[] = {
{ai_move, 0, NULL}
};
mmove_t insane_move_uptodown = {
mmove_t insane_move_uptodown =
{
FRAME_stand1,
FRAME_stand40,
insane_frames_uptodown,
insane_onground
};
mframe_t insane_frames_downtoup[] = {
{ai_move, -0.7, NULL}, /* 41 */
{ai_move, -1.2, NULL}, /* 42 */
{ai_move, -1.5, NULL}, /* 43 */
{ai_move, -4.5, NULL}, /* 44 */
{ai_move, -3.5, NULL}, /* 45 */
{ai_move, -0.2, NULL}, /* 46 */
{ai_move, 0, NULL}, /* 47 */
{ai_move, -1.3, NULL}, /* 48 */
{ai_move, -3, NULL}, /* 49 */
{ai_move, -2, NULL}, /* 50 */
{ai_move, 0, NULL}, /* 51 */
{ai_move, 0, NULL}, /* 52 */
{ai_move, 0, NULL}, /* 53 */
{ai_move, -3.3, NULL}, /* 54 */
{ai_move, -1.6, NULL}, /* 55 */
{ai_move, -0.3, NULL}, /* 56 */
{ai_move, 0, NULL}, /* 57 */
{ai_move, 0, NULL}, /* 58 */
{ai_move, 0, NULL} /* 59 */
static mframe_t insane_frames_downtoup[] = {
{ai_move, -0.7, NULL}, /* 41 */
{ai_move, -1.2, NULL}, /* 42 */
{ai_move, -1.5, NULL}, /* 43 */
{ai_move, -4.5, NULL}, /* 44 */
{ai_move, -3.5, NULL}, /* 45 */
{ai_move, -0.2, NULL}, /* 46 */
{ai_move, 0, NULL}, /* 47 */
{ai_move, -1.3, NULL}, /* 48 */
{ai_move, -3, NULL}, /* 49 */
{ai_move, -2, NULL}, /* 50 */
{ai_move, 0, NULL}, /* 51 */
{ai_move, 0, NULL}, /* 52 */
{ai_move, 0, NULL}, /* 53 */
{ai_move, -3.3, NULL}, /* 54 */
{ai_move, -1.6, NULL}, /* 55 */
{ai_move, -0.3, NULL}, /* 56 */
{ai_move, 0, NULL}, /* 57 */
{ai_move, 0, NULL}, /* 58 */
{ai_move, 0, NULL} /* 59 */
};
mmove_t insane_move_downtoup = {
mmove_t insane_move_downtoup =
{
FRAME_stand41,
FRAME_stand59,
insane_frames_downtoup,
insane_stand
FRAME_stand59,
insane_frames_downtoup,
insane_stand
};
mframe_t insane_frames_jumpdown[] = {
static mframe_t insane_frames_jumpdown[] = {
{ai_move, 0.2, NULL},
{ai_move, 11.5, NULL},
{ai_move, 5.1, NULL},
@ -226,15 +291,16 @@ mframe_t insane_frames_jumpdown[] = {
{ai_move, 0, NULL}
};
mmove_t insane_move_jumpdown = {
mmove_t insane_move_jumpdown =
{
FRAME_stand96,
FRAME_stand100,
FRAME_stand100,
insane_frames_jumpdown,
insane_onground
};
mframe_t insane_frames_down[] = {
{ai_move, 0, NULL}, /* 100 */
static mframe_t insane_frames_down[] = {
{ai_move, 0, NULL}, /* 100 */
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -244,7 +310,7 @@ mframe_t insane_frames_down[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL}, /* 110 */
{ai_move, 0, NULL}, /* 110 */
{ai_move, -1.7, NULL},
{ai_move, -1.6, NULL},
{ai_move, 0, NULL},
@ -254,7 +320,7 @@ mframe_t insane_frames_down[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL}, /* 120 */
{ai_move, 0, NULL}, /* 120 */
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -264,7 +330,7 @@ mframe_t insane_frames_down[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL}, /* 130 */
{ai_move, 0, NULL}, /* 130 */
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, insane_moan},
@ -274,7 +340,7 @@ mframe_t insane_frames_down[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL}, /* 140 */
{ai_move, 0, NULL}, /* 140 */
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -284,7 +350,7 @@ mframe_t insane_frames_down[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL}, /* 150 */
{ai_move, 0, NULL}, /* 150 */
{ai_move, 0.5, NULL},
{ai_move, 0, NULL},
{ai_move, -0.2, insane_scream},
@ -294,95 +360,100 @@ mframe_t insane_frames_down[] = {
{ai_move, 0.6, NULL},
{ai_move, 0.8, NULL},
{ai_move, 0.7, NULL},
{ai_move, 0, insane_checkup} /* 160 */
{ai_move, 0, insane_checkup} /* 160 */
};
mmove_t insane_move_down = {
mmove_t insane_move_down =
{
FRAME_stand100,
FRAME_stand160,
FRAME_stand160,
insane_frames_down,
insane_onground
};
mframe_t insane_frames_walk_normal[] = {
static mframe_t insane_frames_walk_normal[] = {
{ai_walk, 0, insane_scream},
{ai_walk, 2.5, NULL},
{ai_walk, 3.5, NULL},
{ai_walk, 1.7, NULL},
{ai_walk, 2.3, NULL},
{ai_walk, 2.4, NULL},
{ai_walk, 2.2, NULL},
{ai_walk, 2.2, insane_footstep},
{ai_walk, 4.2, NULL},
{ai_walk, 5.6, NULL},
{ai_walk, 3.3, NULL},
{ai_walk, 2.4, NULL},
{ai_walk, 0.9, NULL},
{ai_walk, 0, NULL}
{ai_walk, 0, insane_footstep}
};
mmove_t insane_move_walk_normal = {
mmove_t insane_move_walk_normal =
{
FRAME_walk27,
FRAME_walk39,
insane_frames_walk_normal,
insane_walk
};
mmove_t insane_move_run_normal =
{
FRAME_walk27,
FRAME_walk39,
insane_frames_walk_normal,
insane_walk
insane_run
};
mmove_t insane_move_run_normal = {
FRAME_walk27,
FRAME_walk39,
insane_frames_walk_normal,
insane_run
static mframe_t insane_frames_walk_insane[] = {
{ai_walk, 0, insane_scream}, /* walk 1 */
{ai_walk, 3.4, NULL}, /* walk 2 */
{ai_walk, 3.6, NULL}, /* 3 */
{ai_walk, 2.9, NULL}, /* 4 */
{ai_walk, 2.2, NULL}, /* 5 */
{ai_walk, 2.6, NULL}, /* 6 */
{ai_walk, 0, insane_footstep}, /* 7 */
{ai_walk, 0.7, NULL}, /* 8 */
{ai_walk, 4.8, NULL}, /* 9 */
{ai_walk, 5.3, NULL}, /* 10 */
{ai_walk, 1.1, NULL}, /* 11 */
{ai_walk, 2, insane_footstep}, /* 12 */
{ai_walk, 0.5, NULL}, /* 13 */
{ai_walk, 0, NULL}, /* 14 */
{ai_walk, 0, NULL}, /* 15 */
{ai_walk, 4.9, NULL}, /* 16 */
{ai_walk, 6.7, NULL}, /* 17 */
{ai_walk, 3.8, NULL}, /* 18 */
{ai_walk, 2, insane_footstep}, /* 19 */
{ai_walk, 0.2, NULL}, /* 20 */
{ai_walk, 0, NULL}, /* 21 */
{ai_walk, 3.4, NULL}, /* 22 */
{ai_walk, 6.4, NULL}, /* 23 */
{ai_walk, 5, NULL}, /* 24 */
{ai_walk, 1.8, insane_footstep}, /* 25 */
{ai_walk, 0, NULL} /* 26 */
};
mframe_t insane_frames_walk_insane[] = {
{ai_walk, 0, insane_scream}, /* walk 1 */
{ai_walk, 3.4, NULL}, /* walk 2 */
{ai_walk, 3.6, NULL}, /* 3 */
{ai_walk, 2.9, NULL}, /* 4 */
{ai_walk, 2.2, NULL}, /* 5 */
{ai_walk, 2.6, NULL}, /* 6 */
{ai_walk, 0, NULL}, /* 7 */
{ai_walk, 0.7, NULL}, /* 8 */
{ai_walk, 4.8, NULL}, /* 9 */
{ai_walk, 5.3, NULL}, /* 10 */
{ai_walk, 1.1, NULL}, /* 11 */
{ai_walk, 2, NULL}, /* 12 */
{ai_walk, 0.5, NULL}, /* 13 */
{ai_walk, 0, NULL}, /* 14 */
{ai_walk, 0, NULL}, /* 15 */
{ai_walk, 4.9, NULL}, /* 16 */
{ai_walk, 6.7, NULL}, /* 17 */
{ai_walk, 3.8, NULL}, /* 18 */
{ai_walk, 2, NULL}, /* 19 */
{ai_walk, 0.2, NULL}, /* 20 */
{ai_walk, 0, NULL}, /* 21 */
{ai_walk, 3.4, NULL}, /* 22 */
{ai_walk, 6.4, NULL}, /* 23 */
{ai_walk, 5, NULL}, /* 24 */
{ai_walk, 1.8, NULL}, /* 25 */
{ai_walk, 0, NULL} /* 26 */
};
mmove_t insane_move_walk_insane = {
mmove_t insane_move_walk_insane =
{
FRAME_walk1,
FRAME_walk26,
insane_frames_walk_insane,
insane_walk
};
mmove_t insane_move_run_insane = {
mmove_t insane_move_run_insane =
{
FRAME_walk1,
FRAME_walk26,
FRAME_walk26,
insane_frames_walk_insane,
insane_run
};
mframe_t insane_frames_stand_pain[] = {
{ai_move, 0, NULL},
static mframe_t insane_frames_stand_pain[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, insane_footstep},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -391,14 +462,15 @@ mframe_t insane_frames_stand_pain[] = {
{ai_move, 0, NULL}
};
mmove_t insane_move_stand_pain = {
mmove_t insane_move_stand_pain =
{
FRAME_st_pain2,
FRAME_st_pain12,
insane_frames_stand_pain,
insane_run
};
mframe_t insane_frames_stand_death[] = {
static mframe_t insane_frames_stand_death[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -418,14 +490,15 @@ mframe_t insane_frames_stand_death[] = {
{ai_move, 0, NULL}
};
mmove_t insane_move_stand_death = {
mmove_t insane_move_stand_death =
{
FRAME_st_death2,
FRAME_st_death18,
insane_frames_stand_death,
insane_dead
insane_dead
};
mframe_t insane_frames_crawl[] = {
static mframe_t insane_frames_crawl[] = {
{ai_walk, 0, insane_scream},
{ai_walk, 1.5, NULL},
{ai_walk, 2.1, NULL},
@ -437,21 +510,23 @@ mframe_t insane_frames_crawl[] = {
{ai_walk, 2.4, NULL}
};
mmove_t insane_move_crawl = {
mmove_t insane_move_crawl =
{
FRAME_crawl1,
FRAME_crawl9,
insane_frames_crawl,
NULL
};
mmove_t insane_move_runcrawl = {
mmove_t insane_move_runcrawl =
{
FRAME_crawl1,
FRAME_crawl9,
insane_frames_crawl,
insane_frames_crawl,
NULL
};
mframe_t insane_frames_crawl_pain[] = {
static mframe_t insane_frames_crawl_pain[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -463,14 +538,15 @@ mframe_t insane_frames_crawl_pain[] = {
{ai_move, 0, NULL}
};
mmove_t insane_move_crawl_pain = {
mmove_t insane_move_crawl_pain =
{
FRAME_cr_pain2,
FRAME_cr_pain10,
insane_frames_crawl_pain,
insane_run
};
mframe_t insane_frames_crawl_death[] = {
static mframe_t insane_frames_crawl_death[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -480,14 +556,15 @@ mframe_t insane_frames_crawl_death[] = {
{ai_move, 0, NULL}
};
mmove_t insane_move_crawl_death = {
mmove_t insane_move_crawl_death =
{
FRAME_cr_death10,
FRAME_cr_death16,
FRAME_cr_death16,
insane_frames_crawl_death,
insane_dead
};
mframe_t insane_frames_cross[] = {
static mframe_t insane_frames_cross[] = {
{ai_move, 0, insane_moan},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -505,14 +582,15 @@ mframe_t insane_frames_cross[] = {
{ai_move, 0, NULL}
};
mmove_t insane_move_cross = {
mmove_t insane_move_cross =
{
FRAME_cross1,
FRAME_cross15,
FRAME_cross15,
insane_frames_cross,
insane_cross
};
mframe_t insane_frames_struggle_cross[] = {
static mframe_t insane_frames_struggle_cross[] = {
{ai_move, 0, insane_scream},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -530,11 +608,12 @@ mframe_t insane_frames_struggle_cross[] = {
{ai_move, 0, NULL}
};
mmove_t insane_move_struggle_cross = {
mmove_t insane_move_struggle_cross =
{
FRAME_cross16,
FRAME_cross30,
insane_frames_struggle_cross,
insane_cross
insane_frames_struggle_cross,
insane_cross
};
void
@ -620,7 +699,8 @@ insane_run(edict_t *self)
}
void
insane_pain(edict_t *self, edict_t *other /* unused */, float kick, int damage)
insane_pain(edict_t *self, edict_t *other /* unused */,
float kick /* unused */, int damage)
{
int l, r;
@ -655,7 +735,8 @@ insane_pain(edict_t *self, edict_t *other /* unused */, float kick, int damage)
l = 100;
}
gi.sound(self, CHAN_VOICE, gi.soundindex(va("player/male/pain%i_%i.wav", l, r)), 1, ATTN_IDLE, 0);
gi.sound(self, CHAN_VOICE,
gi.soundindex(va("player/male/pain%i_%i.wav", l, r)), 1, ATTN_IDLE, 0);
/* suppress screaming and moaning for 1 second so pain sound plays */
self->fly_sound_debounce_time = level.time + 1;
@ -666,7 +747,7 @@ insane_pain(edict_t *self, edict_t *other /* unused */, float kick, int damage)
}
/* Don't go into pain frames if crucified. */
if (self->spawnflags & 8)
if (self->spawnflags & SPAWNFLAG_CRUSIFIED)
{
self->monsterinfo.currentmove = &insane_move_struggle_cross;
return;
@ -796,8 +877,9 @@ insane_dead(edict_t *self)
}
void
insane_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* unused */,
int damage, vec3_t point /* unused */)
insane_die(edict_t *self, edict_t *inflictor /* unused */,
edict_t *attacker /* unused */, int damage,
vec3_t point /* unused */)
{
int n;
@ -808,20 +890,22 @@ insane_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /*
if (self->health <= self->gib_health)
{
gi.sound(self, CHAN_VOICE, gi.soundindex(
"misc/udeath.wav"), 1, ATTN_IDLE, 0);
gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_IDLE, 0);
for (n = 0; n < 2; n++)
{
ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
ThrowGib(self, "models/objects/gibs/bone/tris.md2",
damage, GIB_ORGANIC);
}
for (n = 0; n < 4; n++)
{
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2",
damage, GIB_ORGANIC);
}
ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
ThrowHead(self, "models/objects/gibs/head2/tris.md2",
damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
@ -831,7 +915,8 @@ insane_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /*
return;
}
gi.sound(self, CHAN_VOICE, gi.soundindex(va("player/male/death%i.wav", (rand() % 4) + 1)), 1, ATTN_IDLE, 0);
gi.sound(self, CHAN_VOICE, gi.soundindex(va("player/male/death%i.wav",
(rand() % 4) + 1)), 1, ATTN_IDLE, 0);
self->deadflag = DEAD_DEAD;
self->takedamage = DAMAGE_YES;
@ -873,6 +958,13 @@ SP_misc_insane(edict_t *self)
return;
}
// Force recaching at next footstep to ensure
// that the sound indices are correct.
sound_step = 0;
sound_step2 = 0;
sound_step3 = 0;
sound_step4 = 0;
sound_fist = gi.soundindex("insane/insane11.wav");
sound_shake = gi.soundindex("insane/insane5.wav");
sound_moan = gi.soundindex("insane/insane7.wav");

View file

@ -1,4 +1,23 @@
/* =======================================================================
/*
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* Medic and Medic commander.
*
@ -35,6 +54,9 @@ static int sound_hook_hit;
static int sound_hook_heal;
static int sound_hook_retract;
static int sound_step;
static int sound_step2;
/* commander sounds */
static int commander_sound_idle1;
static int commander_sound_pain1;
@ -86,6 +108,29 @@ vec3_t reinforcement_position[] = {
{0, -80, 0}
};
void
medic_footstep(edict_t *self)
{
if (!g_monsterfootsteps->value)
return;
// Lazy loading for savegame compatibility.
if (sound_step == 0 || sound_step2 == 0)
{
sound_step = gi.soundindex("medic/step1.wav");
sound_step2 = gi.soundindex("medic/step2.wav");
}
if (randk() % 2 == 0)
{
gi.sound(self, CHAN_BODY, sound_step, 1, ATTN_NORM, 0);
}
else
{
gi.sound(self, CHAN_BODY, sound_step2, 1, ATTN_NORM, 0);
}
}
void
cleanupHeal(edict_t *self, qboolean change_frame)
{
@ -340,6 +385,11 @@ medic_search(edict_t *self)
{
edict_t *ent;
if (!self)
{
return;
}
/* commander sounds */
if (self->mass == 400)
{
@ -384,7 +434,7 @@ medic_sight(edict_t *self, edict_t *other /* unused */)
}
}
mframe_t medic_frames_stand[] = {
static mframe_t medic_frames_stand[] = {
{ai_stand, 0, medic_idle},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -477,7 +527,8 @@ mframe_t medic_frames_stand[] = {
{ai_stand, 0, NULL},
};
mmove_t medic_move_stand = {
mmove_t medic_move_stand =
{
FRAME_wait1,
FRAME_wait90,
medic_frames_stand,
@ -495,22 +546,23 @@ medic_stand(edict_t *self)
self->monsterinfo.currentmove = &medic_move_stand;
}
mframe_t medic_frames_walk[] = {
static mframe_t medic_frames_walk[] = {
{ai_walk, 6.2, NULL},
{ai_walk, 18.1, NULL},
{ai_walk, 18.1, medic_footstep},
{ai_walk, 1, NULL},
{ai_walk, 9, NULL},
{ai_walk, 10, NULL},
{ai_walk, 9, NULL},
{ai_walk, 11, NULL},
{ai_walk, 11.6, NULL},
{ai_walk, 11.6, medic_footstep},
{ai_walk, 2, NULL},
{ai_walk, 9.9, NULL},
{ai_walk, 14, NULL},
{ai_walk, 9.3, NULL}
};
mmove_t medic_move_walk = {
mmove_t medic_move_walk =
{
FRAME_walk1,
FRAME_walk12,
medic_frames_walk,
@ -528,19 +580,20 @@ medic_walk(edict_t *self)
self->monsterinfo.currentmove = &medic_move_walk;
}
mframe_t medic_frames_run[] = {
{ai_run, 18, NULL},
static mframe_t medic_frames_run[] = {
{ai_run, 18, medic_footstep},
{ai_run, 22.5, NULL},
{ai_run, 25.4, monster_done_dodge},
{ai_run, 23.4, NULL},
{ai_run, 24, NULL},
{ai_run, 24, medic_footstep},
{ai_run, 35.6, NULL}
};
mmove_t medic_move_run = {
mmove_t medic_move_run =
{
FRAME_run1,
FRAME_run6,
medic_frames_run,
FRAME_run6,
medic_frames_run,
NULL
};
@ -581,7 +634,7 @@ medic_run(edict_t *self)
}
}
mframe_t medic_frames_pain1[] = {
static mframe_t medic_frames_pain1[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -592,14 +645,19 @@ mframe_t medic_frames_pain1[] = {
{ai_move, 0, NULL}
};
mmove_t medic_move_pain1 = {
mmove_t medic_move_pain1 =
{
FRAME_paina1,
FRAME_paina8,
FRAME_paina8,
medic_frames_pain1,
medic_run
};
mframe_t medic_frames_pain2[] = {
static mframe_t medic_frames_pain2[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, medic_footstep},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -610,14 +668,11 @@ mframe_t medic_frames_pain2[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL}
{ai_move, 0, medic_footstep}
};
mmove_t medic_move_pain2 = {
mmove_t medic_move_pain2 =
{
FRAME_painb1,
FRAME_painb15,
medic_frames_pain2,
@ -625,7 +680,8 @@ mmove_t medic_move_pain2 = {
};
void
medic_pain(edict_t *self, edict_t *other /* unused */, float kick, int damage)
medic_pain(edict_t *self, edict_t *other /* unused */,
float kick, int damage /* unused */)
{
if (!self)
{
@ -783,7 +839,7 @@ medic_dead(edict_t *self)
gi.linkentity(self);
}
mframe_t medic_frames_death[] = {
static mframe_t medic_frames_death[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -816,7 +872,8 @@ mframe_t medic_frames_death[] = {
{ai_move, 0, NULL}
};
mmove_t medic_move_death = {
mmove_t medic_move_death =
{
FRAME_death1,
FRAME_death30,
medic_frames_death,
@ -824,8 +881,9 @@ mmove_t medic_move_death = {
};
void
medic_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* unused */,
int damage, vec3_t point /* unused */)
medic_die(edict_t *self, edict_t *inflictor /* unused */,
edict_t *attacker /* unused */, int damage,
vec3_t point /* unused */)
{
int n;
@ -841,15 +899,18 @@ medic_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* u
for (n = 0; n < 2; n++)
{
ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
ThrowGib(self, "models/objects/gibs/bone/tris.md2",
damage, GIB_ORGANIC);
}
for (n = 0; n < 4; n++)
{
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2",
damage, GIB_ORGANIC);
}
ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
ThrowHead(self, "models/objects/gibs/head2/tris.md2",
damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
@ -875,7 +936,7 @@ medic_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* u
self->monsterinfo.currentmove = &medic_move_death;
}
mframe_t medic_frames_duck[] = {
static mframe_t medic_frames_duck[] = {
{ai_move, -1, NULL},
{ai_move, -1, NULL},
{ai_move, -1, monster_duck_down},
@ -894,14 +955,15 @@ mframe_t medic_frames_duck[] = {
{ai_move, -1, NULL}
};
mmove_t medic_move_duck = {
mmove_t medic_move_duck =
{
FRAME_duck1,
FRAME_duck16,
medic_frames_duck,
medic_run
};
mframe_t medic_frames_attackHyperBlaster[] = {
static mframe_t medic_frames_attackHyperBlaster[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -920,7 +982,8 @@ mframe_t medic_frames_attackHyperBlaster[] = {
{ai_charge, 0, medic_fire_blaster}
};
mmove_t medic_move_attackHyperBlaster = {
mmove_t medic_move_attackHyperBlaster =
{
FRAME_attack15,
FRAME_attack30,
medic_frames_attackHyperBlaster,
@ -944,7 +1007,7 @@ medic_continue(edict_t *self)
}
}
mframe_t medic_frames_attackBlaster[] = {
static mframe_t medic_frames_attackBlaster[] = {
{ai_charge, 0, NULL},
{ai_charge, 5, NULL},
{ai_charge, 5, NULL},
@ -1227,7 +1290,7 @@ medic_hook_retract(edict_t *self)
}
}
mframe_t medic_frames_attackCable[] = {
static mframe_t medic_frames_attackCable[] = {
{ai_charge, 2, NULL}, /* 33 */
{ai_charge, 3, NULL},
{ai_charge, 5, NULL},
@ -1235,7 +1298,7 @@ mframe_t medic_frames_attackCable[] = {
{ai_charge, -4.7, NULL}, /* 37 */
{ai_charge, -5, NULL},
{ai_charge, -6, NULL},
{ai_charge, -4, NULL}, /* 40 */
{ai_charge, -4, medic_footstep}, /* 40 */
{ai_charge, 0, NULL},
{ai_move, 0, medic_hook_launch}, /* 42 */
{ai_move, 0, medic_cable_attack}, /* 43 */
@ -1249,16 +1312,17 @@ mframe_t medic_frames_attackCable[] = {
{ai_move, 0, medic_cable_attack}, /* 51 */
{ai_move, 0, medic_hook_retract}, /* 52 */
{ai_move, -1.5, NULL},
{ai_move, -1.2, NULL},
{ai_move, -1.2, medic_footstep},
{ai_move, -3, NULL},
{ai_move, -2, NULL},
{ai_move, 0.3, NULL},
{ai_move, 0.7, NULL},
{ai_move, 1.2, NULL},
{ai_move, 1.3, NULL} /* 60 */
};
mmove_t medic_move_attackCable = {
mmove_t medic_move_attackCable =
{
FRAME_attack33,
FRAME_attack60,
medic_frames_attackCable,
@ -1606,7 +1670,7 @@ medic_finish_spawn(edict_t *self)
}
}
mframe_t medic_frames_callReinforcements[] = {
static mframe_t medic_frames_callReinforcements[] = {
{ai_charge, 2, NULL}, /* 33 */
{ai_charge, 3, NULL},
{ai_charge, 5, NULL},
@ -1893,6 +1957,11 @@ SP_monster_medic(edict_t *self)
return;
}
// Force recaching at next footstep to ensure
// that the sound indices are correct.
sound_step = 0;
sound_step2 = 0;
self->movetype = MOVETYPE_STEP;
self->solid = SOLID_BBOX;
self->s.modelindex = gi.modelindex("models/monsters/medic/tris.md2");

View file

@ -83,7 +83,7 @@ mutant_swing(edict_t *self)
gi.sound(self, CHAN_VOICE, sound_swing, 1, ATTN_NORM, 0);
}
mframe_t mutant_frames_stand[] = {
static mframe_t mutant_frames_stand[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -174,7 +174,7 @@ mutant_idle_loop(edict_t *self)
}
}
mframe_t mutant_frames_idle[] = {
static mframe_t mutant_frames_idle[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -209,7 +209,7 @@ mutant_idle(edict_t *self)
gi.sound(self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
}
mframe_t mutant_frames_walk[] = {
static mframe_t mutant_frames_walk[] = {
{ai_walk, 3, NULL},
{ai_walk, 1, NULL},
{ai_walk, 5, NULL},
@ -242,7 +242,7 @@ mutant_walk_loop(edict_t *self)
self->monsterinfo.currentmove = &mutant_move_walk;
}
mframe_t mutant_frames_start_walk[] = {
static mframe_t mutant_frames_start_walk[] = {
{ai_walk, 5, NULL},
{ai_walk, 5, NULL},
{ai_walk, -2, NULL},
@ -267,7 +267,7 @@ mutant_walk(edict_t *self)
self->monsterinfo.currentmove = &mutant_move_start_walk;
}
mframe_t mutant_frames_run[] = {
static mframe_t mutant_frames_run[] = {
{ai_run, 40, NULL},
{ai_run, 40, mutant_step},
{ai_run, 24, NULL},
@ -364,7 +364,7 @@ mutant_check_refire(edict_t *self)
}
}
mframe_t mutant_frames_attack[] = {
static mframe_t mutant_frames_attack[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, mutant_hit_left},
@ -485,7 +485,7 @@ mutant_check_landing(edict_t *self)
}
}
mframe_t mutant_frames_jump[] = {
static mframe_t mutant_frames_jump[] = {
{ai_charge, 0, NULL},
{ai_charge, 17, NULL},
{ai_charge, 15, mutant_jump_takeoff},
@ -600,7 +600,7 @@ mutant_checkattack(edict_t *self)
return false;
}
mframe_t mutant_frames_pain1[] = {
static mframe_t mutant_frames_pain1[] = {
{ai_move, 4, NULL},
{ai_move, -3, NULL},
{ai_move, -8, NULL},
@ -615,7 +615,7 @@ mmove_t mutant_move_pain1 = {
mutant_run
};
mframe_t mutant_frames_pain2[] = {
static mframe_t mutant_frames_pain2[] = {
{ai_move, -24, NULL},
{ai_move, 11, NULL},
{ai_move, 5, NULL},
@ -631,7 +631,7 @@ mmove_t mutant_move_pain2 = {
mutant_run
};
mframe_t mutant_frames_pain3[] = {
static mframe_t mutant_frames_pain3[] = {
{ai_move, -22, NULL},
{ai_move, 3, NULL},
{ai_move, 3, NULL},
@ -715,7 +715,7 @@ mutant_dead(edict_t *self)
M_FlyCheck(self);
}
mframe_t mutant_frames_death1[] = {
static mframe_t mutant_frames_death1[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -734,7 +734,7 @@ mmove_t mutant_move_death1 = {
mutant_dead
};
mframe_t mutant_frames_death2[] = {
static mframe_t mutant_frames_death2[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -841,13 +841,13 @@ mutant_jump_wait_land(edict_t *self)
{
self->monsterinfo.nextframe = self->s.frame;
}
else
else
{
self->monsterinfo.nextframe = self->s.frame + 1;
}
}
mframe_t mutant_frames_jump_up[] = {
static mframe_t mutant_frames_jump_up[] = {
{ai_move, -8, NULL},
{ai_move, -8, mutant_jump_up},
{ai_move, 0, mutant_jump_wait_land},
@ -862,7 +862,7 @@ mmove_t mutant_move_jump_up = {
mutant_run
};
mframe_t mutant_frames_jump_down[] = {
static mframe_t mutant_frames_jump_down[] = {
{ai_move, 0, NULL},
{ai_move, 0, mutant_jump_down},
{ai_move, 0, mutant_jump_wait_land},

View file

@ -1,4 +1,23 @@
/* =======================================================================
/*
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* Parasite.
*
@ -52,7 +71,7 @@ parasite_reel_in(edict_t *self)
}
void
parasite_sight(edict_t *self, edict_t *other)
parasite_sight(edict_t *self, edict_t *other /* unused */)
{
if (!self)
{
@ -73,6 +92,15 @@ parasite_tap(edict_t *self)
gi.sound(self, CHAN_WEAPON, sound_tap, 1, ATTN_IDLE, 0);
}
void
parasite_footstep(edict_t *self)
{
if (g_monsterfootsteps->value)
{
parasite_tap(self);
}
}
void
parasite_scratch(edict_t *self)
{
@ -95,21 +123,22 @@ parasite_search(edict_t *self)
gi.sound(self, CHAN_WEAPON, sound_search, 1, ATTN_IDLE, 0);
}
mframe_t parasite_frames_start_fidget[] = {
static mframe_t parasite_frames_start_fidget[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL}
};
mmove_t parasite_move_start_fidget = {
mmove_t parasite_move_start_fidget =
{
FRAME_stand18,
FRAME_stand21,
FRAME_stand21,
parasite_frames_start_fidget,
parasite_do_fidget
parasite_do_fidget
};
mframe_t parasite_frames_fidget[] = {
static mframe_t parasite_frames_fidget[] = {
{ai_stand, 0, parasite_scratch},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -118,14 +147,15 @@ mframe_t parasite_frames_fidget[] = {
{ai_stand, 0, NULL}
};
mmove_t parasite_move_fidget = {
mmove_t parasite_move_fidget =
{
FRAME_stand22,
FRAME_stand27,
parasite_frames_fidget,
parasite_refidget
};
mframe_t parasite_frames_end_fidget[] = {
static mframe_t parasite_frames_end_fidget[] = {
{ai_stand, 0, parasite_scratch},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -136,7 +166,8 @@ mframe_t parasite_frames_end_fidget[] = {
{ai_stand, 0, NULL}
};
mmove_t parasite_move_end_fidget = {
mmove_t parasite_move_end_fidget =
{
FRAME_stand28,
FRAME_stand35,
parasite_frames_end_fidget,
@ -194,7 +225,7 @@ parasite_idle(edict_t *self)
self->monsterinfo.currentmove = &parasite_move_start_fidget;
}
mframe_t parasite_frames_stand[] = {
static mframe_t parasite_frames_stand[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, parasite_tap},
@ -214,9 +245,10 @@ mframe_t parasite_frames_stand[] = {
{ai_stand, 0, parasite_tap}
};
mmove_t parasite_move_stand = {
mmove_t parasite_move_stand =
{
FRAME_stand01,
FRAME_stand17,
FRAME_stand17,
parasite_frames_stand,
parasite_stand
};
@ -232,49 +264,52 @@ parasite_stand(edict_t *self)
self->monsterinfo.currentmove = &parasite_move_stand;
}
mframe_t parasite_frames_run[] = {
static mframe_t parasite_frames_run[] = {
{ai_run, 30, NULL},
{ai_run, 30, NULL},
{ai_run, 22, NULL},
{ai_run, 19, NULL},
{ai_run, 22, parasite_footstep},
{ai_run, 19, parasite_footstep},
{ai_run, 24, NULL},
{ai_run, 28, NULL},
{ai_run, 28, parasite_footstep},
{ai_run, 25, NULL}
};
mmove_t parasite_move_run = {
mmove_t parasite_move_run =
{
FRAME_run03,
FRAME_run09,
parasite_frames_run,
NULL
FRAME_run09,
parasite_frames_run,
NULL
};
mframe_t parasite_frames_start_run[] = {
static mframe_t parasite_frames_start_run[] = {
{ai_run, 0, NULL},
{ai_run, 30, NULL},
};
mmove_t parasite_move_start_run = {
mmove_t parasite_move_start_run =
{
FRAME_run01,
FRAME_run02,
parasite_frames_start_run,
parasite_run
};
mframe_t parasite_frames_stop_run[] = {
static mframe_t parasite_frames_stop_run[] = {
{ai_run, 20, NULL},
{ai_run, 20, NULL},
{ai_run, 12, NULL},
{ai_run, 12, parasite_footstep},
{ai_run, 10, NULL},
{ai_run, 0, NULL},
{ai_run, 0, NULL}
};
mmove_t parasite_move_stop_run = {
mmove_t parasite_move_stop_run =
{
FRAME_run10,
FRAME_run15,
parasite_frames_stop_run,
NULL
FRAME_run15,
parasite_frames_stop_run,
NULL
};
void
@ -313,45 +348,48 @@ parasite_run(edict_t *self)
}
}
mframe_t parasite_frames_walk[] = {
static mframe_t parasite_frames_walk[] = {
{ai_walk, 30, NULL},
{ai_walk, 30, NULL},
{ai_walk, 22, NULL},
{ai_walk, 22, parasite_footstep},
{ai_walk, 19, NULL},
{ai_walk, 24, NULL},
{ai_walk, 28, NULL},
{ai_walk, 24, parasite_footstep},
{ai_walk, 28, parasite_footstep},
{ai_walk, 25, NULL}
};
mmove_t parasite_move_walk = {
mmove_t parasite_move_walk =
{
FRAME_run03,
FRAME_run09,
parasite_frames_walk,
parasite_walk
FRAME_run09,
parasite_frames_walk,
parasite_walk
};
mframe_t parasite_frames_start_walk[] = {
static mframe_t parasite_frames_start_walk[] = {
{ai_walk, 0, NULL},
{ai_walk, 30, parasite_walk}
};
mmove_t parasite_move_start_walk = {
mmove_t parasite_move_start_walk =
{
FRAME_run01,
FRAME_run02,
FRAME_run02,
parasite_frames_start_walk,
NULL
};
mframe_t parasite_frames_stop_walk[] = {
static mframe_t parasite_frames_stop_walk[] = {
{ai_walk, 20, NULL},
{ai_walk, 20, NULL},
{ai_walk, 12, NULL},
{ai_walk, 12, parasite_footstep},
{ai_walk, 10, NULL},
{ai_walk, 0, NULL},
{ai_walk, 0, NULL}
};
mmove_t parasite_move_stop_walk = {
mmove_t parasite_move_stop_walk =
{
FRAME_run10,
FRAME_run15,
parasite_frames_stop_walk,
@ -380,7 +418,7 @@ parasite_walk(edict_t *self)
self->monsterinfo.currentmove = &parasite_move_walk;
}
mframe_t parasite_frames_pain1[] = {
static mframe_t parasite_frames_pain1[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -394,15 +432,17 @@ mframe_t parasite_frames_pain1[] = {
{ai_move, 0, NULL}
};
mmove_t parasite_move_pain1 = {
mmove_t parasite_move_pain1 =
{
FRAME_pain101,
FRAME_pain111,
FRAME_pain111,
parasite_frames_pain1,
parasite_start_run
};
void
parasite_pain(edict_t *self, edict_t *other /* unused */, float kick, int damage)
parasite_pain(edict_t *self, edict_t *other /* unused */,
float kick /* unused */, int damage /* unused */)
{
if (!self)
{
@ -548,7 +588,7 @@ parasite_drain_attack(edict_t *self)
damage, 0, DAMAGE_NO_KNOCKBACK, MOD_UNKNOWN);
}
mframe_t parasite_frames_drain[] = {
static mframe_t parasite_frames_drain[] = {
{ai_charge, 0, parasite_launch},
{ai_charge, 0, NULL},
{ai_charge, 15, parasite_drain_attack}, /* Target hits */
@ -569,14 +609,15 @@ mframe_t parasite_frames_drain[] = {
{ai_charge, 0, NULL}
};
mmove_t parasite_move_drain = {
mmove_t parasite_move_drain =
{
FRAME_drain01,
FRAME_drain18,
parasite_frames_drain,
parasite_start_run
};
mframe_t parasite_frames_break[] = {
static mframe_t parasite_frames_break[] = {
{ai_charge, 0, NULL},
{ai_charge, -3, NULL},
{ai_charge, 1, NULL},
@ -598,12 +639,12 @@ mframe_t parasite_frames_break[] = {
{ai_charge, 0, NULL},
{ai_charge, -18, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL}, /* airborne */
{ai_charge, 0, NULL}, /* airborne */
{ai_charge, 0, NULL}, /* slides */
{ai_charge, 0, NULL}, /* slides */
{ai_charge, 0, NULL}, /* slides */
{ai_charge, 0, NULL}, /* slides */
{ai_charge, 0, NULL}, /* airborne */
{ai_charge, 0, NULL}, /* airborne */
{ai_charge, 0, NULL}, /* slides */
{ai_charge, 0, NULL}, /* slides */
{ai_charge, 0, NULL}, /* slides */
{ai_charge, 0, NULL}, /* slides */
{ai_charge, 4, NULL},
{ai_charge, 11, NULL},
{ai_charge, -2, NULL},
@ -611,10 +652,11 @@ mframe_t parasite_frames_break[] = {
{ai_charge, 1, NULL}
};
mmove_t parasite_move_break = {
mmove_t parasite_move_break =
{
FRAME_break01,
FRAME_break32,
parasite_frames_break,
FRAME_break32,
parasite_frames_break,
parasite_start_run
};
@ -686,7 +728,7 @@ parasite_jump_wait_land(edict_t *self)
}
}
mframe_t parasite_frames_jump_up[] = {
static mframe_t parasite_frames_jump_up[] = {
{ai_move, -8, NULL},
{ai_move, -8, NULL},
{ai_move, -8, NULL},
@ -704,7 +746,7 @@ mmove_t parasite_move_jump_up = {
parasite_run
};
mframe_t parasite_frames_jump_down[] = {
static mframe_t parasite_frames_jump_down[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -877,7 +919,7 @@ parasite_dead(edict_t *self)
gi.linkentity(self);
}
mframe_t parasite_frames_death[] = {
static mframe_t parasite_frames_death[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -887,7 +929,8 @@ mframe_t parasite_frames_death[] = {
{ai_move, 0, NULL}
};
mmove_t parasite_move_death = {
mmove_t parasite_move_death =
{
FRAME_death101,
FRAME_death107,
parasite_frames_death,
@ -895,12 +938,13 @@ mmove_t parasite_move_death = {
};
void
parasite_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* unused */,
int damage, vec3_t point /* unsued */)
parasite_die(edict_t *self, edict_t *inflictor /* unused */,
edict_t *attacker /* unused */, int damage,
vec3_t point /* unused */)
{
int n;
if (!self)
if (!self)
{
return;
}
@ -912,15 +956,18 @@ parasite_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /
for (n = 0; n < 2; n++)
{
ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
ThrowGib(self, "models/objects/gibs/bone/tris.md2",
damage, GIB_ORGANIC);
}
for (n = 0; n < 4; n++)
{
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2",
damage, GIB_ORGANIC);
}
ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
ThrowHead(self, "models/objects/gibs/head2/tris.md2",
damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}

View file

@ -1,4 +1,23 @@
/* =======================================================================
/*
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* Soldier aka "Guard". This is the most complex enemy in Quake 2, since
* it uses all AI features (dodging, sight, crouching, etc) and comes
@ -21,6 +40,10 @@ static int sound_death_light;
static int sound_death;
static int sound_death_ss;
static int sound_cock;
static int sound_step;
static int sound_step2;
static int sound_step3;
static int sound_step4;
void soldier_duck_up(edict_t *self);
void soldier_stand(edict_t *self);
@ -28,6 +51,42 @@ void soldier_run(edict_t *self);
void soldier_fire(edict_t *self, int);
void soldier_blind(edict_t *self);
void
soldier_footstep(edict_t *self)
{
if (!g_monsterfootsteps->value)
return;
// Lazy loading for savegame compatibility.
if (sound_step == 0 || sound_step2 == 0 || sound_step3 == 0 || sound_step4 == 0)
{
sound_step = gi.soundindex("player/step1.wav");
sound_step2 = gi.soundindex("player/step2.wav");
sound_step3 = gi.soundindex("player/step3.wav");
sound_step4 = gi.soundindex("player/step4.wav");
}
int i;
i = randk() % 4;
if (i == 0)
{
gi.sound(self, CHAN_BODY, sound_step, 1, ATTN_NORM, 0);
}
else if (i == 1)
{
gi.sound(self, CHAN_BODY, sound_step2, 1, ATTN_NORM, 0);
}
else if (i == 2)
{
gi.sound(self, CHAN_BODY, sound_step3, 1, ATTN_NORM, 0);
}
else if (i == 3)
{
gi.sound(self, CHAN_BODY, sound_step4, 1, ATTN_NORM, 0);
}
}
void
soldier_start_charge(edict_t *self)
{
@ -50,6 +109,7 @@ soldier_stop_charge(edict_t *self)
self->monsterinfo.aiflags &= ~AI_CHARGING;
}
void
soldier_idle(edict_t *self)
{
@ -82,7 +142,7 @@ soldier_cock(edict_t *self)
}
}
mframe_t soldier_frames_stand1[] = {
static mframe_t soldier_frames_stand1[] = {
{ai_stand, 0, soldier_idle},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -117,14 +177,15 @@ mframe_t soldier_frames_stand1[] = {
{ai_stand, 0, NULL}
};
mmove_t soldier_move_stand1 = {
mmove_t soldier_move_stand1 =
{
FRAME_stand101,
FRAME_stand130,
soldier_frames_stand1,
soldier_stand
soldier_frames_stand1,
soldier_stand
};
mframe_t soldier_frames_stand3[] = {
static mframe_t soldier_frames_stand3[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -169,7 +230,8 @@ mframe_t soldier_frames_stand3[] = {
{ai_stand, 0, NULL}
};
mmove_t soldier_move_stand3 = {
mmove_t soldier_move_stand3 =
{
FRAME_stand301,
FRAME_stand339,
soldier_frames_stand3,
@ -209,16 +271,16 @@ soldier_walk1_random(edict_t *self)
}
}
mframe_t soldier_frames_walk1[] = {
static mframe_t soldier_frames_walk1[] = {
{ai_walk, 3, NULL},
{ai_walk, 6, NULL},
{ai_walk, 2, NULL},
{ai_walk, 2, NULL},
{ai_walk, 2, soldier_footstep},
{ai_walk, 2, NULL},
{ai_walk, 1, NULL},
{ai_walk, 6, NULL},
{ai_walk, 5, NULL},
{ai_walk, 3, NULL},
{ai_walk, 3, soldier_footstep},
{ai_walk, -1, soldier_walk1_random},
{ai_walk, 0, NULL},
{ai_walk, 0, NULL},
@ -245,19 +307,20 @@ mframe_t soldier_frames_walk1[] = {
{ai_walk, 0, NULL}
};
mmove_t soldier_move_walk1 = {
mmove_t soldier_move_walk1 =
{
FRAME_walk101,
FRAME_walk133,
soldier_frames_walk1,
NULL
FRAME_walk133,
soldier_frames_walk1,
NULL
};
mframe_t soldier_frames_walk2[] = {
{ai_walk, 4, NULL},
static mframe_t soldier_frames_walk2[] = {
{ai_walk, 4, soldier_footstep},
{ai_walk, 4, NULL},
{ai_walk, 9, NULL},
{ai_walk, 8, NULL},
{ai_walk, 5, NULL},
{ai_walk, 5, soldier_footstep},
{ai_walk, 1, NULL},
{ai_walk, 3, NULL},
{ai_walk, 7, NULL},
@ -265,10 +328,11 @@ mframe_t soldier_frames_walk2[] = {
{ai_walk, 7, NULL}
};
mmove_t soldier_move_walk2 = {
mmove_t soldier_move_walk2 =
{
FRAME_walk209,
FRAME_walk218,
soldier_frames_walk2,
soldier_frames_walk2,
NULL
};
@ -290,12 +354,13 @@ soldier_walk(edict_t *self)
}
}
mframe_t soldier_frames_start_run[] = {
static mframe_t soldier_frames_start_run[] = {
{ai_run, 7, NULL},
{ai_run, 5, NULL}
};
mmove_t soldier_move_start_run = {
mmove_t soldier_move_start_run =
{
FRAME_run01,
FRAME_run02,
soldier_frames_start_run,
@ -316,19 +381,20 @@ soldier_fire_run(edict_t *self)
}
}
mframe_t soldier_frames_run[] = {
static mframe_t soldier_frames_run[] = {
{ai_run, 10, NULL},
{ai_run, 11, NULL},
{ai_run, 11, soldier_footstep},
{ai_run, 11, NULL},
{ai_run, 16, NULL},
{ai_run, 10, NULL},
{ai_run, 10, soldier_footstep},
{ai_run, 15, NULL}
};
mmove_t soldier_move_run = {
mmove_t soldier_move_run =
{
FRAME_run03,
FRAME_run08,
soldier_frames_run,
FRAME_run08,
soldier_frames_run,
NULL
};
@ -360,7 +426,7 @@ soldier_run(edict_t *self)
}
}
mframe_t soldier_frames_pain1[] = {
static mframe_t soldier_frames_pain1[] = {
{ai_move, -3, NULL},
{ai_move, 4, NULL},
{ai_move, 1, NULL},
@ -368,14 +434,15 @@ mframe_t soldier_frames_pain1[] = {
{ai_move, 0, NULL}
};
mmove_t soldier_move_pain1 = {
mmove_t soldier_move_pain1 =
{
FRAME_pain101,
FRAME_pain105,
soldier_frames_pain1,
soldier_run
};
mframe_t soldier_frames_pain2[] = {
static mframe_t soldier_frames_pain2[] = {
{ai_move, -13, NULL},
{ai_move, -1, NULL},
{ai_move, 2, NULL},
@ -385,17 +452,18 @@ mframe_t soldier_frames_pain2[] = {
{ai_move, 2, NULL}
};
mmove_t soldier_move_pain2 = {
mmove_t soldier_move_pain2 =
{
FRAME_pain201,
FRAME_pain207,
FRAME_pain207,
soldier_frames_pain2,
soldier_run
};
mframe_t soldier_frames_pain3[] = {
static mframe_t soldier_frames_pain3[] = {
{ai_move, -8, NULL},
{ai_move, 10, NULL},
{ai_move, -4, NULL},
{ai_move, -4, soldier_footstep},
{ai_move, -1, NULL},
{ai_move, -3, NULL},
{ai_move, 0, NULL},
@ -410,17 +478,18 @@ mframe_t soldier_frames_pain3[] = {
{ai_move, 2, NULL},
{ai_move, 4, NULL},
{ai_move, 3, NULL},
{ai_move, 2, NULL}
{ai_move, 2, soldier_footstep}
};
mmove_t soldier_move_pain3 = {
mmove_t soldier_move_pain3 =
{
FRAME_pain301,
FRAME_pain318,
soldier_frames_pain3,
soldier_run
};
mframe_t soldier_frames_pain4[] = {
static mframe_t soldier_frames_pain4[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -440,15 +509,17 @@ mframe_t soldier_frames_pain4[] = {
{ai_move, 0, NULL}
};
mmove_t soldier_move_pain4 = {
mmove_t soldier_move_pain4 =
{
FRAME_pain401,
FRAME_pain417,
soldier_frames_pain4,
FRAME_pain417,
soldier_frames_pain4,
soldier_run
};
void
soldier_pain(edict_t *self, edict_t *other /* unused */, float kick, int damage)
soldier_pain(edict_t *self, edict_t *other /* unused */,
float kick /* unused */, int damage /* unused */)
{
float r;
int n;
@ -473,8 +544,8 @@ soldier_pain(edict_t *self, edict_t *other /* unused */, float kick, int damage)
{
if ((self->velocity[2] > 100) &&
((self->monsterinfo.currentmove == &soldier_move_pain1) ||
(self->monsterinfo.currentmove == &soldier_move_pain2) ||
(self->monsterinfo.currentmove == &soldier_move_pain3)))
(self->monsterinfo.currentmove == &soldier_move_pain2) ||
(self->monsterinfo.currentmove == &soldier_move_pain3)))
{
/* clear duck flag */
if (self->monsterinfo.aiflags & AI_DUCKED)
@ -545,20 +616,40 @@ soldier_pain(edict_t *self, edict_t *other /* unused */, float kick, int damage)
}
static int blaster_flash[] =
{MZ2_SOLDIER_BLASTER_1, MZ2_SOLDIER_BLASTER_2, MZ2_SOLDIER_BLASTER_3,
MZ2_SOLDIER_BLASTER_4, MZ2_SOLDIER_BLASTER_5, MZ2_SOLDIER_BLASTER_6,
MZ2_SOLDIER_BLASTER_7, MZ2_SOLDIER_BLASTER_8};
{
MZ2_SOLDIER_BLASTER_1,
MZ2_SOLDIER_BLASTER_2,
MZ2_SOLDIER_BLASTER_3,
MZ2_SOLDIER_BLASTER_4,
MZ2_SOLDIER_BLASTER_5,
MZ2_SOLDIER_BLASTER_6,
MZ2_SOLDIER_BLASTER_7,
MZ2_SOLDIER_BLASTER_8
};
static int shotgun_flash[] =
{MZ2_SOLDIER_SHOTGUN_1, MZ2_SOLDIER_SHOTGUN_2, MZ2_SOLDIER_SHOTGUN_3,
MZ2_SOLDIER_SHOTGUN_4, MZ2_SOLDIER_SHOTGUN_5, MZ2_SOLDIER_SHOTGUN_6,
MZ2_SOLDIER_SHOTGUN_7, MZ2_SOLDIER_SHOTGUN_8};
{
MZ2_SOLDIER_SHOTGUN_1,
MZ2_SOLDIER_SHOTGUN_2,
MZ2_SOLDIER_SHOTGUN_3,
MZ2_SOLDIER_SHOTGUN_4,
MZ2_SOLDIER_SHOTGUN_5,
MZ2_SOLDIER_SHOTGUN_6,
MZ2_SOLDIER_SHOTGUN_7,
MZ2_SOLDIER_SHOTGUN_8
};
static int machinegun_flash[] =
{MZ2_SOLDIER_MACHINEGUN_1, MZ2_SOLDIER_MACHINEGUN_2, MZ2_SOLDIER_MACHINEGUN_3,
MZ2_SOLDIER_MACHINEGUN_4, MZ2_SOLDIER_MACHINEGUN_5,
MZ2_SOLDIER_MACHINEGUN_6, MZ2_SOLDIER_MACHINEGUN_7,
MZ2_SOLDIER_MACHINEGUN_8};
{
MZ2_SOLDIER_MACHINEGUN_1,
MZ2_SOLDIER_MACHINEGUN_2,
MZ2_SOLDIER_MACHINEGUN_3,
MZ2_SOLDIER_MACHINEGUN_4,
MZ2_SOLDIER_MACHINEGUN_5,
MZ2_SOLDIER_MACHINEGUN_6,
MZ2_SOLDIER_MACHINEGUN_7,
MZ2_SOLDIER_MACHINEGUN_8
};
void
soldier_fire(edict_t *self, int in_flash_number)
@ -779,7 +870,7 @@ soldier_attack1_refire2(edict_t *self)
}
}
mframe_t soldier_frames_attack1[] = {
static mframe_t soldier_frames_attack1[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, soldier_fire1},
@ -794,10 +885,11 @@ mframe_t soldier_frames_attack1[] = {
{ai_charge, 0, NULL}
};
mmove_t soldier_move_attack1 = {
mmove_t soldier_move_attack1 =
{
FRAME_attak101,
FRAME_attak112,
soldier_frames_attack1,
FRAME_attak112,
soldier_frames_attack1,
soldier_run
};
@ -835,7 +927,8 @@ soldier_attack2_refire1(edict_t *self)
return;
}
if (((skill->value == SKILL_HARDPLUS) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE))
if (((skill->value == SKILL_HARDPLUS) &&
(random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE))
{
self->monsterinfo.nextframe = FRAME_attak204;
}
@ -868,13 +961,14 @@ soldier_attack2_refire2(edict_t *self)
return;
}
if (((skill->value == SKILL_HARDPLUS) && (random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE))
if (((skill->value == SKILL_HARDPLUS) &&
(random() < 0.5)) || (range(self, self->enemy) == RANGE_MELEE))
{
self->monsterinfo.nextframe = FRAME_attak204;
}
}
mframe_t soldier_frames_attack2[] = {
static mframe_t soldier_frames_attack2[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -895,7 +989,8 @@ mframe_t soldier_frames_attack2[] = {
{ai_charge, 0, NULL}
};
mmove_t soldier_move_attack2 = {
mmove_t soldier_move_attack2 =
{
FRAME_attak201,
FRAME_attak218,
soldier_frames_attack2,
@ -928,7 +1023,7 @@ soldier_attack3_refire(edict_t *self)
}
}
mframe_t soldier_frames_attack3[] = {
static mframe_t soldier_frames_attack3[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, soldier_fire3},
@ -940,11 +1035,12 @@ mframe_t soldier_frames_attack3[] = {
{ai_charge, 0, NULL}
};
mmove_t soldier_move_attack3 = {
mmove_t soldier_move_attack3 =
{
FRAME_attak301,
FRAME_attak309,
soldier_frames_attack3,
soldier_run
FRAME_attak309,
soldier_frames_attack3,
soldier_run
};
void
@ -958,16 +1054,17 @@ soldier_fire4(edict_t *self)
soldier_fire(self, 3);
}
mframe_t soldier_frames_attack4[] = {
{ai_charge, 0, NULL},
static mframe_t soldier_frames_attack4[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, soldier_footstep},
{ai_charge, 0, soldier_fire4},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL}
{ai_charge, 0, soldier_footstep}
};
mmove_t soldier_move_attack4 = {
mmove_t soldier_move_attack4 =
{
FRAME_attak401,
FRAME_attak406,
soldier_frames_attack4,
@ -1018,11 +1115,11 @@ soldier_attack6_refire(edict_t *self)
}
}
mframe_t soldier_frames_attack6[] = {
static mframe_t soldier_frames_attack6[] = {
{ai_run, 10, soldier_start_charge},
{ai_run, 4, NULL},
{ai_run, 12, soldier_fire8},
{ai_run, 11, NULL},
{ai_run, 11, soldier_footstep},
{ai_run, 13, monster_done_dodge},
{ai_run, 18, NULL},
{ai_run, 15, NULL},
@ -1035,11 +1132,12 @@ mframe_t soldier_frames_attack6[] = {
{ai_run, 17, soldier_attack6_refire}
};
mmove_t soldier_move_attack6 = {
mmove_t soldier_move_attack6 =
{
FRAME_runs01,
FRAME_runs14,
soldier_frames_attack6,
soldier_run
FRAME_runs14,
soldier_frames_attack6,
soldier_run
};
void
@ -1152,7 +1250,7 @@ soldier_sight(edict_t *self, edict_t *other /* unused */)
}
}
mframe_t soldier_frames_duck[] = {
static mframe_t soldier_frames_duck[] = {
{ai_move, 5, monster_duck_down},
{ai_move, -1, monster_duck_hold},
{ai_move, 1, NULL},
@ -1160,7 +1258,8 @@ mframe_t soldier_frames_duck[] = {
{ai_move, 5, NULL}
};
mmove_t soldier_move_duck = {
mmove_t soldier_move_duck =
{
FRAME_duck01,
FRAME_duck05,
soldier_frames_duck,
@ -1268,7 +1367,7 @@ soldier_dead2(edict_t *self)
gi.linkentity(self);
}
mframe_t soldier_frames_death1[] = {
static mframe_t soldier_frames_death1[] = {
{ai_move, 0, NULL},
{ai_move, -10, NULL},
{ai_move, -10, NULL},
@ -1310,14 +1409,15 @@ mframe_t soldier_frames_death1[] = {
{ai_move, 0, NULL}
};
mmove_t soldier_move_death1 = {
mmove_t soldier_move_death1 =
{
FRAME_death101,
FRAME_death136,
soldier_frames_death1,
soldier_dead
FRAME_death136,
soldier_frames_death1,
soldier_dead
};
mframe_t soldier_frames_death2[] = {
static mframe_t soldier_frames_death2[] = {
{ai_move, -5, NULL},
{ai_move, -5, NULL},
{ai_move, -5, NULL},
@ -1358,14 +1458,15 @@ mframe_t soldier_frames_death2[] = {
{ai_move, 0, NULL}
};
mmove_t soldier_move_death2 = {
mmove_t soldier_move_death2 =
{
FRAME_death201,
FRAME_death235,
FRAME_death235,
soldier_frames_death2,
soldier_dead
};
mframe_t soldier_frames_death3[] = {
static mframe_t soldier_frames_death3[] = {
{ai_move, -5, NULL},
{ai_move, -5, NULL},
{ai_move, -5, NULL},
@ -1417,14 +1518,15 @@ mframe_t soldier_frames_death3[] = {
{ai_move, 0, NULL},
};
mmove_t soldier_move_death3 = {
mmove_t soldier_move_death3 =
{
FRAME_death301,
FRAME_death345,
soldier_frames_death3,
soldier_dead
};
mframe_t soldier_frames_death4[] = {
static mframe_t soldier_frames_death4[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -1485,14 +1587,15 @@ mframe_t soldier_frames_death4[] = {
{ai_move, 0, NULL}
};
mmove_t soldier_move_death4 = {
mmove_t soldier_move_death4 =
{
FRAME_death401,
FRAME_death453,
soldier_frames_death4,
soldier_dead2
};
mframe_t soldier_frames_death5[] = {
static mframe_t soldier_frames_death5[] = {
{ai_move, -5, NULL},
{ai_move, -5, NULL},
{ai_move, -5, NULL},
@ -1521,14 +1624,15 @@ mframe_t soldier_frames_death5[] = {
{ai_move, 0, NULL}
};
mmove_t soldier_move_death5 = {
mmove_t soldier_move_death5 =
{
FRAME_death501,
FRAME_death524,
soldier_frames_death5,
soldier_dead
};
mframe_t soldier_frames_death6[] = {
static mframe_t soldier_frames_death6[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -1541,16 +1645,18 @@ mframe_t soldier_frames_death6[] = {
{ai_move, 0, NULL}
};
mmove_t soldier_move_death6 = {
mmove_t soldier_move_death6 =
{
FRAME_death601,
FRAME_death610,
soldier_frames_death6,
soldier_dead
FRAME_death610,
soldier_frames_death6,
soldier_dead
};
void
soldier_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /* unused */,
int damage, vec3_t point /* unused */)
soldier_die(edict_t *self, edict_t *inflictor /* unused */,
edict_t *attacker /* unused */, int damage,
vec3_t point /* unused */)
{
int n;
@ -1566,11 +1672,14 @@ soldier_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker /*
for (n = 0; n < 3; n++)
{
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2",
damage, GIB_ORGANIC);
}
ThrowGib(self, "models/objects/gibs/chest/tris.md2", damage, GIB_ORGANIC);
ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
ThrowGib(self, "models/objects/gibs/chest/tris.md2",
damage, GIB_ORGANIC);
ThrowHead(self, "models/objects/gibs/head2/tris.md2",
damage, GIB_ORGANIC);
self->deadflag = DEAD_DEAD;
return;
}
@ -1687,7 +1796,7 @@ soldier_duck(edict_t *self, float eta)
}
}
mframe_t soldier_frames_blind[] = {
static mframe_t soldier_frames_blind[] = {
{ai_move, 0, soldier_idle},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -1748,6 +1857,13 @@ SP_monster_soldier_x(edict_t *self)
return;
}
// Force recaching at next footstep to ensure
// that the sound indices are correct.
sound_step = 0;
sound_step2 = 0;
sound_step3 = 0;
sound_step4 = 0;
self->s.modelindex = gi.modelindex("models/monsters/soldier/tris.md2");
self->monsterinfo.scale = MODEL_SCALE;
VectorSet(self->mins, -16, -16, -24);
@ -1809,6 +1925,9 @@ SP_monster_soldier_light(edict_t *self)
return;
}
self->health = 20;
self->gib_health = -30;
SP_monster_soldier_x(self);
sound_pain_light = gi.soundindex("soldier/solpain2.wav");
@ -1818,9 +1937,6 @@ SP_monster_soldier_light(edict_t *self)
gi.soundindex("soldier/solatck2.wav");
self->s.skinnum = 0;
self->health = 20;
self->gib_health = -30;
self->monsterinfo.blindfire = true;
}
@ -1843,6 +1959,9 @@ SP_monster_soldier(edict_t *self)
return;
}
self->health = 30;
self->gib_health = -30;
SP_monster_soldier_x(self);
sound_pain = gi.soundindex("soldier/solpain1.wav");
@ -1850,8 +1969,6 @@ SP_monster_soldier(edict_t *self)
gi.soundindex("soldier/solatck1.wav");
self->s.skinnum = 2;
self->health = 30;
self->gib_health = -30;
}
/*
@ -1873,6 +1990,9 @@ SP_monster_soldier_ss(edict_t *self)
return;
}
self->health = 40;
self->gib_health = -30;
SP_monster_soldier_x(self);
sound_pain_ss = gi.soundindex("soldier/solpain3.wav");
@ -1880,6 +2000,4 @@ SP_monster_soldier_ss(edict_t *self)
gi.soundindex("soldier/solatck3.wav");
self->s.skinnum = 4;
self->health = 40;
self->gib_health = -30;
}

View file

@ -196,7 +196,7 @@ stalker_idle_noise(edict_t *self)
gi.sound(self, CHAN_WEAPON, sound_idle, 0.5, ATTN_IDLE, 0);
}
mframe_t stalker_frames_idle[] = {
static mframe_t stalker_frames_idle[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -231,7 +231,7 @@ mmove_t stalker_move_idle = {
stalker_stand
};
mframe_t stalker_frames_idle2[] = {
static mframe_t stalker_frames_idle2[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -274,7 +274,7 @@ stalker_idle(edict_t *self)
}
}
mframe_t stalker_frames_stand[] = {
static mframe_t stalker_frames_stand[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -327,7 +327,7 @@ stalker_stand(edict_t *self)
}
}
mframe_t stalker_frames_run[] = {
static mframe_t stalker_frames_run[] = {
{ai_run, 13, NULL},
{ai_run, 17, NULL},
{ai_run, 21, NULL},
@ -359,7 +359,7 @@ stalker_run(edict_t *self)
}
}
mframe_t stalker_frames_walk[] = {
static mframe_t stalker_frames_walk[] = {
{ai_walk, 4, NULL},
{ai_walk, 6, NULL},
{ai_walk, 8, NULL},
@ -389,7 +389,7 @@ stalker_walk(edict_t *self)
self->monsterinfo.currentmove = &stalker_move_walk;
}
mframe_t stalker_frames_reactivate[] = {
static mframe_t stalker_frames_reactivate[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -448,7 +448,7 @@ stalker_heal(edict_t *self)
}
}
mframe_t stalker_frames_false_death[] = {
static mframe_t stalker_frames_false_death[] = {
{ai_move, 0, stalker_heal},
{ai_move, 0, stalker_heal},
{ai_move, 0, stalker_heal},
@ -480,7 +480,7 @@ stalker_false_death(edict_t *self)
self->monsterinfo.currentmove = &stalker_move_false_death;
}
mframe_t stalker_frames_false_death_start[] = {
static mframe_t stalker_frames_false_death_start[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -515,7 +515,7 @@ stalker_false_death_start(edict_t *self)
self->monsterinfo.currentmove = &stalker_move_false_death_start;
}
mframe_t stalker_frames_pain[] = {
static mframe_t stalker_frames_pain[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -678,7 +678,7 @@ stalker_shoot_attack2(edict_t *self)
}
}
mframe_t stalker_frames_shoot[] = {
static mframe_t stalker_frames_shoot[] = {
{ai_charge, 13, NULL},
{ai_charge, 17, stalker_shoot_attack},
{ai_charge, 21, NULL},
@ -748,7 +748,7 @@ stalker_swing_attack(edict_t *self)
}
}
mframe_t stalker_frames_swing_l[] = {
static mframe_t stalker_frames_swing_l[] = {
{ai_charge, 2, NULL},
{ai_charge, 4, NULL},
{ai_charge, 6, NULL},
@ -766,7 +766,7 @@ mmove_t stalker_move_swing_l = {
stalker_run
};
mframe_t stalker_frames_swing_r[] = {
static mframe_t stalker_frames_swing_r[] = {
{ai_charge, 4, NULL},
{ai_charge, 6, NULL},
{ai_charge, 6, stalker_swing_attack},
@ -1085,7 +1085,7 @@ stalker_jump_straightup(edict_t *self)
}
}
mframe_t stalker_frames_jump_straightup[] = {
static mframe_t stalker_frames_jump_straightup[] = {
{ai_move, 1, stalker_jump_straightup},
{ai_move, 1, stalker_jump_wait_land},
{ai_move, -1, NULL},
@ -1110,7 +1110,7 @@ stalker_dodge_jump(edict_t *self)
self->monsterinfo.currentmove = &stalker_move_jump_straightup;
}
mframe_t stalker_frames_dodge_run[] = {
static mframe_t stalker_frames_dodge_run[] = {
{ai_run, 13, NULL},
{ai_run, 17, NULL},
{ai_run, 21, NULL},
@ -1220,7 +1220,7 @@ stalker_jump_wait_land(edict_t *self)
}
}
mframe_t stalker_frames_jump_up[] = {
static mframe_t stalker_frames_jump_up[] = {
{ai_move, -8, NULL},
{ai_move, -8, NULL},
{ai_move, -8, NULL},
@ -1238,7 +1238,7 @@ mmove_t stalker_move_jump_up = {
stalker_run
};
mframe_t stalker_frames_jump_down[] = {
static mframe_t stalker_frames_jump_down[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -1357,7 +1357,7 @@ stalker_dead(edict_t *self)
gi.linkentity(self);
}
mframe_t stalker_frames_death[] = {
static mframe_t stalker_frames_death[] = {
{ai_move, 0, NULL},
{ai_move, -5, NULL},
{ai_move, -10, NULL},

View file

@ -54,7 +54,7 @@ supertank_search(edict_t *self)
}
}
mframe_t supertank_frames_stand[] = {
static mframe_t supertank_frames_stand[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -135,7 +135,7 @@ supertank_stand(edict_t *self)
self->monsterinfo.currentmove = &supertank_move_stand;
}
mframe_t supertank_frames_run[] = {
static mframe_t supertank_frames_run[] = {
{ai_run, 12, TreadSound},
{ai_run, 12, NULL},
{ai_run, 12, NULL},
@ -163,7 +163,7 @@ mmove_t supertank_move_run = {
NULL
};
mframe_t supertank_frames_forward[] = {
static mframe_t supertank_frames_forward[] = {
{ai_walk, 4, TreadSound},
{ai_walk, 4, NULL},
{ai_walk, 4, NULL},
@ -231,7 +231,7 @@ supertank_run(edict_t *self)
}
}
mframe_t supertank_frames_turn_right[] = {
static mframe_t supertank_frames_turn_right[] = {
{ai_move, 0, TreadSound},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -259,7 +259,7 @@ mmove_t supertank_move_turn_right = {
supertank_run
};
mframe_t supertank_frames_turn_left[] = {
static mframe_t supertank_frames_turn_left[] = {
{ai_move, 0, TreadSound},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -287,7 +287,7 @@ mmove_t supertank_move_turn_left = {
supertank_run
};
mframe_t supertank_frames_pain3[] = {
static mframe_t supertank_frames_pain3[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -301,7 +301,7 @@ mmove_t supertank_move_pain3 = {
supertank_run
};
mframe_t supertank_frames_pain2[] = {
static mframe_t supertank_frames_pain2[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -315,7 +315,7 @@ mmove_t supertank_move_pain2 = {
supertank_run
};
mframe_t supertank_frames_pain1[] = {
static mframe_t supertank_frames_pain1[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -329,7 +329,7 @@ mmove_t supertank_move_pain1 = {
supertank_run
};
mframe_t supertank_frames_death1[] = {
static mframe_t supertank_frames_death1[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -363,7 +363,7 @@ mmove_t supertank_move_death = {
supertank_dead
};
mframe_t supertank_frames_backward[] = {
static mframe_t supertank_frames_backward[] = {
{ai_walk, 0, TreadSound},
{ai_walk, 0, NULL},
{ai_walk, 0, NULL},
@ -391,7 +391,7 @@ mmove_t supertank_move_backward = {
NULL
};
mframe_t supertank_frames_attack4[] = {
static mframe_t supertank_frames_attack4[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -407,7 +407,7 @@ mmove_t supertank_move_attack4 = {
supertank_run
};
mframe_t supertank_frames_attack3[] = {
static mframe_t supertank_frames_attack3[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -444,7 +444,7 @@ mmove_t supertank_move_attack3 = {
supertank_run
};
mframe_t supertank_frames_attack2[] = {
static mframe_t supertank_frames_attack2[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -481,7 +481,7 @@ mmove_t supertank_move_attack2 = {
supertank_run
};
mframe_t supertank_frames_attack1[] = {
static mframe_t supertank_frames_attack1[] = {
{ai_charge, 0, supertankMachineGun},
{ai_charge, 0, supertankMachineGun},
{ai_charge, 0, supertankMachineGun},
@ -497,7 +497,7 @@ mmove_t supertank_move_attack1 = {
supertank_reattack1
};
mframe_t supertank_frames_end_attack1[] = {
static mframe_t supertank_frames_end_attack1[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},

View file

@ -78,7 +78,7 @@ tank_idle(edict_t *self)
gi.sound(self, CHAN_VOICE, sound_idle, 1, ATTN_IDLE, 0);
}
mframe_t tank_frames_stand[] = {
static mframe_t tank_frames_stand[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -129,7 +129,7 @@ tank_stand(edict_t *self)
self->monsterinfo.currentmove = &tank_move_stand;
}
mframe_t tank_frames_start_walk[] = {
static mframe_t tank_frames_start_walk[] = {
{ai_walk, 0, NULL},
{ai_walk, 6, NULL},
{ai_walk, 6, NULL},
@ -143,7 +143,7 @@ mmove_t tank_move_start_walk = {
tank_walk
};
mframe_t tank_frames_walk[] = {
static mframe_t tank_frames_walk[] = {
{ai_walk, 4, NULL},
{ai_walk, 5, NULL},
{ai_walk, 3, NULL},
@ -169,7 +169,7 @@ mmove_t tank_move_walk = {
NULL
};
mframe_t tank_frames_stop_walk[] = {
static mframe_t tank_frames_stop_walk[] = {
{ai_walk, 3, NULL},
{ai_walk, 3, NULL},
{ai_walk, 2, NULL},
@ -195,7 +195,7 @@ tank_walk(edict_t *self)
self->monsterinfo.currentmove = &tank_move_walk;
}
mframe_t tank_frames_start_run[] = {
static mframe_t tank_frames_start_run[] = {
{ai_run, 0, NULL},
{ai_run, 6, NULL},
{ai_run, 6, NULL},
@ -209,7 +209,7 @@ mmove_t tank_move_start_run = {
tank_run
};
mframe_t tank_frames_run[] = {
static mframe_t tank_frames_run[] = {
{ai_run, 4, NULL},
{ai_run, 5, NULL},
{ai_run, 3, NULL},
@ -235,7 +235,7 @@ mmove_t tank_move_run = {
NULL
};
mframe_t tank_frames_stop_run[] = {
static mframe_t tank_frames_stop_run[] = {
{ai_run, 3, NULL},
{ai_run, 3, NULL},
{ai_run, 2, NULL},
@ -284,7 +284,7 @@ tank_run(edict_t *self)
}
}
mframe_t tank_frames_pain1[] = {
static mframe_t tank_frames_pain1[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -298,7 +298,7 @@ mmove_t tank_move_pain1 = {
tank_run
};
mframe_t tank_frames_pain2[] = {
static mframe_t tank_frames_pain2[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -313,7 +313,7 @@ mmove_t tank_move_pain2 = {
tank_run
};
mframe_t tank_frames_pain3[] = {
static mframe_t tank_frames_pain3[] = {
{ai_move, -7, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -547,64 +547,26 @@ TankRocket(edict_t *self)
VectorNormalize(dir);
// Blindfire doesn't check target (done in checkattack). Paranoia:
// Make sure we're not shooting a target right next to us.
trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
if (blindfire)
{
// Blindfire has different fail criteria for the trace
if (!(trace.startsolid || trace.allsolid || (trace.fraction < 0.5)))
/* blindfire has different fail criteria for the trace */
if (!blind_rocket_ok(self, start, right, target, 20.0f, dir))
{
monster_fire_rocket (self, start, dir, 50, rocketSpeed, flash_number);
}
else
{
// Try shifting the target to the left a little (to help counter large offset)
VectorCopy(target, vec);
VectorMA(vec, -20, right, vec);
VectorSubtract(vec, start, dir);
VectorNormalize(dir);
trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
if (!(trace.startsolid || trace.allsolid || (trace.fraction < 0.5)))
{
monster_fire_rocket (self, start, dir, 50, rocketSpeed, flash_number);
}
else
{
// OK, that failed. Try to the right.
VectorCopy(target, vec);
VectorMA(vec, 20, right, vec);
VectorSubtract(vec, start, dir);
VectorNormalize(dir);
trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
if (!(trace.startsolid || trace.allsolid || (trace.fraction < 0.5)))
{
monster_fire_rocket (self, start, dir, 50, rocketSpeed, flash_number);
}
else if ((g_showlogic) && (g_showlogic->value))
{
gi.dprintf ("tank avoiding blindfire shot\n");
}
}
return;
}
}
else
{
trace = gi.trace(start, vec3_origin, vec3_origin, vec, self, MASK_SHOT);
if (trace.ent == self->enemy || trace.ent == world)
if (((trace.ent != self->enemy) && (trace.ent != world)) ||
((trace.fraction <= 0.5f) && !trace.ent->client))
{
if (trace.fraction > 0.5 || (trace.ent && trace.ent->client))
{
monster_fire_rocket (self, start, dir, 50, rocketSpeed, MZ2_CHICK_ROCKET_1);
}
return;
}
}
monster_fire_rocket (self, start, dir, 50, rocketSpeed, flash_number);
}
void
@ -657,7 +619,7 @@ TankMachineGun(edict_t *self)
DEFAULT_BULLET_VSPREAD, flash_number);
}
mframe_t tank_frames_attack_blast[] = {
static mframe_t tank_frames_attack_blast[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -682,7 +644,7 @@ mmove_t tank_move_attack_blast = {
tank_reattack_blaster
};
mframe_t tank_frames_reattack_blast[] = {
static mframe_t tank_frames_reattack_blast[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, TankBlaster},
@ -698,7 +660,7 @@ mmove_t tank_move_reattack_blast = {
tank_reattack_blaster
};
mframe_t tank_frames_attack_post_blast[] = {
static mframe_t tank_frames_attack_post_blast[] = {
{ai_move, 0, NULL}, /* 17 */
{ai_move, 0, NULL},
{ai_move, 2, NULL},
@ -752,7 +714,7 @@ tank_poststrike(edict_t *self)
tank_run(self);
}
mframe_t tank_frames_attack_strike[] = {
static mframe_t tank_frames_attack_strike[] = {
{ai_move, 3, NULL},
{ai_move, 2, NULL},
{ai_move, 2, NULL},
@ -800,7 +762,7 @@ mmove_t tank_move_attack_strike = {
tank_poststrike
};
mframe_t tank_frames_attack_pre_rocket[] = {
static mframe_t tank_frames_attack_pre_rocket[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -833,7 +795,7 @@ mmove_t tank_move_attack_pre_rocket = {
tank_doattack_rocket
};
mframe_t tank_frames_attack_fire_rocket[] = {
static mframe_t tank_frames_attack_fire_rocket[] = {
{ai_charge, -3, NULL}, /* Loop Start 22 */
{ai_charge, 0, NULL},
{ai_charge, 0, TankRocket}, /* 24 */
@ -852,7 +814,7 @@ mmove_t tank_move_attack_fire_rocket = {
tank_refire_rocket
};
mframe_t tank_frames_attack_post_rocket[] = {
static mframe_t tank_frames_attack_post_rocket[] = {
{ai_charge, 0, NULL}, /* 31 */
{ai_charge, -1, NULL},
{ai_charge, -1, NULL},
@ -887,7 +849,7 @@ mmove_t tank_move_attack_post_rocket = {
tank_run
};
mframe_t tank_frames_attack_chain[] = {
static mframe_t tank_frames_attack_chain[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -1091,7 +1053,7 @@ tank_dead(edict_t *self)
gi.linkentity(self);
}
mframe_t tank_frames_death1[] = {
static mframe_t tank_frames_death1[] = {
{ai_move, -7, NULL},
{ai_move, -2, NULL},
{ai_move, -2, NULL},

View file

@ -346,7 +346,7 @@ turret_search(edict_t *self)
{
}
mframe_t turret_frames_stand[] = {
static mframe_t turret_frames_stand[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL}
};
@ -369,7 +369,7 @@ turret_stand(edict_t *self)
self->monsterinfo.currentmove = &turret_move_stand;
}
mframe_t turret_frames_ready_gun[] = {
static mframe_t turret_frames_ready_gun[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -399,7 +399,7 @@ turret_ready_gun(edict_t *self)
self->monsterinfo.currentmove = &turret_move_ready_gun;
}
mframe_t turret_frames_seek[] = {
static mframe_t turret_frames_seek[] = {
{ai_walk, 0, TurretAim},
{ai_walk, 0, TurretAim}
};
@ -429,7 +429,7 @@ turret_walk(edict_t *self)
}
}
mframe_t turret_frames_run[] = {
static mframe_t turret_frames_run[] = {
{ai_run, 0, TurretAim},
{ai_run, 0, TurretAim}
};
@ -653,7 +653,7 @@ TurretFireBlind(edict_t *self)
}
}
mframe_t turret_frames_fire[] = {
static mframe_t turret_frames_fire[] = {
{ai_run, 0, TurretFire},
{ai_run, 0, TurretAim},
{ai_run, 0, TurretAim},
@ -668,7 +668,7 @@ mmove_t turret_move_fire = {
};
/* the blind frames need to aim first */
mframe_t turret_frames_fire_blind[] = {
static mframe_t turret_frames_fire_blind[] = {
{ai_run, 0, TurretAim},
{ai_run, 0, TurretAim},
{ai_run, 0, TurretAim},
@ -887,6 +887,7 @@ turret_wake(edict_t *self)
self->monsterinfo.sight = turret_sight;
self->monsterinfo.search = turret_search;
self->monsterinfo.currentmove = &turret_move_stand;
self->takedamage = DAMAGE_AIM;
self->movetype = MOVETYPE_NONE;
self->monsterinfo.aiflags |= AI_DO_NOT_COUNT;
@ -895,6 +896,11 @@ turret_wake(edict_t *self)
stationarymonster_start(self);
if (self->think)
{
self->think(self);
}
if (self->spawnflags & SPAWN_MACHINEGUN)
{
self->s.skinnum = 1;
@ -915,6 +921,11 @@ turret_activate(edict_t *self, edict_t *other, edict_t *activator)
vec3_t forward;
edict_t *base;
if (self->movetype == MOVETYPE_PUSH)
{
return;
}
self->movetype = MOVETYPE_PUSH;
if (!self->speed)
@ -950,6 +961,10 @@ turret_activate(edict_t *self, edict_t *other, edict_t *activator)
{
VectorSet(forward, 0, -1, 0);
}
else
{
VectorClear(forward);
}
/* start up the turret */
VectorMA(self->s.origin, 32, forward, endpos);
@ -980,7 +995,6 @@ turret_checkattack(edict_t *self)
vec3_t spot1, spot2;
float chance, nexttime;
trace_t tr;
int enemy_range;
if (!self)
{
@ -1048,20 +1062,6 @@ turret_checkattack(edict_t *self)
return false;
}
enemy_range = range(self, self->enemy);
if (enemy_range == RANGE_MELEE)
{
/* don't always melee in easy mode */
if ((skill->value == SKILL_EASY) && (rand() & 3))
{
return false;
}
self->monsterinfo.attack_state = AS_MISSILE;
return true;
}
if (self->spawnflags & SPAWN_ROCKET)
{
chance = 0.10;

View file

@ -452,7 +452,7 @@ widow_step(edict_t *self)
gi.sound(self, CHAN_BODY, gi.soundindex("widow/bwstep3.wav"), 1, ATTN_NORM, 0);
}
mframe_t widow_frames_stand[] = {
static mframe_t widow_frames_stand[] = {
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
{ai_stand, 0, NULL},
@ -473,7 +473,7 @@ mmove_t widow_move_stand = {
NULL
};
mframe_t widow_frames_walk[] = {
static mframe_t widow_frames_walk[] = {
/* auto generated numbers */
{ai_walk, 2.79, widow_step},
{ai_walk, 2.77, NULL},
@ -497,7 +497,7 @@ mmove_t widow_move_walk = {
NULL
};
mframe_t widow_frames_run[] = {
static mframe_t widow_frames_run[] = {
{ai_run, 2.79, widow_step},
{ai_run, 2.77, NULL},
{ai_run, 3.53, NULL},
@ -532,7 +532,7 @@ widow_stepshoot(edict_t *self)
WidowBlaster(self);
}
mframe_t widow_frames_run_attack[] = {
static mframe_t widow_frames_run_attack[] = {
{ai_charge, 13, widow_stepshoot},
{ai_charge, 11.72, WidowBlaster},
{ai_charge, 18.04, WidowBlaster},
@ -588,7 +588,7 @@ widow_start_run_12(edict_t *self)
self->monsterinfo.nextframe = FRAME_walk12;
}
mframe_t widow_frames_attack_pre_blaster[] = {
static mframe_t widow_frames_attack_pre_blaster[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, widow_attack_blaster}
@ -601,7 +601,7 @@ mmove_t widow_move_attack_pre_blaster = {
NULL
};
mframe_t widow_frames_attack_blaster[] = {
static mframe_t widow_frames_attack_blaster[] = {
{ai_charge, 0, widow_reattack_blaster}, /* straight ahead */
{ai_charge, 0, widow_reattack_blaster}, /* 100 degrees right */
{ai_charge, 0, widow_reattack_blaster},
@ -630,7 +630,7 @@ mmove_t widow_move_attack_blaster = {
NULL
};
mframe_t widow_frames_attack_post_blaster[] = {
static mframe_t widow_frames_attack_post_blaster[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL}
};
@ -642,7 +642,7 @@ mmove_t widow_move_attack_post_blaster = {
widow_run
};
mframe_t widow_frames_attack_post_blaster_r[] = {
static mframe_t widow_frames_attack_post_blaster_r[] = {
{ai_charge, -2, NULL},
{ai_charge, -10, NULL},
{ai_charge, -2, NULL},
@ -657,7 +657,7 @@ mmove_t widow_move_attack_post_blaster_r = {
NULL
};
mframe_t widow_frames_attack_post_blaster_l[] = {
static mframe_t widow_frames_attack_post_blaster_l[] = {
{ai_charge, 0, NULL},
{ai_charge, 14, NULL},
{ai_charge, -2, NULL},
@ -746,7 +746,7 @@ widow_rail_done(edict_t *self)
self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING;
}
mframe_t widow_frames_attack_pre_rail[] = {
static mframe_t widow_frames_attack_pre_rail[] = {
{ai_charge, 0, widow_start_rail},
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -760,7 +760,7 @@ mmove_t widow_move_attack_pre_rail = {
NULL
};
mframe_t widow_frames_attack_rail[] = {
static mframe_t widow_frames_attack_rail[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, WidowSaveLoc},
@ -779,7 +779,7 @@ mmove_t widow_move_attack_rail = {
widow_run
};
mframe_t widow_frames_attack_rail_r[] = {
static mframe_t widow_frames_attack_rail_r[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, WidowSaveLoc},
@ -797,7 +797,7 @@ mmove_t widow_move_attack_rail_r = {
widow_run
};
mframe_t widow_frames_attack_rail_l[] = {
static mframe_t widow_frames_attack_rail_l[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, WidowSaveLoc},
@ -864,7 +864,7 @@ widow_done_spawn(edict_t *self)
self->monsterinfo.aiflags &= ~AI_MANUAL_STEERING;
}
mframe_t widow_frames_spawn[] = {
static mframe_t widow_frames_spawn[] = {
{ai_charge, 0, NULL}, /* 1 */
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
@ -892,7 +892,7 @@ mmove_t widow_move_spawn = {
widow_run
};
mframe_t widow_frames_pain_heavy[] = {
static mframe_t widow_frames_pain_heavy[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -915,7 +915,7 @@ mmove_t widow_move_pain_heavy = {
widow_run
};
mframe_t widow_frames_pain_light[] = {
static mframe_t widow_frames_pain_light[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL}
@ -994,7 +994,7 @@ spawn_out_do(edict_t *self)
G_FreeEdict(self);
}
mframe_t widow_frames_death[] = {
static mframe_t widow_frames_death[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -1057,7 +1057,7 @@ widow_attack_kick(edict_t *self)
}
}
mframe_t widow_frames_attack_kick[] = {
static mframe_t widow_frames_attack_kick[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},

View file

@ -292,7 +292,7 @@ widow2_ready_spawn(edict_t *self)
}
}
mframe_t widow2_frames_stand[] = {
static mframe_t widow2_frames_stand[] = {
{ai_stand, 0, NULL}
};
@ -303,7 +303,7 @@ mmove_t widow2_move_stand = {
NULL
};
mframe_t widow2_frames_walk[] = {
static mframe_t widow2_frames_walk[] = {
{ai_walk, 9.01, NULL},
{ai_walk, 7.55, NULL},
{ai_walk, 7.01, NULL},
@ -322,7 +322,7 @@ mmove_t widow2_move_walk = {
NULL
};
mframe_t widow2_frames_run[] = {
static mframe_t widow2_frames_run[] = {
{ai_run, 9.01, NULL},
{ai_run, 7.55, NULL},
{ai_run, 7.01, NULL},
@ -341,7 +341,7 @@ mmove_t widow2_move_run = {
NULL
};
mframe_t widow2_frames_attack_pre_beam[] = {
static mframe_t widow2_frames_attack_pre_beam[] = {
{ai_charge, 4, NULL},
{ai_charge, 4, NULL},
{ai_charge, 4, NULL},
@ -356,7 +356,7 @@ mmove_t widow2_move_attack_pre_beam = {
};
/* Loop this */
mframe_t widow2_frames_attack_beam[] = {
static mframe_t widow2_frames_attack_beam[] = {
{ai_charge, 0, Widow2Beam},
{ai_charge, 0, Widow2Beam},
{ai_charge, 0, Widow2Beam},
@ -371,7 +371,7 @@ mmove_t widow2_move_attack_beam = {
NULL
};
mframe_t widow2_frames_attack_post_beam[] = {
static mframe_t widow2_frames_attack_post_beam[] = {
{ai_charge, 4, NULL},
{ai_charge, 4, NULL},
{ai_charge, 4, NULL}
@ -455,7 +455,7 @@ widow2_disrupt_reattack(edict_t *self)
}
}
mframe_t widow2_frames_attack_disrupt[] = {
static mframe_t widow2_frames_attack_disrupt[] = {
{ai_charge, 2, NULL},
{ai_charge, 2, NULL},
{ai_charge, 2, Widow2SaveDisruptLoc},
@ -515,7 +515,7 @@ Widow2StartSweep(edict_t *self)
Widow2SaveBeamTarget(self);
}
mframe_t widow2_frames_spawn[] = {
static mframe_t widow2_frames_spawn[] = {
{ai_charge, 0, NULL},
{ai_charge, 0, NULL},
{ai_charge, 0, widow_start_spawn},
@ -725,7 +725,7 @@ Widow2Toss(edict_t *self)
return;
}
mframe_t widow2_frames_tongs[] = {
static mframe_t widow2_frames_tongs[] = {
{ai_charge, 0, Widow2Tongue},
{ai_charge, 0, Widow2Tongue},
{ai_charge, 0, Widow2Tongue},
@ -743,7 +743,7 @@ mmove_t widow2_move_tongs = {
widow2_run
};
mframe_t widow2_frames_pain[] = {
static mframe_t widow2_frames_pain[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -758,7 +758,7 @@ mmove_t widow2_move_pain = {
widow2_run
};
mframe_t widow2_frames_death[] = {
static mframe_t widow2_frames_death[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, WidowExplosion1}, /* 3 boom */
@ -820,7 +820,7 @@ mmove_t widow2_move_death = {
NULL
};
mframe_t widow2_frames_dead[] = {
static mframe_t widow2_frames_dead[] = {
{ai_move, 0, widow2_start_searching},
{ai_move, 0, NULL},
{ai_move, 0, NULL},
@ -847,7 +847,7 @@ mmove_t widow2_move_dead = {
NULL
};
mframe_t widow2_frames_really_dead[] = {
static mframe_t widow2_frames_really_dead[] = {
{ai_move, 0, NULL},
{ai_move, 0, NULL},
{ai_move, 0, NULL},

View file

@ -103,7 +103,7 @@ SP_info_player_coop_lava(edict_t *self)
* as well as yaw. 'pitch yaw roll'
*/
void
SP_info_player_intermission(void)
SP_info_player_intermission(edict_t *ent)
{
}
@ -730,8 +730,8 @@ player_die(edict_t *self, edict_t *inflictor, edict_t *attacker,
/* don't toss gibs if we got vaped by the nuke */
if (!(self->flags & FL_NOGIB))
{
/* gib */
gi.sound(self, CHAN_BODY, gi.soundindex( "misc/udeath.wav"), 1, ATTN_NORM, 0);
/* gib (play sound at end of server frame) */
self->sounds = gi.soundindex( "misc/udeath.wav");
/* more meaty gibs for your dollar! */
if ((deathmatch->value) && (self->health < -80))
@ -788,7 +788,11 @@ player_die(edict_t *self, edict_t *inflictor, edict_t *attacker,
}
}
gi.sound(self, CHAN_VOICE, gi.soundindex(va("*death%i.wav", (rand() % 4) + 1)), 1, ATTN_NORM, 0);
/* play sound at end of server frame */
if (!self->sounds)
{
self->sounds = gi.soundindex(va("*death%i.wav", (rand() % 4) + 1));
}
}
}
@ -874,7 +878,7 @@ SaveClientData(void)
game.clients[i].pers.health = ent->health;
game.clients[i].pers.max_health = ent->max_health;
game.clients[i].pers.savedFlags = (ent->flags & (FL_GODMODE | FL_NOTARGET | FL_POWER_ARMOR));
game.clients[i].pers.savedFlags = (ent->flags & (FL_GODMODE | FL_NOTARGET | FL_POWER_ARMOR | FL_DISGUISED));
if (coop->value)
{

View file

@ -113,13 +113,15 @@ BeginIntermission(edict_t *targ)
}
/* strip players of all keys between units */
for (n = 0; n < MAX_ITEMS; n++)
for (n = 0; n < game.num_items; n++)
{
if (itemlist[n].flags & IT_KEY)
{
client->client->pers.inventory[n] = 0;
}
}
client->client->pers.power_cubes = 0;
}
}
}
@ -396,7 +398,7 @@ G_SetStats(edict_t *ent)
/* health */
ent->client->ps.stats[STAT_HEALTH_ICON] = level.pic_health;
ent->client->ps.stats[STAT_HEALTH] = ent->health;
ent->client->ps.stats[STAT_HEALTH] = (ent->health < -99) ? -99 : ent->health;
/* ammo */
if (!ent->client->ammo_index)

View file

@ -63,6 +63,13 @@ P_DamageFeedback(edict_t *player)
return;
}
/* death/gib sound is now aggregated and played here */
if (player->sounds)
{
gi.sound (player, CHAN_VOICE, player->sounds, 1, ATTN_NORM, 0);
player->sounds = 0;
}
client = player->client;
/* flash the backgrounds behind the status numbers */
@ -131,7 +138,8 @@ P_DamageFeedback(edict_t *player)
/* play an apropriate pain sound */
if ((level.time > player->pain_debounce_time) &&
!(player->flags & FL_GODMODE) &&
(client->invincible_framenum <= level.framenum))
(client->invincible_framenum <= level.framenum) &&
player->health > 0)
{
r = 1 + (rand() & 1);
player->pain_debounce_time = level.time + 0.7;
@ -940,7 +948,8 @@ P_WorldEffects(void)
{
if ((current_player->health > 0) &&
(current_player->pain_debounce_time <= level.time) &&
(current_client->invincible_framenum < level.framenum))
(current_client->invincible_framenum < level.framenum) &&
!(current_player->flags & FL_GODMODE))
{
if (rand() & 1)
{
@ -1089,7 +1098,32 @@ G_SetClientEvent(edict_t *ent)
return;
}
if (ent->groundentity && (xyspeed > 225))
if (ent->health <= 0)
{
return;
}
if (g_footsteps->value == 1)
{
if (ent->groundentity && (xyspeed > 225))
{
if ((int)(current_client->bobtime + bobmove) != bobcycle)
{
ent->s.event = EV_FOOTSTEP;
}
}
}
else if (g_footsteps->value == 2)
{
if (ent->groundentity)
{
if ((int)(current_client->bobtime + bobmove) != bobcycle)
{
ent->s.event = EV_FOOTSTEP;
}
}
}
else if (g_footsteps->value >= 3)
{
if ((int)(current_client->bobtime + bobmove) != bobcycle)
{

View file

@ -7,6 +7,10 @@
#include "../header/local.h"
#include "../monster/misc/player.h"
#include <limits.h>
#define PLAYER_NOISE_SELF 0
#define PLAYER_NOISE_IMPACT 1
#define FRAME_FIRE_FIRST (FRAME_ACTIVATE_LAST + 1)
#define FRAME_IDLE_FIRST (FRAME_FIRE_LAST + 1)
@ -63,10 +67,12 @@ P_DamageModifier(edict_t *ent)
}
void
P_ProjectSource(gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward,
P_ProjectSource(edict_t *ent, vec3_t distance, vec3_t forward,
vec3_t right, vec3_t result)
{
vec3_t _distance;
gclient_t *client = ent->client;
float *point = ent->s.origin;
vec3_t _distance;
if (!client)
{
@ -85,13 +91,29 @@ P_ProjectSource(gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward
}
G_ProjectSource(point, _distance, forward, right, result);
// Berserker: fix - now the projectile hits exactly where the scope is pointing.
if (aimfix->value)
{
vec3_t start, end;
VectorSet(start, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] + ent->viewheight);
VectorMA(start, 8192, forward, end);
trace_t tr = gi.trace(start, NULL, NULL, end, ent, MASK_SHOT);
if (tr.fraction < 1)
{
VectorSubtract(tr.endpos, result, forward);
VectorNormalize(forward);
}
}
}
void
P_ProjectSource2(gclient_t *client, vec3_t point, vec3_t distance, vec3_t forward,
P_ProjectSource2(edict_t *ent, vec3_t point, vec3_t distance, vec3_t forward,
vec3_t right, vec3_t up, vec3_t result)
{
vec3_t _distance;
gclient_t *client = ent->client;
vec3_t _distance;
if (!client)
{
@ -110,6 +132,21 @@ P_ProjectSource2(gclient_t *client, vec3_t point, vec3_t distance, vec3_t forwar
}
G_ProjectSource2(point, _distance, forward, right, up, result);
// Berserker: fix - now the projectile hits exactly where the scope is pointing.
if (aimfix->value)
{
vec3_t start, end;
VectorSet(start, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] + ent->viewheight);
VectorMA(start, 8192, forward, end);
trace_t tr = gi.trace(start, NULL, NULL, end, ent, MASK_SHOT);
if (tr.fraction < 1)
{
VectorSubtract(tr.endpos, result, forward);
VectorNormalize(forward);
}
}
}
/*
@ -120,12 +157,111 @@ P_ProjectSource2(gclient_t *client, vec3_t point, vec3_t distance, vec3_t forwar
* Monsters that don't directly see the player can move
* to a noise in hopes of seeing the player from there.
*/
static edict_t *
PlayerNoise_Spawn(edict_t *who, int type)
{
edict_t *noise;
if (!who)
{
return NULL;
}
noise = G_SpawnOptional();
if (!noise)
{
return NULL;
}
noise->classname = "player_noise";
noise->spawnflags = type;
VectorSet (noise->mins, -8, -8, -8);
VectorSet (noise->maxs, 8, 8, 8);
noise->owner = who;
noise->svflags = SVF_NOCLIENT;
return noise;
}
static void
PlayerNoise_Verify(edict_t *who)
{
edict_t *e;
edict_t *n1;
edict_t *n2;
if (!who)
{
return;
}
n1 = who->mynoise;
n2 = who->mynoise2;
if (n1 && !n1->inuse)
{
n1 = NULL;
}
if (n2 && !n2->inuse)
{
n2 = NULL;
}
if (n1 && n2)
{
return;
}
for (e = g_edicts + 1 + game.maxclients; e < &g_edicts[globals.num_edicts]; e++)
{
if (!e->inuse || strcmp(e->classname, "player_noise") != 0)
{
continue;
}
if (e->owner && e->owner != who)
{
continue;
}
e->owner = who;
if (!n2 && (e->spawnflags == PLAYER_NOISE_IMPACT || n1))
{
n2 = e;
}
else
{
n1 = e;
}
if (n1 && n2)
{
break;
}
}
if (!n1)
{
n1 = PlayerNoise_Spawn(who, PLAYER_NOISE_SELF);
}
if (!n2)
{
n2 = PlayerNoise_Spawn(who, PLAYER_NOISE_IMPACT);
}
who->mynoise = n1;
who->mynoise2 = n2;
}
void
PlayerNoise(edict_t *who, vec3_t where, int type)
{
edict_t *noise;
if (!who)
if (!who || !who->client)
{
return;
}
@ -162,24 +298,7 @@ PlayerNoise(edict_t *who, vec3_t where, int type)
}
}
if (!who->mynoise)
{
noise = G_Spawn();
noise->classname = "player_noise";
VectorSet(noise->mins, -8, -8, -8);
VectorSet(noise->maxs, 8, 8, 8);
noise->owner = who;
noise->svflags = SVF_NOCLIENT;
who->mynoise = noise;
noise = G_Spawn();
noise->classname = "player_noise";
VectorSet(noise->mins, -8, -8, -8);
VectorSet(noise->maxs, 8, 8, 8);
noise->owner = who;
noise->svflags = SVF_NOCLIENT;
who->mynoise2 = noise;
}
PlayerNoise_Verify(who);
if ((type == PNOISE_SELF) || (type == PNOISE_WEAPON))
{
@ -188,6 +307,11 @@ PlayerNoise(edict_t *who, vec3_t where, int type)
return;
}
if (!who->mynoise)
{
return;
}
noise = who->mynoise;
level.sound_entity = noise;
level.sound_entity_framenum = level.framenum;
@ -199,6 +323,11 @@ PlayerNoise(edict_t *who, vec3_t where, int type)
return;
}
if (!who->mynoise2)
{
return;
}
noise = who->mynoise2;
level.sound2_entity = noise;
level.sound2_entity_framenum = level.framenum;
@ -226,7 +355,8 @@ Pickup_Weapon(edict_t *ent, edict_t *other)
if ((((int)(dmflags->value) & DF_WEAPONS_STAY) || coop->value) && other->client->pers.inventory[index])
{
if (!(ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM)))
if (!(ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM)) &&
(!coop_pickup_weapons->value || (ent->flags & FL_COOP_TAKEN)))
{
return false; /* leave the weapon for others to pickup */
}
@ -268,6 +398,7 @@ Pickup_Weapon(edict_t *ent, edict_t *other)
if (coop->value)
{
ent->flags |= FL_RESPAWN;
ent->flags |= FL_COOP_TAKEN;
}
}
}
@ -454,6 +585,31 @@ Think_Weapon(edict_t *ent)
}
}
/*
* Client (player) animation for changing weapon
*/
static void
Change_Weap_Animation(edict_t *ent)
{
if (!ent)
{
return;
}
ent->client->anim_priority = ANIM_REVERSE;
if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
{
ent->s.frame = FRAME_crpain4 + 1;
ent->client->anim_end = FRAME_crpain1;
}
else
{
ent->s.frame = FRAME_pain304 + 1;
ent->client->anim_end = FRAME_pain301;
}
}
/*
* Make the weapon ready if there is ammo
*/
@ -536,6 +692,9 @@ Weapon_Generic(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int F
int FRAME_DEACTIVATE_LAST, int *pause_frames, int *fire_frames, void (*fire)(edict_t *ent))
{
int n;
const unsigned short int change_speed = (g_swap_speed->value > 1)?
(g_swap_speed->value < USHRT_MAX)? (unsigned short int)g_swap_speed->value : 1
: 1;
if (!ent || !fire)
{
@ -549,41 +708,36 @@ Weapon_Generic(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int F
if (ent->client->weaponstate == WEAPON_DROPPING)
{
if (ent->client->ps.gunframe == FRAME_DEACTIVATE_LAST)
if (ent->client->ps.gunframe >= FRAME_DEACTIVATE_LAST - change_speed + 1)
{
ChangeWeapon(ent);
return;
}
else if ((FRAME_DEACTIVATE_LAST - ent->client->ps.gunframe) == 4)
else if ( (FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) >= (4 * change_speed) )
{
ent->client->anim_priority = ANIM_REVERSE;
if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
unsigned short int remainder = FRAME_DEACTIVATE_LAST - ent->client->ps.gunframe;
// "if (remainder == 4)" at change_speed == 1
if ( ( remainder <= (4 * change_speed) )
&& ( remainder > (3 * change_speed) ) )
{
ent->s.frame = FRAME_crpain4 + 1;
ent->client->anim_end = FRAME_crpain1;
}
else
{
ent->s.frame = FRAME_pain304 + 1;
ent->client->anim_end = FRAME_pain301;
Change_Weap_Animation(ent);
}
}
ent->client->ps.gunframe++;
ent->client->ps.gunframe += change_speed;
return;
}
if (ent->client->weaponstate == WEAPON_ACTIVATING)
{
if (ent->client->ps.gunframe == FRAME_ACTIVATE_LAST)
if (ent->client->ps.gunframe >= FRAME_ACTIVATE_LAST - change_speed + 1)
{
ent->client->weaponstate = WEAPON_READY;
ent->client->ps.gunframe = FRAME_IDLE_FIRST;
return;
}
ent->client->ps.gunframe++;
ent->client->ps.gunframe += change_speed;
return;
}
@ -592,20 +746,9 @@ Weapon_Generic(edict_t *ent, int FRAME_ACTIVATE_LAST, int FRAME_FIRE_LAST, int F
ent->client->weaponstate = WEAPON_DROPPING;
ent->client->ps.gunframe = FRAME_DEACTIVATE_FIRST;
if ((FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) < 4)
if ( (FRAME_DEACTIVATE_LAST - FRAME_DEACTIVATE_FIRST) < (4 * change_speed) )
{
ent->client->anim_priority = ANIM_REVERSE;
if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
{
ent->s.frame = FRAME_crpain4 + 1;
ent->client->anim_end = FRAME_crpain1;
}
else
{
ent->s.frame = FRAME_pain304 + 1;
ent->client->anim_end = FRAME_pain301;
}
Change_Weap_Animation(ent);
}
return;
@ -760,7 +903,7 @@ weapon_grenade_fire(edict_t *ent, qboolean held)
VectorSet(offset, 2, 6, ent->viewheight - 14);
}
P_ProjectSource2(ent->client, ent->s.origin, offset,
P_ProjectSource2(ent, ent->s.origin, offset,
forward, right, up, start);
timer = ent->client->grenade_time - level.time;
@ -1037,7 +1180,7 @@ weapon_grenadelauncher_fire(edict_t *ent)
VectorSet(offset, 8, 8, ent->viewheight - 8);
AngleVectors(ent->client->v_angle, forward, right, NULL);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
VectorScale(forward, -2, ent->client->kick_origin);
ent->client->kick_angles[0] = -1;
@ -1135,7 +1278,7 @@ Weapon_RocketLauncher_Fire(edict_t *ent)
ent->client->kick_angles[0] = -1;
VectorSet(offset, 8, 8, ent->viewheight - 8);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
fire_rocket(ent, start, forward, damage, 650, damage_radius, radius_damage);
/* send muzzle flash */
@ -1198,7 +1341,7 @@ Blaster_Fire(edict_t *ent, vec3_t g_offset, int damage,
AngleVectors(ent->client->v_angle, forward, right, NULL);
VectorSet(offset, 24, 8, ent->viewheight - 8);
VectorAdd(offset, g_offset, offset);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
VectorScale(forward, -2, ent->client->kick_origin);
ent->client->kick_angles[0] = -1;
@ -1440,7 +1583,7 @@ Machinegun_Fire(edict_t *ent)
ent->client->kick_angles[0] = ent->client->machinegun_shots * -1.5;
/* raise the gun as it is firing */
if (!deathmatch->value)
if (!(deathmatch->value || g_machinegun_norecoil->value))
{
ent->client->machinegun_shots++;
@ -1454,7 +1597,7 @@ Machinegun_Fire(edict_t *ent)
VectorAdd(ent->client->v_angle, ent->client->kick_angles, angles);
AngleVectors(angles, forward, right, NULL);
VectorSet(offset, 0, 8, ent->viewheight - 8);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
fire_bullet(ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD,
DEFAULT_BULLET_VSPREAD, MOD_MACHINEGUN);
@ -1627,7 +1770,7 @@ Chaingun_Fire(edict_t *ent)
r = 7 + crandom() * 4;
u = crandom() * 4;
VectorSet(offset, 0, r, u + ent->viewheight - 8);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
fire_bullet(ent, start, forward, damage, kick, DEFAULT_BULLET_HSPREAD,
DEFAULT_BULLET_VSPREAD, MOD_CHAINGUN);
@ -1696,7 +1839,7 @@ weapon_shotgun_fire(edict_t *ent)
ent->client->kick_angles[0] = -2;
VectorSet(offset, 0, 8, ent->viewheight - 8);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
if (is_quad)
{
@ -1758,7 +1901,7 @@ weapon_supershotgun_fire(edict_t *ent)
ent->client->kick_angles[0] = -2;
VectorSet(offset, 0, 8, ent->viewheight - 8);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
if (is_quad)
{
@ -1770,10 +1913,35 @@ weapon_supershotgun_fire(edict_t *ent)
v[YAW] = ent->client->v_angle[YAW] - 5;
v[ROLL] = ent->client->v_angle[ROLL];
AngleVectors(v, forward, NULL, NULL);
if (aimfix->value)
{
AngleVectors(v, forward, right, NULL);
VectorScale(forward, -2, ent->client->kick_origin);
ent->client->kick_angles[0] = -2;
VectorSet(offset, 0, 8, ent->viewheight - 8);
P_ProjectSource(ent, offset, forward, right, start);
}
fire_shotgun(ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD,
DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT / 2, MOD_SSHOTGUN);
v[YAW] = ent->client->v_angle[YAW] + 5;
AngleVectors(v, forward, NULL, NULL);
if (aimfix->value)
{
AngleVectors(v, forward, right, NULL);
VectorScale(forward, -2, ent->client->kick_origin);
ent->client->kick_angles[0] = -2;
VectorSet(offset, 0, 8, ent->viewheight - 8);
P_ProjectSource(ent, offset, forward, right, start);
}
fire_shotgun(ent, start, forward, damage, kick, DEFAULT_SHOTGUN_HSPREAD,
DEFAULT_SHOTGUN_VSPREAD, DEFAULT_SSHOTGUN_COUNT / 2, MOD_SSHOTGUN);
@ -1853,7 +2021,7 @@ weapon_railgun_fire(edict_t *ent)
ent->client->kick_angles[0] = -3;
VectorSet(offset, 0, 7, ent->viewheight - 8);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
fire_rail(ent, start, forward, damage, kick);
/* send muzzle flash */
@ -1953,7 +2121,7 @@ weapon_bfg_fire(edict_t *ent)
ent->client->v_dmg_time = level.time + DAMAGE_TIME;
VectorSet(offset, 8, 8, ent->viewheight - 8);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
fire_bfg(ent, start, forward, damage, 400, damage_radius);
ent->client->ps.gunframe++;
@ -2016,7 +2184,7 @@ weapon_chainfist_fire(edict_t *ent)
/* set start point */
VectorSet(offset, 0, 8, ent->viewheight - 4);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
fire_player_melee(ent, start, forward, CHAINFIST_REACH, damage,
100, 1, MOD_CHAINFIST);
@ -2043,7 +2211,7 @@ chainfist_smoke(edict_t *ent)
AngleVectors(ent->client->v_angle, forward, right, up);
VectorSet(offset, 8, 8, ent->viewheight - 4);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, tempVec);
P_ProjectSource(ent, offset, forward, right, tempVec);
gi.WriteByte(svc_temp_entity);
gi.WriteByte(TE_CHAINFIST_SMOKE);
@ -2181,7 +2349,7 @@ weapon_tracker_fire(edict_t *self)
VectorSet(maxs, 16, 16, 16);
AngleVectors(self->client->v_angle, forward, right, NULL);
VectorSet(offset, 24, 8, self->viewheight - 8);
P_ProjectSource(self->client, self->s.origin, offset, forward, right, start);
P_ProjectSource(self, offset, forward, right, start);
VectorMA(start, 8192, forward, end);
enemy = NULL;
@ -2305,7 +2473,7 @@ weapon_etf_rifle_fire(edict_t *ent)
VectorCopy(ent->s.origin, tempPt);
tempPt[2] += ent->viewheight;
P_ProjectSource2(ent->client, tempPt, offset, forward, right, up, start);
P_ProjectSource2(ent, tempPt, offset, forward, right, up, start);
fire_flechette(ent, start, forward, damage, 750, kick);
/* send muzzle flash */
@ -2408,7 +2576,7 @@ Heatbeam_Fire(edict_t *ent)
/* This offset is the "view" offset for the beam start (used by trace) */
VectorSet(offset, 7, 2, ent->viewheight - 3);
P_ProjectSource(ent->client, ent->s.origin, offset, forward, right, start);
P_ProjectSource(ent, offset, forward, right, start);
/* This offset is the entity offset */
VectorSet(offset, 2, 7, -3);

View file

@ -51,19 +51,23 @@
* load older savegames. This should be bumped if the files
* in tables/ are changed, otherwise strange things may happen.
*/
#define SAVEGAMEVER "YQ2-4"
#define SAVEGAMEVER "YQ2-6"
#ifndef BUILD_DATE
#define BUILD_DATE __DATE__
#endif
/*
* This macros are used to prohibit loading of savegames
* created on other systems or architectures. This will
* crash q2 in spectacular ways
*/
#ifndef OSTYPE
#error OSTYPE should be defined by the build system
#ifndef YQ2OSTYPE
#error YQ2OSTYPE should be defined by the build system
#endif
#ifndef ARCH
#error ARCH should be defined by the build system
#ifndef YQ2ARCH
#error YQ2ARCH should be defined by the build system
#endif
/*
@ -71,29 +75,29 @@
* macros, implemented by savegame version YQ2-2.
*/
#if defined(__APPLE__)
#define OSTYPE_1 "MacOS X"
#define YQ2OSTYPE_1 "MacOS X"
#elif defined(__FreeBSD__)
#define OSTYPE_1 "FreeBSD"
#define YQ2OSTYPE_1 "FreeBSD"
#elif defined(__OpenBSD__)
#define OSTYPE_1 "OpenBSD"
#define YQ2OSTYPE_1 "OpenBSD"
#elif defined(__linux__)
#define OSTYPE_1 "Linux"
#define YQ2OSTYPE_1 "Linux"
#elif defined(_WIN32)
#define OSTYPE_1 "Windows"
#define YQ2OSTYPE_1 "Windows"
#else
#define OSTYPE_1 "Unknown"
#define YQ2OSTYPE_1 "Unknown"
#endif
#if defined(__i386__)
#define ARCH_1 "i386"
#define YQ2ARCH_1 "i386"
#elif defined(__x86_64__)
#define ARCH_1 "amd64"
#define YQ2ARCH_1 "amd64"
#elif defined(__sparc__)
#define ARCH_1 "sparc64"
#define YQ2ARCH_1 "sparc64"
#elif defined(__ia64__)
#define ARCH_1 "ia64"
#define YQ2ARCH_1 "ia64"
#else
#define ARCH_1 "unknown"
#define YQ2ARCH_1 "unknown"
#endif
/*
@ -118,6 +122,14 @@ typedef struct
mmove_t *mmovePtr;
} mmoveList_t;
typedef struct
{
char ver[32];
char game[32];
char os[32];
char arch[32];
} savegameHeader_t;
/* ========================================================= */
/*
@ -132,12 +144,12 @@ typedef struct
* to each of the functions
* prototyped above.
*/
functionList_t functionList[] = {
static functionList_t functionList[] = {
#include "tables/gamefunc_list.h"
};
/*
* Prtotypes for forward
* Prototypes for forward
* declaration for all game
* mmove_t functions.
*/
@ -149,12 +161,12 @@ functionList_t functionList[] = {
* functions prototyped
* above.
*/
mmoveList_t mmoveList[] = {
static mmoveList_t mmoveList[] = {
#include "tables/gamemmove_list.h"
};
/*
* Fields to be saved
* Fields to be saved (used in g_spawn.c)
*/
field_t fields[] = {
#include "tables/fields.h"
@ -164,7 +176,7 @@ field_t fields[] = {
* Level fields to
* be saved
*/
field_t levelfields[] = {
static field_t levelfields[] = {
#include "tables/levelfields.h"
};
@ -172,7 +184,7 @@ field_t levelfields[] = {
* Client fields to
* be saved
*/
field_t clientfields[] = {
static field_t clientfields[] = {
#include "tables/clientfields.h"
};
@ -187,7 +199,7 @@ void
InitGame(void)
{
gi.dprintf("Game is starting up.\n");
gi.dprintf("Game is %s built on %s.\n", GAMEVERSION, __DATE__);
gi.dprintf("Game is %s built on %s.\n", GAMEVERSION, BUILD_DATE);
gun_x = gi.cvar ("gun_x", "0", 0);
gun_y = gi.cvar ("gun_y", "0", 0);
@ -208,15 +220,20 @@ InitGame(void)
/* latched vars */
sv_cheats = gi.cvar ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH);
gi.cvar ("gamename", GAMEVERSION , CVAR_SERVERINFO | CVAR_LATCH);
gi.cvar ("gamedate", __DATE__ , CVAR_SERVERINFO | CVAR_LATCH);
gi.cvar ("gamedate", BUILD_DATE, CVAR_SERVERINFO | CVAR_LATCH);
maxclients = gi.cvar ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
maxspectators = gi.cvar ("maxspectators", "4", CVAR_SERVERINFO);
deathmatch = gi.cvar ("deathmatch", "0", CVAR_LATCH);
coop = gi.cvar ("coop", "0", CVAR_LATCH);
coop_baseq2 = gi.cvar ("coop_baseq2", "0", CVAR_LATCH);
coop_elevator_delay = gi.cvar("coop_elevator_delay", "1.0", CVAR_ARCHIVE);
coop_pickup_weapons = gi.cvar("coop_pickup_weapons", "0", CVAR_ARCHIVE);
skill = gi.cvar ("skill", "1", CVAR_LATCH);
maxentities = gi.cvar ("maxentities", "1024", CVAR_LATCH);
gamerules = gi.cvar ("gamerules", "0", CVAR_LATCH); //PGM
g_footsteps = gi.cvar ("g_footsteps", "1", CVAR_LATCH);
g_monsterfootsteps = gi.cvar("g_monsterfootsteps", "0", CVAR_ARCHIVE);
g_fix_triggered = gi.cvar ("g_fix_triggered", "0", 0);
/* change anytime vars */
dmflags = gi.cvar ("dmflags", "0", CVAR_SERVERINFO);
@ -245,6 +262,12 @@ InitGame(void)
/* disruptor availability */
g_disruptor = gi.cvar ("g_disruptor", "0", 0);
/* others */
aimfix = gi.cvar("aimfix", "0", CVAR_ARCHIVE);
g_machinegun_norecoil = gi.cvar("g_machinegun_norecoil", "0", CVAR_ARCHIVE);
g_quick_weap = gi.cvar("g_quick_weap", "1", CVAR_ARCHIVE);
g_swap_speed = gi.cvar("g_swap_speed", "1", CVAR_ARCHIVE);
/* items */
InitItems ();
@ -761,12 +784,9 @@ ReadClient(FILE *f, gclient_t *client, short save_ver)
void
WriteGame(const char *filename, qboolean autosave)
{
savegameHeader_t sv;
FILE *f;
int i;
char str_ver[32];
char str_game[32];
char str_os[32];
char str_arch[32];
if (!autosave)
{
@ -781,20 +801,14 @@ WriteGame(const char *filename, qboolean autosave)
}
/* Savegame identification */
memset(str_ver, 0, sizeof(str_ver));
memset(str_game, 0, sizeof(str_game));
memset(str_os, 0, sizeof(str_os));
memset(str_arch, 0, sizeof(str_arch));
memset(&sv, 0, sizeof(sv));
strncpy(str_ver, SAVEGAMEVER, sizeof(str_ver) - 1);
strncpy(str_game, GAMEVERSION, sizeof(str_game) - 1);
strncpy(str_os, OSTYPE, sizeof(str_os) - 1);
strncpy(str_arch, ARCH, sizeof(str_arch) - 1);
Q_strlcpy(sv.ver, SAVEGAMEVER, sizeof(sv.ver) - 1);
Q_strlcpy(sv.game, GAMEVERSION, sizeof(sv.game) - 1);
Q_strlcpy(sv.os, YQ2OSTYPE, sizeof(sv.os) - 1);
Q_strlcpy(sv.arch, YQ2ARCH, sizeof(sv.arch) - 1);
fwrite(str_ver, sizeof(str_ver), 1, f);
fwrite(str_game, sizeof(str_game), 1, f);
fwrite(str_os, sizeof(str_os), 1, f);
fwrite(str_arch, sizeof(str_arch), 1, f);
fwrite(&sv, sizeof(sv), 1, f);
game.autosaved = autosave;
fwrite(&game, sizeof(game), 1, f);
@ -816,12 +830,10 @@ WriteGame(const char *filename, qboolean autosave)
void
ReadGame(const char *filename)
{
savegameHeader_t sv;
FILE *f;
int i;
char str_ver[32];
char str_game[32];
char str_os[32];
char str_arch[32];
short save_ver = 0;
gi.FreeTags(TAG_GAME);
@ -834,89 +846,89 @@ ReadGame(const char *filename)
}
/* Sanity checks */
fread(str_ver, sizeof(str_ver), 1, f);
fread(str_game, sizeof(str_game), 1, f);
fread(str_os, sizeof(str_os), 1, f);
fread(str_arch, sizeof(str_arch), 1, f);
fread(&sv, sizeof(sv), 1, f);
if (!strcmp(str_ver, SAVEGAMEVER))
static const struct {
const char* verstr;
int vernum;
} version_mappings[] = {
{"YQ2-1", 1},
{"YQ2-2", 2},
{"YQ2-3", 3},
{"YQ2-4", 4},
{"YQ2-5", 5},
{"YQ2-6", 6},
};
for (i=0; i < sizeof(version_mappings)/sizeof(version_mappings[0]); ++i)
{
save_ver = 4;
if (strcmp(str_game, GAMEVERSION))
if (strcmp(version_mappings[i].verstr, sv.ver) == 0)
{
fclose(f);
gi.error("Savegame from an other game.so.\n");
}
else if (strcmp(str_os, OSTYPE))
{
fclose(f);
gi.error("Savegame from an other os.\n");
}
else if (strcmp(str_arch, ARCH))
{
fclose(f);
gi.error("Savegame from an other architecure.\n");
save_ver = version_mappings[i].vernum;
break;
}
}
else if (!strcmp(str_ver, "YQ2-3"))
{
save_ver = 3;
if (strcmp(str_game, GAMEVERSION))
{
fclose(f);
gi.error("Savegame from an other game.so.\n");
}
else if (strcmp(str_os, OSTYPE))
{
fclose(f);
gi.error("Savegame from an other os.\n");
}
else if (strcmp(str_arch, ARCH))
{
fclose(f);
gi.error("Savegame from an other architecure.\n");
}
}
else if (!strcmp(str_ver, "YQ2-2"))
{
save_ver = 2;
if (strcmp(str_game, GAMEVERSION))
{
fclose(f);
gi.error("Savegame from an other game.so.\n");
}
else if (strcmp(str_os, OSTYPE_1))
{
fclose(f);
gi.error("Savegame from an other os.\n");
}
if (!strcmp(str_os, "Windows"))
{
/* Windows was forced to i386 */
if (strcmp(str_arch, "i386"))
{
fclose(f);
gi.error("Savegame from an other architecure.\n");
}
}
else
{
if (strcmp(str_arch, ARCH_1))
{
fclose(f);
gi.error("Savegame from an other architecure.\n");
}
}
}
else
if(save_ver < 2)
{
fclose(f);
gi.error("Savegame from an incompatible version.\n");
}
else if (save_ver == 2)
{
if (strcmp(sv.game, GAMEVERSION))
{
fclose(f);
gi.error("Savegame from an other game.so.\n");
}
else if (strcmp(sv.os, YQ2OSTYPE_1))
{
fclose(f);
gi.error("Savegame from an other os.\n");
}
#ifdef _WIN32
/* Windows was forced to i386 */
if (strcmp(sv.arch, "i386") != 0)
{
fclose(f);
gi.error("Savegame from another architecture.\n");
}
#else
if (strcmp(sv.arch, YQ2ARCH_1) != 0)
{
fclose(f);
gi.error("Savegame from another architecture.\n");
}
#endif
}
else // all newer savegame versions
{
if (strcmp(sv.game, GAMEVERSION) != 0)
{
fclose(f);
gi.error("Savegame from another game.so.\n");
}
else if (strcmp(sv.os, YQ2OSTYPE) != 0)
{
fclose(f);
gi.error("Savegame from another os.\n");
}
else if (strcmp(sv.arch, YQ2ARCH) != 0)
{
#if defined(_WIN32) && (defined(__i386__) || defined(_M_IX86))
// before savegame version "YQ2-5" (and after version 2),
// the official Win32 binaries accidentally had the YQ2ARCH "AMD64"
// instead of "i386" set due to a bug in the Makefile.
// This quirk allows loading those savegames anyway
if (save_ver >= 5 || strcmp(sv.arch, "AMD64") != 0)
#endif
{
fclose(f);
gi.error("Savegame from another architecture.\n");
}
}
}
g_edicts = gi.TagMalloc(game.maxentities * sizeof(g_edicts[0]), TAG_GAME);
globals.edicts = g_edicts;
@ -966,7 +978,7 @@ WriteEdict(FILE *f, edict_t *ent)
}
/*
* Helper fcuntion to write the
* Helper function to write the
* level local data into a file.
* Called by WriteLevel.
*/
@ -1082,10 +1094,10 @@ ReadLevelLocals(FILE *f)
/*
* Reads a level back into the memory.
* SpawnEntities were allready called
* SpawnEntities were already called
* in the same way when the level was
* saved. All world links were cleared
* befor this function was called. When
* before this function was called. When
* this function is called, no clients
* are connected to the server.
*/

View file

@ -1,4 +1,23 @@
/*
* Copyright (C) 1997-2001 Id Software, Inc.
* Copyright (C) 2011 Yamagi Burmeister
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* Prototypes for every function in the game.so.
@ -34,7 +53,7 @@ extern int Q_strncasecmp ( char * s1 , char * s2 , int n ) ;
extern int Q_stricmp ( const char * s1 , const char * s2 ) ;
extern void Com_PageInMemory ( byte * buffer , int size ) ;
extern char * COM_Parse ( char * * data_p ) ;
extern char * va ( char * format , ... ) ;
extern char * va ( const char * format , ... ) ;
extern void Swap_Init ( void ) ;
extern float FloatNoSwap ( float f ) ;
extern float FloatSwap ( float f ) ;
@ -123,7 +142,7 @@ extern void ChangeWeapon ( edict_t * ent ) ;
extern qboolean Pickup_Weapon ( edict_t * ent , edict_t * other ) ;
extern void PlayerNoise ( edict_t * who , vec3_t where , int type ) ;
extern void P_ProjectSource2 ( gclient_t * client , vec3_t point , vec3_t distance , vec3_t forward , vec3_t right , vec3_t up , vec3_t result ) ;
extern void P_ProjectSource ( gclient_t * client , vec3_t point , vec3_t distance , vec3_t forward , vec3_t right , vec3_t result ) ;
extern void P_ProjectSource(edict_t *ent, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result);
extern byte P_DamageModifier ( edict_t * ent ) ;
extern void ClientEndServerFrame ( edict_t * ent ) ;
extern void G_SetClientFrame ( edict_t * ent ) ;
@ -187,7 +206,7 @@ extern void ClientObituary ( edict_t * self , edict_t * inflictor , edict_t * at
extern qboolean IsNeutral ( edict_t * ent ) ;
extern qboolean IsFemale ( edict_t * ent ) ;
extern void player_pain ( edict_t * self , edict_t * other , float kick , int damage ) ;
extern void SP_info_player_intermission ( void ) ;
extern void SP_info_player_intermission ( edict_t *ent );
extern void SP_info_player_coop_lava ( edict_t * self ) ;
extern void SP_info_player_coop ( edict_t * self ) ;
extern void SP_info_player_deathmatch ( edict_t * self ) ;
@ -380,6 +399,7 @@ extern void SP_monster_soldier_ss ( edict_t * self ) ;
extern void SP_monster_soldier ( edict_t * self ) ;
extern void SP_monster_soldier_light ( edict_t * self ) ;
extern void SP_monster_soldier_x ( edict_t * self ) ;
extern void soldier_footstep( edict_t *self ) ;
extern void soldier_blind ( edict_t * self ) ;
extern void soldier_duck ( edict_t * self , float eta ) ;
extern void soldier_sidestep ( edict_t * self ) ;
@ -481,11 +501,12 @@ extern void SP_monster_medic ( edict_t * self ) ;
extern qboolean medic_blocked ( edict_t *self, float dist ) ;
extern void medic_sidestep( edict_t *self ) ;
extern void medic_duck( edict_t *self, float eta ) ;
extern void medic_footstep( edict_t *self ) ;
extern qboolean medic_checkattack ( edict_t * self ) ;
extern void medic_finish_spawn ( edict_t *self );
extern void medic_spawngrows ( edict_t *self );
extern void medic_determine_spawn ( edict_t *self ) ;
extern void medic_start_spawn ( edict_t *self ) ;
extern void medic_start_spawn ( edict_t *self ) ;
extern void medic_attack ( edict_t * self ) ;
extern void medic_hook_retract ( edict_t * self ) ;
extern void medic_cable_attack ( edict_t * self ) ;
@ -506,6 +527,7 @@ extern void abortHeal( edict_t *self, qboolean change_frame, qboolean gib, qbool
extern qboolean canReach ( edict_t *self, edict_t *other ) ;
extern edict_t * medic_FindDeadMonster ( edict_t * self ) ;
extern void SP_misc_insane ( edict_t * self ) ;
extern void insane_footstep( edict_t *self ) ;
extern void insane_die ( edict_t * self , edict_t * inflictor , edict_t * attacker , int damage , vec3_t point ) ;
extern void insane_dead ( edict_t * self ) ;
extern void insane_stand ( edict_t * self ) ;
@ -521,6 +543,7 @@ extern void insane_moan ( edict_t * self ) ;
extern void insane_shake ( edict_t * self ) ;
extern void insane_fist ( edict_t * self ) ;
extern void SP_monster_infantry ( edict_t * self ) ;
extern void infantry_footstep( edict_t *self ) ;
extern void infantry_sidestep ( edict_t * self ) ;
extern void infantry_duck ( edict_t * self , float eta ) ;
extern qboolean infantry_blocked ( edict_t * self , float dist ) ;
@ -559,6 +582,7 @@ extern void hover_reattack ( edict_t * self ) ;
extern void hover_search ( edict_t * self ) ;
extern void hover_sight ( edict_t * self , edict_t * other ) ;
extern void SP_monster_gunner ( edict_t * self ) ;
extern void gunner_footstep( edict_t *self ) ;
extern void gunner_sidestep ( edict_t * self ) ;
extern void gunner_duck ( edict_t * self , float eta ) ;
extern qboolean gunner_blocked ( edict_t * self , float dist ) ;
@ -588,6 +612,7 @@ extern void gunner_sight ( edict_t * self , edict_t * other ) ;
extern void gunner_idlesound ( edict_t * self ) ;
extern void SP_monster_gladiator ( edict_t * self ) ;
qboolean gladiator_blocked ( edict_t *self , float dist ) ;
extern void gladiator_footstep( edict_t *self ) ;
extern void gladiator_die ( edict_t * self , edict_t * inflictor , edict_t * attacker , int damage , vec3_t point ) ;
extern void gladiator_dead ( edict_t * self ) ;
extern void gladiator_pain ( edict_t * self , edict_t * other , float kick , int damage ) ;
@ -658,6 +683,7 @@ extern void flipper_run ( edict_t * self ) ;
extern void flipper_run_loop ( edict_t * self ) ;
extern void flipper_stand ( edict_t * self ) ;
extern void SP_monster_chick ( edict_t * self ) ;
extern void chick_footstep( edict_t *self ) ;
extern void chick_sidestep ( edict_t * self ) ;
extern void chick_duck ( edict_t * self , float eta ) ;
extern qboolean chick_blocked ( edict_t * self , float dist ) ;
@ -711,6 +737,7 @@ extern void CarrierGrenade ( edict_t * self ) ;
extern void CarrierCoopCheck ( edict_t * self ) ;
extern void carrier_sight ( edict_t * self , edict_t * other ) ;
extern void SP_monster_brain ( edict_t * self ) ;
extern void brain_footstep( edict_t *self ) ;
extern void brain_duck ( edict_t * self , float eta ) ;
extern void brain_die ( edict_t * self , edict_t * inflictor , edict_t * attacker , int damage , vec3_t point ) ;
extern void brain_dead ( edict_t * self ) ;
@ -735,6 +762,7 @@ extern void SP_monster_makron ( edict_t * self ) ;
extern void MakronPrecache ( void ) ;
extern qboolean Makron_CheckAttack ( edict_t * self ) ;
extern void makron_die ( edict_t * self , edict_t * inflictor , edict_t * attacker , int damage , vec3_t point ) ;
extern void makron_torso_die ( edict_t * self , edict_t * inflictor , edict_t * attacker , int damage , vec3_t point ) ;
extern void makron_dead ( edict_t * self ) ;
extern void makron_torso ( edict_t * ent ) ;
extern void makron_torso_think ( edict_t * self ) ;
@ -795,6 +823,7 @@ extern void boss2_firebullet_right ( edict_t * self ) ;
extern void Boss2Rocket ( edict_t * self ) ;
extern void boss2_search ( edict_t * self ) ;
extern void SP_monster_berserk ( edict_t * self ) ;
extern void berserk_footstep( edict_t *self ) ;
extern void berserk_sidestep ( edict_t * self ) ;
extern qboolean berserk_blocked ( edict_t * self , float dist ) ;
extern void berserk_die ( edict_t * self , edict_t * inflictor , edict_t * attacker , int damage , vec3_t point ) ;
@ -927,6 +956,7 @@ extern void SP_target_secret ( edict_t * ent ) ;
extern void use_target_secret ( edict_t * ent , edict_t * other , edict_t * activator ) ;
extern void SP_target_help ( edict_t * ent ) ;
extern void Use_Target_Help ( edict_t * ent , edict_t * other , edict_t * activator ) ;
extern void Target_Help_Think ( edict_t * ent );
extern void SP_target_speaker ( edict_t * ent ) ;
extern void Use_Target_Speaker ( edict_t * ent , edict_t * other , edict_t * activator ) ;
extern void SP_target_temp_entity ( edict_t * ent ) ;
@ -1487,3 +1517,4 @@ extern void DBall_GameInit ( void ) ;
extern void DBall_SelectSpawnPoint ( edict_t * ent , vec3_t origin , vec3_t angles ) ;
extern void DBall_ClientBegin ( edict_t * ent ) ;
extern int DBall_CheckDMRules ( void ) ;
extern void wait_and_change_think(edict_t* ent);

View file

@ -1,10 +1,29 @@
/*
* Copyright (C) 1997-2001 Id Software, Inc.
* Copyright (C) 2011 Yamagi Burmeister
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* Functionpointers to every function in the game.so.
*
* =======================================================================
*/
*/
{"ReadLevel", (byte *)ReadLevel},
{"ReadLevelLocals", (byte *)ReadLevelLocals},
@ -380,6 +399,7 @@
{"SP_monster_soldier", (byte *)SP_monster_soldier},
{"SP_monster_soldier_light", (byte *)SP_monster_soldier_light},
{"SP_monster_soldier_x", (byte *)SP_monster_soldier_x},
{"soldier_footstep", (byte *)soldier_footstep},
{"soldier_blind", (byte *)soldier_blind},
{"soldier_duck", (byte *)soldier_duck},
{"soldier_sidestep", (byte *)soldier_sidestep},
@ -481,6 +501,7 @@
{"medic_blocked", (byte *)medic_blocked},
{"medic_sidestep", (byte *)medic_sidestep},
{"medic_duck", (byte *)medic_duck},
{"medic_footstep", (byte *)medic_footstep},
{"medic_checkattack", (byte *)medic_checkattack},
{"medic_attack", (byte *)medic_attack},
{"medic_finish_spawn", (byte *)medic_finish_spawn},
@ -506,6 +527,7 @@
{"canReach", (byte *)canReach},
{"medic_FindDeadMonster", (byte *)medic_FindDeadMonster},
{"SP_misc_insane", (byte *)SP_misc_insane},
{"insane_footstep", (byte *)insane_footstep},
{"insane_die", (byte *)insane_die},
{"insane_dead", (byte *)insane_dead},
{"insane_stand", (byte *)insane_stand},
@ -521,6 +543,7 @@
{"insane_shake", (byte *)insane_shake},
{"insane_fist", (byte *)insane_fist},
{"SP_monster_infantry", (byte *)SP_monster_infantry},
{"infantry_footstep", (byte *)infantry_footstep},
{"infantry_sidestep", (byte *)infantry_sidestep},
{"infantry_duck", (byte *)infantry_duck},
{"infantry_blocked", (byte *)infantry_blocked},
@ -559,6 +582,7 @@
{"hover_search", (byte *)hover_search},
{"hover_sight", (byte *)hover_sight},
{"SP_monster_gunner", (byte *)SP_monster_gunner},
{"gunner_footstep", (byte *)gunner_footstep},
{"gunner_sidestep", (byte *)gunner_sidestep},
{"gunner_duck", (byte *)gunner_duck},
{"gunner_blocked", (byte *)gunner_blocked},
@ -587,6 +611,7 @@
{"gunner_sight", (byte *)gunner_sight},
{"gunner_idlesound", (byte *)gunner_idlesound},
{"SP_monster_gladiator", (byte *)SP_monster_gladiator},
{"gladiator_footstep", (byte *)gladiator_footstep},
{"gladiator_blocked", (byte *)gladiator_blocked},
{"gladiator_die", (byte *)gladiator_die},
{"gladiator_dead", (byte *)gladiator_dead},
@ -658,6 +683,7 @@
{"flipper_run_loop", (byte *)flipper_run_loop},
{"flipper_stand", (byte *)flipper_stand},
{"SP_monster_chick", (byte *)SP_monster_chick},
{"chick_footstep", (byte *)chick_footstep},
{"chick_sidestep", (byte *)chick_sidestep},
{"chick_duck", (byte *)chick_duck},
{"chick_blocked", (byte *)chick_blocked},
@ -711,6 +737,7 @@
{"CarrierCoopCheck", (byte *)CarrierCoopCheck},
{"carrier_sight", (byte *)carrier_sight},
{"SP_monster_brain", (byte *)SP_monster_brain},
{"brain_footstep", (byte *)brain_footstep},
{"brain_duck", (byte *)brain_duck},
{"brain_die", (byte *)brain_die},
{"brain_dead", (byte *)brain_dead},
@ -735,6 +762,7 @@
{"MakronPrecache", (byte *)MakronPrecache},
{"Makron_CheckAttack", (byte *)Makron_CheckAttack},
{"makron_die", (byte *)makron_die},
{"makron_torso_die", (byte *)makron_torso_die},
{"makron_dead", (byte *)makron_dead},
{"makron_torso", (byte *)makron_torso},
{"makron_torso_think", (byte *)makron_torso_think},
@ -795,6 +823,7 @@
{"Boss2Rocket", (byte *)Boss2Rocket},
{"boss2_search", (byte *)boss2_search},
{"SP_monster_berserk", (byte *)SP_monster_berserk},
{"berserk_footstep", (byte *)berserk_footstep},
{"berserk_sidestep", (byte *)berserk_sidestep},
{"berserk_blocked", (byte *)berserk_blocked},
{"berserk_die", (byte *)berserk_die},
@ -927,6 +956,7 @@
{"use_target_secret", (byte *)use_target_secret},
{"SP_target_help", (byte *)SP_target_help},
{"Use_Target_Help", (byte *)Use_Target_Help},
{"Target_Help_Think", (byte *)Target_Help_Think},
{"SP_target_speaker", (byte *)SP_target_speaker},
{"Use_Target_Speaker", (byte *)Use_Target_Speaker},
{"SP_target_temp_entity", (byte *)SP_target_temp_entity},
@ -1488,4 +1518,5 @@
{"DBall_SelectSpawnPoint", (byte *)DBall_SelectSpawnPoint},
{"DBall_ClientBegin", (byte *)DBall_ClientBegin},
{"DBall_CheckDMRules", (byte *)DBall_CheckDMRules},
{"wait_and_change_think", (byte *)wait_and_change_think},
{0, 0}

View file

@ -503,20 +503,9 @@ VectorNormalize(vec3_t v)
vec_t
VectorNormalize2(vec3_t v, vec3_t out)
{
float length, ilength;
VectorCopy(v, out);
length = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];
length = (float)sqrt(length);
if (length)
{
ilength = 1 / length;
out[0] = v[0] * ilength;
out[1] = v[1] * ilength;
out[2] = v[2] * ilength;
}
return length;
return VectorNormalize(out);
}
void
@ -884,7 +873,7 @@ Swap_Init(void)
* need to have varargs versions of all text functions.
*/
char *
va(char *format, ...)
va(const char *format, ...)
{
va_list argptr;
static char string[1024];
@ -1333,7 +1322,7 @@ Info_SetValueForKey(char *s, char *key, char *value)
Com_sprintf(newi, sizeof(newi), "\\%s\\%s", key, value);
if (strlen(newi) + strlen(s) > maxsize)
if (strlen(newi) + strlen(s) >= maxsize)
{
Com_Printf("Info string length exceeded\n");
return;

6123
stuff/mapfixes/rammo1.ent Normal file

File diff suppressed because it is too large Load diff

5423
stuff/mapfixes/rbase1.ent Normal file

File diff suppressed because it is too large Load diff

7436
stuff/mapfixes/rhangar2.ent Normal file

File diff suppressed because it is too large Load diff

7107
stuff/mapfixes/rmine1.ent Normal file

File diff suppressed because it is too large Load diff

5282
stuff/mapfixes/rsewer1.ent Normal file

File diff suppressed because it is too large Load diff

6805
stuff/mapfixes/rsewer2.ent Normal file

File diff suppressed because it is too large Load diff

8317
stuff/mapfixes/rware2.ent Normal file

File diff suppressed because it is too large Load diff