Changeset 77:6d865a4a045a
- Timestamp:
- 11/22/07 12:01:03 (3 years ago)
- Branch:
- madcat
- convert_revision:
- svn:7c786126-522e-0410-a822-d6d8feae56ca/branches/madcat@99
- Location:
- src/game
- Files:
-
- 6 modified
-
bg_public.h (modified) (2 diffs)
-
g_active.c (modified) (3 diffs)
-
g_local.h (modified) (2 diffs)
-
g_main.c (modified) (1 diff)
-
g_weapon.c (modified) (3 diffs)
-
tremulous.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
src/game/bg_public.h
r73 r77 580 580 EV_DCC_ATTACK, //TA: dcc under attack 581 581 582 EV_RPTUSE_SOUND //TA: trigger a sound 582 EV_RPTUSE_SOUND, //TA: trigger a sound 583 EV_LEV2_ZAP 583 584 } entity_event_t; 584 585 … … 1269 1270 ET_MODELDOOR, 1270 1271 ET_LIGHTFLARE, 1271 ET_LEV2_ZAP_CHAIN, 1272 ET_LEV2_ZAP_CHAIN, // TODO: REMOVE ME !!! 1272 1273 1273 1274 ET_EVENTS // any of the EV_* events can be added freestanding -
src/game/g_active.c
r76 r77 1338 1338 } 1339 1339 1340 static void G_CheckZap( gentity_t *ent ) 1341 { 1342 int i; 1343 1344 if( !ent->zapping ) 1345 { 1346 // clear out established targets 1347 for( i = 0; i < LEVEL2_AREAZAP_MAX_TARGETS; i++ ) 1348 { 1349 ent->zapTargets[ i ] = -1; 1350 } 1351 ent->zapDmg = 0.0f; 1352 } 1353 ent->wasZapping = ent->zapping; 1354 ent->zapping = qfalse; 1355 1356 if( ent->client->ps.weapon == WP_ALEVEL2_UPG && 1357 ( ent->client->pers.cmd.buttons & BUTTON_ATTACK2 ) ) 1358 { 1359 ent->zapping = qtrue; 1360 } 1361 1362 if( ent->wasZapping && !ent->zapping ) 1363 ent->client->ps.weaponTime = LEVEL2_AREAZAP_REPEAT; 1364 } 1365 1340 1366 /* 1341 1367 ============== … … 1691 1717 // touch other objects 1692 1718 ClientImpacts( ent, &pm ); 1693 1719 1720 G_CheckZap( ent ); 1721 1694 1722 // execute client events 1695 1723 ClientEvents( ent, oldEventSequence ); … … 1976 2004 G_SetClientSound( ent ); 1977 2005 2006 G_UpdateZaps( ent ); 2007 1978 2008 // set the latest infor 1979 2009 if( g_smoothClients.integer ) -
src/game/g_local.h
r68 r77 241 241 242 242 int lastDamageTime; 243 244 qboolean zapping; // adv maurader is zapping 245 qboolean wasZapping; // adv maurader was zapping 246 int zapTargets[ LEVEL2_AREAZAP_MAX_TARGETS ]; 247 float zapDmg; // keep track of damage 243 248 }; 244 249 … … 911 916 qboolean CheckPounceAttack( gentity_t *ent ); 912 917 void ChargeAttack( gentity_t *ent, gentity_t *victim ); 913 void G_UpdateZaps( int msec);918 void G_UpdateZaps( gentity_t *ent ); 914 919 915 920 -
src/game/g_main.c
r72 r77 2468 2468 G_SpawnClients( PTE_HUMANS ); 2469 2469 G_CalculateAvgPlayers( ); 2470 G_UpdateZaps( msec );2471 2470 2472 2471 // see if it is time to end the level -
src/game/g_weapon.c
r75 r77 1018 1018 */ 1019 1019 1020 #define MAX_ZAPS 64 1021 1022 static zap_t zaps[ MAX_CLIENTS ]; 1023 1024 /* 1025 =============== 1026 G_FindNewZapTarget 1027 =============== 1028 */ 1029 static gentity_t *G_FindNewZapTarget( gentity_t *ent ) 1020 static vec3_t sortReference; 1021 1022 static int QDECL G_SortDistance( const void *a, const void *b ) 1023 { 1024 gentity_t *aent, *bent; 1025 float adist, bdist; 1026 aent = &g_entities[ *(int *)a ]; 1027 bent = &g_entities[ *(int *)b ]; 1028 adist = Distance( sortReference, aent->s.origin ); 1029 bdist = Distance( sortReference, bent->s.origin ); 1030 if( adist > bdist ) 1031 return -1; 1032 else if( adist < bdist ) 1033 return 1; 1034 else 1035 return 0; 1036 } 1037 1038 /* 1039 =============== 1040 G_UpdateZaps 1041 =============== 1042 */ 1043 void G_UpdateZaps( gentity_t *ent ) 1030 1044 { 1031 1045 int entityList[ MAX_GENTITIES ]; 1032 vec3_t range = { LEVEL2_AREAZAP_RANGE, LEVEL2_AREAZAP_RANGE, LEVEL2_AREAZAP_RANGE }; 1046 int hitList[ MAX_GENTITIES ]; 1047 vec3_t range = { LEVEL2_AREAZAP_CUTOFF, 1048 LEVEL2_AREAZAP_CUTOFF, 1049 LEVEL2_AREAZAP_CUTOFF }; 1033 1050 vec3_t mins, maxs; 1034 int i, j, k, num; 1051 int i, j; 1052 int hit = 0; 1053 int num; 1035 1054 gentity_t *enemy; 1055 gentity_t *effect; 1036 1056 trace_t tr; 1057 qboolean alreadyTargeted = qfalse; 1058 int damage; 1059 1060 if( !ent->zapping || ent->health <= 0 ) 1061 return; 1037 1062 1038 1063 VectorScale( range, 1.0f / M_ROOT3, range ); … … 1046 1071 enemy = &g_entities[ entityList[ i ] ]; 1047 1072 1048 if( ( ( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) || 1073 if( ( ( enemy->client && 1074 enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) || 1049 1075 ( enemy->s.eType == ET_BUILDABLE && 1050 BG_FindTeamForBuildable( enemy->s.modelindex ) == BIT_HUMANS ) ) && enemy->health > 0 ) 1076 BG_FindTeamForBuildable( enemy->s.modelindex ) == BIT_HUMANS ) ) && 1077 enemy->health > 0 ) 1051 1078 { 1052 qboolean foundOldTarget = qfalse; 1053 1054 trap_Trace( &tr, muzzle, NULL, NULL, enemy->s.origin, ent->s.number, MASK_SHOT ); 1055 1056 //can't see target from here 1057 if( tr.entityNum == ENTITYNUM_WORLD ) 1058 continue; 1059 1060 for( j = 0; j < MAX_ZAPS; j++ ) 1079 alreadyTargeted = qfalse; 1080 for( j = 0; j < LEVEL2_AREAZAP_MAX_TARGETS; j++ ) 1061 1081 { 1062 zap_t *zap = &zaps[ j ]; 1063 1064 for( k = 0; k < zap->numTargets; k++ ) 1082 if( ent->zapTargets[ j ] == entityList[ i ] ) 1065 1083 { 1066 if( zap->targets[ k ] == enemy ) 1067 { 1068 foundOldTarget = qtrue; 1069 break; 1070 } 1071 } 1072 1073 if( foundOldTarget ) 1084 alreadyTargeted = qtrue; 1074 1085 break; 1075 }1076 1077 // enemy is already targetted1078 if( foundOldTarget )1079 continue;1080 1081 return enemy;1082 }1083 }1084 1085 return NULL;1086 }1087 1088 /*1089 ===============1090 G_UpdateZapEffect1091 ===============1092 */1093 static void G_UpdateZapEffect( zap_t *zap )1094 {1095 int j;1096 gentity_t *effect = zap->effectChannel;1097 1098 effect->s.eType = ET_LEV2_ZAP_CHAIN;1099 effect->classname = "lev2zapchain";1100 G_SetOrigin( effect, zap->creator->s.origin );1101 effect->s.powerups = zap->creator->s.number;1102 1103 effect->s.time = effect->s.time2 = effect->s.constantLight = -1;1104 1105 for( j = 0; j < zap->numTargets; j++ )1106 {1107 int number = zap->targets[ j ]->s.number;1108 1109 switch( j )1110 {1111 case 0: effect->s.time = number; break;1112 case 1: effect->s.time2 = number; break;1113 case 2: effect->s.constantLight = number; break;1114 default: break;1115 }1116 }1117 1118 trap_LinkEntity( effect );1119 }1120 1121 /*1122 ===============1123 G_CreateNewZap1124 ===============1125 */1126 static void G_CreateNewZap( gentity_t *creator, gentity_t *target )1127 {1128 int i, j;1129 zap_t *zap;1130 1131 for( i = 0; i < MAX_ZAPS; i++ )1132 {1133 zap = &zaps[ i ];1134 1135 if( !zap->used )1136 {1137 zap->used = qtrue;1138 1139 zap->timeToLive = LEVEL2_AREAZAP_TIME;1140 zap->damageUsed = 0;1141 1142 zap->creator = creator;1143 1144 zap->targets[ 0 ] = target;1145 zap->numTargets = 1;1146 1147 for( j = 1; j < MAX_ZAP_TARGETS && zap->targets[ j - 1 ]; j++ )1148 {1149 zap->targets[ j ] = G_FindNewZapTarget( zap->targets[ j - 1 ] );1150 1151 if( zap->targets[ j ] )1152 zap->numTargets++;1153 }1154 1155 zap->effectChannel = G_Spawn( );1156 G_UpdateZapEffect( zap );1157 1158 return;1159 }1160 }1161 }1162 1163 1164 /*1165 ===============1166 G_UpdateZaps1167 ===============1168 */1169 void G_UpdateZaps( int msec )1170 {1171 int i, j;1172 zap_t *zap;1173 int damage;1174 1175 for( i = 0; i < MAX_ZAPS; i++ )1176 {1177 zap = &zaps[ i ];1178 1179 if( zap->used )1180 {1181 //check each target is valid1182 for( j = 0; j < zap->numTargets; j++ )1183 {1184 gentity_t *source;1185 gentity_t *target = zap->targets[ j ];1186 1187 if( j == 0 )1188 source = zap->creator;1189 else1190 source = zap->targets[ j - 1 ];1191 1192 if( target->health <= 0 || !target->inuse || //early out1193 Distance( source->s.origin, target->s.origin ) > LEVEL2_AREAZAP_RANGE )1194 {1195 target = zap->targets[ j ] = G_FindNewZapTarget( source );1196 1197 //couldn't find a target, so forget about the rest of the chain1198 if( !target )1199 zap->numTargets = j;1200 1086 } 1201 1087 } 1202 1088 1203 if( zap->numTargets ) 1089 if( !alreadyTargeted && 1090 Distance( ent->s.origin, enemy->s.origin ) > LEVEL2_AREAZAP_RANGE ) 1204 1091 { 1205 for( j = 0; j < zap->numTargets; j++ ) 1206 { 1207 gentity_t *source; 1208 gentity_t *target = zap->targets[ j ]; 1209 float r = 1.0f / zap->numTargets; 1210 float damageFraction = 2 * r - 2 * j * r * r - r * r; 1211 vec3_t forward; 1212 1213 if( j == 0 ) 1214 source = zap->creator; 1215 else 1216 source = zap->targets[ j - 1 ]; 1217 1218 damage = ceil( ( (float)msec / LEVEL2_AREAZAP_TIME ) * 1219 LEVEL2_AREAZAP_DMG * damageFraction ); 1220 1221 // don't let a high msec value inflate the total damage 1222 if( damage + zap->damageUsed > LEVEL2_AREAZAP_DMG ) 1223 damage = LEVEL2_AREAZAP_DMG - zap->damageUsed; 1224 1225 VectorSubtract( target->s.origin, source->s.origin, forward ); 1226 VectorNormalize( forward ); 1227 1228 //do the damage 1229 if( damage ) 1230 { 1231 G_Damage( target, source, zap->creator, forward, target->s.origin, 1232 damage, DAMAGE_NO_KNOCKBACK | DAMAGE_NO_LOCDAMAGE, MOD_LEVEL2_ZAP ); 1233 zap->damageUsed += damage; 1234 } 1235 } 1092 continue; 1236 1093 } 1237 1238 G_UpdateZapEffect( zap ); 1239 1240 zap->timeToLive -= msec; 1241 1242 if( zap->timeToLive <= 0 || zap->numTargets == 0 || zap->creator->health <= 0 ) 1243 { 1244 zap->used = qfalse; 1245 G_FreeEntity( zap->effectChannel ); 1246 } 1094 trap_Trace( &tr, ent->s.origin, NULL, NULL, enemy->s.origin, 1095 ent-g_entities, MASK_SHOT ); 1096 if( tr.entityNum == enemy-g_entities ) 1097 hitList[ hit++ ] = tr.entityNum; 1247 1098 } 1248 1099 } 1249 } 1250 1251 /* 1252 =============== 1253 areaZapFire 1254 =============== 1255 */ 1256 void areaZapFire( gentity_t *ent ) 1257 { 1258 trace_t tr; 1259 vec3_t end; 1260 gentity_t *traceEnt; 1261 vec3_t mins, maxs; 1262 1263 VectorSet( mins, -LEVEL2_AREAZAP_WIDTH, -LEVEL2_AREAZAP_WIDTH, -LEVEL2_AREAZAP_WIDTH ); 1264 VectorSet( maxs, LEVEL2_AREAZAP_WIDTH, LEVEL2_AREAZAP_WIDTH, LEVEL2_AREAZAP_WIDTH ); 1265 1266 // set aiming directions 1267 AngleVectors( ent->client->ps.viewangles, forward, right, up ); 1268 1269 CalcMuzzlePoint( ent, forward, right, up, muzzle ); 1270 1271 VectorMA( muzzle, LEVEL2_AREAZAP_RANGE, forward, end ); 1272 1273 G_UnlaggedOn( muzzle, LEVEL2_AREAZAP_RANGE ); 1274 trap_Trace( &tr, muzzle, mins, maxs, end, ent->s.number, MASK_SHOT ); 1275 G_UnlaggedOff( ); 1276 1277 if( tr.surfaceFlags & SURF_NOIMPACT ) 1278 return; 1279 1280 traceEnt = &g_entities[ tr.entityNum ]; 1281 1282 if( ( ( traceEnt->client && traceEnt->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) || 1283 ( traceEnt->s.eType == ET_BUILDABLE && 1284 BG_FindTeamForBuildable( traceEnt->s.modelindex ) == BIT_HUMANS ) ) && traceEnt->health > 0 ) 1285 { 1286 G_CreateNewZap( ent, traceEnt ); 1287 } 1288 } 1289 1100 1101 for( i = 0; i < LEVEL2_AREAZAP_MAX_TARGETS; i++ ) 1102 ent->zapTargets[ i ] = -1; 1103 1104 if( !hit ) 1105 return; 1106 1107 ent->zapDmg += ( (float)( level.time - level.previousTime ) / 1000.0f ) 1108 * LEVEL2_AREAZAP_DMG; 1109 damage = (int)ent->zapDmg; 1110 // wait until we've accumulated enough damage for bsuit to take at 1111 // least 1 HP 1112 if( damage < 5 ) 1113 damage = 0; 1114 else 1115 ent->zapDmg -= (int)damage; 1116 1117 VectorCopy( ent->s.origin, sortReference ); 1118 qsort( hitList, hit, sizeof( int ), G_SortDistance ); 1119 1120 // FIXME: event should be EV_LEV2_ZAP, but unknow by standard client 1121 // temporary give old zap effect (is it valid ?) 1122 effect = G_TempEntity( ent->s.origin, ET_LEV2_ZAP_CHAIN ); 1123 1124 effect->s.powerups = ent-g_entities; 1125 effect->s.time = effect->s.time2 = effect->s.constantLight = -1; 1126 for( i = 0; i < hit; i++ ) 1127 { 1128 if( i >= LEVEL2_AREAZAP_MAX_TARGETS ) 1129 break; 1130 1131 ent->zapTargets[ i ] = hitList[ i ]; 1132 1133 enemy = &g_entities[ hitList[ i ] ]; 1134 1135 if( damage > 0 ) 1136 { 1137 G_Damage( enemy, ent, ent, NULL, enemy->s.origin, 1138 damage, DAMAGE_NO_KNOCKBACK | DAMAGE_NO_LOCDAMAGE, MOD_LEVEL2_ZAP ); 1139 } 1140 switch( i ) 1141 { 1142 case 0: effect->s.time = hitList[ i ]; break; 1143 case 1: effect->s.time2 = hitList[ i ]; break; 1144 case 2: effect->s.constantLight = hitList[ i ]; break; 1145 default: break; 1146 } 1147 } 1148 } 1290 1149 1291 1150 /* … … 1506 1365 poisonCloud( ent ); 1507 1366 break; 1508 case WP_ALEVEL2_UPG:1509 areaZapFire( ent );1510 break;1511 1367 1512 1368 case WP_LUCIFER_CANNON: -
src/game/tremulous.h
r76 r77 75 75 #define LEVEL2_CLAW_DMG ADM(40) 76 76 #define LEVEL2_CLAW_RANGE 96.0f 77 #define LEVEL2_CLAW_WIDTH 1 2.0f77 #define LEVEL2_CLAW_WIDTH 16.0f 78 78 #define LEVEL2_CLAW_REPEAT 500 79 79 #define LEVEL2_CLAW_K_SCALE 1.0f 80 80 #define LEVEL2_CLAW_U_REPEAT 400 81 81 #define LEVEL2_CLAW_U_K_SCALE 1.0f 82 #define LEVEL2_AREAZAP_DMG ADM(80) 83 #define LEVEL2_AREAZAP_RANGE 200.0f 84 #define LEVEL2_AREAZAP_WIDTH 15.0f 85 #define LEVEL2_AREAZAP_REPEAT 1500 86 #define LEVEL2_AREAZAP_TIME 1000 82 #define LEVEL2_AREAZAP_DMG ADM(33) 83 #define LEVEL2_AREAZAP_RANGE 90.0f 84 #define LEVEL2_AREAZAP_CUTOFF 350.0f 85 #define LEVEL2_AREAZAP_REPEAT 500 87 86 #define LEVEL2_AREAZAP_MAX_TARGETS 3 88 87 #define LEVEL2_WALLJUMP_MAXSPEED 1000.0f
