Compare commits

...

2 commits
v1.5 ... master

Author SHA1 Message Date
archive
5a8aa10e57 as released 1999-06-20 1999-06-20 00:00:00 +00:00
archive
bccddaa7fd as released 1999-03-14 1999-03-14 00:00:00 +00:00
31 changed files with 10013 additions and 6984 deletions

239
CHANGES
View file

@ -1,3 +1,242 @@
CHANGES FROM ACTION 1.51 to ACTION 1.52
o Support for friendly-fire in teamplay added. IF YOU ARE NOT ALREADY
USING THE "NO FRIENDLY FIRE" FLAG IN YOUR DMFLAGS, YOU NEED TO ADD IT NOW
IF YOU DON'T WANT TO USE FRIENDLY FIRE. The value for "no friendly fire"
is 256. For a normal AQ teamplay game, you should set your dmflags to 256
in your server.cfg ("set dmflags 256"). I believe the only other dmflag
that would have a worthwhile effect on AQ teamplay is the "spawn farthest"
flag (512), no others should be set unless you want the spawn farthest
behavior. So...if you want FF in teamplay, set your dmflags to 0. If you
don't, set it to 256. No friendly fire is the "normal" style of play, so
the default/standard dmflags for AQ teamplay should be considered to be
256. When FF is in effect, notification of it will be on the standard
MOTD. Temporary banning for people who kill too many team members is
available. The "maxteamkills" server cvar can be used to control the
maximum number of teamkills that a player can make on a given map before
he is kicked and temporarily banned, the default is 0 which means never
temporarily ban. The "tkbanrounds" and "twbanrounds" variables affect ban
time, see the README file for complete info. Players lose one frag for
killing a teammate. Thanks go to Eek and Azerov for providing the patch
which we used as a basis for this feature.
o Shot placement on crouching players is much improved and should
basically be consistent with standing players now. Also, the view height
of crouching players has been modified somewhat so it's more consistent
with the actual amount of height loss that occurs. (thanks go to Mikael
Lindh from AQ:Gangsters for lots of help in this area.)
o The shotgun and handcannon now inform you who you're hitting, when you
hit someone, much like all the other weapons already did.
o New server variable "limchasecam" now available for clan match usage.
See info in the README. When the chase cam limits are in effect, a line
will be added to the MOTD stating it. (thanks to Black Cross for
submitting the patch for this feature.)
o Breakable glass now added. Two new server variables for this:
"breakableglass" and "glassfragmentlimit". This is not recommended for
Internet games (much like the ejecting shells, blood splats, and bullet
holes). This was contributed by William van der Sterren of the CGF
project. It requires maps that are designed with breakable glass. For
more info on how to make breakable glass in maps, see
http://www.botepidemic.com/aid/cgf/exp_glass.shtml. For more info on the
server variables, see the README.
o Door kicking added. You can now jump-kick a door open when it opens in
the opposite direction. If there is a player sitting on the other side of
the door, that player will be kicked along with the door. This was
contributed by AQDT (written by Hal, sent to us by Homer).
o Vertical component of kicking has returned. You can kick people upwards
or downwards by looking in that direction before kicking them.
o New commands "use throwing combat knife" and "use slashing combat knife"
allow you to pull out the knife in whichever mode you want, instead of
pulling out your knife then switching modes.
o A new item has been added to the secondary teamplay scoreboard: damage
dealt. This number is the amount of damage the given player has inflicted
upon other players on the current map. Note this is total damage, not
just damage required to kill someone. For example, a point blank
handcannon blast can count for a lot more than 100 health, even though it
only takes 100 to kill someone. This isn't in the scoreboard if you have
turned on the "noscore" option.
o New "sv nextmap" command allows a server operator to skip to the next
map in the rotation (thanks go to Black Cross for submitting the patch for
this command).
o The "spawn farthest" dmflag now works on teamplay games. The second
team will spawn as far away from the first team as possible (unlike the
normal behavior, where the farthest 1-4 spawn candidates are considered,
depending on the total number of candidates).
o The "needpass" variable is now provided. This allows things like
GameSpy to prompt you for a password when you try to connect to a
passworded server.
o Players can no longer use say_team when not on a team, or say_partner
when they have no partner.
o Delayed-death attribution bug fixed (you wouldn't get credit for a kill
when someone bled for a while).
o Various reloading changes: switching from a reloading weapon to a new
weapon will not cause the new weapon to be reloaded any longer. The
reloading "queue" will immediately empty now whenever a player tries to
shoot (assuming he has any ammo left in the gun to shoot) or bandage. Your
pistol will no longer begin to reload after you get a sniper rifle or
shotgun kicked from your hands while reloading it. The "reload" command
no longer does anything during the "lights, camera, action" countdown in a
teamplay game. You can no longer reload the pistols, M4's, or MP5's when
you've already got a full magazine (to be consistent with the way the
other weapons work).
o Switching between slashing and throwing for knives now gives a message.
o Increased knife slashing damage.
o Repeating "Out of ammo" message bug fixed.
o Lasersight now falls in the correct place if you're using one of the
"classic" hand modes.
o Problem with sniper rifle's "weapon" command/bolt animation fixed (you
could fire faster than normal using the right aliases).
o Dropped grenades now do the same amount of damage as thrown grenades.
o Green flash when players enter the game in a teamplay game removed (for
real this time), as well as the red flash when a player exits the game in
a teamplay game.
o The through-eyes chasecam now properly tracks weapon kick (ie with the
M4), and also now gives you IR vision if the person you're viewing through
the eyes of is using IR.
o A few bugs fixed in the way bodies fly after death. Floating bodies and
bouncing bodies should be gone.
o Spectators can no longer drop a knife upon entering a teamplay game.
o Dead bodies no longer appear red when using IR vision.
o %-vars (ie %W, %H, and the others) are no longer parsed within players'
names (ie a player named %W won't appear as his weapon when he says
something).
o Minor bug in bleeding from grenades fixed.
o Bug where sniper rifle icon would be stuck on your screen if you were
zoomed in when the other team all quit and you got "Not enough players to
play!" is fixed.
o Adjusted spacing in MOTD so certain combinations don't cause lines to go
off the edge of the screen.
o Shotgun shell ejection animation (when using "shelloff 0") improved.
o Fixed crash that occurred when a server ran a huge amount of maps in the
rotation (around 100 or more).
o ReadConfigFile() now closes its file and SelectFarTeamplaySpawnPoint()
frees its memory.
o Updated Action web page URL in MOTD.
CHANGES FROM ACTION 1.5 TO ACTION 1.51
o Now remembers how many times reload key was pressed.
o Shotgun reduced to Action Quake 1.0c levels beyond distance of 450.
o Bandolier/weapon-dropping bug fixed.
o Empty pistols animation setup improved.
o Firing sequence for dual pistols fixed (firing was simultaneously
before).
o Various grenade-related fixes.
o Knife slashing damage changed (should be more damaging now).
o You can now switch weapons while bandaging again.
o Leg damage (from falling) no longer taken while in god mode.
o Spelling of "trepanned" fixed.
o Item spawning problem that affected some old/odd maps fixed.
o Reloading sound/speed issues fixed.
o Point-blank knife-throwing bug fixed.
o Blood trail fixes.
o Death sound fixes.
o Negative value for "tgren" server variable is treated as 0 now.
o New server variable "skipmotd" allows you to leave out the standard
Action MOTD contents (except the two lines at the top), for people who
want really big local motd.txt files.
o Many server variables that didn't need to be SERVERINFO (ie: appearing
in GameSpy, etc) are no longer SERVERINFO.
o New server command "sv reloadmotd" allows you to reload the MOTD from
disk. Also, the MOTD is always reloaded at the end of each level.
o The "playerlist" and "players" commands no longer contain frags when
"noscore" is turned on.
o New "ininame" variable lets you change the name of your Action INI file
from "action.ini" to something else. Useful for people who run multiple
servers from the same directory tree.
o Deathmatch mode is now forced on always, as in previous versions of
Action. This was the cause of the "failed to find special item spawn
point" error when starting a game locally on your computer.
o Delayed kill attribution for falling damage fixes.
o Lasersight properly follows M4 during ride-up.
o Scoreboard cosmetic fixes.
o Players entering the game in a teamplay game no longer generate the "enter
game" teleport effect (green flash, etc) at a spawn point.
o Bug fixed that could cause crash when certain weird combinations of dmflags
were used (ie teams-by-skin with teamplay turned on).
o Players can now select "classic" style firing where shots land slightly
right or left (depending on your handedness) and down from the crosshair
(see the "hand" command in the README for info).
o The [DEAD] flag on a dead chatter's name previously didn't get tacked on
starting at the right time, so sometimes you'd see someone who appeared to
be alive (due to no [DEAD] on their name) say something but %-variables
(ie %W, %H, etc) didn't get expanded. This also caused dead people's
messages to be able to reach teammates sometimes in the moments after
dying.
o After a team round has ended, all players (including players who
survived) can now see the scoreboard as if they were dead, to see who else
survived the round.
o The join-a-team menu now, if both teams have the same number of players,
defaults to the team that's losing (instead of defaulting to the first
team).
o Optimization in SetIDView and DetermineViewedTeammate suggested by
hal[9k].
CHANGES FROM ACTION 1.1b2 TO ACTION 1.5

91
LICENSE.TXT Normal file
View file

@ -0,0 +1,91 @@
LIMITED PROGRAM SOURCE CODE LICENSE
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.
R E C I T A L S
WHEREAS, Id Software is the owner and developer of the computer software program source code accompanied by this Agreement (the "Code");
WHEREAS, Id Software desires to license certain limited non-exclusive rights regarding the Code to Licensee; and
WHEREAS, Licensee desires to receive a limited license for such rights.
T E R M S A N D C O N D I T I O N S
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:
1. Definitions. The parties hereto agree the following definitions shall apply to this Agreement:
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;
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;
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;
d. "Game" shall mean QUAKE II;
e. "Licensee" shall mean you, the person who is in possession of an Authorized Copy by Authorized Means; and
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.
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.
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.
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:
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
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.
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.
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.
7. Term and Termination.
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. 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. 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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
20. Miscellaneous.
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.
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.
BY DOWNLOADING THE CODE, AS DEFINED ABOVE, YOU, THE LICENSEE, AGREE TO ALL THE TERMS AND CONDITIONS OF THIS AGREEMENT.
February 12, 1998
LIMITED PROGRAM SOURCE CODE LICENSE PAGE 1

View file

@ -34,7 +34,8 @@ GAME_OBJS = \
g_monster.o g_phys.o g_save.o g_spawn.o g_svcmds.o \
g_target.o g_trigger.o g_turret.o g_utils.o g_weapon.o g_chase.o \
p_client.o p_hud.o p_trail.o p_view.o p_weapon.o q_shared.o \
m_move.o a_team.o a_game.o a_items.o a_cmds.o a_radio.o a_menu.o
m_move.o a_team.o a_game.o a_items.o a_cmds.o a_radio.o a_menu.o \
cgf_sfx_glass.o a_doorkick.o
game$(ARCH).$(SHLIBEXT) : $(GAME_OBJS)
$(CC) $(CFLAGS) $(SHLIBLDFLAGS) -o $@ $(GAME_OBJS)
@ -63,7 +64,7 @@ g_ai.o: g_ai.c g_local.h q_shared.h game.h a_team.h a_game.h a_menu.h \
g_cmds.o: g_cmds.c g_local.h q_shared.h game.h a_team.h a_game.h \
a_menu.h a_radio.h m_player.h
g_combat.o: g_combat.c g_local.h q_shared.h game.h a_team.h a_game.h \
a_menu.h a_radio.h
a_menu.h a_radio.h cgf_sfx_glass.h
g_func.o: g_func.c g_local.h q_shared.h game.h a_team.h a_game.h \
a_menu.h a_radio.h
g_items.o: g_items.c g_local.h q_shared.h game.h a_team.h a_game.h \
@ -71,13 +72,13 @@ g_items.o: g_items.c g_local.h q_shared.h game.h a_team.h a_game.h \
g_main.o: g_main.c g_local.h q_shared.h game.h a_team.h a_game.h \
a_menu.h a_radio.h
g_misc.o: g_misc.c g_local.h q_shared.h game.h a_team.h a_game.h \
a_menu.h a_radio.h
a_menu.h a_radio.h cgf_sfx_glass.h
g_monster.o: g_monster.c g_local.h q_shared.h game.h a_team.h a_game.h \
a_menu.h a_radio.h
g_phys.o: g_phys.c g_local.h q_shared.h game.h a_team.h a_game.h \
a_menu.h a_radio.h
a_menu.h a_radio.h cgf_sfx_glass.h
g_save.o: g_save.c g_local.h q_shared.h game.h a_team.h a_game.h \
a_menu.h a_radio.h
a_menu.h a_radio.h cgf_sfx_glass.h
g_spawn.o: g_spawn.c g_local.h q_shared.h game.h a_team.h a_game.h \
a_menu.h a_radio.h
g_svcmds.o: g_svcmds.c g_local.h q_shared.h game.h a_team.h a_game.h \
@ -91,11 +92,11 @@ g_turret.o: g_turret.c g_local.h q_shared.h game.h a_team.h a_game.h \
g_utils.o: g_utils.c g_local.h q_shared.h game.h a_team.h a_game.h \
a_menu.h a_radio.h
g_weapon.o: g_weapon.c g_local.h q_shared.h game.h a_team.h a_game.h \
a_menu.h a_radio.h
a_menu.h a_radio.h cgf_sfx_glass.h
g_chase.o: g_chase.c g_local.h q_shared.h game.h a_team.h a_game.h \
a_menu.h a_radio.h
p_client.o: p_client.c g_local.h q_shared.h game.h a_team.h a_game.h \
a_menu.h a_radio.h m_player.h
a_menu.h a_radio.h m_player.h cgf_sfx_glass.h
p_hud.o: p_hud.c g_local.h q_shared.h game.h a_team.h a_game.h \
a_menu.h a_radio.h
p_trail.o: p_trail.c g_local.h q_shared.h game.h a_team.h a_game.h \
@ -108,9 +109,9 @@ q_shared.o: q_shared.c q_shared.h
m_move.o: m_move.c g_local.h q_shared.h game.h a_team.h a_game.h \
a_menu.h a_radio.h
a_team.o: a_team.c g_local.h q_shared.h game.h a_team.h a_game.h \
a_menu.h a_radio.h
a_menu.h a_radio.h cgf_sfx_glass.h
a_game.o: a_game.c g_local.h q_shared.h game.h a_team.h a_game.h \
a_menu.h a_radio.h
a_menu.h a_radio.h cgf_sfx_glass.h
a_items.o: a_items.c g_local.h q_shared.h game.h a_team.h a_game.h \
a_menu.h a_radio.h
a_cmds.o: a_cmds.c g_local.h q_shared.h game.h a_team.h a_game.h \
@ -119,3 +120,7 @@ a_radio.o: a_radio.c g_local.h q_shared.h game.h a_team.h a_game.h \
a_menu.h a_radio.h
a_menu.o: a_menu.c g_local.h q_shared.h game.h a_team.h a_game.h \
a_menu.h a_radio.h
cgf_sfx_glass.o: cgf_sfx_glass.c g_local.h q_shared.h game.h a_team.h \
a_game.h a_menu.h a_radio.h cgf_sfx_glass.h
a_doorkick.o: a_doorkick.c g_local.h q_shared.h game.h a_team.h \
a_game.h a_menu.h a_radio.h

106
README
View file

@ -1,4 +1,4 @@
SERVER/PLAYER DOCUMENTATION FOR ACTION 1.5
SERVER/PLAYER DOCUMENTATION FOR ACTION 1.52
ACTION-SPECIFIC SERVER VARIABLES
@ -18,6 +18,10 @@ motd_time: the number of seconds that the initial MOTD should remain on the
player's screen. This number is rounded up to the nearest 2-second interval
(default = 2).
skipmotd: allows you to skip all but the top two lines of the normal
Action MOTD, for server operators who want large motd.txt files
(default = 0 [don't skip]).
weapons: the maximum number of "unique weapons" a player can carry (the
bandolier adds 1 to a player's max carry) (default = 1).
@ -52,13 +56,47 @@ allitem: gives all the items to each player in teamplay/DM
tgren: sets the number of grenades that come with the bandolier in
teamplay (default = 0).
noscore: if set to 1, individual scores are not in effect for teamplay,
the only scores visible will be team wins and total frags (default = 0).
noscore: if set to 1, individual scores (and damage stats) are not in
effect for teamplay, the only scores visible will be team wins and total
frags (default = 0).
nohud: if set to 1, the standard HUD (health, ammo, etc) is disabled for
all players. This can allow you to record better-looking demos of staged
scenes (default = 0).
ininame: if set, changes the name of the Action INI file from "action.ini"
to whatever you specify. The file must always be located in your Action
game directory. This should be used on the Quake2 commandline, ie:
quake2 +set game action +set ininame alternate.ini +set dedicated 1 ...
(default = "action.ini").
limchasecam: if set to 1, will prevent all players on teams from free
floating, or chase-camming enemy players. If set to 2, will prevent all
players on teams from using the normal chase cam as well (only the
through-eyes cam on teammates will be allowed). This variable should be
set to 2 for clan matches, etc (default = 0).
shelloff: turns off the dropping of expended shells from your gun
(default = 1 [turn off shells, for a faster Internet game]).
breakableglass: turns on breakable glass. Not recommended for Internet
games (default = 0).
glassfragmentlimit: controls the maximum number of glass fragments present
on the map at any time (default = 30).
maxteamkills: the maximum number of teammates a player can kill in one map
before he is temporarily banned from the server. Only applies during
friendly-fire enabled teamplay games. Players will also be banned for
wounding teammates, if they wound 4*maxteamkills teammates. Setting this
to zero disables the feature (default = 0).
tkbanrounds: the number of maps a player will be banned for when he is
banned for killing teammates (default = 2).
twbanrounds: the number of maps a player will be banned for when he is
banned for wounding teammates (default = 2).
ACTION-SPECIFIC PLAYER COMMANDS
@ -91,6 +129,14 @@ motd: brings up the MOTD (message of the day) again.
spectator: can be set to 0 or 1 ("spectator 0", "spectator 1") to toggle being
a spectator in DM games.
hand: in addition to the normal Q2 modes (0 = right-handed, 1 =
left-handed, 2 = "center"-handed), you can select "classic" style shooting
(where shots end up left/right and below the crosshair), or "classic high"
style shooting (where shots end up left/right of the crosshair). The
proper commands to select those modes are: hand "0 classic" (right-handed
classic), hand "0 classic high" (right-handed classic high), etc. Note
that the double-quotes are required.
choose: chooses a particular item or weapon as your item or weapon, without
going through the menus, in teamplay (ie: "choose mp5/10 submachinegun" or
"choose lasersight").
@ -140,7 +186,7 @@ unpartner: breaks your current partnership.
WEAPON/ITEM NAMES
These are the exact names of all the weapons/items in the game, for use with
commands like "drop", "choose", "give", etc:
commands like "use", "drop", "choose", "give", etc:
MK23 Pistol
M3 Super 90 Assault Shotgun
@ -149,7 +195,8 @@ Handcannon
Sniper Rifle
M4 Assault Rifle
Dual MK23 Pistols
Combat Knife
Combat Knife (also aliases "throwing combat knife" and
"slashing combat knife" for the "use" command)
Pistol Clip
12 Gauge Shells
@ -187,37 +234,48 @@ Flood protection is supported using the standard Q2 3.20 variables,
"flood_msgs" (default 4), "flood_persecond" (default 4), and "flood_waitdelay"
(default 10).
DM teams-by-model, teams-by-skin, friendly fire, etc are supported using the
standard Q2 "dmflags" values.
DM teams-by-model, teams-by-skin, friendly fire, etc are supported using
the standard Q2 "dmflags" values. A server should use dmflags 256 for
"normal" play (including no friendly fire), 0 for friendly fire. Some of
the other regular dmflags are also available, such as "spawn farthest"
(512).
action/action.ini is the configuration file for map rotation and teamplay team
name/model/skin setup. See the example for information on the format.
action/motd.txt, if present, will be appended to the server MOTD.
action/motd.txt, if present, will be appended to the server MOTD. The
server command "sv reloadmotd" can be used to reload it from disk at any
time, and it is also reloaded at the end of each level automatically.
IP BANNING
Commands: addip, removeip, listip, writeip
Commands: sv addip, sv removeip, sv listip, sv writeip
Server variables: filterban
You can add or remove addresses from the IP filter list with the commands
"addip <ip>" and "removeip <ip>". The IP address is specified in numeric dot
format, and any unspecified digits will match any value, so you can specify an
entire class C network with "addip 240.200.100", for example. "removeip" will
only remove an address specified in the exact same way. The "listip" command
will print the current list of filters. The "writeip" command will dump the
current filters to a config file, "listip.cfg" in your Action directory. You
should add a line in your normal server.cfg that does an "exec listip.cfg" to
load this file by default. IP addresses in the filter list will only be
prohibited from connecting if the "filterban" variable is set to 1 (this is the
default).
"sv addip <ip>" and "sv removeip <ip>". The IP address is specified in
numeric dot format, and any unspecified digits will match any value, so
you can specify an entire class C network with "addip 240.200.100", for
example. "sv removeip" will only remove an address specified in the exact
same way. The "sv listip" command will print the current list of filters.
The "sv writeip" command will dump the current filters to a config file,
"listip.cfg" in your Action directory. You should add a line in your
normal server.cfg that does an "exec listip.cfg" to load this file by
default. IP addresses in the filter list will only be prohibited from
connecting if the "filterban" variable is set to 1 (this is the default).
OTHER SERVER COMMANDS
sv reloadmotd: reloads the MOTD file from disk.
sv nextmap: immediately skips to the next map in the rotation.
REPORTING BUGS OR MAKING COMMENTS
As of this writing, you can contact the authors of the Action 1.5 server
code (Zucchini and Fireblade) at spikard@u.washington.edu and
ucs_brf@shsu.edu, respectively. The Action Quake 2 website is at
http://action.telefragged.com/ and has a message board where discussions
about Action Quake 2 take place.
The maintainers of the Action server code, Zucchini and Fireblade, can be
contacted at spikard@u.washington.edu and ucs_brf@shsu.edu, respectively.
The Action Quake 2 website is at http://aq2.action-web.net/ and has a
message board where discussions about Action Quake 2 take place.

213
a_cmds.c
View file

@ -108,9 +108,13 @@ void LaserSightThink (edict_t *self)
{
vec3_t start,end,endp,offset;
vec3_t forward,right,up;
vec3_t angles;
trace_t tr;
int height = 0;
AngleVectors (self->owner->client->v_angle, forward, right, up);
// zucc compensate for weapon ride up
VectorAdd (self->owner->client->v_angle, self->owner->client->kick_angles, angles);
AngleVectors (/*self->owner->client->v_angle*/angles, forward, right, up);
if ( self->owner->lasersight != self )
@ -118,13 +122,18 @@ void LaserSightThink (edict_t *self)
self->think = G_FreeEdict;
}
if (self->owner->client->pers.firing_style == ACTION_FIRING_CLASSIC)
height = 8;
VectorSet(offset,24 , 0, self->owner->viewheight);
VectorSet(offset,24 , 8, self->owner->viewheight- height);
P_ProjectSource (self->owner->client, self->owner->s.origin, offset, forward, right, start);
VectorMA(start,8192,forward,end);
tr = do_trace (start,NULL,NULL, end,self->owner,CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER);
PRETRACE();
tr = gi.trace (start,NULL,NULL, end,self->owner,CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER);
POSTTRACE();
if (tr.fraction != 1) {
VectorMA(tr.endpos,-4,forward,endp);
@ -139,6 +148,17 @@ void LaserSightThink (edict_t *self)
}
void Cmd_New_Reload_f( edict_t *ent )
{
//FB 6/1/99 - refuse to reload during LCA
if ((int)teamplay->value && lights_camera_action)
return;
//FB 6/1/99
ent->client->reload_attempts++;
}
//+BD ENTIRE CODE BLOCK NEW
// Cmd_Reload_f()
// Handles weapon reload requests
@ -158,11 +178,16 @@ void Cmd_Reload_f (edict_t *ent)
|| ent->client->bandaging == 1
|| ent->client->bandage_stopped == 1
|| ent->client->weaponstate == WEAPON_ACTIVATING
|| ent->client->weaponstate == WEAPON_DROPPING )
|| ent->client->weaponstate == WEAPON_DROPPING
|| ent->client->weaponstate == WEAPON_FIRING )
{
return;
}
if (!ent->client->fast_reload)
ent->client->reload_attempts--;
if ( ent->client->reload_attempts < 0 )
ent->client->reload_attempts = 0;
//First, grab the current magazine max count...
if ( ( ent->client->curr_weap == MK23_NUM )
@ -184,12 +209,7 @@ void Cmd_Reload_f (edict_t *ent)
if(ent->client->pers.inventory[ent->client->ammo_index])
{
/*if((ent->client->weaponstate != WEAPON_END_MAG) && (ent->client->pers.inventory[ent->client->ammo_index] < rds_left))
{
gi.centerprintf(ent,"Buy a clue-\nYou're on your last magazine!\n");
}
else*/
//Set the weaponstate...
//Set the weaponstate...
if ( ent->client->curr_weap == M3_NUM )
{
if (ent->client->shot_rds >= ent->client->shot_max)
@ -199,17 +219,26 @@ void Cmd_Reload_f (edict_t *ent)
// already in the process of reloading!
if ( ent->client->weaponstate == WEAPON_RELOADING && (ent->client->shot_rds < (ent->client->shot_max -1)) && !(ent->client->fast_reload) && ((ent->client->pers.inventory[ent->client->ammo_index] -1) > 0 ))
{
ent->client->fast_reload = 1;
(ent->client->pers.inventory[ent->client->ammo_index])--;
// don't let them start fast reloading until far enough into the firing sequence
// this gives them a chance to break off from reloading to fire the weapon - zucc
if ( ent->client->ps.gunframe >= 48 )
{
ent->client->fast_reload = 1;
(ent->client->pers.inventory[ent->client->ammo_index])--;
}
else
{
ent->client->reload_attempts++;
}
}
}
if ( ent->client->curr_weap == HC_NUM )
{
if (ent->client->cannon_rds >= ent->client->cannon_max)
{
return;
}
if (ent->client->cannon_rds >= ent->client->cannon_max)
{
return;
}
if (!(ent->client->pers.inventory[ent->client->ammo_index] >= 2))
return;
@ -221,22 +250,48 @@ void Cmd_Reload_f (edict_t *ent)
return;
}
// already in the process of reloading!
if ( ent->client->weaponstate == WEAPON_RELOADING && (ent->client->sniper_rds < (ent->client->sniper_max -1)) && !(ent->client->fast_reload) && ((ent->client->pers.inventory[ent->client->ammo_index] -1) > 0 ))
if ( ent->client->weaponstate == WEAPON_RELOADING && (ent->client->sniper_rds < (ent->client->sniper_max -1)) && !(ent->client->fast_reload) && ((ent->client->pers.inventory[ent->client->ammo_index] -1) > 0 ) )
{
ent->client->fast_reload = 1;
(ent->client->pers.inventory[ent->client->ammo_index])--;
// don't let them start fast reloading until far enough into the firing sequence
// this gives them a chance to break off from reloading to fire the weapon - zucc
if ( ent->client->ps.gunframe >= 72 )
{
ent->client->fast_reload = 1;
(ent->client->pers.inventory[ent->client->ammo_index])--;
}
else
{
ent->client->reload_attempts++;
}
}
ent->client->ps.fov = 90;
if ( ent->client->pers.weapon )
ent->client->ps.gunindex = gi.modelindex( ent->client->pers.weapon->view_model );
}
if ( ent->client->curr_weap == DUAL_NUM )
{
if (!(ent->client->pers.inventory[ent->client->ammo_index] >= 2))
return;
//FIREBLADE 7/11/1999 - stop reloading when weapon already full
if (ent->client->dual_rds == ent->client->dual_max)
return;
}
if (ent->client->curr_weap == MP5_NUM)
{
if (ent->client->mp5_rds == ent->client->mp5_max)
return;
}
if (ent->client->curr_weap == M4_NUM)
{
if (ent->client->m4_rds == ent->client->m4_max)
return;
}
if (ent->client->curr_weap == MK23_NUM)
{
if (ent->client->mk23_rds == ent->client->mk23_max)
return;
}
//FIREBLADE
ent->client->weaponstate = WEAPON_RELOADING;
//(ent->client->pers.inventory[ent->client->ammo_index])--;
@ -247,6 +302,14 @@ void Cmd_Reload_f (edict_t *ent)
}
//+BD END CODE BLOCK
void Cmd_New_Weapon_f( edict_t *ent )
{
ent->client->weapon_attempts++;
if ( ent->client->weapon_attempts == 1 )
Cmd_Weapon_f(ent);
}
// function to change the firing mode of weapons (when appropriate)
void Cmd_Weapon_f ( edict_t *ent )
@ -255,13 +318,26 @@ void Cmd_Weapon_f ( edict_t *ent )
dead = (ent->solid == SOLID_NOT || ent->deadflag == DEAD_DEAD);
if ( ent->client->bandaging || ent->client->bandage_stopped )
ent->client->weapon_attempts--;
if ( ent->client->weapon_attempts < 0 )
ent->client->weapon_attempts = 0;
if ( ent->client->bandaging || ent->client->bandage_stopped )
{
gi.cprintf(ent, PRINT_HIGH, "You can't mess with your weapon while bandaging!\n");
return;
gi.cprintf(ent, PRINT_HIGH, "You'll get to your weapon when your done bandaging!\n");
ent->client->weapon_attempts++;
return;
}
if ( ent->client->curr_weap == MK23_NUM )
if ( ent->client->weaponstate == WEAPON_FIRING || ent->client->weaponstate == WEAPON_BUSY )
{
//gi.cprintf(ent, PRINT_HIGH, "Try again when you aren't using your weapon.\n");
ent->client->weapon_attempts++;
return;
}
if ( ent->client->curr_weap == MK23_NUM )
{
if (!dead)
gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/click.wav"), 1, ATTN_NORM, 0);
@ -295,15 +371,18 @@ void Cmd_Weapon_f ( edict_t *ent )
if ( ent->client->curr_weap == SNIPER_NUM )
{
if (dead)
return;
return;
if ( ent->client->resp.sniper_mode == SNIPER_1X )
{
gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/lensflik.wav"), 1, ATTN_NORM, 0);
ent->client->weaponstate = WEAPON_BUSY;
gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/lensflik.wav"), 1, ATTN_NORM, 0);
ent->client->resp.sniper_mode = SNIPER_2X;
ent->client->desired_fov = 45;
ent->client->idle_weapon = 6; // 6 frames of idleness
ent->client->ps.gunframe = 22;
if ( ent->client->weaponstate != WEAPON_RELOADING )
{
ent->client->idle_weapon = 6; // 6 frames of idleness
ent->client->ps.gunframe = 22;
ent->client->weaponstate = WEAPON_BUSY;
}
}
else if ( ent->client->resp.sniper_mode == SNIPER_2X )
{
@ -336,9 +415,15 @@ void Cmd_Weapon_f ( edict_t *ent )
ent->client->resp.knife_mode = !(ent->client->resp.knife_mode);
ent->client->weaponstate = WEAPON_ACTIVATING;
if ( ent->client->resp.knife_mode )
ent->client->ps.gunframe = 0;
{
gi.cprintf(ent, PRINT_HIGH, "Switching to throwing\n");
ent->client->ps.gunframe = 0;
}
else
ent->client->ps.gunframe = 106;
{
gi.cprintf(ent, PRINT_HIGH, "Switching to slashing\n");
ent->client->ps.gunframe = 106;
}
}
}
@ -376,8 +461,15 @@ void Cmd_OpenDoor_f (edict_t *ent )
void Cmd_Bandage_f ( edict_t *ent )
{
gitem_t *item;
if ( (ent->client->weaponstate == WEAPON_READY || ent->client->weaponstate == WEAPON_END_MAG )
gitem_t *item;
if ( (ent->client->bleeding != 0 || ent->client->leg_damage != 0) && ent->client->bandaging != 1 )
ent->client->reload_attempts = 0; // prevent any further reloading
if ( (ent->client->weaponstate == WEAPON_READY || ent->client->weaponstate == WEAPON_END_MAG )
&& (ent->client->bleeding != 0 || ent->client->leg_damage != 0 )
&& ent->client->bandaging != 1 )
{
@ -385,22 +477,24 @@ void Cmd_Bandage_f ( edict_t *ent )
// zucc - check if they have a primed grenade
if ( ent->client->curr_weap == GRENADE_NUM
&& ( ent->client->ps.gunframe >= GRENADE_IDLE_FIRST
&& ent->client->ps.gunframe <= GRENADE_IDLE_LAST ) )
&& ( ( ent->client->ps.gunframe >= GRENADE_IDLE_FIRST
&& ent->client->ps.gunframe <= GRENADE_IDLE_LAST )
|| ( ent->client->ps.gunframe >= GRENADE_THROW_FIRST
&& ent->client->ps.gunframe <= GRENADE_THROW_LAST ) ) )
{
ent->client->ps.gunframe = 0;
fire_grenade2 (ent, ent->s.origin, tv(0,0,0), GRENADE_DAMRAD, 0, 2, GRENADE_DAMRAD*2, false);
item = FindItem(GRENADE_NAME);
ent->client->pers.inventory[ITEM_INDEX(item)]--;
if ( ent->client->pers.inventory[ITEM_INDEX(item)] <= 0 )
{
ent->client->newweapon = FindItem( MK23_NAME );
item = FindItem(GRENADE_NAME);
ent->client->pers.inventory[ITEM_INDEX(item)]--;
if ( ent->client->pers.inventory[ITEM_INDEX(item)] <= 0 )
{
ent->client->newweapon = FindItem( MK23_NAME );
}
}
}
}
ent->client->bandaging = 1;
ent->client->resp.sniper_mode = SNIPER_1X;
ent->client->resp.sniper_mode = SNIPER_1X;
ent->client->ps.fov = 90;
ent->client->desired_fov = 90;
if ( ent->client->pers.weapon )
@ -422,16 +516,16 @@ void Bandage( edict_t* ent )
{
ent->client->leg_noise = 0;
ent->client->leg_damage = 0;
ent->client->leghits = 0;
ent->client->bleeding = 0;
ent->client->leghits = 0;
ent->client->bleeding = 0;
ent->client->bleed_remain = 0;
// ent->client->bleedcount = 0;
// ent->client->bleeddelay = 0;
ent->client->bandaging = 0;
ent->client->leg_dam_count = 0;
ent->client->attacker = NULL;
ent->client->bandage_stopped = 1;
ent->client->idle_weapon = BANDAGE_TIME;
ent->client->bandaging = 0;
ent->client->leg_dam_count = 0;
ent->client->attacker = NULL;
ent->client->bandage_stopped = 1;
ent->client->idle_weapon = BANDAGE_TIME;
}
@ -487,7 +581,9 @@ qboolean loc_CanSee (edict_t *targ, edict_t *inflictor)
viewpoint[2] += inflictor->viewheight;
for (i = 0; i < 8; i++) {
trace = do_trace (viewpoint, vec3_origin, vec3_origin, targpoints[i], inflictor, MASK_SOLID);
PRETRACE();
trace = gi.trace (viewpoint, vec3_origin, vec3_origin, targpoints[i], inflictor, MASK_SOLID);
POSTTRACE();
if (trace.fraction == 1.0)
return true;
}
@ -502,7 +598,10 @@ void SetIDView(edict_t *ent)
vec3_t forward, dir;
trace_t tr;
edict_t *who, *best;
float bd = 0, d;
//FIREBLADE, suggested by hal[9k] 3/11/1999
float bd = 0.9;
//FIREBLADE
float d;
int i;
ent->client->ps.stats[STAT_ID_VIEW] = 0;
@ -533,7 +632,9 @@ void SetIDView(edict_t *ent)
AngleVectors(ent->client->v_angle, forward, NULL, NULL);
VectorScale(forward, 8192, forward);
VectorAdd(ent->s.origin, forward, forward);
tr = do_trace(ent->s.origin, NULL, NULL, forward, ent, MASK_SOLID);
PRETRACE();
tr = gi.trace(ent->s.origin, NULL, NULL, forward, ent, MASK_SOLID);
POSTTRACE();
if (tr.fraction < 1 && tr.ent && tr.ent->client) {
ent->client->ps.stats[STAT_ID_VIEW] =
CS_PLAYERSKINS + (ent - g_edicts - 1);

135
a_doorkick.c Normal file
View file

@ -0,0 +1,135 @@
/* a_doorkick.c
* Door kicking code by hal[9k]
* originally for AQ:Espionage (http://aqdt.fear.net/)
* email: hal9000@telefragged.com
* Assembled here by Homer (homer@fear.net)
*/
#include "g_local.h"
#define STATE_TOP 0
#define STATE_BOTTOM 1
#define STATE_UP 2
#define STATE_DOWN 3
#define DOOR_START_OPEN 1
#define DOOR_REVERSE 2
extern void door_use (edict_t *self, edict_t *other, edict_t *activator);
// needed for KickDoor
void VectorRotate(vec3_t in, vec3_t angles, vec3_t out)
{
float cv, sv, angle, tv;
VectorCopy(in, out);
angle = (-angles[PITCH]) * M_PI / 180;
cv = cos(angle);
sv = sin(angle);
tv = (out[0] * cv) - (out[2] * sv);
out[2] = (out[2] * cv) + (out[0] * sv);
out[0] = tv;
angle = (angles[YAW]) * M_PI / 180;
cv = cos(angle);
sv = sin(angle);
tv = (out[0] * cv) - (out[1] * sv);
out[1] = (out[1] * cv) + (out[0] * sv);
out[0] = tv;
angle = (angles[ROLL]) * M_PI / 180;
cv = cos(angle);
sv = sin(angle);
tv = (out[1] * cv) - (out[2] * sv);
out[2] = (out[2] * cv) + (out[1] * sv);
out[1] = tv;
}
int KickDoor( trace_t *tr_old, edict_t *ent, vec3_t forward )
{
trace_t tr;
vec3_t d_forward, right, end;
float d;
if ( !Q_strcasecmp( tr_old->ent->classname, "func_door_rotating" ) )
{
// Make that the door is closed
tr = *tr_old;
#if 1
if ( (!(tr.ent->spawnflags & DOOR_START_OPEN) &&
!(tr.ent->moveinfo.state == STATE_TOP)) ||
( (tr.ent->spawnflags & DOOR_START_OPEN) &&
!(tr.ent->moveinfo.state == STATE_BOTTOM)) )
#else
if ( (!(tr.ent->spawnflags & DOOR_START_OPEN) &&
((tr.ent->moveinfo.state == STATE_BOTTOM) ||
(tr.ent->moveinfo.state == STATE_DOWN))) ||
((tr.ent->spawnflags & DOOR_START_OPEN) &&
((tr.ent->moveinfo.state == STATE_TOP) ||
(tr.ent->moveinfo.state == STATE_UP))) )
#endif
{
//gi.dprintf( "Kicking a closed door\n" );
// Find out if we are on the "outside"
#if 0
gi.WriteByte (svc_temp_entity);
gi.WriteByte (TE_RAILTRAIL);
gi.WritePosition (tr.ent->s.origin);
gi.WritePosition (tr.endpos);
gi.multicast (tr.ent->s.origin, MULTICAST_PHS);
#endif
VectorSubtract( tr.endpos, tr.ent->s.origin, d_forward );
forward[2] = 0;
d_forward[2] = 0;
VectorNormalize( forward );
VectorNormalize( d_forward );
VectorSet( right, 0, 90, 0 );
VectorRotate( d_forward, right, d_forward );
d = DotProduct( forward, d_forward );
if ( tr.ent->spawnflags & DOOR_REVERSE )
d = -d;
// d = sin( acos( d ) );
if ( d > 0.0 )
{
// gi.dprintf( "we think we are on the outside\n" );
//if ( tr.ent->spawnflags & DOOR_REVERSE )
// gi.dprintf( "but DOOR_REVERSE is set\n" );
// Only use the door if it's not already opening
if ( (!( tr.ent->spawnflags & DOOR_START_OPEN ) &&
!( tr.ent->moveinfo.state == STATE_UP )) ||
((tr.ent->spawnflags & DOOR_START_OPEN ) &&
(tr.ent->moveinfo.state == STATE_DOWN) ) )
door_use( tr.ent, ent, ent );
// Find out if someone else is on the other side
VectorMA( tr.endpos, 25, forward, end );
PRETRACE();
tr = gi.trace (tr.endpos, NULL, NULL, end, tr.ent, MASK_SHOT);
POSTTRACE();
if (!((tr.surface) && (tr.surface->flags & SURF_SKY)))
{
if (tr.fraction < 1.0)
{
if (tr.ent->client)
{
//gi.dprintf("we found a client on the other side\n");
*tr_old = tr;
return( 1 );
}
}
}
}
}
}
return( 0 );
}

1244
a_game.c

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@
* Include for base Action game-related things
*/
#define ACTION_VERSION "1.5"
#define ACTION_VERSION "1.52"
extern char team1_name[];
extern char team2_name[];
@ -13,14 +13,27 @@ extern char team2_skin_index[];
extern char *map_rotation[];
extern int num_maps, cur_map;
extern char *tnames[];
extern int *took_damage;
void ReadConfigFile();
void ReadMOTDFile();
void PrintMOTD(edict_t *);
void stuffcmd(edict_t *, char *);
int KickDoor( trace_t *tr_old, edict_t *ent, vec3_t forward );
// Prototypes of base Q2 functions that weren't included in any Q2 header
qboolean loc_CanSee(edict_t *, edict_t *);
qboolean IsNeutral(edict_t *);
qboolean IsFemale(edict_t *);
void ParseSayText(edict_t *, char *);
// Firing styles (where shots originate from)
#define ACTION_FIRING_CENTER 0
#define ACTION_FIRING_CLASSIC 1
#define ACTION_FIRING_CLASSIC_HIGH 2
// maxs[2] of a player when crouching (we modify it from the normal 4)
// ...also the modified viewheight -FB 7/18/99
#define CROUCHING_MAXS2 16
#define CROUCHING_VIEWHEIGHT 8

View file

@ -33,7 +33,9 @@ static edict_t *FindSpecSpawn(void)
if (spot == NULL)
{
/* FB 6/24/99
gi.dprintf("Warning: failed to find special item spawn point!\n");
*/
}
return spot;

View file

@ -100,7 +100,27 @@ void DeleteFirstRadioQueueEntry(edict_t *ent)
return;
}
for (i = 1; i < MAX_RADIO_QUEUE_SIZE; i++)
for (i = 1; i < ent->client->resp.radio_queue_size; i++)
{
memcpy(&(ent->client->resp.radio_queue[i - 1]),
&(ent->client->resp.radio_queue[i]),
sizeof(radio_queue_entry_t));
}
ent->client->resp.radio_queue_size--;
}
void DeleteRadioQueueEntry(edict_t *ent, int entry_num)
{
int i;
if (ent->client->resp.radio_queue_size <= entry_num)
{
gi.dprintf("DeleteRadioQueueEntry: attempt to delete out of range queue entry\n");
return;
}
for (i = entry_num + 1; i < ent->client->resp.radio_queue_size; i++)
{
memcpy(&(ent->client->resp.radio_queue[i - 1]),
&(ent->client->resp.radio_queue[i]),
@ -161,6 +181,7 @@ void RadioThink(edict_t *ent)
{
char snd_play_cmd[512];
edict_t *from;
int check;
from = ent->client->resp.radio_queue[0].from_player;
@ -177,6 +198,15 @@ void RadioThink(edict_t *ent)
strcpy(ent->client->resp.radio_queue[0].soundfile, RADIO_DEATH_MALE);
ent->client->resp.radio_queue[0].length = RADIO_DEATH_MALE_LEN;
}
for (check = 1; check < ent->client->resp.radio_queue_size; check++)
{
if (ent->client->resp.radio_queue[check].from_player == from)
{
DeleteRadioQueueEntry(ent, check);
check--;
}
}
}
sprintf(snd_play_cmd, "play %s", ent->client->resp.radio_queue[0].soundfile);
@ -455,13 +485,18 @@ edict_t *DetermineViewedTeammate(edict_t *ent)
vec3_t forward, dir;
trace_t tr;
edict_t *who, *best;
float bd = 0, d;
//FIREBLADE, suggested by hal[9k] 3/11/1999
float bd = 0.9;
//FIREBLADE
float d;
int i;
AngleVectors(ent->client->v_angle, forward, NULL, NULL);
VectorScale(forward, 8192, forward);
VectorAdd(ent->s.origin, forward, forward);
tr = do_trace(ent->s.origin, NULL, NULL, forward, ent, MASK_SOLID);
PRETRACE();
tr = gi.trace(ent->s.origin, NULL, NULL, forward, ent, MASK_SOLID);
POSTTRACE();
if (tr.fraction < 1 && tr.ent && tr.ent->client) {
return NULL;
}

381
a_team.c
View file

@ -5,6 +5,7 @@
*/
#include "g_local.h"
#include "cgf_sfx_glass.h"
qboolean team_game_going = 0; // is a team game going right now?
qboolean team_round_going = 0; // is an actual round of a team game going right now?
@ -36,95 +37,95 @@ void CreditsMenu(edict_t *ent, pmenu_t *p);
void InitTransparentList()
{
if (transparent_list != NULL)
{
transparent_list_t *p, *q;
if (transparent_list != NULL)
{
transparent_list_t *p, *q;
p = transparent_list;
while (p != NULL)
{
q = p->next;
gi.TagFree(p);
p = q;
}
p = transparent_list;
while (p != NULL)
{
q = p->next;
gi.TagFree(p);
p = q;
}
transparent_list = NULL;
}
transparent_list = NULL;
}
}
void AddToTransparentList(edict_t *ent)
{
transparent_list_t *p, *n;
transparent_list_t *p, *n;
n = (transparent_list_t *)gi.TagMalloc(sizeof(transparent_list_t), TAG_GAME);
if (n == NULL)
{
gi.dprintf("Out of memory\n");
exit(1);
}
n->ent = ent;
n->next = NULL;
n = (transparent_list_t *)gi.TagMalloc(sizeof(transparent_list_t), TAG_GAME);
if (n == NULL)
{
gi.dprintf("Out of memory\n");
exit(1);
}
n->ent = ent;
n->next = NULL;
if (transparent_list == NULL)
{
transparent_list = n;
}
else
{
p = transparent_list;
while (p->next != NULL)
{
p = p->next;
}
p->next = n;
}
if (transparent_list == NULL)
{
transparent_list = n;
}
else
{
p = transparent_list;
while (p->next != NULL)
{
p = p->next;
}
p->next = n;
}
}
void RemoveFromTransparentList(edict_t *ent)
{
transparent_list_t *p, *q, *r;
transparent_list_t *p, *q, *r;
if (transparent_list != NULL)
{
if (transparent_list->ent == ent)
{
q = transparent_list->next;
gi.TagFree(transparent_list);
transparent_list = q;
return;
}
else
{
p = transparent_list;
q = p->next;
while (q != NULL)
{
if (q->ent == ent)
{
r = q->next;
gi.TagFree(q);
p->next = r;
return;
}
p = p->next;
q = p->next;
}
}
}
if (transparent_list != NULL)
{
if (transparent_list->ent == ent)
{
q = transparent_list->next;
gi.TagFree(transparent_list);
transparent_list = q;
return;
}
else
{
p = transparent_list;
q = p->next;
while (q != NULL)
{
if (q->ent == ent)
{
r = q->next;
gi.TagFree(q);
p->next = r;
return;
}
p = p->next;
q = p->next;
}
}
}
gi.dprintf("Warning: attempt to RemoveFromTransparentList when not in it\n");
}
gi.dprintf("Warning: attempt to RemoveFromTransparentList when not in it\n");
}
void TransparentListSet(solid_t solid_type)
{
transparent_list_t *p = transparent_list;
transparent_list_t *p = transparent_list;
while (p != NULL)
{
p->ent->solid = solid_type;
gi.linkentity(p->ent);
p = p->next;
}
while (p != NULL)
{
p->ent->solid = solid_type;
gi.linkentity(p->ent);
p = p->next;
}
}
void ReprintMOTD(edict_t *ent, pmenu_t *p)
@ -581,7 +582,11 @@ int UpdateJoinMenu(edict_t *ent)
return TEAM2;
else if (num2 > num1)
return TEAM1;
else
else if (team1_score > team2_score)
return TEAM2;
else if (team2_score > team1_score)
return TEAM1;
else
return TEAM1;
}
@ -631,8 +636,8 @@ void CleanLevel()
"item_band",
"item_lasersight",
"item_vest",
"thrown_knife",
"hgrenade",
"thrown_knife",
"hgrenade",
};
int i;
@ -655,6 +660,9 @@ void CleanLevel()
}
CleanBodies();
// fix glass
CGF_SFX_RebuildAllBrokenGlass();
}
qboolean StartClient(edict_t *ent)
@ -714,7 +722,7 @@ int CheckForWinner()
int onteam1 = 0, onteam2 = 0, i;
edict_t *ent;
for (i = 0; i < game.maxclients; i++)
for (i = 0; i < game.maxclients; i++)
{
ent = &g_edicts[1+i];
if (!ent->inuse)
@ -784,18 +792,18 @@ void SpawnPlayers()
{
int i;
edict_t *ent;
GetSpawnPoints();
SetupTeamSpawnPoints();
InitTransparentList();
InitTransparentList();
for (i = 0; i < game.maxclients; i++)
{
ent = &g_edicts[1+i];
if (ent->inuse && ent->client->resp.team != NOTEAM)
{
{
PutClientInServer(ent);
AddToTransparentList(ent);
}
AddToTransparentList(ent);
}
}
}
@ -808,6 +816,7 @@ void StartRound()
void StartLCA()
{
CleanLevel();
CenterPrintAll("LIGHTS...\n");
gi.sound(&g_edicts[0], CHAN_VOICE | CHAN_NO_PHS_ADD,
gi.soundindex("atl/lights.wav"), 1.0, ATTN_NONE, 0.0);
@ -853,10 +862,10 @@ void ContinueLCA()
}
else if (lights_camera_action == 1)
{
CenterPrintAll("ACTION!\n");
gi.sound(&g_edicts[0], CHAN_VOICE | CHAN_NO_PHS_ADD,
gi.soundindex("atl/action.wav"), 1.0, ATTN_NONE, 0.0);
StartRound();
CenterPrintAll("ACTION!\n");
gi.sound(&g_edicts[0], CHAN_VOICE | CHAN_NO_PHS_ADD,
gi.soundindex("atl/action.wav"), 1.0, ATTN_NONE, 0.0);
StartRound();
}
lights_camera_action--;
}
@ -993,7 +1002,7 @@ void CheckTeamRules()
if (BothTeamsHavePlayers())
{
CenterPrintAll("The round will begin in 20 seconds!\n");
team_round_countdown = 201;
team_round_countdown = 201;
}
}
}
@ -1067,15 +1076,14 @@ void A_Scoreboard(edict_t *ent)
void A_ScoreboardMessage (edict_t *ent, edict_t *killer)
{
char string[1400];
char string[1400], damage[50];
gclient_t *cl;
edict_t *cl_ent;
int maxsize = 1000, i, j, k;
if (ent->client->scoreboardnum == 1)
{
int team, len;
int team, len, deadview;
int sorted[TEAM_TOP][MAX_CLIENTS];
int sortedscores[TEAM_TOP][MAX_CLIENTS];
int score, total[TEAM_TOP], totalscore[TEAM_TOP];
@ -1083,6 +1091,10 @@ void A_ScoreboardMessage (edict_t *ent, edict_t *killer)
int stoppedat[TEAM_TOP];
int name_pos[TEAM_TOP];
deadview = (ent->solid == SOLID_NOT ||
ent->deadflag == DEAD_DEAD ||
!team_round_going);
ent->client->ps.stats[STAT_TEAM_HEADER] = gi.imageindex ("tag3");
total[TEAM1] = total[TEAM2] = totalalive[TEAM1] = totalalive[TEAM2] =
@ -1100,28 +1112,29 @@ void A_ScoreboardMessage (edict_t *ent, edict_t *killer)
team = game.clients[i].resp.team;
score = game.clients[i].resp.score;
if (noscore->value)
{
j = total[team];
}
else
{
for (j = 0; j < total[team]; j++)
{
if (score > sortedscores[team][j])
break;
}
for (k=total[team] ; k>j ; k--)
{
sorted[team][k] = sorted[team][k-1];
sortedscores[team][k] = sortedscores[team][k-1];
}
}
if (noscore->value)
{
j = total[team];
}
else
{
for (j = 0; j < total[team]; j++)
{
if (score > sortedscores[team][j])
break;
}
for (k=total[team] ; k>j ; k--)
{
sorted[team][k] = sorted[team][k-1];
sortedscores[team][k] = sortedscores[team][k-1];
}
}
sorted[team][j] = i;
sortedscores[team][j] = score;
totalscore[team] += score;
total[team]++;
if (cl_ent->solid != SOLID_NOT)
if (cl_ent->solid != SOLID_NOT &&
cl_ent->deadflag != DEAD_DEAD)
totalalive[team]++;
}
@ -1183,7 +1196,8 @@ void A_ScoreboardMessage (edict_t *ent, edict_t *killer)
{
cl = &game.clients[sorted[TEAM1][i]];
cl_ent = g_edicts + 1 + sorted[TEAM1][i];
if (cl_ent->solid != SOLID_NOT)
if (cl_ent->solid != SOLID_NOT &&
cl_ent->deadflag != DEAD_DEAD)
totalaliveprinted[TEAM1]++;
// AQ truncates names at 12, not sure why, except maybe to conserve scoreboard
@ -1192,7 +1206,7 @@ void A_ScoreboardMessage (edict_t *ent, edict_t *killer)
sprintf(string+strlen(string),
"xv 0 yv %d string%s \"%s\" ",
42 + i * 8,
(ent->solid == SOLID_NOT) ? (cl_ent->solid == SOLID_NOT ? "" : "2") : "",
deadview ? (cl_ent->solid == SOLID_NOT ? "" : "2") : "",
game.clients[sorted[TEAM1][i]].pers.netname);
}
@ -1200,7 +1214,8 @@ void A_ScoreboardMessage (edict_t *ent, edict_t *killer)
{
cl = &game.clients[sorted[TEAM2][i]];
cl_ent = g_edicts + 1 + sorted[TEAM2][i];
if (cl_ent->solid != SOLID_NOT)
if (cl_ent->solid != SOLID_NOT &&
cl_ent->deadflag != DEAD_DEAD)
totalaliveprinted[TEAM2]++;
// AQ truncates names at 12, not sure why, except maybe to conserve scoreboard
@ -1209,7 +1224,7 @@ void A_ScoreboardMessage (edict_t *ent, edict_t *killer)
sprintf(string+strlen(string),
"xv 160 yv %d string%s \"%s\" ",
42 + i * 8,
(ent->solid == SOLID_NOT) ? (cl_ent->solid == SOLID_NOT ? "" : "2") : "",
deadview ? (cl_ent->solid == SOLID_NOT ? "" : "2") : "",
game.clients[sorted[TEAM2][i]].pers.netname);
}
@ -1217,7 +1232,7 @@ void A_ScoreboardMessage (edict_t *ent, edict_t *killer)
}
// Print remaining players if we ran out of room...
if (ent->solid != SOLID_NOT) // live player viewing scoreboard...
if (!deadview) // live player viewing scoreboard...
{
if (stoppedat[TEAM1] > -1)
{
@ -1243,7 +1258,7 @@ void A_ScoreboardMessage (edict_t *ent, edict_t *killer)
if (stoppedat[TEAM2] > -1)
{
sprintf(string + strlen(string), "xv 160 yv %d string%s \"..and %d/%d more\" ",
42 + (stoppedat[TEAM1] * 8),
42 + (stoppedat[TEAM2] * 8),
(totalalive[TEAM2] - totalaliveprinted[TEAM2]) ? "2" : "",
totalalive[TEAM2] - totalaliveprinted[TEAM2],
total[TEAM2] - stoppedat[TEAM2]);
@ -1266,63 +1281,67 @@ void A_ScoreboardMessage (edict_t *ent, edict_t *killer)
continue;
score = game.clients[i].resp.score;
if (noscore->value)
{
j = total;
}
else
{
for (j = 0; j < total; j++)
{
if (score > sortedscores[j])
break;
}
for (k = total ; k > j ; k--)
{
sorted[k] = sorted[k-1];
sortedscores[k] = sortedscores[k-1];
}
}
sorted[j] = i;
sortedscores[j] = score;
if (noscore->value)
{
j = total;
}
else
{
for (j = 0; j < total; j++)
{
if (score > sortedscores[j])
break;
}
for (k = total ; k > j ; k--)
{
sorted[k] = sorted[k-1];
sortedscores[k] = sortedscores[k-1];
}
}
sorted[j] = i;
sortedscores[j] = score;
total++;
}
if (noscore->value)
{
strcpy(string, "xv 0 yv 32 string2 \"Player Time Ping\" "
"xv 0 yv 40 string2 \"--------------- ---- ----\" ");
}
else
{
strcpy(string, "xv 0 yv 32 string2 \"Frags Player Time Ping\" "
"xv 0 yv 40 string2 \"----- --------------- ---- ----\" ");
}
if (noscore->value)
{
strcpy(string, "xv 0 yv 32 string2 \"Player Time Ping\" "
"xv 0 yv 40 string2 \"--------------- ---- ----\" ");
}
else
{
strcpy(string, "xv 0 yv 32 string2 \"Frags Player Time Ping Damage\" "
"xv 0 yv 40 string2 \"----- --------------- ---- ---- ------\" ");
}
for (i = 0; i < total; i++)
{
ping = game.clients[sorted[i]].ping;
if (ping > 999)
ping = 999;
if (noscore->value)
{
sprintf(string + strlen(string),
"xv 0 yv %d string \"%-15s %4d %4d\" ",
48 + i * 8,
game.clients[sorted[i]].pers.netname,
(level.framenum - game.clients[sorted[i]].resp.enterframe)/600,
ping);
}
else
{
sprintf(string + strlen(string),
"xv 0 yv %d string \"%5d %-15s %4d %4d\" ",
48 + i * 8,
sortedscores[i],
game.clients[sorted[i]].pers.netname,
(level.framenum - game.clients[sorted[i]].resp.enterframe)/600,
ping);
}
ping = game.clients[sorted[i]].ping;
if (ping > 999)
ping = 999;
if (noscore->value)
{
sprintf(string + strlen(string),
"xv 0 yv %d string \"%-15s %4d %4d\" ",
48 + i * 8,
game.clients[sorted[i]].pers.netname,
(level.framenum - game.clients[sorted[i]].resp.enterframe)/600,
ping);
}
else
{
if (game.clients[sorted[i]].resp.damage_dealt < 1000000)
sprintf(damage, "%d", game.clients[sorted[i]].resp.damage_dealt);
else
strcpy(damage, "******");
sprintf(string + strlen(string),
"xv 0 yv %d string \"%5d %-15s %4d %4d %6s\" ",
48 + i * 8,
sortedscores[i],
game.clients[sorted[i]].pers.netname,
(level.framenum - game.clients[sorted[i]].resp.enterframe)/600,
ping, damage);
}
if (strlen(string) > (maxsize - 100) &&
i < (total - 2))
@ -1393,11 +1412,11 @@ void GetSpawnPoints()
{
potential_spawns[num_potential_spawns] = spot;
num_potential_spawns++;
if (num_potential_spawns >= MAX_SPAWNS)
{
gi.dprintf("Warning: MAX_SPAWNS exceeded\n");
return;
}
if (num_potential_spawns >= MAX_SPAWNS)
{
gi.dprintf("Warning: MAX_SPAWNS exceeded\n");
return;
}
}
}
@ -1474,10 +1493,24 @@ void SelectFarTeamplaySpawnPoint(int team, qboolean teams_assigned[])
else
preferred_spawn_points = 3;
//FB 6/1/99 - make DF_SPAWN_FARTHEST force far spawn points in TP
if ((int)dmflags->value & DF_SPAWN_FARTHEST)
preferred_spawn_points = 1;
//FB 6/1/99
spawn_to_use = newrand(preferred_spawn_points);
teams_assigned[team] = true;
teamplay_spawns[team] = spawn_distances[num_potential_spawns - spawn_to_use - 1].s;
if (team < 0 || team >= MAX_TEAMS)
{
gi.dprintf("Out-of-range teams value in SelectFarTeamplaySpawnPoint, skipping...\n");
}
else
{
teams_assigned[team] = true;
teamplay_spawns[team] = spawn_distances[num_potential_spawns - spawn_to_use - 1].s;
}
gi.TagFree(spawn_distances);
}
// SetupTeamSpawnPoints:
@ -1499,10 +1532,10 @@ void SetupTeamSpawnPoints()
firstassignment = 1;
do
{
if (l < 0 || l >= MAX_TEAMS)
{
gi.dprintf("Warning: attempt to setup spawns for out-of-range team (%d)\n", l);
}
if (l < 0 || l >= MAX_TEAMS)
{
gi.dprintf("Warning: attempt to setup spawns for out-of-range team (%d)\n", l);
}
if (firstassignment)
{

View file

@ -14,20 +14,22 @@
#define WINNER_TEAM2 2
#define WINNER_TIE 3
// Override normal trace for our teamplay anti-stick stuff. If there are
// Pre- and post-trace code for our teamplay anti-stick stuff. If there are
// still "transparent" (SOLID_TRIGGER) players, they need to be set to
// SOLID_BBOX before a trace is performed, then changed back again
// afterwards. do_trace() should be used instead of gi.trace() in all
// areas where "transparent" players should be detected.
#define do_trace(a, b, c, d, e, f) \
(((int)teamplay->value && transparent_list && !lights_camera_action) ? \
(TransparentListSet(SOLID_BBOX), \
(trace_t_temp = gi.trace(a, b, c, d, e, f)), \
TransparentListSet(SOLID_TRIGGER), \
trace_t_temp) \
: \
gi.trace(a, b, c, d, e, f))
trace_t our_trace(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passent, int contentmask);
// afterwards. PRETRACE() and POSTTRACE() should be called before and after
// traces in all places where combat is taking place (ie "transparent" players
// should be detected), ie shots being traced etc.
// FB 6/1/99: Now crouching players will have their bounding box adjusted here
// too, for better shot areas. (there has to be a better way to do this?)
#define PRETRACE() \
if (transparent_list && (int)teamplay->value && !lights_camera_action) \
TransparentListSet(SOLID_BBOX)
#define POSTTRACE() \
if (transparent_list && (int)teamplay->value && !lights_camera_action) \
TransparentListSet(SOLID_TRIGGER)
edict_t *SelectTeamplaySpawnPoint(edict_t *);
qboolean FallingDamageAmnesty(edict_t *targ);
@ -61,8 +63,8 @@ typedef struct spawn_distances_s
typedef struct transparent_list_s
{
edict_t *ent;
struct transparent_list_s *next;
edict_t *ent;
struct transparent_list_s *next;
} transparent_list_t;

704
cgf_sfx_glass.c Normal file
View file

@ -0,0 +1,704 @@
/****************************************************************************/
/* */
/* project : CGF (c) 1999 William van der Sterren */
/* parts (c) 1998 id software */
/* */
/* file : cgf_sfx_glass.cpp "special effects for glass entities" */
/* author(s): William van der Sterren */
/* version : 0.5 */
/* */
/* date (last revision): Jun 12, 99 */
/* date (creation) : Jun 04, 99 */
/* */
/* */
/* revision history */
/* -- date ---- | -- revision ---------------------- | -- revisor -- */
/* Jun 12, 1999 | fixed knife slash breaks glass | William */
/* Jun 08, 1999 | improved fragment limit | William */
/* */
/******* http://www.botepidemic.com/aid/cgf for CGF for Action Quake2 *******/
#ifdef __cplusplus
// VC++, for CGF
#include <cmath> // prevent problems between C and STL
extern "C"
{
#include "g_local.h"
#include "cgf_sfx_glass.h"
}
#else
// C, for other AQ2 variants
#include "g_local.h"
#include "cgf_sfx_glass.h"
#endif
// cvar for breaking glass
static cvar_t *breakableglass = 0;
// cvar for max glass fragment count
static cvar_t *glassfragmentlimit = 0;
static int glassfragmentcount = 0;
// additional functions - Q2 expects C calling convention
#ifdef __cplusplus
extern "C"
{
#endif
void CGF_SFX_TouchGlass(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf);
// called whenever an entity hits the trigger spawned for the glass
void CGF_SFX_EmitGlass (edict_t* aGlassPane, edict_t* anInflictor, vec3_t aPoint);
// emits glass fragments from aPoint, to show effects of firing thru window
void CGF_SFX_BreakGlass(edict_t* aGlassPane, edict_t* anOther, edict_t* anAttacker,
int aDamage, vec3_t aPoint, vec_t aPaneDestructDelay
);
// breaks glass
void CGF_SFX_InstallBreakableGlass(edict_t* aGlassPane);
// when working on a glass pane for the first time, just install trigger
// when working on a glass pane again (after a game ended), move
// glass back to original location
void CGF_SFX_HideBreakableGlass(edict_t* aGlassPane);
// after being broken, the pane cannot be removed as it is needed in
// subsequent missions/games, so hide it at about z = -1000
void CGF_SFX_ApplyGlassFragmentLimit(const char* aClassName);
// updates glassfragmentcount and removes oldest glass fragement if
// necessary to meet limit
void CGF_SFX_MiscGlassUse(edict_t *self, edict_t *other, edict_t *activator);
// catches use from unforeseen objects (weapons, debris,
// etc. touching the window)
void CGF_SFX_MiscGlassDie(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
// catches die calls caused by unforeseen objects (weapons, debris,
// etc. damaging the window)
void CGF_SFX_GlassThrowDebris (edict_t *self, char *modelname, float speed, vec3_t origin);
// variant of id software's ThrowDebris, now numbering the entity (for later removal)
extern // from a_game.c
edict_t *FindEdictByClassnum (char *classname, int classnum);
// declaration from g_misc.c
extern // from g_misc.c
void debris_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
#ifdef __cplusplus
}
#endif
void CGF_SFX_InstallGlassSupport()
{
breakableglass = gi.cvar("breakableglass", "0", 0);
glassfragmentlimit = gi.cvar("glassfragmentlimit", "30", 0);
}
int CGF_SFX_IsBreakableGlassEnabled()
{
// returns whether breakable glass is enabled (cvar) and allowed (dm mode)
return breakableglass->value;
}
void CGF_SFX_TestBreakableGlassAndRemoveIfNot_Think(edict_t* aPossibleGlassEntity)
{
// at level.time == 0.1 the entity has been introduced in the game,
// and we can use gi.pointcontents and gi.trace to check the entity
vec3_t origin;
int breakingglass;
trace_t trace;
// test for cvar
if (!CGF_SFX_IsBreakableGlassEnabled())
{
G_FreeEdict(aPossibleGlassEntity);
return;
}
VectorAdd(aPossibleGlassEntity->absmax, aPossibleGlassEntity->absmin, origin);
VectorScale(origin, 0.5, origin);
// detect glass (does not work for complex shapes,
// for example, the glass window near the satellite
// dish at Q2 base3
breakingglass = (gi.pointcontents(origin) & CONTENTS_TRANSLUCENT);
if (!breakingglass)
{
// test for complex brushes that happen to be
// hollow in their origin (for instance, the
// window at Q2 base3, near the satellite dish
trace = gi.trace(origin, vec3_origin, vec3_origin, aPossibleGlassEntity->absmax, 0,
MASK_PLAYERSOLID
);
breakingglass = ((trace.ent == aPossibleGlassEntity) &&
(trace.contents & CONTENTS_TRANSLUCENT)
);
trace = gi.trace(origin, vec3_origin, vec3_origin, aPossibleGlassEntity->absmin, 0,
MASK_PLAYERSOLID
);
breakingglass = ((breakingglass) ||
((trace.ent == aPossibleGlassEntity) &&
(trace.contents & CONTENTS_TRANSLUCENT)
)
);
}
if (!breakingglass)
{
// do remove other func_explosives
G_FreeEdict (aPossibleGlassEntity);
return;
}
// discovered some glass - now make store the origin
// we need that after hiding the glass
VectorCopy(aPossibleGlassEntity->s.origin, aPossibleGlassEntity->pos1); // IMPORTANT!
// make a backup of the health in light_level
aPossibleGlassEntity->light_level = aPossibleGlassEntity->health;
// install the glass
CGF_SFX_InstallBreakableGlass(aPossibleGlassEntity);
}
void CGF_SFX_InstallBreakableGlass(edict_t* aGlassPane)
{
// when working on a glass pane for the first time, just install trigger
// when working on a glass pane again (after a game ended), move
// glass back to original location
edict_t* trigger;
vec3_t maxs;
vec3_t mins;
// reset origin based on aGlassPane->pos1
VectorCopy(aGlassPane->pos1, aGlassPane->s.origin);
// reset health based on aGlassPane->light_level
aGlassPane->health = aGlassPane->light_level;
// replace die and use functions by glass specific ones
aGlassPane->die = CGF_SFX_MiscGlassDie;
aGlassPane->use = CGF_SFX_MiscGlassUse;
// reset some pane attributes
aGlassPane->takedamage = DAMAGE_YES;
aGlassPane->solid = SOLID_BSP;
aGlassPane->movetype = MOVETYPE_FLYMISSILE;
// for other movetypes, cannot move pane to hidden location and back
// try to establish size
VectorCopy(aGlassPane->maxs, maxs);
VectorCopy(aGlassPane->mins, mins);
// set up trigger, similar to triggers for doors
// but with a smaller box
mins[0] -= 24;
mins[1] -= 24;
mins[2] -= 24;
maxs[0] += 24;
maxs[1] += 24;
maxs[2] += 24;
// adjust some settings
trigger = G_Spawn ();
trigger->classname = "breakableglass_trigger";
VectorCopy (mins, trigger->mins);
VectorCopy (maxs, trigger->maxs);
trigger->owner = aGlassPane;
trigger->solid = SOLID_TRIGGER;
trigger->movetype = MOVETYPE_NONE;
trigger->touch = CGF_SFX_TouchGlass;
gi.linkentity (trigger);
}
void CGF_SFX_ShootBreakableGlass(edict_t* aGlassPane,
edict_t* anAttacker,
/*trace_t**/ void* tr,
int mod
)
{
// process gunshots thru glass
edict_t* trigger;
int destruct;
// depending on mod, destroy window or emit fragments
switch (mod)
{
// break for ap, shotgun, handcannon, and kick, destory window
case MOD_M3 :
case MOD_HC :
case MOD_SNIPER :
case MOD_KICK :
case MOD_GRENADE :
case MOD_G_SPLASH:
case MOD_HANDGRENADE:
case MOD_HG_SPLASH:
case MOD_KNIFE : // slash damage
destruct = true;
break;
default :
destruct = (rand() % 3 == 0);
break;
};
if (destruct)
{
// break glass (and hurt if doing kick)
CGF_SFX_BreakGlass(aGlassPane, anAttacker, 0, aGlassPane->health, vec3_origin, FRAMETIME);
if (mod == MOD_KICK)
{
vec3_t bloodorigin;
vec3_t dir;
vec3_t normal;
VectorAdd(aGlassPane->absmax, aGlassPane->absmin, bloodorigin);
VectorScale(bloodorigin, 0.5, bloodorigin);
VectorSubtract(bloodorigin, anAttacker->s.origin, dir);
VectorNormalize(dir);
VectorMA(anAttacker->s.origin, 32.0, dir, bloodorigin);
VectorSet(normal, 0, 0, -1);
T_Damage(anAttacker, aGlassPane, anAttacker, dir, bloodorigin, normal, 15.0, 0, 0, MOD_BREAKINGGLASS);
}
// remove corresponding trigger
trigger = 0;
while (trigger = G_Find(trigger, FOFS(classname), "breakableglass_trigger"))
{
if (trigger->owner == aGlassPane)
{
// remove it
G_FreeEdict(trigger);
// only one to be found
break;
}
}
}
else
{
// add decal (if not grenade)
if ( (mod != MOD_HANDGRENADE)
&& (mod != MOD_HG_SPLASH)
&& (mod != MOD_GRENADE)
&& (mod != MOD_G_SPLASH)
)
{
AddDecal(anAttacker, (trace_t*) tr);
}
// and emit glass
CGF_SFX_EmitGlass(aGlassPane, anAttacker, ((trace_t*) tr)->endpos);
}
}
void CGF_SFX_TouchGlass(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
{
// called whenever an entity hits the trigger spawned for the glass
vec3_t origin;
vec3_t normal;
vec3_t spot;
trace_t trace;
edict_t* glass;
vec3_t velocity;
vec_t speed;
vec_t projected_speed;
int is_hgrenade;
int is_knife;
is_hgrenade = is_knife = false;
// ignore non-clients-non-grenade-non-knife
if (!other->client)
{
is_knife = (0 == Q_stricmp("weapon_knife", other->classname));
if (!is_knife)
{
is_hgrenade = (0 == Q_stricmp("hgrenade", other->classname));
}
if ((!is_knife) && (!is_hgrenade))
return;
if (is_knife)
goto knife_and_grenade_handling;
}
// test whether other really hits the glass - deal with
// the special case that other hits some boundary close to the border of the glass pane
//
//
// ....trigger.......
// +++++++++ +++++++++++
// .+---glass------+.
// wall .+--------------+.wall
// +++++++++ +++++++++++
// ----->..................
// wrong ^ ^
// | |
// wrong ok
//
glass = self->owner;
// hack - set glass' movetype to MOVETYPE_PUSH as it is not
// moving as long as the trigger is active
glass->movetype = MOVETYPE_PUSH;
VectorAdd(glass->absmax, glass->absmin, origin);
VectorScale(origin, 0.5, origin);
// other needs to be able to trace to glass origin
trace = gi.trace(other->s.origin, vec3_origin, vec3_origin, origin, other,
MASK_PLAYERSOLID
);
if (trace.ent != glass)
return;
// we can reach the glass origin, so we have the normal of
// the glass plane
VectorCopy(trace.plane.normal, normal);
// we need to check if client is not running into wall next
// to the glass (the trigger stretches into the wall)
VectorScale(normal, -1000.0, spot);
VectorAdd(spot, other->s.origin, spot);
// line between other->s.origin and spot (perpendicular to glass
// surface should not hit wall but glass instead
trace = gi.trace(other->s.origin, vec3_origin, vec3_origin, spot, other,
MASK_PLAYERSOLID
);
if (trace.ent != glass)
return;
// now, we check if the client's speed perpendicular to
// the glass plane, exceeds the required 175
// (speed should be < -200, as the plane's normal
// points towards the client
VectorCopy(other->velocity, velocity);
speed = VectorNormalize(velocity);
projected_speed = speed * DotProduct(velocity, normal);
// bump projected speed for grenades - they should break
// the window more easily
if (is_hgrenade)
projected_speed *= 1.5;
// if hitting the glass with sufficient speed (project < -175),
// being jumpkicked (speed > 700, project < -5) break the window
if (!((projected_speed < -175.0) ||
((projected_speed < -5) && (speed > 700))
)
)
goto knife_and_grenade_handling;
// break glass
CGF_SFX_BreakGlass(glass, other, other, glass->health, vec3_origin, 3.0 * FRAMETIME);
// glass can take care of itself, but the trigger isn't needed anymore
G_FreeEdict (self);
/* not needed
// reduce momentum of the client (he just broke the window
// so he should lose speed. in addition, it doesn't feel
// right if he overtakes the glass fragments
// VectorScale(normal, 200.0, velocity);
// VectorAdd(other->velocity, velocity, other->velocity);
*/
// make sure client takes damage
T_Damage(other, glass, other, normal, other->s.origin, normal, 15.0, 0, 0, MOD_BREAKINGGLASS);
return;
// goto label
knife_and_grenade_handling:
// if knife or grenade, bounce them
if ((is_knife) || (is_hgrenade))
{
// change clipmask to bounce of glass
other->clipmask = MASK_SOLID;
}
}
void CGF_SFX_BreakGlass(edict_t* aGlassPane, edict_t* anInflictor, edict_t* anAttacker,
int aDamage, vec3_t aPoint, vec_t aPaneDestructDelay
)
{
// based on func_explode, but with lotsa subtle differences
vec3_t origin;
vec3_t old_origin;
vec3_t chunkorigin;
vec3_t size;
int count;
int mass;
// bmodel origins are (0 0 0), we need to adjust that here
VectorCopy(aGlassPane->s.origin, old_origin);
VectorScale (aGlassPane->size, 0.5, size);
VectorAdd (aGlassPane->absmin, size, origin);
VectorCopy (origin, aGlassPane->s.origin);
aGlassPane->takedamage = DAMAGE_NO;
VectorSubtract (aGlassPane->s.origin, anInflictor->s.origin, aGlassPane->velocity);
VectorNormalize (aGlassPane->velocity);
// use speed 250 instead of 150 for funkier glass spray
VectorScale (aGlassPane->velocity, 250.0, aGlassPane->velocity);
// start chunks towards the center
VectorScale (size, 0.75, size);
mass = aGlassPane->mass;
if (!mass)
mass = 75;
// big chunks
if (mass >= 100)
{
count = mass / 100;
if (count > 8)
count = 8;
while(count--)
{
CGF_SFX_ApplyGlassFragmentLimit("debris");
chunkorigin[0] = origin[0] + crandom() * size[0];
chunkorigin[1] = origin[1] + crandom() * size[1];
chunkorigin[2] = origin[2] + crandom() * size[2];
CGF_SFX_GlassThrowDebris (aGlassPane, "models/objects/debris1/tris.md2", 1, chunkorigin);
}
}
// small chunks
count = mass / 25;
if (count > 16)
count = 16;
while(count--)
{
CGF_SFX_ApplyGlassFragmentLimit("debris");
chunkorigin[0] = origin[0] + crandom() * size[0];
chunkorigin[1] = origin[1] + crandom() * size[1];
chunkorigin[2] = origin[2] + crandom() * size[2];
CGF_SFX_GlassThrowDebris (aGlassPane, "models/objects/debris2/tris.md2", 2, chunkorigin);
}
// clear velocity, reset origin (that has been abused in ThrowDebris)
VectorClear(aGlassPane->velocity);
VectorCopy (old_origin, aGlassPane->s.origin);
if (anAttacker)
{
// jumping thru
G_UseTargets (aGlassPane, anAttacker);
}
else
{
// firing thru - the pane has no direct attacker to hurt,
// but G_UseTargets expects one. So make it a DIY
G_UseTargets (aGlassPane, aGlassPane);
}
// have glass plane be visible for two more frames,
// and have it self-destruct then
// meanwhile, make sure the player can move thru
aGlassPane->solid = SOLID_NOT;
aGlassPane->think = CGF_SFX_HideBreakableGlass;
aGlassPane->nextthink = level.time + aPaneDestructDelay;
}
void CGF_SFX_EmitGlass (edict_t* aGlassPane, edict_t* anInflictor, vec3_t aPoint)
{
// based on func_explode, but with lotsa subtle differences
vec3_t old_origin;
vec3_t chunkorigin;
vec3_t size;
int count;
// bmodel origins are (0 0 0), we need to adjust that here
VectorCopy(aGlassPane->s.origin, old_origin);
VectorCopy (aPoint, aGlassPane->s.origin);
VectorSubtract (aGlassPane->s.origin, anInflictor->s.origin, aGlassPane->velocity);
VectorNormalize (aGlassPane->velocity);
// use speed 250 instead of 150 for funkier glass spray
VectorScale (aGlassPane->velocity, 250.0, aGlassPane->velocity);
// start chunks towards the center
VectorScale (aGlassPane->size, 0.25, size);
count = 4;
while(count--)
{
CGF_SFX_ApplyGlassFragmentLimit("debris");
chunkorigin[0] = aPoint[0] + crandom() * size[0];
chunkorigin[1] = aPoint[1] + crandom() * size[1];
chunkorigin[2] = aPoint[2] + crandom() * size[2];
CGF_SFX_GlassThrowDebris (aGlassPane, "models/objects/debris2/tris.md2", 2, chunkorigin);
}
// clear velocity, reset origin (that has been abused in ThrowDebris)
VectorClear(aGlassPane->velocity);
VectorCopy (old_origin, aGlassPane->s.origin);
// firing thru - the pane has no direct attacker to hurt,
// but G_UseTargets expects one. So make it a DIY
G_UseTargets (aGlassPane, aGlassPane);
}
void CGF_SFX_HideBreakableGlass(edict_t* aGlassPane)
{
// remove all attached decals
edict_t* decal;
decal = 0;
while (decal = G_Find(decal, FOFS(classname), "decal"))
{
if (decal->owner == aGlassPane)
{
// make it goaway in the next frame
decal->nextthink = level.time + FRAMETIME;
}
}
while (decal = G_Find(decal, FOFS(classname), "splat"))
{
if (decal->owner == aGlassPane)
{
// make it goaway in the next frame
decal->nextthink = level.time + FRAMETIME;
}
}
// after being broken, the pane cannot be freed as it is needed in
// subsequent missions/games, so hide it at about z = -1000 lower
aGlassPane->movetype = MOVETYPE_FLYMISSILE;
VectorCopy(aGlassPane->s.origin, aGlassPane->pos1);
aGlassPane->s.origin[2] -=1000.0;
}
void CGF_SFX_AttachDecalToGlass(edict_t* aGlassPane, edict_t* aDecal)
{
// just set aDecal's owner to be the glass pane
aDecal->owner = aGlassPane;
}
void CGF_SFX_RebuildAllBrokenGlass()
{
// iterate over all func_explosives
edict_t* glass;
glass = 0;
while (glass = G_Find(glass, FOFS(classname), "func_explosive"))
{
// glass is broken if solid != SOLID_BSP
if (glass->solid != SOLID_BSP)
{
CGF_SFX_InstallBreakableGlass(glass);
}
}
}
void CGF_SFX_ApplyGlassFragmentLimit(const char* aClassName)
{
edict_t* oldfragment;
glassfragmentcount++;
if (glassfragmentcount > glassfragmentlimit->value)
glassfragmentcount = 1;
// remove fragment with corresponding number if any
oldfragment = FindEdictByClassnum((char*) aClassName, glassfragmentcount);
if (oldfragment)
{
// oldfragment->nextthink = level.time + FRAMETIME;
G_FreeEdict(oldfragment);
}
}
void CGF_SFX_MiscGlassUse(edict_t *self, edict_t *other, edict_t *activator)
{
#ifdef _DEBUG
const char* classname;
classname = other->classname;
#endif
}
void CGF_SFX_MiscGlassDie(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
#ifdef _DEBUG
const char* classname;
classname = inflictor->classname;
#endif
}
static vec_t previous_throw_time = 0;
static int this_throw_count = 0;
void CGF_SFX_GlassThrowDebris (edict_t *self, char *modelname, float speed, vec3_t origin)
{
// based on ThrowDebris from id software - now returns debris created
edict_t *chunk;
vec3_t v;
if (level.time != previous_throw_time)
{
previous_throw_time = level.time;
this_throw_count = 0;
}
else
{
this_throw_count++;
if (this_throw_count > glassfragmentlimit->value)
return;
}
chunk = G_Spawn();
VectorCopy (origin, chunk->s.origin);
gi.setmodel (chunk, modelname);
v[0] = 100 * crandom();
v[1] = 100 * crandom();
v[2] = 100 + 100 * crandom();
VectorMA (self->velocity, speed, v, chunk->velocity);
chunk->movetype = MOVETYPE_BOUNCE;
chunk->solid = SOLID_NOT;
chunk->avelocity[0] = random()*600;
chunk->avelocity[1] = random()*600;
chunk->avelocity[2] = random()*600;
chunk->think = G_FreeEdict;
chunk->nextthink = level.time + 5 + random()*5;
chunk->s.frame = 0;
chunk->flags = 0;
chunk->classname = "debris";
chunk->takedamage = DAMAGE_YES;
chunk->die = debris_die;
gi.linkentity (chunk);
// number chunk
chunk->classnum = glassfragmentcount;
}

281
cgf_sfx_glass.h Normal file
View file

@ -0,0 +1,281 @@
/****************************************************************************/
/* */
/* project : CGF (c) 1999 William van der Sterren */
/* parts (c) 1998 id software */
/* */
/* file : cgf_sfx_glass.h "special effects for glass entities" */
/* author(s): William van der Sterren */
/* version : 0.5 */
/* */
/* date (last revision): Jun 12, 99 */
/* date (creation) : Jun 04, 99 */
/* */
/* */
/* revision history */
/* -- date ---- | -- revision ---------------------- | -- revisor -- */
/* Jun 12, 1999 | fixed knife slash breaks glass | William */
/* */
/******* http://www.botepidemic.com/aid/cgf for CGF for Action Quake2 *******/
#ifndef __CGF_SFX_GLASS_H_
#define __CGF_SFX_GLASS_H_
// defines (should be consistent with other weapon defs in g_local.h)
#define MOD_BREAKINGGLASS 46
/*
// forward definitions
typedef struct edict_s edict_t;
*/
// export a number of functions to g_func.c:
//
//
void CGF_SFX_InstallGlassSupport();
// registers cvar breakableglass (default 0)
// registers cvar glassfragmentlimit (default 30)
void CGF_SFX_RebuildAllBrokenGlass();
// upon starting a new team play game, reconstruct any
// broken glass because we like to break it again
int CGF_SFX_IsBreakableGlassEnabled();
// returns whether breakable glass is enabled (cvar breakableglass)
void CGF_SFX_TestBreakableGlassAndRemoveIfNot_Think(edict_t* aPossibleGlassEntity);
// initial think function for all func_explosives
// because we cannot verify the contents of the entity unless the entity
// has been spawned, we need to first introduce the entity, and remove
// it later (level.time == 0.1) if required
void CGF_SFX_ShootBreakableGlass(edict_t* aGlassPane,
edict_t* anAttacker,
/*trace_t*/ void* tr,
int mod
);
// shoot thru glass - depending on bullet types and
// random effects, glass just emits fragments, or breaks
void CGF_SFX_AttachDecalToGlass(edict_t* aGlassPane, edict_t* aDecal);
// a glass that breaks will remove all decals (blood splashes, bullet
// holes) if they are attached
#endif
/*
further documentation:
cgf_sfx_glass.cpp can be compiled with ordinary c compilers as
well - just change the extension from .cpp to .c
to install breakable glass in the ActionQuake2 1.51 code base,
do the following:
@ file a_game.h
+ modify
#define ACTION_VERSION "1.51"
to something that tells users breakable glass is supported
@ file a_team.c
+ add #include "cgf_sfx_glass.h"
+ in void CleanLevel()
add
CGF_SFX_RebuildAllBrokenGlass();
as the last statement (thus after CleanBodies();)
@ file g_misc.c
+ add #include "cgf_sfx_glass.h"
+ in void SP_func_explosive (edict_t *self)
disable the statements (put them within comments):
if (deathmatch->value)
{ // auto-remove for deathmatch
G_FreeEdict (self);
return;
}
+ in void SP_func_explosive (edict_t *self)
add
self->think = CGF_SFX_TestBreakableGlassAndRemoveIfNot_Think;
self->nextthink = level.time + FRAMETIME;
as the last statement (thus after gi.linkentity (self);)
@ file g_save.c
+ add #include "cgf_sfx_glass.h"
+ in void InitGame (void)
add
CGF_SFX_InstallGlassSupport();
under (splatlimit = gi.cvar ("splatlimit", "0", 0);)
@ file g_local.h
+ replace
void AddDecal (edict_t *self, vec3_t point, vec3_t direct);
void AddSplat (edict_t *self, vec3_t point, vec3_t direct);
by
void AddDecal (edict_t *self, trace_t* tr);
void AddSplat (edict_t *self, vec3_t point, trace_t* tr);
@ file a_game.c
+ add #include "cgf_sfx_glass.h"
+ replace
void AddDecal (edict_t *self, vec3_t point, vec3_t direct)
by
void AddDecal (edict_t *self, trace_t* tr)
+ replace
void AddSplat (edict_t *self, vec3_t point, vec3_t direct);
by
void AddSplat (edict_t *self, vec3_t point, trace_t* tr);
+ in void AddDecal (edict_t *self, trace_t* tr)
replace each occurrence of 'point' by tr->endpos
+ in void AddDecal (edict_t *self, trace_t* tr)
replace each occurrence of 'direct' by tr->plane.normal
+ in void AddDecal (edict_t *self, trace_t* tr)
add (as the last line, thus under gi.linkentity (decal);)
if ((tr->ent) && (0 == Q_stricmp("func_explosive", tr->ent->classname)))
{
CGF_SFX_AttachDecalToGlass(tr->ent, decal);
}
+ in void AddSplat (edict_t *self, vec3_t point, trace_t* tr)
replace each occurrence of 'direct' by tr->plane.normal
+ in void AddSplat (edict_t *self, vec3_t point, trace_t* tr)
add (as the last line, thus under gi.linkentity (decal);)
if ((tr->ent) && (0 == Q_stricmp("func_explosive", tr->ent->classname)))
{
CGF_SFX_AttachDecalToGlass(tr->ent, splat);
}
@ file g_weapon.c
+ add #include "cgf_sfx_glass.h"
+ in static void fire_lead (edict_t *self, ...)
replace
AddDecal (self, tr.endpos, tr.plane.normal);
by
AddDecal (self, &tr);
+ in void fire_lead_ap (edict_t *self, ...)
replace
AddDecal (self, tr.endpos, tr.plane.normal);
by
AddDecal (self, &tr);
+ in static void fire_lead (edict_t *self, ...)
add
between
tr = do_trace (start, NULL, NULL, end, self, content_mask);
and
// see if we hit water
the following
// catch case of firing thru one or breakable glasses
while ( (tr.fraction < 1.0)
&& (tr.surface->flags & (SURF_TRANS33 | SURF_TRANS66))
&& (tr.ent)
&& (0 == Q_stricmp(tr.ent->classname, "func_explosive"))
)
{
// break glass
CGF_SFX_ShootBreakableGlass(tr.ent, self, &tr, mod);
// continue trace from current endpos to start
tr = do_trace (tr.endpos, NULL, NULL, end, tr.ent, content_mask);
}
+ in static void fire_lead_ap (edict_t *self, ...)
add
between
tr = do_trace (start, NULL, NULL, end, self, content_mask);
and
// see if we hit water
the following
// catch case of firing thru one or breakable glasses
while ( (tr.fraction < 1.0)
&& (tr.surface->flags & (SURF_TRANS33 | SURF_TRANS66))
&& (tr.ent)
&& (0 == Q_stricmp(tr.ent->classname, "func_explosive"))
)
{
// break glass
CGF_SFX_ShootBreakableGlass(tr.ent, self, &tr, mod);
// continue trace from current endpos to start
tr = do_trace (tr.endpos, NULL, NULL, end, tr.ent, content_mask);
}
+ in void knife_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
replace
if (other->takedamage)
by
if (0 == Q_stricmp(other->classname, "func_explosive"))
{
// ignore it, so it can bounce
return;
}
else
if (other->takedamage)
+ in void kick_attack (edict_t * ent )
between
// zucc stop powerful upwards kicking
forward[2] = 0;
and
T_Damage (tr.ent, ent, ent, forward, tr.endpos, tr.plane.normal, damage, kick, 0, MOD_KICK );
add
if (0 == Q_stricmp(tr.ent->classname, "func_explosive"))
{
CGF_SFX_ShootBreakableGlass(tr.ent, ent, &tr, MOD_KICK);
}
+ in int knife_attack ( edict_t *self, vec3_t start, vec3_t aimdir, int damage, int kick)
replace
if (tr.ent->takedamage)
by
if (0 == Q_stricmp(tr.ent->classname, "func_explosive"))
{
CGF_SFX_ShootBreakableGlass(tr.ent, self, &tr, MOD_KNIFE);
}
else
if (tr.ent->takedamage)
@ file g_phys.c
+ add #include "cgf_sfx_glass.h"
+ in void SV_Physics_Toss (edict_t *ent)
replace
AddSplat (self, tr.endpos, tr.plane.normal);
by
AddSplat (self, &tr);
@ file g_combat.c
+ add #include "cgf_sfx_glass.h"
+ in void T_Damage (edict_t *targ, ...)
replace
if ( (mod == MOD_M3) || (mod == MOD_HC) || (mod == MOD_HELD_GRENADE) ||
(mod == MOD_HG_SPLASH) || (mod == MOD_G_SPLASH) )
by
if ( (mod == MOD_M3)
|| (mod == MOD_HC)
|| (mod == MOD_HELD_GRENADE)
|| (mod == MOD_HG_SPLASH)
|| (mod == MOD_G_SPLASH)
|| (mod == MOD_BREAKINGGLASS)
)
+ in void T_RadiusDamage (...)
add before if (CanDamage (ent, inflictor))
if (0 == Q_stricmp(ent->classname, "func_explosive"))
{
CGF_SFX_ShootBreakableGlass(ent, inflictor, 0, mod);
}
else
@ file p_client.c
+ add #include "cgf_sfx_glass.h"
+ in void ClientObituary (edict_t *self, edict_t *inflictor, edict_t *attacker)
between
switch (mod)
{
and
case MOD_SUICIDE:
add
case MOD_BREAKINGGLASS:
message = "ate too much glass";
break;
*/

View file

@ -19,7 +19,7 @@ int ChaseTargetGone(edict_t *ent)
{
ent->client->chase_target = NULL;
ent->client->desired_fov = 90;
ent->client->ps.fov = 90;
ent->client->ps.fov = 90;
ent->client->chase_mode = 0;
ent->client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
return 1;
@ -45,7 +45,7 @@ void UpdateChaseCam(edict_t *ent)
if (ent->client->chase_mode == 1)
{
ent->client->desired_fov = 90;
ent->client->ps.fov = 90;
ent->client->ps.fov = 90;
if (ent->client->resp.cmd_angles[PITCH] > 89)
ent->client->resp.cmd_angles[PITCH] = 89;
@ -69,7 +69,9 @@ void UpdateChaseCam(edict_t *ent)
if (!targ->groundentity)
o[2] += 16;
trace = do_trace(ownerv, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
PRETRACE();
trace = gi.trace(ownerv, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
POSTTRACE();
VectorCopy(trace.endpos, goal);
@ -78,7 +80,9 @@ void UpdateChaseCam(edict_t *ent)
// pad for floors and ceilings
VectorCopy(goal, o);
o[2] += 6;
trace = do_trace(goal, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
PRETRACE();
trace = gi.trace(goal, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
POSTTRACE();
if (trace.fraction < 1) {
VectorCopy(trace.endpos, goal);
goal[2] -= 6;
@ -86,7 +90,9 @@ void UpdateChaseCam(edict_t *ent)
VectorCopy(goal, o);
o[2] -= 6;
trace = do_trace(goal, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
PRETRACE();
trace = gi.trace(goal, vec3_origin, vec3_origin, o, targ, MASK_SOLID);
POSTTRACE();
if (trace.fraction < 1) {
VectorCopy(trace.endpos, goal);
goal[2] += 6;
@ -118,7 +124,7 @@ void UpdateChaseCam(edict_t *ent)
VectorCopy(o, ent->s.origin);
ent->client->ps.fov = targ->client->ps.fov;
ent->client->desired_fov = targ->client->ps.fov;
ent->client->desired_fov = targ->client->ps.fov;
for (i=0 ; i<3 ; i++)
ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(targ->client->v_angle[i] - ent->client->resp.cmd_angles[i]);
@ -131,8 +137,11 @@ void UpdateChaseCam(edict_t *ent)
}
else
{
VectorCopy(targ->client->v_angle, ent->client->ps.viewangles);
VectorCopy(targ->client->v_angle, ent->client->v_angle);
VectorAdd(targ->client->v_angle,
targ->client->ps.kick_angles,
angles);
VectorCopy(angles, ent->client->ps.viewangles);
VectorCopy(angles, ent->client->v_angle);
}
}
@ -157,6 +166,12 @@ void ChaseNext(edict_t *ent)
e = g_edicts + i;
if (!e->inuse)
continue;
//Black Cross - Begin
if (teamplay->value && limchasecam->value &&
ent->client->resp.team != NOTEAM &&
ent->client->resp.team != e->client->resp.team)
continue;
//Black Cross - End
if (e->solid != SOLID_NOT || e->deadflag == DEAD_DEAD)
break;
} while (e != ent->client->chase_target);
@ -180,6 +195,12 @@ void ChasePrev(edict_t *ent)
e = g_edicts + i;
if (!e->inuse)
continue;
//Black Cross - Begin
if (teamplay->value && limchasecam->value &&
ent->client->resp.team != NOTEAM &&
ent->client->resp.team != e->client->resp.team)
continue;
//Black Cross - End
if (e->solid != SOLID_NOT || e->deadflag == DEAD_DEAD)
break;
} while (e != ent->client->chase_target);
@ -194,30 +215,36 @@ void GetChaseTarget(edict_t *ent)
start_target = ent->client->resp.last_chase_target;
if (start_target == NULL)
{
start_target = g_edicts + 1;
}
else
{
if (start_target < (g_edicts + 1) ||
start_target > (g_edicts + game.maxclients))
{
gi.dprintf("Warning: start_target ended up out of range\n");
}
}
if (start_target == NULL)
{
start_target = g_edicts + 1;
}
else
{
if (start_target < (g_edicts + 1) ||
start_target > (g_edicts + game.maxclients))
{
gi.dprintf("Warning: start_target ended up out of range\n");
}
}
i = (start_target - g_edicts) + 1;
found = searched = 0;
do
{
searched++;
{
searched++;
i--;
if (i < 1)
i = game.maxclients;
e = g_edicts + i;
if (!e->inuse)
continue;
//Black Cross - Begin
if (teamplay->value && limchasecam->value &&
ent->client->resp.team != NOTEAM &&
ent->client->resp.team != e->client->resp.team)
continue;
//Black Cross - End
if (e->solid != SOLID_NOT || e->deadflag == DEAD_DEAD)
{
found = 1;
@ -225,14 +252,13 @@ void GetChaseTarget(edict_t *ent)
}
} while ((e != (start_target + 1)) && searched < 100);
if (searched >= 100)
{
gi.dprintf("Warning: prevented loop in GetChaseTarget\n");
}
if (searched >= 100)
{
gi.dprintf("Warning: prevented loop in GetChaseTarget\n");
}
if (found)
{
ent->client->chase_target = e;
}
}

139
g_cmds.c
View file

@ -33,6 +33,9 @@ qboolean OnSameTeam (edict_t *ent1, edict_t *ent2)
char ent2Team [512];
//FIREBLADE
if (!ent1->client || !ent2->client)
return false;
if (teamplay->value)
{
return ent1->client->resp.team == ent2->client->resp.team;
@ -165,11 +168,11 @@ void Cmd_Give_f (edict_t *ent)
return;
}
if (ent->solid == SOLID_NOT)
{
gi.cprintf(ent, PRINT_HIGH, "This command can't be used by spectators.\n");
return;
}
if (ent->solid == SOLID_NOT)
{
gi.cprintf(ent, PRINT_HIGH, "This command can't be used by spectators.\n");
return;
}
name = gi.args();
@ -334,9 +337,9 @@ void Cmd_Give_f (edict_t *ent)
/* if (gi.argc() == 5)
ent->client->pers.inventory[index] = atoi(gi.argv(4));
else if ( (gi.argc() == 4) && !(stricmp(it->pickup_name, "12 Gauge Shells")) )
ent->client->pers.inventory[index] = atoi(gi.argv(3));
else */
ent->client->pers.inventory[index] += it->quantity;
ent->client->pers.inventory[index] = atoi(gi.argv(3));
else */
ent->client->pers.inventory[index] += it->quantity;
}
else if ( it->flags & IT_ITEM)
{
@ -487,6 +490,33 @@ void Cmd_Use_f (edict_t *ent)
s = SNIPER_NAME;
if (!stricmp(s, "bfg10k"))
s = KNIFE_NAME;
// zucc - let people pull up a knife ready to be thrown
if (!stricmp(s, "throwing combat knife"))
{
if ( ent->client->curr_weap != KNIFE_NUM )
{
ent->client->resp.knife_mode = 1;
}
// switch to throwing mode if a knife is already out
else
{
Cmd_New_Weapon_f( ent );
}
s = KNIFE_NAME;
}
if (!stricmp(s, "slashing combat knife"))
{
if ( ent->client->curr_weap != KNIFE_NUM )
{
ent->client->resp.knife_mode = 0;
}
// switch to slashing mode if a knife is already out
else
{
Cmd_New_Weapon_f( ent );
}
s = KNIFE_NAME;
}
if (!stricmp(s, "grenade launcher"))
s = M4_NAME;
if (!stricmp(s, "grenades"))
@ -870,23 +900,33 @@ void Cmd_Players_f (edict_t *ent)
count = 0;
for (i = 0 ; i < maxclients->value ; i++)
{
if (game.clients[i].pers.connected)
{
index[count] = i;
count++;
}
}
// sort by frags
qsort (index, count, sizeof(index[0]), PlayerSort);
if (!teamplay->value || !noscore->value)
{
// sort by frags
qsort (index, count, sizeof(index[0]), PlayerSort);
}
// print information
large[0] = 0;
for (i = 0 ; i < count ; i++)
{
Com_sprintf (small, sizeof(small), "%3i %s\n",
game.clients[index[i]].ps.stats[STAT_FRAGS],
game.clients[index[i]].pers.netname);
if (!teamplay->value || !noscore->value)
Com_sprintf (small, sizeof(small), "%3i %s\n",
game.clients[index[i]].ps.stats[STAT_FRAGS],
game.clients[index[i]].pers.netname);
else
Com_sprintf (small, sizeof(small), "%s\n",
game.clients[index[i]].pers.netname);
if (strlen (small) + strlen(large) > sizeof(large) - 100 )
{ // can't print all of them in one packet
strcat (large, "...\n");
@ -956,11 +996,11 @@ Cmd_Say_f
*/
void Cmd_Say_f (edict_t *ent, qboolean team, qboolean arg0, qboolean partner_msg)
{
int j, i;
int j, i, offset_of_text;
edict_t *other;
char *p;
char text[2048];
gclient_t *cl;
gclient_t *cl;
if (gi.argc () < 2 && !arg0)
return;
@ -974,18 +1014,36 @@ void Cmd_Say_f (edict_t *ent, qboolean team, qboolean arg0, qboolean partner_msg
}
if (team)
{
if (ent->client->resp.team == NOTEAM)
{
gi.cprintf(ent, PRINT_HIGH, "You're not on a team.\n");
return;
}
Com_sprintf (text, sizeof(text), "%s(%s): ",
(teamplay->value && ent->solid == SOLID_NOT) ? "[DEAD] " : "",
(teamplay->value && (ent->solid == SOLID_NOT || ent->deadflag == DEAD_DEAD)) ? "[DEAD] " : "",
ent->client->pers.netname);
}
else if (partner_msg)
{
if (ent->client->resp.radio_partner == NULL)
{
gi.cprintf(ent, PRINT_HIGH, "You don't have a partner.\n");
return;
}
Com_sprintf (text, sizeof(text), "[%sPARTNER] %s: ",
(ent->solid == SOLID_NOT) ? "DEAD " : "",
(teamplay->value && (ent->solid == SOLID_NOT || ent->deadflag == DEAD_DEAD)) ? "DEAD " : "",
ent->client->pers.netname);
}
else
{
Com_sprintf (text, sizeof(text), "%s%s: ",
(teamplay->value && ent->solid == SOLID_NOT) ? "[DEAD] " : "",
(teamplay->value && (ent->solid == SOLID_NOT || ent->deadflag == DEAD_DEAD)) ? "[DEAD] " : "",
ent->client->pers.netname);
}
offset_of_text = strlen(text); //FB 5/31/99
if (arg0)
{
strcat (text, gi.argv(0));
@ -1009,10 +1067,11 @@ void Cmd_Say_f (edict_t *ent, qboolean team, qboolean arg0, qboolean partner_msg
if (strlen(text) > 300)
text[300] = 0;
if (ent->solid != SOLID_NOT && ent->deadflag != DEAD_DEAD)
ParseSayText(ent, text);
// this will parse the % variables,
// and again check 300 limit afterwards -FB
if (ent->solid != SOLID_NOT && ent->deadflag != DEAD_DEAD)
ParseSayText(ent, text + offset_of_text); //FB 5/31/99 - offset change
// this will parse the % variables,
// and again check 300 limit afterwards -FB
// (although it checks it without the name in front, oh well)
strcat(text, "\n");
@ -1065,7 +1124,8 @@ void Cmd_Say_f (edict_t *ent, qboolean team, qboolean arg0, qboolean partner_msg
//FIREBLADE
if (teamplay->value && team_round_going)
{
if (ent->solid == SOLID_NOT && other->solid != SOLID_NOT)
if ((ent->solid == SOLID_NOT || ent->deadflag == DEAD_DEAD) &&
(other->solid != SOLID_NOT && other->deadflag != DEAD_DEAD))
continue;
}
//FIREBLADE
@ -1077,7 +1137,7 @@ void Cmd_PlayerList_f(edict_t *ent)
{
int i;
char st[80];
char text[1400];
char text[1280];
edict_t *e2;
// connect time, ping, score, name
@ -1086,15 +1146,24 @@ void Cmd_PlayerList_f(edict_t *ent)
if (!e2->inuse)
continue;
Com_sprintf(st, sizeof(st), "%02d:%02d %4d %3d %s%s\n",
(level.framenum - e2->client->resp.enterframe) / 600,
((level.framenum - e2->client->resp.enterframe) % 600)/10,
e2->client->ping,
e2->client->resp.score,
e2->client->pers.netname,
(e2->solid == SOLID_NOT && e2->deadflag != DEAD_DEAD) ? " (spectator)" : "");
if (strlen(text) + strlen(st) > sizeof(text) - 50) {
sprintf(text+strlen(text), "...and more.\n");
if (!teamplay->value || !noscore->value)
Com_sprintf(st, sizeof(st), "%02d:%02d %4d %3d %s%s\n",
(level.framenum - e2->client->resp.enterframe) / 600,
((level.framenum - e2->client->resp.enterframe) % 600)/10,
e2->client->ping,
e2->client->resp.score,
e2->client->pers.netname,
(e2->solid == SOLID_NOT && e2->deadflag != DEAD_DEAD) ? " (spectator)" : "");
else
Com_sprintf(st, sizeof(st), "%02d:%02d %4d %s%s\n",
(level.framenum - e2->client->resp.enterframe) / 600,
((level.framenum - e2->client->resp.enterframe) % 600)/10,
e2->client->ping,
e2->client->pers.netname,
(e2->solid == SOLID_NOT && e2->deadflag != DEAD_DEAD) ? " (spectator)" : "");
if (strlen(text) + strlen(st) > sizeof(text) - 100) {
sprintf(text+strlen(text), "...\n");
gi.cprintf(ent, PRINT_HIGH, "%s", text);
return;
}
@ -1193,9 +1262,9 @@ void ClientCommand (edict_t *ent)
// else if (Q_stricmp (cmd, "laser") == 0)
// SP_LaserSight (ent);
else if (Q_stricmp (cmd, "reload") == 0)
Cmd_Reload_f (ent);
Cmd_New_Reload_f (ent);
else if (Q_stricmp (cmd, "weapon") == 0)
Cmd_Weapon_f (ent);
Cmd_New_Weapon_f (ent);
else if (Q_stricmp (cmd, "opendoor") == 0)
Cmd_OpenDoor_f (ent);
else if (Q_stricmp (cmd, "bandage") == 0)

2057
g_combat.c

File diff suppressed because it is too large Load diff

View file

@ -235,40 +235,40 @@ void Drop_Special( edict_t *ent, gitem_t *item)
}
*/
if ( stricmp( item->pickup_name, BAND_NAME ) == 0
&& ent->client->pers.inventory[ITEM_INDEX(item)] <= 1 )
&& ent->client->pers.inventory[ITEM_INDEX(item)] <= 1 )
{
ent->client->pers.max_bullets = 2;
if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("Pistol Clip"))] > 2 )
ent->client->pers.inventory[ITEM_INDEX(FindItem("Pistol Clip"))] = 2;
ent->client->pers.max_shells = 14;
if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("12 Gauge Shells"))] > 14 )
ent->client->pers.inventory[ITEM_INDEX(FindItem("12 Gauge Shells"))] = 14;
ent->client->pers.max_cells = 1;
if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("M4 Clip"))] > 1 )
ent->client->pers.inventory[ITEM_INDEX(FindItem("M4 Clip"))] = 1;
ent->client->pers.max_grenades = 2;
if ( ent->client->pers.inventory[ITEM_INDEX(FindItem(GRENADE_NAME))] > 2 )
ent->client->pers.inventory[ITEM_INDEX(FindItem(GRENADE_NAME))] = 2;
ent->client->pers.max_rockets = 2;
if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("Machinegun Magazine"))] > 2 )
ent->client->pers.inventory[ITEM_INDEX(FindItem("Machinegun Magazine"))] = 2;
ent->client->knife_max = 10;
if ( ent->client->pers.inventory[ITEM_INDEX(FindItem(KNIFE_NAME))] > 10 )
ent->client->pers.inventory[ITEM_INDEX(FindItem(KNIFE_NAME))] = 10;
ent->client->pers.max_slugs = 20;
if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("AP Sniper Ammo"))] > 20 )
ent->client->pers.inventory[ITEM_INDEX(FindItem("AP Sniper Ammo"))] = 20;
if ( ent->client->unique_weapon_total > unique_weapons->value && !allweapon->value )
{
DropExtraSpecial(ent);
gi.cprintf(ent, PRINT_HIGH, "One of your guns is dropped with the bandolier.\n");
}
}
ent->client->pers.max_bullets = 2;
if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("Pistol Clip"))] > 2 )
ent->client->pers.inventory[ITEM_INDEX(FindItem("Pistol Clip"))] = 2;
ent->client->pers.max_shells = 14;
if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("12 Gauge Shells"))] > 14 )
ent->client->pers.inventory[ITEM_INDEX(FindItem("12 Gauge Shells"))] = 14;
ent->client->pers.max_cells = 1;
if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("M4 Clip"))] > 1 )
ent->client->pers.inventory[ITEM_INDEX(FindItem("M4 Clip"))] = 1;
ent->client->grenade_max = 2;
if ( ent->client->pers.inventory[ITEM_INDEX(FindItem(GRENADE_NAME))] > 2 )
ent->client->pers.inventory[ITEM_INDEX(FindItem(GRENADE_NAME))] = 2;
ent->client->pers.max_rockets = 2;
if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("Machinegun Magazine"))] > 2 )
ent->client->pers.inventory[ITEM_INDEX(FindItem("Machinegun Magazine"))] = 2;
ent->client->knife_max = 10;
if ( ent->client->pers.inventory[ITEM_INDEX(FindItem(KNIFE_NAME))] > 10 )
ent->client->pers.inventory[ITEM_INDEX(FindItem(KNIFE_NAME))] = 10;
ent->client->pers.max_slugs = 20;
if ( ent->client->pers.inventory[ITEM_INDEX(FindItem("AP Sniper Ammo"))] > 20 )
ent->client->pers.inventory[ITEM_INDEX(FindItem("AP Sniper Ammo"))] = 20;
if ( ent->client->unique_weapon_total > unique_weapons->value && !allweapon->value )
{
DropExtraSpecial(ent);
gi.cprintf(ent, PRINT_HIGH, "One of your guns is dropped with the bandolier.\n");
}
}
Drop_Spec (ent, item);
ValidateSelectedItem (ent);
SP_LaserSight(ent, item);
@ -985,8 +985,10 @@ edict_t *Drop_Item (edict_t *ent, gitem_t *item)
AngleVectors (ent->client->v_angle, forward, right, NULL);
VectorSet(offset, 24, 0, -16);
G_ProjectSource (ent->s.origin, offset, forward, right, dropped->s.origin);
trace = do_trace (ent->s.origin, dropped->mins, dropped->maxs,
PRETRACE();
trace = gi.trace (ent->s.origin, dropped->mins, dropped->maxs,
dropped->s.origin, ent, CONTENTS_SOLID);
POSTTRACE();
VectorCopy (trace.endpos, dropped->s.origin);
}
else
@ -1065,7 +1067,9 @@ void droptofloor (edict_t *ent)
v = tv(0,0,-128);
VectorAdd (ent->s.origin, v, dest);
tr = do_trace (ent->s.origin, ent->mins, ent->maxs, dest, ent, MASK_SOLID);
PRETRACE();
tr = gi.trace (ent->s.origin, ent->mins, ent->maxs, dest, ent, MASK_SOLID);
POSTTRACE();
if (tr.startsolid)
{
gi.dprintf ("droptofloor: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin));

View file

@ -519,15 +519,21 @@ extern cvar_t *deathmatch;
extern cvar_t *coop;
extern cvar_t *dmflags;
//FIREBLADE
extern cvar_t *needpass;
extern cvar_t *hostname;
extern cvar_t *teamplay;
extern cvar_t *radiolog;
extern cvar_t *motd_time;
extern cvar_t *actionmaps;
extern cvar_t *roundtimelimit;
extern cvar_t *maxteamkills;
extern cvar_t *tkbanrounds;
extern cvar_t *twbanrounds;
extern cvar_t *limchasecam;
extern cvar_t *roundlimit;
extern cvar_t *nohud;
extern cvar_t *noscore;
extern cvar_t *skipmotd;
extern cvar_t *nohud;
extern cvar_t *noscore;
extern cvar_t *actionversion;
//FIREBLADE
extern cvar_t *skill;
@ -893,6 +899,7 @@ typedef struct
//FIREBLADE
qboolean spectator;
int firing_style;
//FIREBLADE
} client_persistant_t;
@ -905,15 +912,9 @@ typedef struct
vec3_t cmd_angles; // angles sent over in the last command
int game_helpchanged;
int helpchanged;
int mk23_mode; // firing mode, semi or auto
int sniper_mode; //level of zoom
int mp5_mode;
int m4_mode;
int knife_mode;
int grenade_mode;
int id; // id command on or off
int ir; // ir on or off (only matters if player has ir device, currently bandolier)
int kills; // real kills
int damage_dealt; // keep track of damage dealt by player to other players
int streak; // kills in a row
gitem_t *item; // item for teamplay
gitem_t *weapon; // weapon for teamplay
@ -926,9 +927,6 @@ typedef struct
radio_queue_entry_t radio_queue[MAX_RADIO_QUEUE_SIZE];
int radio_queue_size;
edict_t *radio_partner; // current partner
qboolean radio_partner_mode; // 'radio' command using team or partner
qboolean radio_gender; // radiogender
qboolean radio_power_off; // radio_power
edict_t *partner_last_offered_to; // last person I offered a partnership to
edict_t *partner_last_offered_from; // last person I received a partnership offer from
edict_t *partner_last_denied_from; // last person I denied a partnership offer from
@ -938,6 +936,18 @@ typedef struct
int last_motd_refresh;
edict_t *last_chase_target; // last person they chased, to resume at the same place later...
//FIREBLADE
//Action
int mk23_mode; // firing mode, semi or auto
int mp5_mode;
int m4_mode;
int knife_mode;
int grenade_mode;
int id; // id command on or off
int ir; // ir on or off (only matters if player has ir device, currently bandolier)
qboolean radio_partner_mode; // 'radio' command using team or partner
qboolean radio_gender; // radiogender
qboolean radio_power_off; // radio_power
//---
} client_respawn_t;
// this structure is cleared on each PutClientInServer(),
@ -1080,13 +1090,17 @@ struct gclient_s
int doortoggle; // set by player with opendoor command
edict_t* attacker; // keep track of the last person to hit us
edict_t* attacker; // keep track of the last person to hit us
int attacker_mod; // and how they hit us
int attacker_loc; // location of the hit
int push_timeout; // timeout for how long an attacker will get fall death credit
int push_timeout; // timeout for how long an attacker will get fall death credit
int jumping;
int reload_attempts;
int weapon_attempts;
//FIREBLADE
qboolean inmenu; // in menu
@ -1095,6 +1109,22 @@ struct gclient_s
qboolean update_chase;
int chase_mode;
//FIREBLADE
//AZEROV
// Number of team kills this game
int team_kills;
//AZEROV
//EEK
// Number of teammate woundings this game and a "before attack" tracker
int team_wounds;
int team_wounds_before;
int ff_warning;
// IP address of this host to be collected at Connection time.
// (getting at it later seems to be unreliable)
char ipaddr[100]; // changed to 100 -FB
//EEK
};
@ -1260,6 +1290,8 @@ struct edict_s
void LaserSightThink (edict_t *self);
void SP_LaserSight(edict_t *self, gitem_t *item );
void Cmd_Reload_f (edict_t *ent);
void Cmd_New_Reload_f (edict_t *ent);
void Cmd_New_Weapon_f (edict_t *ent);
void Cmd_Weapon_f ( edict_t *ent );
void Cmd_OpenDoor_f (edict_t *ent );
void Cmd_Bandage_f ( edict_t *ent );
@ -1309,8 +1341,8 @@ edict_t *FindEdictByClassnum (char *classname, int classnum);
void EjectBlooder (edict_t *self, vec3_t start, vec3_t veloc );
void EjectShell (edict_t *self, vec3_t start, int toggle);
void AddSplat (edict_t *self, vec3_t point, vec3_t direct);
void AddDecal (edict_t *self, vec3_t point, vec3_t direct);
void AddDecal (edict_t *self, trace_t* tr);
void AddSplat (edict_t *self, vec3_t point, trace_t* tr);
// weapon names
/*
bind 2 "use M3 Super 90 Assault Shotgun;"
@ -1366,6 +1398,8 @@ bind 6 "use Sniper Rifle"
#define GRENADE_IDLE_FIRST 40
#define GRENADE_IDLE_LAST 69
#define GRENADE_THROW_FIRST 4
#define GRENADE_THROW_LAST 9 // throw it on frame 8?
// these should be server variables, when I get around to it

View file

@ -23,10 +23,16 @@ cvar_t *radiolog;
cvar_t *motd_time;
cvar_t *actionmaps;
cvar_t *roundtimelimit;
cvar_t *maxteamkills;
cvar_t *twbanrounds;
cvar_t *tkbanrounds;
cvar_t *limchasecam;
cvar_t *roundlimit;
cvar_t *nohud;
cvar_t *noscore;
cvar_t *skipmotd;
cvar_t *nohud;
cvar_t *noscore;
cvar_t *actionversion;
cvar_t *needpass;
//FIREBLADE
cvar_t *deathmatch;
cvar_t *coop;
@ -85,6 +91,7 @@ void ClientUserinfoChanged (edict_t *ent, char *userinfo);
void ClientDisconnect (edict_t *ent);
void ClientBegin (edict_t *ent);
void ClientCommand (edict_t *ent);
void CheckNeedPass (void);
void RunEntity (edict_t *ent);
void WriteGame (char *filename, qboolean autosave);
void ReadGame (char *filename);
@ -204,6 +211,11 @@ EndDMLevel
The timelimit or fraglimit has been exceeded
=================
*/
//AZEROV
extern void UnBan_TeamKillers (void);
//AZEROV
void EndDMLevel (void)
{
edict_t *ent;
@ -257,7 +269,12 @@ void EndDMLevel (void)
}
//FIREBLADE
ReadMOTDFile();
BeginIntermission (ent);
//AZEROV
UnBan_TeamKillers ();
//AZEROV
}
/*
@ -413,7 +430,41 @@ void G_RunFrame (void)
// see if it is time to end a deathmatch
CheckDMRules ();
//FIREBLADE
CheckNeedPass();
//FIREBLADE
// build the playerstate_t structures for all players
ClientEndServerFrames ();
}
//ADDED FROM 3.20 SOURCE -FB
//Commented out spectator_password stuff since we don't have that now.
/*
=================
CheckNeedPass
=================
*/
void CheckNeedPass (void)
{
int need;
// if password or spectator_password has changed, update needpass
// as needed
if (password->modified /*|| spectator_password->modified*/)
{
password->modified = /*spectator_password->modified = */ false;
need = 0;
if (*password->string && Q_stricmp(password->string, "none"))
need |= 1;
/*
if (*spectator_password->string && Q_stricmp(spectator_password->string, "none"))
need |= 2;
*/
gi.cvar_set("needpass", va("%d", need));
}
}
//FROM 3.20 END

