Compare commits
2 commits
Author | SHA1 | Date | |
---|---|---|---|
|
5a8aa10e57 | ||
|
bccddaa7fd |
31 changed files with 10013 additions and 6984 deletions
239
CHANGES
239
CHANGES
|
@ -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
91
LICENSE.TXT
Normal 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
|
||||
|
||||
|
23
Makefile
23
Makefile
|
@ -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
106
README
|
@ -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
213
a_cmds.c
|
@ -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
135
a_doorkick.c
Normal 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 );
|
||||
}
|
15
a_game.h
15
a_game.h
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
41
a_radio.c
41
a_radio.c
|
@ -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
381
a_team.c
|
@ -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)
|
||||
{
|
||||
|
|
30
a_team.h
30
a_team.h
|
@ -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
704
cgf_sfx_glass.c
Normal 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
281
cgf_sfx_glass.h
Normal 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;
|
||||
*/
|
80
g_chase.c
80
g_chase.c
|
@ -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
139
g_cmds.c
|
@ -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
2057
g_combat.c
File diff suppressed because it is too large
Load diff
74
g_items.c
74
g_items.c
|
@ -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));
|
||||
|
|
70
g_local.h
70
g_local.h
|
@ -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
|
||||
|
|
55
g_main.c
55
g_main.c
|
@ -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
|
||||
|
|
6
g_misc.c
6
g_misc.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
15
g_phys.c
15
g_phys.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
49
g_save.c
49
g_save.c
|
@ -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);
|
||||
|
||||
|
|
56
g_spawn.c
56
g_spawn.c
|
@ -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
|
||||
}
|
||||
|
||||
|
|
172
g_svcmds.c
172
g_svcmds.c
|
@ -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
|
||||
|
||||
|
|
|
@ -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
3086
g_weapon.c
File diff suppressed because it is too large
Load diff
4731
p_client.c
4731
p_client.c
File diff suppressed because it is too large
Load diff
25
p_hud.c
25
p_hud.c
|
@ -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);
|
||||
|
|
953
p_weapon.c
953
p_weapon.c
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue