1 /*
2 ===========================================================================
3 Copyright (C) 2000 - 2013, Raven Software, Inc.
4 Copyright (C) 2001 - 2013, Activision, Inc.
5 Copyright (C) 2013 - 2015, OpenJK contributors
6 
7 This file is part of the OpenJK source code.
8 
9 OpenJK is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License version 2 as
11 published by the Free Software Foundation.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, see <http://www.gnu.org/licenses/>.
20 ===========================================================================
21 */
22 #include "g_headers.h"
23 
24 #include "b_local.h"
25 #include "g_local.h"
26 #include "wp_saber.h"
27 #include "w_local.h"
28 #include "g_functions.h"
29 
30 //-------------------
31 //	Wookiee Bowcaster
32 //-------------------
33 
34 //---------------------------------------------------------
WP_BowcasterMainFire(gentity_t * ent)35 static void WP_BowcasterMainFire( gentity_t *ent )
36 //---------------------------------------------------------
37 {
38 	int			damage	= weaponData[WP_BOWCASTER].damage, count;
39 	float		vel;
40 	vec3_t		angs, dir, start;
41 	gentity_t	*missile;
42 
43 	VectorCopy( wpMuzzle, start );
44 	WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall
45 
46 	// Do the damages
47 	if ( ent->s.number != 0 )
48 	{
49 		if ( g_spskill->integer == 0 )
50 		{
51 			damage = BOWCASTER_NPC_DAMAGE_EASY;
52 		}
53 		else if ( g_spskill->integer == 1 )
54 		{
55 			damage = BOWCASTER_NPC_DAMAGE_NORMAL;
56 		}
57 		else
58 		{
59 			damage = BOWCASTER_NPC_DAMAGE_HARD;
60 		}
61 	}
62 
63 	count = ( level.time - ent->client->ps.weaponChargeTime ) / BOWCASTER_CHARGE_UNIT;
64 
65 	if ( count < 1 )
66 	{
67 		count = 1;
68 	}
69 	else if ( count > 5 )
70 	{
71 		count = 5;
72 	}
73 
74 	if ( !(count & 1 ))
75 	{
76 		// if we aren't odd, knock us down a level
77 		count--;
78 	}
79 
80 //	if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time )
81 //	{
82 //		// in overcharge mode, so doing double damage
83 //		damage *= 2;
84 //	}
85 
86 	for ( int i = 0; i < count; i++ )
87 	{
88 		// create a range of different velocities
89 		vel = BOWCASTER_VELOCITY * ( Q_flrand(-1.0f, 1.0f) * BOWCASTER_VEL_RANGE + 1.0f );
90 
91 		vectoangles( wpFwd, angs );
92 
93 		// add some slop to the fire direction
94 		angs[PITCH] += Q_flrand(-1.0f, 1.0f) * BOWCASTER_ALT_SPREAD * 0.2f;
95 		angs[YAW]	+= ((i+0.5f) * BOWCASTER_ALT_SPREAD - count * 0.5f * BOWCASTER_ALT_SPREAD );
96 		if ( ent->NPC )
97 		{
98 			angs[PITCH] += ( Q_flrand(-1.0f, 1.0f) * (BLASTER_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f) );
99 			angs[YAW]	+= ( Q_flrand(-1.0f, 1.0f) * (BLASTER_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f) );
100 		}
101 
102 		AngleVectors( angs, dir, NULL, NULL );
103 
104 		missile = CreateMissile( start, dir, vel, 10000, ent );
105 
106 		missile->classname = "bowcaster_proj";
107 		missile->s.weapon = WP_BOWCASTER;
108 
109 		VectorSet( missile->maxs, BOWCASTER_SIZE, BOWCASTER_SIZE, BOWCASTER_SIZE );
110 		VectorScale( missile->maxs, -1, missile->mins );
111 
112 //		if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time )
113 //		{
114 //			missile->flags |= FL_OVERCHARGED;
115 //		}
116 
117 		missile->damage = damage;
118 		missile->dflags = DAMAGE_DEATH_KNOCKBACK;
119 		missile->methodOfDeath = MOD_BOWCASTER;
120 		missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
121 		missile->splashDamage = weaponData[WP_BOWCASTER].splashDamage;
122 		missile->splashRadius = weaponData[WP_BOWCASTER].splashRadius;
123 
124 		// we don't want it to bounce
125 		missile->bounceCount = 0;
126 		ent->client->sess.missionStats.shotsFired++;
127 	}
128 }
129 
130 //---------------------------------------------------------
WP_BowcasterAltFire(gentity_t * ent)131 static void WP_BowcasterAltFire( gentity_t *ent )
132 //---------------------------------------------------------
133 {
134 	vec3_t	start;
135 	int		damage	= weaponData[WP_BOWCASTER].altDamage;
136 
137 	VectorCopy( wpMuzzle, start );
138 	WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall
139 
140 	gentity_t *missile = CreateMissile( start, wpFwd, BOWCASTER_VELOCITY, 10000, ent, qtrue );
141 
142 	missile->classname = "bowcaster_alt_proj";
143 	missile->s.weapon = WP_BOWCASTER;
144 
145 	// Do the damages
146 	if ( ent->s.number != 0 )
147 	{
148 		if ( g_spskill->integer == 0 )
149 		{
150 			damage = BOWCASTER_NPC_DAMAGE_EASY;
151 		}
152 		else if ( g_spskill->integer == 1 )
153 		{
154 			damage = BOWCASTER_NPC_DAMAGE_NORMAL;
155 		}
156 		else
157 		{
158 			damage = BOWCASTER_NPC_DAMAGE_HARD;
159 		}
160 	}
161 
162 	VectorSet( missile->maxs, BOWCASTER_SIZE, BOWCASTER_SIZE, BOWCASTER_SIZE );
163 	VectorScale( missile->maxs, -1, missile->mins );
164 
165 //	if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time )
166 //	{
167 //		// in overcharge mode, so doing double damage
168 //		missile->flags |= FL_OVERCHARGED;
169 //		damage *= 2;
170 //	}
171 
172 	missile->s.eFlags |= EF_BOUNCE;
173 	missile->bounceCount = 3;
174 
175 	missile->damage = damage;
176 	missile->dflags = DAMAGE_DEATH_KNOCKBACK;
177 	missile->methodOfDeath = MOD_BOWCASTER_ALT;
178 	missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER;
179 	missile->splashDamage = weaponData[WP_BOWCASTER].splashDamage;
180 	missile->splashRadius = weaponData[WP_BOWCASTER].splashRadius;
181 }
182 
183 //---------------------------------------------------------
WP_FireBowcaster(gentity_t * ent,qboolean alt_fire)184 void WP_FireBowcaster( gentity_t *ent, qboolean alt_fire )
185 //---------------------------------------------------------
186 {
187 	if ( alt_fire )
188 	{
189 		WP_BowcasterAltFire( ent );
190 	}
191 	else
192 	{
193 		WP_BowcasterMainFire( ent );
194 	}
195 }