View file

@ -1,7 +1,7 @@
// g_misc.c
#include "g_local.h"
#include "cgf_sfx_glass.h"
/*QUAKED func_group (0 0 0) ?
Used to group brushes together just for editor convenience.
@ -797,11 +797,13 @@ void func_explosive_spawn (edict_t *self, edict_t *other, edict_t *activator)
void SP_func_explosive (edict_t *self)
{
/* removed for glass fx
if (deathmatch->value)
{ // auto-remove for deathmatch
G_FreeEdict (self);
return;
}
*/
self->movetype = MOVETYPE_PUSH;
@ -837,6 +839,8 @@ void SP_func_explosive (edict_t *self)
}
gi.linkentity (self);
self->think = CGF_SFX_TestBreakableGlassAndRemoveIfNot_Think;
self->nextthink = level.time + FRAMETIME;
}

View file

@ -1,6 +1,7 @@
// g_phys.c
#include "g_local.h"
#include "cgf_sfx_glass.h"
/*
@ -36,7 +37,9 @@ edict_t *SV_TestEntityPosition (edict_t *ent)
mask = ent->clipmask;
else
mask = MASK_SOLID;
trace = do_trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, ent, mask);
PRETRACE();
trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, ent, mask);
POSTTRACE();
if (trace.startsolid)
return g_edicts;
@ -191,7 +194,9 @@ int SV_FlyMove (edict_t *ent, float time, int mask)
for (i=0 ; i<3 ; i++)
end[i] = ent->s.origin[i] + time_left * ent->velocity[i];
trace = do_trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask);
PRETRACE();
trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask);
POSTTRACE();
if (trace.allsolid)
{ // entity is trapped in another solid
@ -336,7 +341,9 @@ retry:
else
mask = MASK_SOLID;
trace = do_trace (start, ent->mins, ent->maxs, end, ent, mask);
PRETRACE();
trace = gi.trace (start, ent->mins, ent->maxs, end, ent, mask);
POSTTRACE();
VectorCopy (trace.endpos, ent->s.origin);
gi.linkentity (ent);
@ -824,7 +831,7 @@ void SV_Physics_Toss (edict_t *ent)
{
if (!ent->splatted)
{
AddSplat (ent->owner, ent->s.origin, trace.plane.normal);
AddSplat (ent->owner, ent->s.origin, &trace);
ent->splatted = true;
}

View file

@ -1,5 +1,5 @@
#include "g_local.h"
#include "cgf_sfx_glass.h"
field_t fields[] = {
{"classname", FOFS(classname), F_LSTRING},
@ -156,6 +156,19 @@ void InitGame (void)
skill = gi.cvar ("skill", "1", CVAR_LATCH);
maxentities = gi.cvar ("maxentities", "1024", CVAR_LATCH);
//FIREBLADE
if (!deathmatch->value)
{
gi.dprintf("Turning deathmatch on.\n");
gi.cvar_set("deathmatch", "1");
}
if (coop->value)
{
gi.dprintf("Turning coop off.\n");
gi.cvar_set("coop", "0");
}
//FIREBLADE
// change anytime vars
dmflags = gi.cvar ("dmflags", "0", CVAR_SERVERINFO);
fraglimit = gi.cvar ("fraglimit", "0", CVAR_SERVERINFO);
@ -163,20 +176,26 @@ void InitGame (void)
password = gi.cvar ("password", "", CVAR_USERINFO);
filterban = gi.cvar("filterban", "1", 0);
//FIREBLADE
radiolog = gi.cvar("radiolog", "0", CVAR_SERVERINFO);
needpass = gi.cvar("needpass", "0", CVAR_SERVERINFO);
radiolog = gi.cvar("radiolog", "0", 0);
teamplay = gi.cvar ("teamplay", "0", CVAR_SERVERINFO|CVAR_LATCH);
motd_time = gi.cvar("motd_time", "2", CVAR_SERVERINFO);
motd_time = gi.cvar("motd_time", "2", 0);
hostname = gi.cvar("hostname", "unnamed", CVAR_SERVERINFO);
actionmaps = gi.cvar ("actionmaps", "1", CVAR_SERVERINFO);
actionmaps = gi.cvar ("actionmaps", "1", 0);
if (actionmaps->value && num_maps < 1)
{
gi.dprintf("No maps were read from the config file, \"actionmaps\" won't be used.\n");
gi.cvar_set("actionmaps", "0");
}
nohud = gi.cvar("nohud", "0", CVAR_SERVERINFO|CVAR_LATCH);
nohud = gi.cvar("nohud", "0", CVAR_LATCH);
roundlimit = gi.cvar("roundlimit", "0", CVAR_SERVERINFO);
limchasecam = gi.cvar("limchasecam", "0", CVAR_SERVERINFO|CVAR_LATCH);
skipmotd = gi.cvar("skipmotd", "0", 0);
roundtimelimit = gi.cvar("roundtimelimit", "0", CVAR_SERVERINFO);
noscore = gi.cvar("noscore", "0", CVAR_SERVERINFO|CVAR_LATCH);
maxteamkills = gi.cvar("maxteamkills", "0", 0);
twbanrounds = gi.cvar("twbanrounds", "2", 0);
tkbanrounds = gi.cvar("tkbanrounds", "2", 0);
noscore = gi.cvar("noscore", "0", CVAR_SERVERINFO|CVAR_LATCH);
actionversion = gi.cvar("actionversion", "none set", CVAR_SERVERINFO|CVAR_LATCH);
gi.cvar_set("actionversion", ACTION_VERSION);
//FIREBLADE
@ -190,15 +209,19 @@ void InitGame (void)
unique_items = gi.cvar("items", "1", CVAR_SERVERINFO|CVAR_LATCH);
// zucc changed ir to 1, enabled
ir = gi.cvar("ir", "1", CVAR_SERVERINFO);
knifelimit = gi.cvar ("knifelimit", "40", CVAR_SERVERINFO);
ir = gi.cvar("ir", "1", CVAR_SERVERINFO);
knifelimit = gi.cvar ("knifelimit", "40", 0);
allweapon = gi.cvar ("allweapon", "0", CVAR_SERVERINFO);
allitem = gi.cvar ("allitem", "0", CVAR_SERVERINFO);
tgren = gi.cvar ("tgren", "0", CVAR_SERVERINFO);
// zucc from action
sv_shelloff = gi.cvar ("shelloff", "1", CVAR_SERVERINFO);
bholelimit = gi.cvar ("bholelimit", "0", CVAR_SERVERINFO);
splatlimit = gi.cvar ("splatlimit", "0", CVAR_SERVERINFO);
tgren = gi.cvar ("tgren", "0", CVAR_SERVERINFO);
// zucc from action
sv_shelloff = gi.cvar ("shelloff", "1", 0);
bholelimit = gi.cvar ("bholelimit", "0", 0);
splatlimit = gi.cvar ("splatlimit", "0", 0);
// william for CGF (glass fx)
CGF_SFX_InstallGlassSupport();
g_select_empty = gi.cvar ("g_select_empty", "0", CVAR_ARCHIVE);

View file

@ -315,7 +315,7 @@ void ED_CallSpawn (edict_t *ent)
//item[i][0] = the Q2 item to look for
//item[i][1] = the NS2 item to actually spawn
#define ITEM_SWITCH_COUNT 12
#define ITEM_SWITCH_COUNT 15
char *sp_item[ITEM_SWITCH_COUNT][2]=
{
@ -333,6 +333,10 @@ char *sp_item[ITEM_SWITCH_COUNT][2]=
{"ammo_slugs", "ammo_sniper"},
{"ammo_shells", "ammo_m3"},
{"ammo_grenades", "weapon_Grenade"}
,
{"ammo_box", "ammo_m3"},
{"weapon_cannon", "weapon_HC"},
{"weapon_sniper", "weapon_Sniper"}
};
@ -346,7 +350,7 @@ void CheckItem(edict_t *ent, gitem_t *item)
if(!sp_item[i][0])
continue;
//Do the passed ent and our list match?
if(Q_stricmp(ent->classname,sp_item[i][0])==0)
if(strcmp(ent->classname,sp_item[i][0])==0)
{
//Yep. Replace the Q2 entity with our own.
ent->classname = item->classname = sp_item[i][1];
@ -1139,30 +1143,30 @@ void SP_worldspawn (edict_t *ent)
gi.configstring (CS_MAXCLIENTS, va("%i", (int)(maxclients->value) ) );
//FIREBLADE
if (nohud->value)
{
gi.configstring(CS_STATUSBAR, "");
}
else
if (nohud->value)
{
gi.configstring(CS_STATUSBAR, "");
}
else
//FIREBLADE
{
// status bar program
if (deathmatch->value)
{
// status bar program
if (deathmatch->value)
//FIREBLADE
{
if (noscore->value && teamplay->value)
{
gi.configstring (CS_STATUSBAR, dm_noscore_statusbar);
}
else
{
gi.configstring (CS_STATUSBAR, dm_statusbar);
}
}
{
if (noscore->value && teamplay->value)
{
gi.configstring (CS_STATUSBAR, dm_noscore_statusbar);
}
else
{
gi.configstring (CS_STATUSBAR, dm_statusbar);
}
}
//FIREBLADE
else
gi.configstring (CS_STATUSBAR, single_statusbar);
}
else
gi.configstring (CS_STATUSBAR, single_statusbar);
}
//---------------
@ -1334,5 +1338,11 @@ void SP_worldspawn (edict_t *ent)
// 63 testing
gi.configstring(CS_LIGHTS+63, "a");
//FB 6/2/99
if (took_damage != NULL)
gi.TagFree(took_damage);
took_damage = (int *)gi.TagMalloc(sizeof(int) * game.maxclients, TAG_GAME);
//FB 6/2/99
}

View file

@ -1,10 +1,9 @@
#include "g_local.h"
void Svcmd_Test_f (void)
void SVCmd_ReloadMOTD_f()
{
gi.cprintf (NULL, PRINT_HIGH, "Svcmd_Test_f()\n");
ReadMOTDFile();
gi.cprintf(NULL, PRINT_HIGH, "MOTD reloaded.\n");
}
/*
@ -42,6 +41,10 @@ typedef struct
{
unsigned mask;
unsigned compare;
//AZEROV
int temp_ban_games;
//AZEROV
} ipfilter_t;
#define MAX_IPFILTERS 1024
@ -54,7 +57,7 @@ int numipfilters;
StringToFilter
=================
*/
static qboolean StringToFilter (char *s, ipfilter_t *f)
static qboolean StringToFilter (char *s, ipfilter_t *f, int temp_ban_games)
{
char num[128];
int i, j;
@ -93,6 +96,8 @@ static qboolean StringToFilter (char *s, ipfilter_t *f)
f->mask = *(unsigned *)m;
f->compare = *(unsigned *)b;
f->temp_ban_games = temp_ban_games;
return true;
}
@ -158,7 +163,7 @@ void SVCmd_AddIP_f (void)
numipfilters++;
}
if (!StringToFilter (gi.argv(2), &ipfilters[i]))
if (!StringToFilter (gi.argv(2), &ipfilters[i], 0))
ipfilters[i].compare = 0xffffffff;
}
@ -177,7 +182,7 @@ void SVCmd_RemoveIP_f (void)
return;
}
if (!StringToFilter (gi.argv(2), &f))
if (!StringToFilter (gi.argv(2), &f, 0))
return;
for (i=0 ; i<numipfilters ; i++)
@ -203,12 +208,19 @@ void SVCmd_ListIP_f (void)
int i;
byte b[4];
gi.cprintf (NULL, PRINT_HIGH, "Filter list:\n");
gi.cprintf (NULL, PRINT_HIGH, "Filter list:\n");
for (i=0 ; i<numipfilters ; i++)
{
*(unsigned *)b = ipfilters[i].compare;
gi.cprintf (NULL, PRINT_HIGH, "%3i.%3i.%3i.%3i\n", b[0], b[1], b[2], b[3]);
}
*(unsigned *)b = ipfilters[i].compare;
if (!ipfilters[i].temp_ban_games)
{
gi.cprintf (NULL, PRINT_HIGH, "%3i.%3i.%3i.%3i\n", b[0], b[1], b[2], b[3]);
}
else
{
gi.cprintf (NULL, PRINT_HIGH, "%3i.%3i.%3i.%3i (%d more game(s))\n", b[0], b[1], b[2], b[3], ipfilters[i].temp_ban_games);
}
}
}
/*
@ -244,13 +256,38 @@ void SVCmd_WriteIP_f (void)
for (i=0 ; i<numipfilters ; i++)
{
*(unsigned *)b = ipfilters[i].compare;
fprintf (f, "sv addip %i.%i.%i.%i\n", b[0], b[1], b[2], b[3]);
if (!ipfilters[i].temp_ban_games)
{
*(unsigned *)b = ipfilters[i].compare;
fprintf (f, "sv addip %i.%i.%i.%i\n", b[0], b[1], b[2], b[3]);
}
}
fclose (f);
}
// zucc so it works under vc++
void ExitLevel (void);
//Black Cross - Begin
/*
=================
SV_Nextmap_f
=================
*/
void SVCmd_Nextmap_f (char *arg)
{
// end level and go to next map in map rotation
gi.bprintf(PRINT_HIGH, "Changing to next map in rotation.\n");
EndDMLevel ();
if (arg != NULL && Q_stricmp(arg, "force") == 0)
ExitLevel ();
return;
}
//Black Cross - End
/*
=================
ServerCommand
@ -265,9 +302,8 @@ void ServerCommand (void)
char *cmd;
cmd = gi.argv(1);
if (Q_stricmp (cmd, "test") == 0)
Svcmd_Test_f ();
else if (Q_stricmp (cmd, "addip") == 0)
if (Q_stricmp (cmd, "addip") == 0)
SVCmd_AddIP_f ();
else if (Q_stricmp (cmd, "removeip") == 0)
SVCmd_RemoveIP_f ();
@ -275,7 +311,111 @@ void ServerCommand (void)
SVCmd_ListIP_f ();
else if (Q_stricmp (cmd, "writeip") == 0)
SVCmd_WriteIP_f ();
else if (Q_stricmp (cmd, "nextmap") == 0)
SVCmd_Nextmap_f (gi.argv(2)); // Added by Black Cross
else if (Q_stricmp (cmd, "reloadmotd") == 0)
SVCmd_ReloadMOTD_f();
else
gi.cprintf (NULL, PRINT_HIGH, "Unknown server command \"%s\"\n", cmd);
}
/*
==========================
Kick a client entity
==========================
*/
void Kick_Client (edict_t *ent)
{
int i = 0;
char ban_string[256];
edict_t *entL;
if (!ent->client)
{
return;
}
// We used to kick on names, but people got crafty and figured
// out that putting in a space after their name let them get
// around the stupid 'kick' function. So now we kick by number.
for (i=0 ; i<game.maxclients ; i++)
{
entL = &g_edicts[1+i];
if (!entL || !entL->inuse)
continue;
if (entL->client && ent == entL)
{
sprintf (ban_string, "kick %d\n", i);
gi.AddCommandString (ban_string);
}
}
}
/*
==========================
Ban a client for N rounds
==========================
*/
qboolean Ban_TeamKiller ( edict_t *ent, int rounds )
{
int i = 0;
if (!ent || !ent->client || !ent->client->ipaddr)
{
gi.cprintf (NULL, PRINT_HIGH, "Unable to determine client->ipaddr for edict\n");
return false;
}
for (i=0 ; i<numipfilters ; i++)
{
if (ipfilters[i].compare == 0xffffffff)
break; // free spot
}
if (i == numipfilters)
{
if (numipfilters == MAX_IPFILTERS)
{
gi.cprintf (NULL, PRINT_HIGH, "IP filter list is full\n");
return false;
}
numipfilters++;
}
if (!StringToFilter (ent->client->ipaddr, &ipfilters[i], rounds))
{
ipfilters[i].compare = 0xffffffff;
return false;
}
return true;
}
void UnBan_TeamKillers (void)
{
// We don't directly unban them all - we subtract 1 from temp_ban_games,
// and unban them if it's 0.
int i, j;
for (i=0 ; i<numipfilters ; i++)
{
if (ipfilters[i].temp_ban_games > 0)
{
if (!--ipfilters[i].temp_ban_games)
{
// re-pack the filters
for (j=i+1 ; j<numipfilters ; j++)
ipfilters[j-1] = ipfilters[j];
numipfilters--;
gi.cprintf (NULL, PRINT_HIGH, "Unbanned teamkiller.\n");
// since we removed the current we have to re-process the new current
i--;
}
}
}
}
//AZEROV

View file

@ -503,7 +503,9 @@ void target_laser_think (edict_t *self)
VectorMA (start, 2048, self->movedir, end);
while(1)
{
tr = do_trace (start, NULL, NULL, end, ignore, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER);
PRETRACE();
tr = gi.trace (start, NULL, NULL, end, ignore, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER);
POSTTRACE();
if (!tr.ent)
break;

3086
g_weapon.c

File diff suppressed because it is too large Load diff

4731
p_client.c

File diff suppressed because it is too large Load diff

25
p_hud.c
View file

@ -45,10 +45,10 @@ void MoveClientToIntermission (edict_t *ent)
ent->solid = SOLID_NOT;
//FIREBLADE
ent->client->resp.sniper_mode = SNIPER_1X;
ent->client->desired_fov = 90;
ent->client->ps.fov = 90;
ent->client->ps.stats[STAT_SNIPER_ICON] = 0;
ent->client->resp.sniper_mode = SNIPER_1X;
ent->client->desired_fov = 90;
ent->client->ps.fov = 90;
ent->client->ps.stats[STAT_SNIPER_ICON] = 0;
//FIREBLADE
// add the layout
@ -148,6 +148,23 @@ void BeginIntermission (edict_t *targ)
continue;
MoveClientToIntermission (client);
}
// AZEROV: Clear the team kills for everyone
//gi.cprintf(NULL,PRINT_MEDIUM,"Resetting all team kills\n");
for (i=1; i<=maxclients->value; i++)
{
edict_t *temp_ent;
temp_ent = g_edicts + i;
if (!temp_ent->inuse || !temp_ent->client)
{
continue;
}
temp_ent->client->team_wounds = 0;
temp_ent->client->team_kills = 0;
}
// AZEROV
}
void A_ScoreboardMessage (edict_t *ent, edict_t *killer);

1920
p_view.c

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff