Index: src/cgame/cg_draw.c =================================================================== --- src/cgame/cg_draw.c (revision 894) +++ src/cgame/cg_draw.c (working copy) @@ -2545,6 +2545,7 @@ { float *color; char *name; + int health; float w, x; if( !cg_drawCrosshair.integer ) @@ -2568,9 +2569,25 @@ } name = cgs.clientinfo[ cg.crosshairClientNum ].name; + health = cgs.clientinfo[ cg.crosshairClientNum ].health; w = CG_Text_Width( name, scale, 0 ); x = rect->x + rect->w / 2; CG_Text_Paint( x - w / 2, rect->y + rect->h, scale, color, name, 0, 0, textStyle ); + + if( health > 0 ) + { + entityState_t *es = &cg_entities[cg.crosshairClientNum].currentState; + pClass_t class = ( es->powerups >> 8 ) & 0xFF; + float hp = BG_FindHealthForClass(class); + + hp=100.0f*(float)health/hp; + if( hp > 33 ) + CG_DrawPic( x - hp / 2, rect->y + 1.5 * rect->h, hp, 7, + cgs.media.greenBuildShader ); + else + CG_DrawPic( x - hp / 2, rect->y + 1.5 * rect->h, hp, 7, + cgs.media.redBuildShader ); + } trap_R_SetColor( NULL ); } Index: src/cgame/cg_event.c =================================================================== --- src/cgame/cg_event.c (revision 894) +++ src/cgame/cg_event.c (working copy) @@ -160,6 +160,15 @@ message = "irradiated himself"; break; + case MOD_XAEL_SPLASH: + if( gender == GENDER_FEMALE ) + message = "pulverized herself"; + else if( gender == GENDER_NEUTER ) + message = "pulverized itself"; + else + message = "pulverized himself"; + break; + case MOD_GRENADE: if( gender == GENDER_FEMALE ) message = "blew herself up"; @@ -245,6 +254,14 @@ message = "was caught in the fallout of"; message2 = "'s lucifer cannon"; break; + case MOD_XAEL: + message = "felt the full force of"; + message2 = "'s xael"; + break; + case MOD_XAEL_SPLASH: + message = "was caught in the fallout of"; + message2 = "'s xael"; + break; case MOD_GRENADE: message = "couldn't escape"; message2 = "'s grenade"; @@ -269,8 +286,8 @@ BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL2 ) ); message2 = className; break; - case MOD_LEVEL2_ZAP: - message = "was zapped by"; + case MOD_LEVEL2_BOUNCEBALL: + message = "was sniped by"; Com_sprintf( className, 64, "'s %s", BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL2 ) ); message2 = className; @@ -305,6 +322,12 @@ BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL4 ) ); message2 = className; break; + case MOD_LEVEL4_EBLOB: + message = "couldn't escape acid of"; + Com_sprintf( className, 64, "'s %s", + BG_FindHumanNameForClassNum( PCL_ALIEN_LEVEL4 ) ); + message2 = className; + break; case MOD_POISON: message = "should have used a medkit against"; Index: src/cgame/cg_local.h =================================================================== --- src/cgame/cg_local.h (revision 894) +++ src/cgame/cg_local.h (working copy) @@ -652,6 +652,9 @@ particleSystem_t *jetPackPS; jetPackState_t jetPackState; + qboolean isVisible; + int stopTime; + particleSystem_t *entityPS; qboolean entityPSMissing; @@ -1170,6 +1173,9 @@ qhandle_t shadowMarkShader; qhandle_t wakeMarkShader; + //invisible shader + qhandle_t invisible; + // buildable shaders qhandle_t greenBuildShader; qhandle_t redBuildShader; @@ -1241,6 +1247,7 @@ qhandle_t jetpackModel; qhandle_t jetpackFlashModel; qhandle_t battpackModel; + qhandle_t ammopackModel; sfxHandle_t repeaterUseSound; Index: src/cgame/cg_main.c =================================================================== --- src/cgame/cg_main.c (revision 894) +++ src/cgame/cg_main.c (working copy) @@ -782,6 +782,7 @@ cgs.media.backTileShader = trap_R_RegisterShader( "console" ); + cgs.media.invisible = trap_R_RegisterShader("gfx/invisible" ); //TA: building shaders cgs.media.greenBuildShader = trap_R_RegisterShader("gfx/misc/greenbuild" ); @@ -943,6 +944,7 @@ cgs.media.jetpackModel = trap_R_RegisterModel( "models/players/human_base/jetpack.md3" ); cgs.media.jetpackFlashModel = trap_R_RegisterModel( "models/players/human_base/jetpack_flash.md3" ); cgs.media.battpackModel = trap_R_RegisterModel( "models/players/human_base/battpack.md3" ); + cgs.media.ammopackModel = trap_R_RegisterModel( "models/players/human_base/ammopack.md3" ); cg.charModelFraction = 1.0f; trap_UpdateScreen( ); @@ -1496,9 +1498,11 @@ switch( sp->weapon ) { case WP_ABUILD2: + case WP_ALEVEL0_UPG: case WP_ALEVEL1_UPG: case WP_ALEVEL2_UPG: case WP_ALEVEL3_UPG: + case WP_ALEVEL4_UPG: *handle = cgs.media.upgradeClassIconShader; break; Index: src/cgame/cg_players.c =================================================================== --- src/cgame/cg_players.c (revision 894) +++ src/cgame/cg_players.c (working copy) @@ -1547,6 +1547,7 @@ int held, active; refEntity_t jetpack; refEntity_t battpack; + refEntity_t ammopack; refEntity_t flash; entityState_t *es = ¢->currentState; @@ -1667,6 +1668,24 @@ trap_R_AddRefEntityToScene( &battpack ); } + if( held & ( 1 << UP_AMMOPACK ) ) + { + memset( &ammopack, 0, sizeof( ammopack ) ); + VectorCopy( torso->lightingOrigin, ammopack.lightingOrigin ); + ammopack.shadowPlane = torso->shadowPlane; + ammopack.renderfx = torso->renderfx; + + ammopack.hModel = cgs.media.ammopackModel; + + //identity matrix + AxisCopy( axisDefault, ammopack.axis ); + + //FIXME: change to tag_back when it exists + CG_PositionRotatedEntityOnTag( &ammopack, torso, torso->hModel, "tag_head" ); + + trap_R_AddRefEntityToScene( &ammopack ); + } + if( es->eFlags & EF_BLOBLOCKED ) { vec3_t temp, origin, up = { 0.0f, 0.0f, 1.0f }; @@ -1766,6 +1785,12 @@ mins[ 2 ] = 0.0f; maxs[ 2 ] = 2.0f; + //no shadow for adv basi + if( es->weapon == WP_ALEVEL1_UPG && es->eFlags & EF_MOVER_STOP ) + { + return qfalse; + } + if( es->eFlags & EF_WALLCLIMB ) { if( es->eFlags & EF_WALLCLIMBCEILING ) @@ -2130,6 +2155,27 @@ { legs.hModel = ci->nonSegModel; legs.customSkin = ci->nonSegSkin; + + /*if( es->weapon == WP_ALEVEL1_UPG ) + { + cent->isVisible = qtrue; + + if( VectorLength( es->pos.trDelta ) < 1.0f && + VectorLength( es->apos.trDelta ) < 1.0f ) + { + if( cent->stopTime + 2000 < cg.time ) + { + legs.customShader = cgs.media.invisible; + cent->isVisible = qfalse; + } + } + else + cent->stopTime=cg.time; + }*/ + if( es->weapon == WP_ALEVEL1_UPG && es->eFlags & EF_MOVER_STOP ) + { + legs.customShader = cgs.media.invisible; + } } VectorCopy( cent->lerpOrigin, legs.origin ); Index: src/cgame/cg_view.c =================================================================== --- src/cgame/cg_view.c (revision 894) +++ src/cgame/cg_view.c (working copy) @@ -494,7 +494,7 @@ #define LEVEL4_FEEDBACK 10.0f //give a charging player some feedback - if( ps->weapon == WP_ALEVEL4 ) + if( ps->weapon == WP_ALEVEL4 || ps->weapon == WP_ALEVEL4_UPG ) { if( ps->stats[ STAT_MISC ] > 0 ) { @@ -528,6 +528,7 @@ } #define LEVEL3_FEEDBACK 20.0f +#define LEVEL0_FEEDBACK 10.0f //provide some feedback for pouncing if( cg.predictedPlayerState.weapon == WP_ALEVEL3 || @@ -552,6 +553,28 @@ } } + //provide some feedback for drill + if( cg.predictedPlayerState.weapon == WP_ALEVEL0_UPG ) + { + if( cg.predictedPlayerState.stats[ STAT_MISC ] > 0 ) + { + float fraction1, fraction2; + vec3_t forward; + + AngleVectors( angles, forward, NULL, NULL ); + VectorNormalize( forward ); + + fraction1 = (float)( cg.time - cg.weapon2Time ) / (float)LEVEL0_DRILL_CHARGE_TIME; + + if( fraction1 > 1.0f ) + fraction1 = 1.0f; + + fraction2 = -sin( fraction1 * M_PI / 2 ); + + VectorMA( origin, LEVEL0_FEEDBACK * fraction2, forward, origin ); + } + } + #define STRUGGLE_DIST 5.0f #define STRUGGLE_TIME 250 Index: src/cgame/cg_weapons.c =================================================================== --- src/cgame/cg_weapons.c (revision 894) +++ src/cgame/cg_weapons.c (working copy) @@ -1010,6 +1010,12 @@ trap_S_AddLoopingSound( ps->clientNum, ps->origin, vec3_origin, cgs.media.lCannonWarningSound ); } + if( weapon == WP_XAEL && ps->stats[ STAT_MISC ] > 0 ) + { + if( ps->stats[ STAT_MISC ] > ( XAEL_TOTAL_CHARGE - ( XAEL_TOTAL_CHARGE / 3 ) ) ) + trap_S_AddLoopingSound( ps->clientNum, ps->origin, vec3_origin, cgs.media.lCannonWarningSound ); + } + // no gun if in third person view if( cg.renderingThirdPerson ) return; @@ -1069,6 +1075,14 @@ VectorMA( hand.origin, random( ) * fraction, cg.refdef.viewaxis[ 1 ], hand.origin ); } + if( weapon == WP_XAEL && ps->stats[ STAT_MISC ] > 0 ) + { + float fraction = (float)ps->stats[ STAT_MISC ] / (float)XAEL_TOTAL_CHARGE; + + VectorMA( hand.origin, random( ) * fraction, cg.refdef.viewaxis[ 0 ], hand.origin ); + VectorMA( hand.origin, random( ) * fraction, cg.refdef.viewaxis[ 1 ], hand.origin ); + } + AnglesToAxis( angles, hand.axis ); // map torso animations to weapon animations Index: src/client/cl_ui.c =================================================================== --- src/client/cl_ui.c (revision 894) +++ src/client/cl_ui.c (working copy) @@ -459,6 +459,9 @@ res = 0; } break; + case SORT_GAMETYPE : + res = Q_stricmp( server1->game, server2->game ); + break; } if (sortDir) { Index: src/game/bg_misc.c =================================================================== --- src/game/bg_misc.c (revision 894) +++ src/game/bg_misc.c (working copy) @@ -401,7 +401,7 @@ MGTURRET_BP, //int buildPoints; ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages MGTURRET_HEALTH, //int health; - 0, //int regenRate; + MGTURRET_DCC_REGEN, //int regenRate; MGTURRET_SPLASHDAMAGE, //int splashDamage; MGTURRET_SPLASHRADIUS, //int splashRadius; MOD_HSPAWN, //int meansOfDeath; @@ -436,7 +436,7 @@ TESLAGEN_BP, //int buildPoints; ( 1 << S3 ), //int stages TESLAGEN_HEALTH, //int health; - 0, //int regenRate; + TESLAGEN_DCC_REGEN, //int regenRate; TESLAGEN_SPLASHDAMAGE, //int splashDamage; TESLAGEN_SPLASHRADIUS, //int splashRadius; MOD_HSPAWN, //int meansOfDeath; @@ -471,7 +471,7 @@ DC_BP, //int buildPoints; ( 1 << S2 )|( 1 << S3 ), //int stages DC_HEALTH, //int health; - 0, //int regenRate; + DC_DCC_REGEN, //int regenRate; DC_SPLASHDAMAGE, //int splashDamage; DC_SPLASHRADIUS, //int splashRadius; MOD_HSPAWN, //int meansOfDeath; @@ -1528,7 +1528,7 @@ 100.0f, //float stopSpeed; 195.0f, //float jumpMagnitude; 1.0f, //float knockbackScale; - { PCL_ALIEN_BUILDER0_UPG, PCL_ALIEN_LEVEL0, PCL_NONE }, //int children[ 3 ]; + { PCL_ALIEN_BUILDER0_UPG, PCL_ALIEN_LEVEL1, PCL_NONE }, //int children[ 3 ]; ABUILDER_COST, //int cost; ABUILDER_VALUE //int value; }, @@ -1566,7 +1566,7 @@ 100.0f, //float stopSpeed; 270.0f, //float jumpMagnitude; 1.0f, //float knockbackScale; - { PCL_ALIEN_LEVEL0, PCL_NONE, PCL_NONE }, //int children[ 3 ]; + { PCL_ALIEN_LEVEL1, PCL_NONE, PCL_NONE }, //int children[ 3 ]; ABUILDER_UPG_COST, //int cost; ABUILDER_UPG_VALUE //int value; }, @@ -1605,11 +1605,50 @@ 400.0f, //float stopSpeed; 250.0f, //float jumpMagnitude; 2.0f, //float knockbackScale; - { PCL_ALIEN_LEVEL1, PCL_NONE, PCL_NONE }, //int children[ 3 ]; + { PCL_ALIEN_LEVEL1, PCL_ALIEN_LEVEL0_UPG, PCL_ALIEN_BUILDER0 }, //int children[ 3 ]; LEVEL0_COST, //int cost; LEVEL0_VALUE //int value; }, { + PCL_ALIEN_LEVEL0_UPG, //int classnum; + "level0upg", //char *classname; + "Soldier Upgrade", //char *humanname; + "jumper", //char *modelname; + 0.2f, //float modelScale; + "default", //char *skinname; + 0.3f, //float shadowScale; + "alien_general_hud", //char *hudname; + ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages + { -15, -15, -15 }, //vec3_t mins; + { 15, 15, 15 }, //vec3_t maxs; + { 15, 15, 15 }, //vec3_t crouchmaxs; + { -15, -15, -4 }, //vec3_t deadmins; + { 15, 15, 4 }, //vec3_t deadmaxs; + -8.0f, //float zOffset + 0, 0, //int viewheight, crouchviewheight; + LEVEL0_UPG_HEALTH, //int health; + 0.0f, //float fallDamage; + LEVEL0_UPG_REGEN, //int regenRate; + SCA_WALLCLIMBER|SCA_NOWEAPONDRIFT| + SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities; + WP_ALEVEL0_UPG, //weapon_t startWeapon + 0.0f, //float buildDist; + 140, //int fov; + 0.0f, //float bob; + 2.5f, //float bobCycle; + 25, //int steptime; + LEVEL0_UPG_SPEED, //float speed; + 10.0f, //float acceleration; + 1.0f, //float airAcceleration; + 6.0f, //float friction; + 400.0f, //float stopSpeed; + 250.0f, //float jumpMagnitude; + 2.0f, //float knockbackScale; + { PCL_ALIEN_LEVEL1, PCL_ALIEN_BUILDER0, PCL_NONE }, //int children[ 3 ]; + LEVEL0_UPG_COST, //int cost; + LEVEL0_UPG_VALUE //int value; + }, + { PCL_ALIEN_LEVEL1, //int classnum; "level1", //char *classname; "Hydra", //char *humanname; @@ -1878,11 +1917,50 @@ 100.0f, //float stopSpeed; 170.0f, //float jumpMagnitude; 0.1f, //float knockbackScale; - { PCL_NONE, PCL_NONE, PCL_NONE }, //int children[ 3 ]; + { PCL_ALIEN_LEVEL4_UPG, PCL_NONE, PCL_NONE }, //int children[ 3 ]; LEVEL4_COST, //int cost; LEVEL4_VALUE //int value; }, { + PCL_ALIEN_LEVEL4_UPG, //int classnum; + "level4upg", //char *classname; + "Big Mofo Upgrade", //char *humanname; + "mofo", //char *modelname; + 1.0f, //float modelScale; + "default", //char *skinname; + 2.0f, //float shadowScale; + "alien_general_hud", //char *hudname; + ( 1 << S3 ), //int stages + { -30, -30, -20 }, //vec3_t mins; + { 30, 30, 20 }, //vec3_t maxs; + { 30, 30, 20 }, //vec3_t crouchmaxs; + { -15, -15, -4 }, //vec3_t deadmins; + { 15, 15, 4 }, //vec3_t deadmaxs; + 0.0f, //float zOffset + 35, 35, //int viewheight, crouchviewheight; + LEVEL4_UPG_HEALTH, //int health; + 0.0f, //float fallDamage; + LEVEL4_UPG_REGEN, //int regenRate; + SCA_NOWEAPONDRIFT| + SCA_FOVWARPS|SCA_ALIENSENSE, //int abilities; + WP_ALEVEL4_UPG, //weapon_t startWeapon + 0.0f, //float buildDist; + 90, //int fov; + 0.001f, //float bob; + 1.1f, //float bobCycle; + 100, //int steptime; + LEVEL4_UPG_SPEED, //float speed; + 10.0f, //float acceleration; + 1.0f, //float airAcceleration; + 6.0f, //float friction; + 100.0f, //float stopSpeed; + 220.0f, //float jumpMagnitude; + 0.1f, //float knockbackScale; + { PCL_NONE, PCL_NONE, PCL_NONE }, //int children[ 3 ]; + LEVEL4_UPG_COST, //int cost; + LEVEL4_UPG_VALUE //int value; + }, + { PCL_HUMAN, //int classnum; "human_base", //char *classname; "Human", //char *humanname; @@ -3013,11 +3091,11 @@ qfalse, //int infiniteAmmo; qfalse, //int usesEnergy; SHOTGUN_REPEAT, //int repeatRate1; - 0, //int repeatRate2; + SHOTGUN_NADE_REPEAT, //int repeatRate2; 0, //int repeatRate3; SHOTGUN_RELOAD, //int reloadTime; SHOTGUN_K_SCALE, //float knockbackScale; - qfalse, //qboolean hasAltMode; + qtrue, //qboolean hasAltMode; qfalse, //qboolean hasThirdMode; qfalse, //qboolean canZoom; 90.0f, //float zoomFov; @@ -3039,7 +3117,7 @@ FLAMER_REPEAT, //int repeatRate1; 0, //int repeatRate2; 0, //int repeatRate3; - 0, //int reloadTime; + SHOTGUN_RELOAD, //int reloadTime; FLAMER_K_SCALE, //float knockbackScale; qfalse, //qboolean hasAltMode; qfalse, //qboolean hasThirdMode; @@ -3063,7 +3141,7 @@ CHAINGUN_REPEAT, //int repeatRate1; 0, //int repeatRate2; 0, //int repeatRate3; - 0, //int reloadTime; + SHOTGUN_RELOAD, //int reloadTime; CHAINGUN_K_SCALE, //float knockbackScale; qfalse, //qboolean hasAltMode; qfalse, //qboolean hasThirdMode; @@ -3092,7 +3170,7 @@ qfalse, //qboolean hasAltMode; qfalse, //qboolean hasThirdMode; qtrue, //qboolean canZoom; - 20.0f, //float zoomFov; + 10.0f, //float zoomFov; qtrue, //qboolean purchasable; 0, //int buildDelay; WUT_HUMANS //WUTeam_t team; @@ -3122,6 +3200,30 @@ WUT_HUMANS //WUTeam_t team; }, { + WP_STASIS_GUN, //int weaponNum; + STASIS_PRICE, //int price; + ( 1 << S2 )|( 1 << S3 ), //int stages + SLOT_WEAPON, //int slots; + "stasis", //char *weaponName; + "Stasis Gun", //char *weaponHumanName; + STASIS_BULLETS, //int maxAmmo; + 0, //int maxClips; + qtrue, //int infiniteAmmo; + qfalse, //int usesEnergy; + STASIS_REPEAT, //int repeatRate1; + STASIS_S_REPEAT, //int repeatRate2; + 0, //int repeatRate3; + 0, //int reloadTime; + STASIS_K_SCALE, //float knockbackScale; + qtrue, //qboolean hasAltMode; + qfalse, //qboolean hasThirdMode; + qfalse, //qboolean canZoom; + 90.0f, //float zoomFov; + qtrue, //qboolean purchasable; + 0, //int buildDelay; + WUT_HUMANS //WUTeam_t team; + }, + { WP_LUCIFER_CANNON, //int weaponNum; LCANNON_PRICE, //int price; ( 1 << S3 ), //int stages @@ -3146,6 +3248,30 @@ WUT_HUMANS //WUTeam_t team; }, { + WP_XAEL, //int weaponNum; + XAEL_PRICE, //int price; + ( 1 << S3 ), //int stages + SLOT_WEAPON, //int slots; + "xael", //char *weaponName; + "Xael", //char *weaponHumanName; + XAEL_AMMO, //int maxAmmo; + 0, //int maxClips; + qfalse, //int infiniteAmmo; + qtrue, //int usesEnergy; + XAEL_REPEAT, //int repeatRate1; + XAEL_CHARGEREPEAT, //int repeatRate2; + 0, //int repeatRate3; + XAEL_RELOAD, //int reloadTime; + XAEL_K_SCALE, //float knockbackScale; + qtrue, //qboolean hasAltMode; + qfalse, //qboolean hasThirdMode; + qfalse, //qboolean canZoom; + 90.0f, //float zoomFov; + qtrue, //qboolean purchasable; + 0, //int buildDelay; + WUT_HUMANS //WUTeam_t team; + }, + { WP_LAS_GUN, //int weaponNum; LASGUN_PRICE, //int price; ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages @@ -3163,8 +3289,8 @@ LASGUN_K_SCALE, //float knockbackScale; qfalse, //qboolean hasAltMode; qfalse, //qboolean hasThirdMode; - qfalse, //qboolean canZoom; - 90.0f, //float zoomFov; + qtrue, //qboolean canZoom; + 60.0f, //float zoomFov; qtrue, //qboolean purchasable; 0, //int buildDelay; WUT_HUMANS //WUTeam_t team; @@ -3277,12 +3403,12 @@ qtrue, //int infiniteAmmo; qfalse, //int usesEnergy; ABUILDER_BUILD_REPEAT,//int repeatRate1; - ABUILDER_BUILD_REPEAT,//int repeatRate2; - 0, //int repeatRate3; + ABUILDER_CLAW_REPEAT,//int repeatRate2; + ABUILDER_BLOB_REPEAT,//int repeatRate3; 0, //int reloadTime; 0.0f, //float knockbackScale; qtrue, //qboolean hasAltMode; - qfalse, //qboolean hasThirdMode; + qtrue, //qboolean hasThirdMode; qfalse, //qboolean canZoom; 90.0f, //float zoomFov; qtrue, //qboolean purchasable; @@ -3338,6 +3464,30 @@ WUT_ALIENS //WUTeam_t team; }, { + WP_ALEVEL0_UPG, //int weaponNum; + 0, //int price; + ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages + SLOT_WEAPON, //int slots; + "level0upg", //char *weaponName; + "Bite Upgrade", //char *weaponHumanName; + 0, //int maxAmmo; + 0, //int maxClips; + qtrue, //int infiniteAmmo; + qfalse, //int usesEnergy; + LEVEL0_BITE_REPEAT, //int repeatRate1; + 0, //int repeatRate2; + 0, //int repeatRate3; + 0, //int reloadTime; + LEVEL0_BITE_K_SCALE, //float knockbackScale; + qfalse, //qboolean hasAltMode; + qfalse, //qboolean hasThirdMode; + qfalse, //qboolean canZoom; + 90.0f, //float zoomFov; + qfalse, //qboolean purchasable; + 0, //int buildDelay; + WUT_ALIENS //WUTeam_t team; + }, + { WP_ALEVEL1, //int weaponNum; 0, //int price; ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages @@ -3416,12 +3566,12 @@ SLOT_WEAPON, //int slots; "level2upg", //char *weaponName; "Zap", //char *weaponHumanName; - 0, //int maxAmmo; + 3, //int maxAmmo; 0, //int maxClips; qtrue, //int infiniteAmmo; qfalse, //int usesEnergy; LEVEL2_CLAW_U_REPEAT, //int repeatRate1; - LEVEL2_AREAZAP_REPEAT,//int repeatRate2; + LEVEL2_BOUNCEBALL_REPEAT,//int repeatRate2; 0, //int repeatRate3; 0, //int reloadTime; LEVEL2_CLAW_U_K_SCALE,//float knockbackScale; @@ -3506,6 +3656,30 @@ WUT_ALIENS //WUTeam_t team; }, { + WP_ALEVEL4_UPG, //int weaponNum; + 0, //int price; + ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages + SLOT_WEAPON, //int slots; + "level4upg", //char *weaponName; + "Charge Upgrade", //char *weaponHumanName; + 1, //int maxAmmo; + 0, //int maxClips; + qtrue, //int infiniteAmmo; + qfalse, //int usesEnergy; + LEVEL4_CLAW_REPEAT, //int repeatRate1; + 0, //int repeatRate2; + LEVEL4_EBLOB_REPEAT, //int repeatRate3; + 0, //int reloadTime; + LEVEL4_CLAW_U_K_SCALE, //float knockbackScale; + qfalse, //qboolean hasAltMode; + qtrue, //qboolean hasThirdMode; + qfalse, //qboolean canZoom; + 90.0f, //float zoomFov; + qfalse, //qboolean purchasable; + 0, //int buildDelay; + WUT_ALIENS //WUTeam_t team; + }, + { WP_LOCKBLOB_LAUNCHER, //int weaponNum; 0, //int price; ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages @@ -4076,6 +4250,18 @@ WUT_HUMANS //WUTeam_t team; }, { + UP_AMMOPACK, //int upgradeNum; + AMMOPACK_PRICE, //int price; + ( 1 << S2 )|( 1 << S3 ), //int stages + SLOT_BACKPACK, //int slots; + "ammopack", //char *upgradeName; + "Ammo Pack", //char *upgradeHumanName; + "icons/iconu_ammopack", + qtrue, //qboolean purchasable + qfalse, //qboolean usable + WUT_HUMANS //WUTeam_t team; + }, + { UP_JETPACK, //int upgradeNum; JETPACK_PRICE, //int price; ( 1 << S2 )|( 1 << S3 ), //int stages @@ -4122,6 +4308,30 @@ qtrue, //qboolean purchasable qfalse, //qboolean usable WUT_HUMANS //WUTeam_t team; + }, + { + UP_REGEN, //int upgradeNum; + REGEN_PRICE, //int price; + ( 1 << S1 )|( 1 << S2 )|( 1 << S3 ), //int stages + SLOT_NONE, //int slots; + "regen", //char *upgradeName; + "Biokit", //char *upgradeHumanName; + "icons/iconu_regen", + qtrue, //qboolean purchasable + qfalse, //qboolean usable + WUT_HUMANS //WUTeam_t team; + }, + { + UP_SURGE, //int upgradeNum; + SURGE_PRICE, //int price; + ( 1 << S2 )|( 1 << S3 ), //int stages + SLOT_NONE, //int slots; + "surge", //char *upgradeName; + "Surge", //char *upgradeHumanName; + "icons/iconu_surge", + qtrue, //qboolean purchasable + qfalse, //qboolean usable + WUT_HUMANS //WUTeam_t team; } }; @@ -4844,12 +5054,17 @@ { int maxAmmo, maxClips; int ammo, clips; + qboolean isEnergy = BG_FindUsesEnergyForWeapon( weapon ); BG_FindAmmoForWeapon( weapon, &maxAmmo, &maxClips ); BG_UnpackAmmoArray( weapon, psAmmo, psAmmo2, &ammo, &clips ); - if( BG_InventoryContainsUpgrade( UP_BATTPACK, stats ) ) + if( ( BG_InventoryContainsUpgrade( UP_BATTPACK, stats ) || + BG_InventoryContainsUpgrade( UP_BATTLESUIT, stats ) ) && isEnergy ) maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER ); + else if( ( BG_InventoryContainsUpgrade( UP_AMMOPACK, stats ) || + BG_InventoryContainsUpgrade( UP_BATTLESUIT, stats ) ) && !isEnergy ) + maxClips = (int)( 1 + (float)(maxClips) * AMMOPACK_MODIFIER ); return ( maxAmmo == ammo ) && ( maxClips == clips ); } Index: src/game/bg_pmove.c =================================================================== --- src/game/bg_pmove.c (revision 894) +++ src/game/bg_pmove.c (working copy) @@ -389,7 +389,7 @@ } } - if( pm->ps->weapon == WP_ALEVEL4 && pm->ps->pm_flags & PMF_CHARGE ) + if( ( pm->ps->weapon == WP_ALEVEL4 || pm->ps->weapon == WP_ALEVEL4_UPG ) && pm->ps->pm_flags & PMF_CHARGE ) modifier *= ( 1.0f + ( pm->ps->stats[ STAT_MISC ] / (float)LEVEL4_CHARGE_TIME ) * ( LEVEL4_CHARGE_SPEED - 1.0f ) ); @@ -398,6 +398,11 @@ cmd->buttons & BUTTON_ATTACK2 ) modifier *= LEVEL3_POUNCE_SPEED_MOD; + //slow player if charging up for a drill + if(pm->ps->weapon == WP_ALEVEL0_UPG && + cmd->buttons & BUTTON_ATTACK2 ) + modifier *= LEVEL0_DRILL_SPEED_MOD; + //slow the player if slow locked if( pm->ps->stats[ STAT_STATE ] & SS_SLOWLOCKED ) modifier *= ABUILDER_BLOB_SPEED_MOD; @@ -483,7 +488,7 @@ */ static void PM_CheckCharge( void ) { - if( pm->ps->weapon != WP_ALEVEL4 ) + if( pm->ps->weapon != WP_ALEVEL4 && pm->ps->weapon != WP_ALEVEL4_UPG ) return; if( pm->cmd.buttons & BUTTON_ATTACK2 && @@ -507,7 +512,8 @@ static qboolean PM_CheckPounce( void ) { if( pm->ps->weapon != WP_ALEVEL3 && - pm->ps->weapon != WP_ALEVEL3_UPG ) + pm->ps->weapon != WP_ALEVEL3_UPG && + pm->ps->weapon != WP_ALEVEL0_UPG ) return qfalse; if( pm->cmd.buttons & BUTTON_ATTACK2 ) @@ -664,6 +670,10 @@ if( BG_ClassHasAbility( pm->ps->stats[ STAT_PCLASS ], SCA_WALLJUMPER ) ) return PM_CheckWallJump( ); + if( ( pm->ps->weapon == WP_ALEVEL0_UPG ) && + pm->ps->stats[ STAT_MISC ] > 0 ) + return qfalse; + //can't jump and pounce at the same time if( ( pm->ps->weapon == WP_ALEVEL3 || pm->ps->weapon == WP_ALEVEL3_UPG ) && @@ -671,7 +681,8 @@ return qfalse; //can't jump and charge at the same time - if( ( pm->ps->weapon == WP_ALEVEL4 ) && + if( ( pm->ps->weapon == WP_ALEVEL4 || + pm->ps->weapon == WP_ALEVEL4_UPG ) && pm->ps->stats[ STAT_MISC ] > 0 ) return qfalse; @@ -2279,7 +2290,7 @@ BG_FindBBoxForClass( pm->ps->stats[ STAT_PCLASS ], PCmins, PCmaxs, PCcmaxs, NULL, NULL ); BG_FindViewheightForClass( pm->ps->stats[ STAT_PCLASS ], &PCvh, &PCcvh ); - + //TA: iD bug? you can still crouch when you're a spectator if( pm->ps->persistant[ PERS_TEAM ] == TEAM_SPECTATOR ) PCcvh = PCvh; @@ -2330,6 +2341,13 @@ pm->maxs[ 2 ] = PCmaxs[ 2 ]; pm->ps->viewheight = PCvh; } + + if( BG_InventoryContainsUpgrade( UP_BATTLESUIT, pm->ps->stats ) ) + { + pm->ps->viewheight *= 1.4f; + pm->maxs[ 2 ] *= 1.4f; + } + } @@ -2445,7 +2463,7 @@ { bobmove = 0.4f; // faster speeds bob faster - if( pm->ps->weapon == WP_ALEVEL4 && pm->ps->pm_flags & PMF_CHARGE ) + if( ( pm->ps->weapon == WP_ALEVEL4 || pm->ps->weapon == WP_ALEVEL4_UPG ) && pm->ps->pm_flags & PMF_CHARGE ) PM_ContinueLegsAnim( NSPA_CHARGE ); else if( pm->ps->pm_flags & PMF_BACKWARDS_RUN ) { @@ -2602,6 +2620,9 @@ //special case to prevent storing a charged up lcannon if( pm->ps->weapon == WP_LUCIFER_CANNON ) pm->ps->stats[ STAT_MISC ] = 0; + //special case to prevent storing a charged up xael + if( pm->ps->weapon == WP_XAEL ) + pm->ps->stats[ STAT_MISC ] = 0; PM_AddEvent( EV_CHANGE_WEAPON ); pm->ps->weaponstate = WEAPON_DROPPING; @@ -2772,6 +2793,10 @@ BG_UnpackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, &ammo, &clips ); BG_FindAmmoForWeapon( pm->ps->weapon, NULL, &maxClips ); + if( !BG_FindUsesEnergyForWeapon( pm->ps->weapon ) && + ( BG_InventoryContainsUpgrade( UP_AMMOPACK, pm->ps->stats ) || + BG_InventoryContainsUpgrade( UP_BATTLESUIT, pm->ps->stats ) ) ) + maxClips = (int)( 1 + (float)maxClips * AMMOPACK_MODIFIER ); // check for out of ammo if( !ammo && !clips && !BG_FindInfinteAmmoForWeapon( pm->ps->weapon ) ) @@ -2795,7 +2820,8 @@ } if( BG_FindUsesEnergyForWeapon( pm->ps->weapon ) && - BG_InventoryContainsUpgrade( UP_BATTPACK, pm->ps->stats ) ) + ( BG_InventoryContainsUpgrade( UP_BATTPACK, pm->ps->stats ) || + BG_InventoryContainsUpgrade( UP_BATTLESUIT, pm->ps->stats ) ) ) ammo = (int)( (float)ammo * BATTPACK_MODIFIER ); BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips ); @@ -2827,6 +2853,7 @@ switch( pm->ps->weapon ) { case WP_ALEVEL0: + case WP_ALEVEL0_UPG: //venom is only autohit attack1 = attack2 = attack3 = qfalse; @@ -2882,7 +2909,51 @@ } break; + case WP_XAEL: + attack1 = pm->cmd.buttons & BUTTON_ATTACK; + attack2 = pm->cmd.buttons & BUTTON_ATTACK2; + attack3 = pm->cmd.buttons & BUTTON_USE_HOLDABLE; + + if( ( attack1 || pm->ps->stats[ STAT_MISC ] == 0 ) && !attack2 && !attack3 ) + { + if( pm->ps->stats[ STAT_MISC ] < XAEL_TOTAL_CHARGE ) + { + pm->ps->weaponTime = 0; + pm->ps->weaponstate = WEAPON_READY; + return; + } + else + attack1 = !attack1; + } + + //erp this looks confusing + if( pm->ps->stats[ STAT_MISC ] > XAEL_MIN_CHARGE ) + attack1 = !attack1; + else if( pm->ps->stats[ STAT_MISC ] > 0 ) + { + pm->ps->stats[ STAT_MISC ] = 0; + pm->ps->weaponTime = 0; + pm->ps->weaponstate = WEAPON_READY; + return; + } + break; + + case WP_SHOTGUN: + //by default primary and secondary attacks are allowed + attack1 = pm->cmd.buttons & BUTTON_ATTACK; + attack2 = pm->cmd.buttons & BUTTON_ATTACK2; + attack3 = pm->cmd.buttons & BUTTON_USE_HOLDABLE; + + if( !attack1 && !attack2 && !attack3 ) + { + pm->ps->weaponTime = 0; + pm->ps->weaponstate = WEAPON_READY; + return; + } + break; + case WP_MASS_DRIVER: + case WP_LAS_GUN: attack1 = pm->cmd.buttons & BUTTON_ATTACK; // attack2 is handled on the client for zooming (cg_view.c) @@ -2921,6 +2992,12 @@ pm->ps->weaponTime += 200; return; } + else if( pm->ps->weapon == WP_ALEVEL4_UPG && !ammo ) + { + PM_AddEvent( EV_NOAMMO ); + pm->ps->weaponTime += 200; + return; + } pm->ps->generic1 = WPM_TERTIARY; PM_AddEvent( EV_FIRE_WEAPON3 ); @@ -2938,6 +3015,25 @@ { if( BG_WeaponHasAltMode( pm->ps->weapon ) ) { + if( pm->ps->weapon == WP_SHOTGUN && !clips ) + { + PM_AddEvent( EV_NOAMMO ); + pm->ps->weaponTime += 200; + return; + } + else if( pm->ps->weapon == WP_ALEVEL2_UPG && !ammo ) + { + PM_AddEvent( EV_NOAMMO ); + pm->ps->weaponTime += 200; + return; + } + else if( pm->ps->weapon == WP_STASIS_GUN && !ammo ) + { + PM_AddEvent( EV_NOAMMO ); + pm->ps->weaponTime += 200; + return; + } + pm->ps->generic1 = WPM_SECONDARY; PM_AddEvent( EV_FIRE_WEAPON2 ); addTime = BG_FindRepeatRate2ForWeapon( pm->ps->weapon ); @@ -2955,6 +3051,9 @@ pm->ps->generic1 = WPM_PRIMARY; PM_AddEvent( EV_FIRE_WEAPON ); addTime = BG_FindRepeatRate1ForWeapon( pm->ps->weapon ); + if( BG_InventoryContainsUpgrade( UP_SURGE, pm->ps->stats ) && + ( pm->ps->weapon==WP_LAS_GUN || pm->ps->weapon==WP_MASS_DRIVER ) ) + addTime -= addTime / 3; } //TA: fire events for autohit weapons @@ -2963,6 +3062,7 @@ switch( pm->ps->weapon ) { case WP_ALEVEL0: + case WP_ALEVEL0_UPG: pm->ps->generic1 = WPM_PRIMARY; PM_AddEvent( EV_FIRE_WEAPON ); addTime = BG_FindRepeatRate1ForWeapon( pm->ps->weapon ); @@ -3003,18 +3103,25 @@ } else { - if( pm->ps->weapon == WP_ALEVEL4 ) + if( pm->ps->weapon == WP_ALEVEL4 || pm->ps->weapon == WP_ALEVEL4_UPG ) { - //hack to get random attack animations - //FIXME: does pm->ps->weaponTime cycle enough? - int num = abs( pm->ps->weaponTime ) % 3; + if(attack1||attack2) + { + //hack to get random attack animations + //FIXME: does pm->ps->weaponTime cycle enough? + int num = abs( pm->ps->weaponTime ) % 3; - if( num == 0 ) - PM_ForceLegsAnim( NSPA_ATTACK1 ); - else if( num == 1 ) - PM_ForceLegsAnim( NSPA_ATTACK2 ); - else if( num == 2 ) - PM_ForceLegsAnim( NSPA_ATTACK3 ); + if( num == 0 ) + PM_ForceLegsAnim( NSPA_ATTACK1 ); + else if( num == 1 ) + PM_ForceLegsAnim( NSPA_ATTACK2 ); + else if( num == 2 ) + PM_ForceLegsAnim( NSPA_ATTACK3 ); + } + else if(attack3) + { + PM_ForceLegsAnim( NSPA_GESTURE ); + } } else { @@ -3043,6 +3150,24 @@ if( ammo < 0 ) ammo = 0; } + //special case for xael + else if( pm->ps->weapon == WP_XAEL && attack1 && !attack2 ) + { + ammo -= (int)( ceil( ( (float)pm->ps->stats[ STAT_MISC ] / (float)XAEL_TOTAL_CHARGE ) * 10.0f ) ); + + //stay on the safe side + if( ammo < 0 ) + ammo = 0; + } + //special case for xael + else if( pm->ps->weapon == WP_SHOTGUN && attack2 && !attack1 ) + { + clips--; + + //stay on the safe side + if( clips < 0 ) + clips = 0; + } else ammo--; @@ -3054,6 +3179,24 @@ ammo--; BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips ); } + else if( pm->ps->weapon == WP_STASIS_GUN && attack2 ) + { + //special case for stasis_gun + ammo--; + BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips ); + } + else if( pm->ps->weapon == WP_ALEVEL2_UPG && attack2 ) + { + //special case for slowblob + ammo--; + BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips ); + } + else if( pm->ps->weapon == WP_ALEVEL4_UPG && attack3 ) + { + //special case for eblob + ammo--; + BG_PackAmmoArray( pm->ps->weapon, pm->ps->ammo, pm->ps->powerups, ammo, clips ); + } //FIXME: predicted angles miss a problem?? if( pm->ps->weapon == WP_CHAINGUN ) Index: src/game/bg_public.h =================================================================== --- src/game/bg_public.h (revision 894) +++ src/game/bg_public.h (working copy) @@ -28,10 +28,12 @@ // because games can change separately from the main system version, we need a // second version that must match between game and cgame -#define GAME_VERSION "base" +#define GAME_VERSION "tremx" #define DEFAULT_GRAVITY 800 +#define GIB_HEALTH -10 + #define VOTE_TIME 30000 // 30 seconds before vote times out #define MINS_Z -24 @@ -342,6 +344,7 @@ WP_NONE, WP_ALEVEL0, + WP_ALEVEL0_UPG, WP_ALEVEL1, WP_ALEVEL1_UPG, WP_ALEVEL2, @@ -349,6 +352,7 @@ WP_ALEVEL3, WP_ALEVEL3_UPG, WP_ALEVEL4, + WP_ALEVEL4_UPG, WP_BLASTER, WP_MACHINEGUN, @@ -358,8 +362,10 @@ WP_MASS_DRIVER, WP_CHAINGUN, WP_PULSE_RIFLE, + WP_STASIS_GUN, WP_FLAMER, WP_LUCIFER_CANNON, + WP_XAEL, WP_GRENADE, WP_LOCKBLOB_LAUNCHER, @@ -385,11 +391,15 @@ UP_HELMET, UP_MEDKIT, UP_BATTPACK, + UP_AMMOPACK, UP_JETPACK, UP_BATTLESUIT, UP_GRENADE, UP_AMMO, + + UP_REGEN, + UP_SURGE, UP_NUM_UPGRADES } upgrade_t; @@ -802,6 +812,7 @@ //offensive classes PCL_ALIEN_LEVEL0, + PCL_ALIEN_LEVEL0_UPG, PCL_ALIEN_LEVEL1, PCL_ALIEN_LEVEL1_UPG, PCL_ALIEN_LEVEL2, @@ -809,6 +820,7 @@ PCL_ALIEN_LEVEL3, PCL_ALIEN_LEVEL3_UPG, PCL_ALIEN_LEVEL4, + PCL_ALIEN_LEVEL4_UPG, //human class PCL_HUMAN, @@ -839,10 +851,13 @@ MOD_MACHINEGUN, MOD_CHAINGUN, MOD_PRIFLE, + MOD_STASIS, MOD_MDRIVER, MOD_LASGUN, MOD_LCANNON, MOD_LCANNON_SPLASH, + MOD_XAEL, + MOD_XAEL_SPLASH, MOD_FLAMER, MOD_FLAMER_SPLASH, MOD_GRENADE, @@ -860,13 +875,15 @@ MOD_LEVEL0_BITE, MOD_LEVEL1_CLAW, MOD_LEVEL1_PCLOUD, + MOD_LEVEL2_CLAW, + MOD_LEVEL2_ZAP, + MOD_LEVEL2_BOUNCEBALL, MOD_LEVEL3_CLAW, MOD_LEVEL3_POUNCE, MOD_LEVEL3_BOUNCEBALL, - MOD_LEVEL2_CLAW, - MOD_LEVEL2_ZAP, MOD_LEVEL4_CLAW, MOD_LEVEL4_CHARGE, + MOD_LEVEL4_EBLOB, MOD_SLOWBLOB, MOD_POISON, Index: src/game/g_active.c =================================================================== --- src/game/g_active.c (revision 894) +++ src/game/g_active.c (working copy) @@ -275,7 +275,8 @@ other->client->unlaggedCalc.used = qfalse; //charge attack - if( ent->client->ps.weapon == WP_ALEVEL4 && + if( (ent->client->ps.weapon == WP_ALEVEL4 || + ent->client->ps.weapon == WP_ALEVEL4_UPG) && ent->client->ps.stats[ STAT_MISC ] > 0 && ent->client->charging ) ChargeAttack( ent, other ); @@ -512,12 +513,13 @@ { gclient_t *client; usercmd_t *ucmd; - int aForward, aRight; + int aForward, aRight, aUp; ucmd = &ent->client->pers.cmd; aForward = abs( ucmd->forwardmove ); aRight = abs( ucmd->rightmove ); + aUp = abs( ucmd->upmove ); client = ent->client; client->time100 += msec; @@ -586,9 +588,36 @@ if( client->ps.stats[ STAT_MISC ] > pounceSpeed ) client->ps.stats[ STAT_MISC ] = pounceSpeed; } + + //client is charging up for a... charge + if( client->ps.weapon == WP_ALEVEL1_UPG ) + { + client->ps.eFlags &= ~EF_MOVER_STOP; + if( aForward <= 5 && aRight <= 5 && aUp <= 5 &&!( ucmd->buttons & BUTTON_ATTACK ) ) + client->ps.eFlags |= EF_MOVER_STOP; + + else if(client->ps.stats[ STAT_STATE ] & SS_BOOSTED) + client->ps.eFlags |= EF_MOVER_STOP; + } + //client is charging up for a drill + if( client->ps.weapon == WP_ALEVEL0_UPG ) + { + if( client->ps.stats[ STAT_MISC ] < LEVEL0_DRILL_SPEED && ucmd->buttons & BUTTON_ATTACK2 ) + client->ps.stats[ STAT_MISC ] += ( 100.0f / (float)LEVEL0_DRILL_CHARGE_TIME ) * LEVEL0_DRILL_SPEED; + + if( !( ucmd->buttons & BUTTON_ATTACK2 ) ) + { + if( client->pmext.pouncePayload > 0 ) + client->allowedToPounce = qtrue; + } + + if( client->ps.stats[ STAT_MISC ] > LEVEL0_DRILL_SPEED ) + client->ps.stats[ STAT_MISC ] = LEVEL0_DRILL_SPEED; + } + //client is charging up for a... charge - if( client->ps.weapon == WP_ALEVEL4 ) + if( client->ps.weapon == WP_ALEVEL4 || client->ps.weapon == WP_ALEVEL4_UPG ) { if( client->ps.stats[ STAT_MISC ] < LEVEL4_CHARGE_TIME && ucmd->buttons & BUTTON_ATTACK2 && !client->charging ) @@ -662,6 +691,23 @@ client->ps.stats[ STAT_MISC ] = ammo * LCANNON_TOTAL_CHARGE / 10; } + //client is charging up a xael + if( client->ps.weapon == WP_XAEL ) + { + int ammo; + + BG_UnpackAmmoArray( WP_XAEL, client->ps.ammo, client->ps.powerups, &ammo, NULL ); + + if( client->ps.stats[ STAT_MISC ] < XAEL_TOTAL_CHARGE && ucmd->buttons & BUTTON_ATTACK ) + client->ps.stats[ STAT_MISC ] += ( 100.0f / XAEL_CHARGE_TIME ) * XAEL_TOTAL_CHARGE; + + if( client->ps.stats[ STAT_MISC ] > XAEL_TOTAL_CHARGE ) + client->ps.stats[ STAT_MISC ] = XAEL_TOTAL_CHARGE; + + if( client->ps.stats[ STAT_MISC ] > ( ammo * XAEL_TOTAL_CHARGE ) / 10 ) + client->ps.stats[ STAT_MISC ] = ammo * XAEL_TOTAL_CHARGE / 10; + } + switch( client->ps.weapon ) { case WP_ABUILD: @@ -735,6 +781,21 @@ { client->time1000 -= 1000; + //charge stasis gun + if( client->ps.weapon == WP_STASIS_GUN ) + { + int ammo, maxAmmo; + + BG_FindAmmoForWeapon( WP_STASIS_GUN, &maxAmmo, NULL ); + BG_UnpackAmmoArray( WP_STASIS_GUN, client->ps.ammo, client->ps.powerups, &ammo, NULL ); + + if( ammo < maxAmmo ) + { + ammo++; + BG_PackAmmoArray( WP_STASIS_GUN, client->ps.ammo, client->ps.powerups, ammo, 0 ); + } + } + //client is poison clouded if( client->ps.stats[ STAT_STATE ] & SS_POISONCLOUDED ) G_Damage( ent, client->lastPoisonCloudedClient, client->lastPoisonCloudedClient, NULL, NULL, @@ -780,7 +841,8 @@ boostEntity = &g_entities[ entityList[ i ] ]; if( boostEntity->client && boostEntity->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS && - boostEntity->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_LEVEL4 ) + ( boostEntity->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_LEVEL4 || + boostEntity->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_LEVEL4_UPG ) ) { modifier = LEVEL4_REGEN_MOD; break; @@ -801,6 +863,21 @@ if( ent->health > client->ps.stats[ STAT_MAX_HEALTH ] ) ent->health = client->ps.stats[ STAT_MAX_HEALTH ]; } + //use regen upgrade + if( BG_InventoryContainsUpgrade( UP_REGEN, client->ps.stats ) ) + { + //regen health + if( ent->health > 0 && ent->health < client->ps.stats[ STAT_MAX_HEALTH ] && + ( ent->lastDamageTime + ALIEN_REGEN_DAMAGE_TIME ) < level.time ) + ent->health += REGEN_HEALTH_RATE; + if( ent->health > client->ps.stats[ STAT_MAX_HEALTH ] ) + ent->health = client->ps.stats[ STAT_MAX_HEALTH ]; + //regen stamina + if( client->ps.stats[ STAT_STAMINA ] < MAX_STAMINA ) + client->ps.stats[ STAT_STAMINA ] += REGEN_STAMINA_RATE; + else + client->ps.stats[ STAT_STAMINA ] = MAX_STAMINA; + } } while( client->time10000 >= 10000 ) @@ -820,6 +897,32 @@ BG_PackAmmoArray( WP_ALEVEL3_UPG, client->ps.ammo, client->ps.powerups, ammo, 0 ); } } + else if( client->ps.weapon == WP_ALEVEL2_UPG ) + { + int ammo, maxAmmo; + + BG_FindAmmoForWeapon( WP_ALEVEL2_UPG, &maxAmmo, NULL ); + BG_UnpackAmmoArray( WP_ALEVEL2_UPG, client->ps.ammo, client->ps.powerups, &ammo, NULL ); + + if( ammo < maxAmmo ) + { + ammo++; + BG_PackAmmoArray( WP_ALEVEL2_UPG, client->ps.ammo, client->ps.powerups, ammo, 0 ); + } + } + else if( client->ps.weapon == WP_ALEVEL4_UPG ) + { + int ammo, maxAmmo; + + BG_FindAmmoForWeapon( WP_ALEVEL4_UPG, &maxAmmo, NULL ); + BG_UnpackAmmoArray( WP_ALEVEL4_UPG, client->ps.ammo, client->ps.powerups, &ammo, NULL ); + //near booster regain ammo + if( (ammo < maxAmmo) && (client->ps.stats[ STAT_STATE ] & SS_BOOSTED) ) + { + ammo++; + BG_PackAmmoArray( WP_ALEVEL4_UPG, client->ps.ammo, client->ps.powerups, ammo, 0 ); + } + } } } @@ -1456,6 +1559,11 @@ pm.autoWeaponHit[ client->ps.weapon ] = CheckVenomAttack( ent ); break; + case WP_ALEVEL0_UPG: + if( client->ps.weaponTime <= 0 ) + pm.autoWeaponHit[ client->ps.weapon ] = CheckVenomAttack2( ent ); + break; + case WP_ALEVEL1: case WP_ALEVEL1_UPG: CheckGrabAttack( ent ); @@ -1647,8 +1755,8 @@ if( client->ps.stats[ STAT_HEALTH ] <= 0 ) { // wait for the attack button to be pressed - if( level.time > client->respawnTime ) - { + //if( level.time > client->respawnTime ) + //{ // forcerespawn is to prevent users from waiting out powerups if( g_forcerespawn.integer > 0 && ( level.time - client->respawnTime ) > 0 ) @@ -1658,11 +1766,11 @@ } // pressing attack or use is the normal respawn method - if( ucmd->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) ) + if( ucmd->buttons & ( BUTTON_ATTACK2 | BUTTON_USE_HOLDABLE ) ) { respawn( ent ); } - } + //} return; } Index: src/game/g_buildable.c =================================================================== --- src/game/g_buildable.c (revision 894) +++ src/game/g_buildable.c (working copy) @@ -191,7 +191,9 @@ continue; //if entity is a power item calculate the distance to it - if( ( ent->s.modelindex == BA_H_REACTOR || ent->s.modelindex == BA_H_REPEATER ) && + if( ( ent->s.modelindex == BA_H_REACTOR + || ent->s.modelindex == BA_H_REPEATER + || ent->s.modelindex == BA_H_SPAWN ) && ent->spawned ) { VectorSubtract( self->s.origin, ent->s.origin, temp_v ); @@ -201,7 +203,9 @@ ( ( ent->s.modelindex == BA_H_REACTOR && distance <= REACTOR_BASESIZE ) || ( ent->s.modelindex == BA_H_REPEATER && - distance <= REPEATER_BASESIZE ) ) ) { + distance <= REPEATER_BASESIZE ) || + ( ent->s.modelindex == BA_H_SPAWN && + distance <= HSPAWN_BASESIZE ) ) ) { closestPower = ent; minDistance = distance; @@ -885,16 +889,43 @@ */ void ABarricade_Think( gentity_t *self ) { + int entityList[ MAX_GENTITIES ]; + vec3_t range = { BARRICADE_ATTACK_RANGE, BARRICADE_ATTACK_RANGE, BARRICADE_ATTACK_RANGE }; + vec3_t mins, maxs; + int i, num, dmgTimer=0; + gentity_t *enemy; + + VectorAdd( self->s.origin, range, maxs ); + VectorSubtract( self->s.origin, range, mins ); + //if there is no creep nearby die if( !G_FindCreep( self ) ) { G_Damage( self, NULL, NULL, NULL, NULL, 10000, 0, MOD_SUICIDE ); return; } + + if( self->spawned && G_FindOvermind( self ) ) + { + //do some damage + num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); + for( i = 0; i < num; i++ ) + { + enemy = &g_entities[ entityList[ i ] ]; + if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) + { + self->timestamp = level.time; + G_SelectiveRadiusDamage( self->s.pos.trBase, self, BARRICADE_ATTACK_DAMAGE, + BARRICADE_ATTACK_RANGE, self, MOD_HSPAWN, PTE_ALIENS ); + G_SetBuildableAnim( self, BANIM_PAIN1, qfalse ); + dmgTimer=BARRICADE_ATTACK_TIMER; + } + } + } G_CreepSlow( self ); - self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); + self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ) + dmgTimer; } @@ -2282,11 +2313,55 @@ { gentity_t *ent; + int i; + qboolean reactor = qfalse; + + int entityList[ MAX_GENTITIES ]; + vec3_t range = { HSPAWN_ATTACK_RANGE, HSPAWN_ATTACK_RANGE, HSPAWN_ATTACK_RANGE }; + vec3_t mins, maxs; + int num, dmgTimer=0; + gentity_t *enemy, *tent; + + VectorAdd( self->s.origin, range, maxs ); + VectorSubtract( self->s.origin, range, mins ); + //make sure we have power - self->powered = G_FindPower( self ); + //self->powered = G_FindPower( self ); if( self->spawned ) { + //iterate through entities + for ( i = 1, ent = g_entities + i; i < level.num_entities; i++, ent++ ) + { + if( ent->s.eType != ET_BUILDABLE ) + continue; + + if( ent->s.modelindex == BA_H_REACTOR && ent->spawned ) + reactor = qtrue; + } + + //do some damage + num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); + for( i = 0; i < num; i++ ) + { + enemy = &g_entities[ entityList[ i ] ]; + + if( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS && reactor ) + { + self->timestamp = level.time; + G_SelectiveRadiusDamage( self->s.pos.trBase, self, HSPAWN_ATTACK_DAMAGE, + HSPAWN_ATTACK_RANGE, self, MOD_HSPAWN, PTE_HUMANS ); + + tent = G_TempEntity( enemy->s.pos.trBase, EV_TESLATRAIL ); + + VectorCopy( self->s.pos.trBase, tent->s.origin2 ); + + tent->s.generic1 = self->s.number; //src + tent->s.clientNum = enemy->s.number; //dest + dmgTimer = HSPAWN_ATTACK_TIMER; + } + } + //only suicide if at rest if( self->s.groundEntityNum ) { @@ -2316,7 +2391,9 @@ self->lastHealth = self->health; } - self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ); + self->powered = reactor; + + self->nextthink = level.time + BG_FindNextThinkForBuildable( self->s.modelindex ) + dmgTimer; } @@ -2434,6 +2511,9 @@ else if( ent->biteam == BIT_ALIENS && ent->health > 0 && ent->health < bHealth && bRegen && ( ent->lastDamageTime + ALIEN_REGEN_DAMAGE_TIME ) < level.time ) ent->health += bRegen; + else if( ent->biteam == BIT_HUMANS && ent->health > 0 && ent->health < bHealth && + bRegen && G_IsDCCBuilt() && ( ent->lastDamageTime + HUMAN_REGEN_DAMAGE_TIME ) < level.time ) + ent->health += bRegen; if( ent->health > bHealth ) ent->health = bHealth; @@ -2821,7 +2901,8 @@ if( !G_IsPowered( entity_origin ) ) { //tell player to build a repeater to provide power - if( buildable != BA_H_REACTOR && buildable != BA_H_REPEATER ) + if( buildable != BA_H_REACTOR && buildable != BA_H_REPEATER && + buildable != BA_H_SPAWN) reason = IBE_REPEATER; } @@ -2866,6 +2947,28 @@ reason = IBE_RPTWARN2; } + //check that there is a parent reactor when building a spawn + if( buildable == BA_H_SPAWN ) + { + for ( i = 1, tempent = g_entities + i; i < level.num_entities; i++, tempent++ ) + { + if( tempent->s.eType != ET_BUILDABLE ) + continue; + + if( tempent->s.modelindex == BA_H_REACTOR ) + break; + } + + if( i >= level.num_entities ) + { + //no reactor present + if( reason == IBE_NONE ) + reason = IBE_REPEATER; + } + //else if( G_isPower( entity_origin ) ) + // reason = IBE_RPTWARN2; + } + //check permission to build here if( tr1.surfaceFlags & SURF_NOHUMANBUILD || tr1.surfaceFlags & SURF_NOBUILD || contents & CONTENTS_NOHUMANBUILD || contents & CONTENTS_NOBUILD ) @@ -3137,6 +3240,19 @@ trap_LinkEntity( built ); + if( builder->client ) + { + G_TeamCommand( builder->client->pers.teamSelection, + va( "print \"%s ^3PLACED^7 by %s^7\n\"", + BG_FindHumanNameForBuildable( built->s.modelindex ), + builder->client->pers.netname ) ); + G_LogPrintf("Build: %i %i 0: %s^7 is ^2building^7 %s\n", + builder->client->ps.clientNum, + built->s.modelindex, + builder->client->pers.netname, + BG_FindNameForBuildable( built->s.modelindex ) ); + } + return built; } Index: src/game/g_cmds.c =================================================================== --- src/game/g_cmds.c (revision 894) +++ src/game/g_cmds.c (working copy) @@ -276,6 +276,12 @@ upgrade = UP_JETPACK; else if( BG_InventoryContainsUpgrade( UP_BATTPACK, cl->ps.stats ) ) upgrade = UP_BATTPACK; + else if( BG_InventoryContainsUpgrade( UP_AMMOPACK, cl->ps.stats ) ) + upgrade = UP_AMMOPACK; + else if( BG_InventoryContainsUpgrade( UP_REGEN, cl->ps.stats ) ) + upgrade = UP_REGEN; + else if( BG_InventoryContainsUpgrade( UP_SURGE, cl->ps.stats ) ) + upgrade = UP_SURGE; else if( BG_InventoryContainsUpgrade( UP_HELMET, cl->ps.stats ) ) upgrade = UP_HELMET; else if( BG_InventoryContainsUpgrade( UP_LIGHTARMOUR, cl->ps.stats ) ) @@ -1476,7 +1482,7 @@ } #define EVOLVE_TRACE_HEIGHT 128.0f -#define AS_OVER_RT3 ((ALIENSENSE_RANGE*0.5f)/M_ROOT3) +#define AS_OVER_RT3 ((ALIENSENSE_RANGE*0.20f)/M_ROOT3) /* ================= @@ -1511,12 +1517,12 @@ clientNum = ent->client - level.clients; trap_Argv( 1, s, sizeof( s ) ); - if( BG_ClassIsAllowed( PCL_ALIEN_BUILDER0 ) ) - allowedClasses[ numClasses++ ] = PCL_ALIEN_BUILDER0; + //if( BG_ClassIsAllowed( PCL_ALIEN_BUILDER0 ) ) + // allowedClasses[ numClasses++ ] = PCL_ALIEN_BUILDER0; - if( BG_ClassIsAllowed( PCL_ALIEN_BUILDER0_UPG ) && - BG_FindStagesForClass( PCL_ALIEN_BUILDER0_UPG, g_alienStage.integer ) ) - allowedClasses[ numClasses++ ] = PCL_ALIEN_BUILDER0_UPG; + //if( BG_ClassIsAllowed( PCL_ALIEN_BUILDER0_UPG ) && + // BG_FindStagesForClass( PCL_ALIEN_BUILDER0_UPG, g_alienStage.integer ) ) + // allowedClasses[ numClasses++ ] = PCL_ALIEN_BUILDER0_UPG; if( BG_ClassIsAllowed( PCL_ALIEN_LEVEL0 ) ) allowedClasses[ numClasses++ ] = PCL_ALIEN_LEVEL0; @@ -1559,7 +1565,7 @@ } } - if( !level.overmindPresent ) + if( !level.overmindPresent && newClass != PCL_ALIEN_BUILDER0 && newClass != PCL_ALIEN_BUILDER0_UPG ) { G_TriggerMenu( clientNum, MN_A_NOOVMND_EVOLVE ); return; @@ -2031,11 +2037,19 @@ //add to inventory BG_AddWeaponToInventory( weapon, ent->client->ps.stats ); BG_FindAmmoForWeapon( weapon, &maxAmmo, &maxClips ); + if( !BG_FindInfinteAmmoForWeapon( weapon ) ) + { + //battle suit has both battpack and ammopack - integrated :P + if( BG_FindUsesEnergyForWeapon( weapon ) && + ( BG_InventoryContainsUpgrade( UP_BATTPACK, ent->client->ps.stats ) || + BG_InventoryContainsUpgrade( UP_BATTLESUIT, ent->client->ps.stats ) ) ) + maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER ); + else if( !BG_FindUsesEnergyForWeapon( weapon ) && + ( BG_InventoryContainsUpgrade( UP_AMMOPACK, ent->client->ps.stats ) || + BG_InventoryContainsUpgrade( UP_BATTLESUIT, ent->client->ps.stats ) ) ) + maxClips = (int)( 1 + (float)(maxClips) * AMMOPACK_MODIFIER ); + } - if( BG_FindUsesEnergyForWeapon( weapon ) && - BG_InventoryContainsUpgrade( UP_BATTPACK, ent->client->ps.stats ) ) - maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER ); - BG_PackAmmoArray( weapon, ent->client->ps.ammo, ent->client->ps.powerups, maxAmmo, maxClips ); @@ -2102,6 +2116,12 @@ if( upgrade == UP_BATTPACK ) G_GiveClientMaxAmmo( ent, qtrue ); + if( upgrade == UP_AMMOPACK ) + G_GiveClientMaxAmmo( ent, qfalse ); + + if( upgrade == UP_BATTLESUIT ) + G_GiveClientMaxAmmo( ent, qtrue ); + //subtract from funds G_AddCreditToClient( ent->client, -(short)BG_FindPriceForUpgrade( upgrade ), qfalse ); } @@ -2196,6 +2216,11 @@ if( upgrade == UP_BATTPACK ) G_GiveClientMaxAmmo( ent, qtrue ); + if( upgrade == UP_AMMOPACK ) + G_GiveClientMaxAmmo( ent, qfalse ); + //second arg of G_GiveClientMaxAmmo is not used for battlesuit + if( upgrade == UP_BATTLESUIT ) + G_GiveClientMaxAmmo( ent, qtrue ); //add to funds G_AddCreditToClient( ent->client, (short)BG_FindPriceForUpgrade( upgrade ), qfalse ); @@ -2237,7 +2262,7 @@ { BG_RemoveUpgradeFromInventory( i, ent->client->ps.stats ); - if( i == UP_BATTPACK ) + if( i == UP_BATTPACK || i == UP_BATTLESUIT ) { int j; @@ -2253,6 +2278,22 @@ } } + if( i == UP_AMMOPACK || i == UP_BATTLESUIT ) + { + int j; + + //remove ammo + for( j = WP_NONE; j < WP_NUM_WEAPONS; j++ ) + { + if( BG_InventoryContainsWeapon( j, ent->client->ps.stats ) && + !BG_FindUsesEnergyForWeapon( j ) && + !BG_FindInfinteAmmoForWeapon( j ) ) + { + BG_PackAmmoArray( j, ent->client->ps.ammo, ent->client->ps.powerups, 0, 0 ); + } + } + } + //add to funds G_AddCreditToClient( ent->client, (short)BG_FindPriceForUpgrade( i ), qfalse ); } @@ -2665,7 +2706,162 @@ ent->client->lastPoisonClient = ent;*/ } +/* +================= +Cmd_Share_f +================= +*/ +void Cmd_Share_f( gentity_t *ent ) +{ + int i, clientNum = 0, creds = 0; + int clientNums[ MAX_CLIENTS ] = { -1 }; + char arg1[ MAX_STRING_TOKENS ]; + char arg2[ MAX_STRING_TOKENS ]; + pTeam_t team; + if( !ent || !ent->client || ( ent->client->pers.teamSelection == PTE_NONE ) ) + { + return; + } + + team = ent->client->pers.teamSelection; + trap_Argv( 1, arg1, sizeof( arg1 ) ); + trap_Argv( 2, arg2, sizeof( arg2 ) ); + + if( arg1[0] && !strchr( arg1, ';' ) ) // target player name is in arg1 + { + //check arg1 is a number + for( i = 0; arg1[ i ]; i++ ) + { + if( arg1[ i ] < '0' || arg1[ i ] > '9' ) + { + clientNum = -1; + break; + } + } + + if( clientNum >= 0 ) + { + clientNum = atoi( arg1 ); + } + else if( G_ClientNumbersFromString( arg1, clientNums ) == 1 ) + { + // there was one partial name match name was clientNum + clientNum = clientNums[ 0 ]; + } + else + { + // look for an exact name match before bailing out + clientNum = G_ClientNumberFromString( ent, arg1 ); + if( clientNum == -1 ) + { + trap_SendServerCommand( ent-g_entities, + "print \"share: invalid player\n\"" ); + return; + } + } + } + else // arg1 not set + { + vec3_t forward, end; + trace_t tr; + gentity_t *traceEnt; + + + // trace a teammate + AngleVectors( ent->client->ps.viewangles, forward, NULL, NULL ); + VectorMA( ent->client->ps.origin, 8192 * 16, forward, end ); + + trap_Trace( &tr, ent->client->ps.origin, NULL, NULL, end, ent->s.number, MASK_PLAYERSOLID ); + traceEnt = &g_entities[ tr.entityNum ]; + + if( tr.fraction < 1.0f && traceEnt->client && + ( traceEnt->client->pers.teamSelection == team ) ) + { + clientNum = traceEnt - g_entities; + } + else + { + trap_SendServerCommand( ent-g_entities, + "print \"share: no player to transfer credits to found.\n\"" ); + return; + } + } + + // verify target player team + if( ( clientNum < 0 ) || ( clientNum >= level.maxclients ) || + ( level.clients[ clientNum ].pers.teamSelection != team ) ) + { + trap_SendServerCommand( ent-g_entities, + "print \"share: not a valid player on your team.\n\"" ); + return; + } + + if( !arg1[0] || strchr( arg1, ';' ) || !arg2[0] || strchr( arg2, ';' ) ) + { + // default credit count + if( team == PTE_HUMANS ) + { + creds = FREEKILL_HUMAN; + } + else if( team == PTE_ALIENS ) + { + creds = FREEKILL_ALIEN; + } + } + else + { + //check arg2 is a number + for( i = 0; arg2[ i ]; i++ ) + { + if( arg2[ i ] < '0' || arg2[ i ] > '9' ) + { + trap_SendServerCommand( ent-g_entities, + "print \"Usage: share (name|slot#) (amount)\n\"" ); + break; + } + } + + // credit count from parameter + creds = atoi( arg2 ); + } + + // transfer only credits the player really has + if( creds > ent->client->ps.persistant[ PERS_CREDIT ] ) + { + creds = ent->client->ps.persistant[ PERS_CREDIT ]; + } + + // allow transfers only up to the credit/evo limit + if( ( team == PTE_HUMANS ) && + ( creds > HUMAN_MAX_CREDITS - level.clients[ clientNum ].ps.persistant[ PERS_CREDIT ] ) ) + { + creds = HUMAN_MAX_CREDITS - level.clients[ clientNum ].ps.persistant[ PERS_CREDIT ]; + } + else if( ( team == PTE_ALIENS ) && + ( creds > ALIEN_MAX_KILLS - level.clients[ clientNum ].ps.persistant[ PERS_CREDIT ] ) ) + { + creds = ALIEN_MAX_KILLS - level.clients[ clientNum ].ps.persistant[ PERS_CREDIT ]; + } + + if( creds <= 0 ) + { + trap_SendServerCommand( ent-g_entities, + "print \"share: no credits to transfer.\n\"" ); + return; + } + + // transfer credits + ent->client->ps.persistant[ PERS_CREDIT ] -= creds; + trap_SendServerCommand( ent-g_entities, + va( "print \"share: transfering %d credits to %s.\n\"", creds, + level.clients[ clientNum ].pers.netname ) ); + level.clients[ clientNum ].ps.persistant[ PERS_CREDIT ] += creds; + trap_SendServerCommand( clientNum, + va( "print \"You have received %d credits from %s.\n\"", creds, + ent->client->pers.netname) ); +} + /* ================= ClientCommand @@ -2779,6 +2975,8 @@ Cmd_PTRCRestore_f( ent ); else if( Q_stricmp( cmd, "test" ) == 0 ) Cmd_Test_f( ent ); + else if( Q_stricmp( cmd, "share" ) == 0 ) + Cmd_Share_f( ent ); else trap_SendServerCommand( clientNum, va( "print \"unknown cmd %s\n\"", cmd ) ); } Index: src/game/g_combat.c =================================================================== --- src/game/g_combat.c (revision 894) +++ src/game/g_combat.c (working copy) @@ -81,10 +81,13 @@ "MOD_MACHINEGUN", "MOD_CHAINGUN", "MOD_PRIFLE", + "MOD_STASIS", "MOD_MDRIVER", "MOD_LASGUN", "MOD_LCANNON", "MOD_LCANNON_SPLASH", + "MOD_XAEL", + "MOD_XAEL_SPLASH", "MOD_FLAMER", "MOD_FLAMER_SPLASH", "MOD_GRENADE", @@ -102,13 +105,15 @@ "MOD_LEVEL0_BITE", "MOD_LEVEL1_CLAW", "MOD_LEVEL1_PCLOUD", + "MOD_LEVEL2_CLAW", + "MOD_LEVEL2_ZAP", + "MOD_LEVEL2_BOUNCEBALL", "MOD_LEVEL3_CLAW", "MOD_LEVEL3_POUNCE", "MOD_LEVEL3_BOUNCEBALL", - "MOD_LEVEL2_CLAW", - "MOD_LEVEL2_ZAP", "MOD_LEVEL4_CLAW", "MOD_LEVEL4_CHARGE", + "MOD_LEVEL4_EBLOB", "MOD_SLOWBLOB", "MOD_POISON", @@ -392,7 +397,7 @@ // don't allow respawn until the death anim is done // g_forcerespawn may force spawning at some later time - self->client->respawnTime = level.time + 1700; + self->client->respawnTime = level.time + 10000; // remove powerups memset( self->client->ps.powerups, 0, sizeof( self->client->ps.powerups ) ); @@ -1024,8 +1029,21 @@ // if the attacker was on the same team if( targ != attacker && OnSameTeam( targ, attacker ) ) { - if( !g_friendlyFire.integer ) + if( g_dretchPunt.integer && + ( targ->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_LEVEL0|| + targ->client->ps.stats[ STAT_PCLASS ] == PCL_ALIEN_LEVEL0_UPG ) ) { + vec3_t dir, push; + + VectorSubtract( targ->r.currentOrigin, attacker->r.currentOrigin, dir ); + VectorNormalizeFast( dir ); + VectorScale( dir, ( damage * 10.0f ), push ); + push[2] = 64.0f; + VectorAdd( targ->client->ps.velocity, push, targ->client->ps.velocity ); + return; + } + else if( !g_friendlyFire.integer ) + { if( !g_friendlyFireHumans.integer && targ->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) { Index: src/game/g_local.h =================================================================== --- src/game/g_local.h (revision 894) +++ src/game/g_local.h (working copy) @@ -818,15 +818,18 @@ gentity_t *fire_flamer( gentity_t *self, vec3_t start, vec3_t aimdir ); gentity_t *fire_blaster( gentity_t *self, vec3_t start, vec3_t dir ); gentity_t *fire_pulseRifle( gentity_t *self, vec3_t start, vec3_t dir ); +gentity_t *fire_stasisGun( gentity_t *self, vec3_t start, vec3_t dir ); gentity_t *fire_luciferCannon( gentity_t *self, vec3_t start, vec3_t dir, int damage, int radius ); +gentity_t *fire_xael( gentity_t *self, vec3_t start, vec3_t dir, int damage, int radius ); gentity_t *fire_lockblob( gentity_t *self, vec3_t start, vec3_t dir ); gentity_t *fire_paraLockBlob( gentity_t *self, vec3_t start, vec3_t dir ); gentity_t *fire_slowBlob( gentity_t *self, vec3_t start, vec3_t dir ); -gentity_t *fire_bounceBall( gentity_t *self, vec3_t start, vec3_t dir ); +gentity_t *fire_bounceBall( gentity_t *self, vec3_t start, vec3_t dir, int weapon, int dmg, int mod, int speed ); gentity_t *fire_hive( gentity_t *self, vec3_t start, vec3_t dir ); +gentity_t *fire_eBlob( gentity_t *self, vec3_t start, vec3_t dir ); gentity_t *launch_grenade( gentity_t *self, vec3_t start, vec3_t dir ); +gentity_t *launch_shotgunNade( gentity_t *self, vec3_t start, vec3_t dir ); - // // g_mover.c // @@ -872,6 +875,7 @@ void CalcMuzzlePoint( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ); void SnapVectorTowards( vec3_t v, vec3_t to ); qboolean CheckVenomAttack( gentity_t *ent ); +qboolean CheckVenomAttack2( gentity_t *ent ); void CheckGrabAttack( gentity_t *ent ); qboolean CheckPounceAttack( gentity_t *ent ); void ChargeAttack( gentity_t *ent, gentity_t *victim ); @@ -1161,6 +1165,7 @@ extern vmCvar_t g_adminTempBan; extern vmCvar_t g_privateMessages; +extern vmCvar_t g_dretchPunt; void trap_Printf( const char *fmt ); void trap_Error( const char *fmt ); Index: src/game/g_main.c =================================================================== --- src/game/g_main.c (revision 894) +++ src/game/g_main.c (working copy) @@ -131,6 +131,7 @@ vmCvar_t g_privateMessages; +vmCvar_t g_dretchPunt; vmCvar_t g_tag; static cvarTable_t gameCvarTable[ ] = @@ -247,7 +248,7 @@ { &g_adminTempBan, "g_adminTempBan", "120", CVAR_ARCHIVE, 0, qfalse }, { &g_privateMessages, "g_privateMessages", "1", CVAR_ARCHIVE, 0, qfalse }, - + { &g_dretchPunt, "g_dretchPunt", "0", CVAR_ARCHIVE, 0, qfalse }, { &g_tag, "g_tag", "main", CVAR_INIT, 0, qfalse }, { &g_rankings, "g_rankings", "0", 0, 0, qfalse} Index: src/game/g_missile.c =================================================================== --- src/game/g_missile.c (revision 894) +++ src/game/g_missile.c (working copy) @@ -152,12 +152,40 @@ { if( other->client && other->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) { - other->client->ps.stats[ STAT_STATE ] |= SS_SLOWLOCKED; - other->client->lastSlowTime = level.time; + if( attacker->client->ps.weapon == WP_ABUILD2 ) + { + other->client->ps.stats[ STAT_STATE ] |= SS_BLOBLOCKED; + other->client->lastLockTime = level.time; + } + else + { + other->client->ps.stats[ STAT_STATE ] |= SS_SLOWLOCKED; + other->client->lastSlowTime = level.time; + } AngleVectors( other->client->ps.viewangles, dir, NULL, NULL ); other->client->ps.stats[ STAT_VIEWLOCK ] = DirToByte( dir ); } } + else if( !strcmp( ent->classname, "stsblob" ) ) + { + if( other->client ) + { + if( other->client->ps.stats[ STAT_STATE ] & SS_SLOWLOCKED && + !( other->s.weapon == WP_ALEVEL3 || other->s.weapon == WP_ALEVEL3_UPG || + other->s.weapon == WP_ALEVEL4 || other->s.weapon == WP_ALEVEL4_UPG ) ) + { + other->client->ps.stats[ STAT_STATE ] |= SS_BLOBLOCKED; + other->client->lastLockTime = level.time; + } + else + { + other->client->ps.stats[ STAT_STATE ] |= SS_SLOWLOCKED; + other->client->lastSlowTime = level.time; + } + AngleVectors( other->client->ps.viewangles, dir, NULL, NULL ); + other->client->ps.stats[ STAT_VIEWLOCK ] = DirToByte( dir ); + } + } else if( !strcmp( ent->classname, "hive" ) ) { if( other->s.eType == ET_BUILDABLE && other->s.modelindex == BA_A_HIVE ) @@ -430,6 +458,94 @@ //============================================================================= /* +================ +lCannon_think +Homing Lucifer Cannon +================ +*/ +void lCannon_think( gentity_t *self ) +{ + int entityList[ MAX_GENTITIES ]; + gentity_t *target, *enemy; + vec3_t range = { ACIDTUBE_RANGE*10, ACIDTUBE_RANGE*10, ACIDTUBE_RANGE*10 }; + float targetlength, tentlength; + int i,num; + vec3_t mins, maxs; + vec3_t tentdir, targetdir, forward, midbody; + trace_t tr; + + target = NULL; + targetlength = 1000; + + VectorAdd( self->s.origin, range, maxs ); + VectorSubtract( self->s.origin, range, mins ); + + // Best way to get forward vector for this rocket? + VectorCopy(self->s.pos.trDelta, forward); + VectorNormalize(forward); + + num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); + for (i = 0; i < num; i++) { + // Here we use tent to point to potential targets + enemy = &g_entities[ entityList[ i ] ]; + + if (!enemy->inuse) continue; + if (enemy == self->parent) continue; + if( !enemy->takedamage ) continue; + + //dont chase human buildables + if( enemy->s.eType == ET_BUILDABLE && enemy->health > 0 ) + { + if( BG_FindTeamForBuildable( enemy->s.modelindex ) == BIT_HUMANS ) + continue; + } + //chase healthy aliens + if( enemy->client ) + { + if( enemy->client->ps.stats[ STAT_PTEAM ] != PTE_ALIENS ) + continue; + if( enemy->client->ps.stats[ STAT_HEALTH ] <= 0 ) + continue; + } + // Aim for the body, not the feet + midbody[0] = enemy->r.currentOrigin[0] + + (enemy->r.mins[0] + enemy->r.maxs[0]) * 0.5; + midbody[1] = enemy->r.currentOrigin[1] + + (enemy->r.mins[1] + enemy->r.maxs[1]) * 0.5; + midbody[2] = enemy->r.currentOrigin[2] + + (enemy->r.mins[2] + enemy->r.maxs[2]) * 0.5; + + VectorSubtract(midbody, self->r.currentOrigin, tentdir); + tentlength = VectorLength(tentdir); + if ( tentlength > targetlength ) continue; + + // Quick normalization of tentdir since + // we already have the length + tentdir[0] /= tentlength; + tentdir[1] /= tentlength; + tentdir[2] /= tentlength; + if ( DotProduct(forward, tentdir) < 0.95 ) continue; + + trap_Trace( &tr, self->r.currentOrigin, NULL, NULL, + enemy->r.currentOrigin, ENTITYNUM_NONE, MASK_SHOT ); + + if ( enemy != &g_entities[tr.entityNum] ) continue; + + target = enemy; + targetlength = tentlength; + VectorCopy(tentdir, targetdir); + } + + self->nextthink += 50; + + if (!target) return; + + VectorMA(forward, 0.05, targetdir, targetdir); + VectorNormalize(targetdir); + VectorScale(targetdir, LCANNON_SPEED , self->s.pos.trDelta); +} + +/* ================= fire_luciferCannon @@ -447,11 +563,21 @@ bolt->classname = "lcannon"; if( damage == LCANNON_TOTAL_CHARGE ) + { bolt->nextthink = level.time; + bolt->think = G_ExplodeMissile; + } + else if( damage > LCANNON_MIN_CHARGE ) + { + bolt->nextthink = level.time + 10000; + bolt->think = G_ExplodeMissile; + } else - bolt->nextthink = level.time + 10000; + { + bolt->nextthink = level.time + 1; + bolt->think = lCannon_think; + } - bolt->think = G_ExplodeMissile; bolt->s.eType = ET_MISSILE; bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; bolt->s.weapon = WP_LUCIFER_CANNON; @@ -477,8 +603,59 @@ return bolt; } +//============================================================================= + /* ================= +fire_xael + +================= +*/ +gentity_t *fire_xael( gentity_t *self, vec3_t start, vec3_t dir, int damage, int radius ) +{ + gentity_t *bolt; + int localDamage = (int)( ceil( ( (float)damage / + (float)XAEL_TOTAL_CHARGE ) * (float)XAEL_DAMAGE ) ); + int speed = (int) ( 200.0f * (float)XAEL_TOTAL_CHARGE / (float)damage + 200.0f ); + + VectorNormalize( dir ); + + bolt = G_Spawn( ); + bolt->classname = "xael"; + + if( damage == XAEL_TOTAL_CHARGE ) + bolt->nextthink = level.time; + else + bolt->nextthink = level.time + 10000; + + bolt->think = G_ExplodeMissile; + bolt->s.eType = ET_MISSILE; + bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; + bolt->s.weapon = WP_XAEL; + bolt->s.generic1 = self->s.generic1; //weaponMode + bolt->r.ownerNum = self->s.number; + bolt->parent = self; + bolt->damage = localDamage; + bolt->splashDamage = localDamage / 2; + bolt->splashRadius = radius; + bolt->methodOfDeath = MOD_XAEL; + bolt->splashMethodOfDeath = MOD_XAEL_SPLASH; + bolt->clipmask = MASK_SHOT; + bolt->target_ent = NULL; + + bolt->s.pos.trType = TR_GRAVITY; + bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame + VectorCopy( start, bolt->s.pos.trBase ); + VectorScale( dir, speed, bolt->s.pos.trDelta ); + SnapVector( bolt->s.pos.trDelta ); // save net bandwidth + + VectorCopy( start, bolt->r.currentOrigin ); + + return bolt; +} + +/* +================= launch_grenade ================= @@ -521,6 +698,52 @@ return bolt; } + +/* +================= +shotgun_grenade + +================= +*/ +gentity_t *launch_shotgunNade( gentity_t *self, vec3_t start, vec3_t dir ) +{ + gentity_t *bolt; + + VectorNormalize( dir ); + + bolt = G_Spawn( ); + bolt->classname = "shotnade"; + bolt->nextthink = level.time + 1000; + bolt->think = G_ExplodeMissile; + bolt->s.eType = ET_MISSILE; + bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; + bolt->s.weapon = WP_SHOTGUN; + bolt->s.eFlags = EF_BOUNCE_HALF; + bolt->s.generic1 = self->s.generic1; //weaponMode + bolt->r.ownerNum = self->s.number; + bolt->parent = self; + bolt->damage = SHOTGUN_NADE_DAMAGE; + bolt->splashDamage = SHOTGUN_NADE_DAMAGE; + bolt->splashRadius = SHOTGUN_NADE_RANGE; + bolt->methodOfDeath = MOD_SHOTGUN; + bolt->splashMethodOfDeath = MOD_SHOTGUN; + bolt->clipmask = MASK_SHOT; + bolt->target_ent = NULL; + bolt->r.mins[ 0 ] = bolt->r.mins[ 1 ] = bolt->r.mins[ 2 ] = -3.0f; + bolt->r.maxs[ 0 ] = bolt->r.maxs[ 1 ] = bolt->r.maxs[ 2 ] = 3.0f; + bolt->s.time = level.time; + + bolt->s.pos.trType = TR_GRAVITY; + bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame + VectorCopy( start, bolt->s.pos.trBase ); + VectorScale( dir, SHOTGUN_NADE_SPEED, bolt->s.pos.trDelta ); + SnapVector( bolt->s.pos.trDelta ); // save net bandwidth + + VectorCopy( start, bolt->r.currentOrigin ); + + return bolt; +} + //============================================================================= /* @@ -656,6 +879,50 @@ /* ================= +fire_eBlob +================= +*/ +gentity_t *fire_eBlob( gentity_t *self, vec3_t start, vec3_t dir ) +{ + gentity_t *bolt; + + VectorNormalize ( dir ); + + bolt = G_Spawn( ); + bolt->classname = "eBlob"; + bolt->nextthink = level.time + LEVEL4_EBLOB_THINK_TIME; + bolt->think = G_ExplodeMissile; + bolt->s.eType = ET_MISSILE; + //bolt->s.eFlags |= EF_BOUNCE|EF_NO_BOUNCE_SOUND; + bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; + bolt->s.weapon = WP_ALEVEL4_UPG; + bolt->s.generic1 = self->s.generic1; //weaponMode + bolt->r.ownerNum = self->s.number; + bolt->parent = self; + bolt->damage = LEVEL4_EBLOB_DMG; + bolt->splashDamage = LEVEL4_EBLOB_DMG; + bolt->splashRadius = LEVEL4_EBLOB_RANGE; + bolt->methodOfDeath = MOD_LEVEL4_EBLOB; + bolt->splashMethodOfDeath = MOD_LEVEL4_EBLOB; + bolt->clipmask = MASK_SHOT; + bolt->target_ent = NULL; + bolt->r.mins[ 0 ] = bolt->r.mins[ 1 ] = bolt->r.mins[ 2 ] = -4.0f; + bolt->r.maxs[ 0 ] = bolt->r.maxs[ 1 ] = bolt->r.maxs[ 2 ] = 4.0f; + + bolt->s.pos.trType = TR_GRAVITY; + bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame + VectorCopy( start, bolt->s.pos.trBase ); + VectorScale( dir, LEVEL4_EBLOB_SPEED, bolt->s.pos.trDelta ); + SnapVector( bolt->s.pos.trDelta ); // save net bandwidth + VectorCopy( start, bolt->r.currentOrigin ); + //VectorScale( dir, LEVEL4_EBLOB_SPEED, dir ); + //VectorSubtract( self->client->ps.velocity, dir, self->client->ps.velocity ); + + return bolt; +} + +/* +================= fire_lockblob ================= */ @@ -694,6 +961,44 @@ /* ================= +fire_stasisGun +================= +*/ +gentity_t *fire_stasisGun( gentity_t *self, vec3_t start, vec3_t dir ) +{ + gentity_t *bolt; + + VectorNormalize ( dir ); + + bolt = G_Spawn( ); + bolt->classname = "stsblob"; + bolt->nextthink = level.time + 15000; + bolt->think = G_ExplodeMissile; + bolt->s.eType = ET_MISSILE; + bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; + bolt->s.weapon = WP_STASIS_GUN; + bolt->s.generic1 = self->s.generic1; //weaponMode + bolt->r.ownerNum = self->s.number; + bolt->parent = self; + bolt->damage = 0; + bolt->splashDamage = 0; + bolt->splashRadius = 0; + bolt->methodOfDeath = MOD_UNKNOWN; //doesn't do damage so will never kill + bolt->clipmask = MASK_SHOT; + bolt->target_ent = NULL; + + bolt->s.pos.trType = TR_LINEAR; + bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame + VectorCopy( start, bolt->s.pos.trBase ); + VectorScale( dir, STASIS_SPEED, bolt->s.pos.trDelta ); + SnapVector( bolt->s.pos.trDelta ); // save net bandwidth + VectorCopy( start, bolt->r.currentOrigin ); + + return bolt; +} + +/* +================= fire_slowBlob ================= */ @@ -773,7 +1078,8 @@ fire_bounceBall ================= */ -gentity_t *fire_bounceBall( gentity_t *self, vec3_t start, vec3_t dir ) +gentity_t *fire_bounceBall( gentity_t *self, vec3_t start, vec3_t dir, + int weapon, int dmg, int mod, int speed) { gentity_t *bolt; @@ -785,22 +1091,22 @@ bolt->think = G_ExplodeMissile; bolt->s.eType = ET_MISSILE; bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; - bolt->s.weapon = WP_ALEVEL3_UPG; + bolt->s.weapon = weapon; bolt->s.generic1 = self->s.generic1; //weaponMode bolt->r.ownerNum = self->s.number; bolt->parent = self; - bolt->damage = LEVEL3_BOUNCEBALL_DMG; + bolt->damage = dmg; bolt->splashDamage = 0; bolt->splashRadius = 0; - bolt->methodOfDeath = MOD_LEVEL3_BOUNCEBALL; - bolt->splashMethodOfDeath = MOD_LEVEL3_BOUNCEBALL; + bolt->methodOfDeath = mod; + bolt->splashMethodOfDeath = mod; bolt->clipmask = MASK_SHOT; bolt->target_ent = NULL; bolt->s.pos.trType = TR_GRAVITY; bolt->s.pos.trTime = level.time - MISSILE_PRESTEP_TIME; // move a bit on the very first frame VectorCopy( start, bolt->s.pos.trBase ); - VectorScale( dir, LEVEL3_BOUNCEBALL_SPEED, bolt->s.pos.trDelta ); + VectorScale( dir, speed, bolt->s.pos.trDelta ); SnapVector( bolt->s.pos.trDelta ); // save net bandwidth VectorCopy( start, bolt->r.currentOrigin ); /*bolt->s.eFlags |= EF_BOUNCE;*/ Index: src/game/g_weapon.c =================================================================== --- src/game/g_weapon.c (revision 894) +++ src/game/g_weapon.c (working copy) @@ -81,35 +81,60 @@ { int i; int maxAmmo, maxClips; - qboolean weaponType, restoredAmmo = qfalse; + qboolean isEnergy, restoredAmmo = qfalse; for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ ) { - if( buyingEnergyAmmo ) - weaponType = BG_FindUsesEnergyForWeapon( i ); - else - weaponType = !BG_FindUsesEnergyForWeapon( i ); + isEnergy = BG_FindUsesEnergyForWeapon( i ); + if( BG_InventoryContainsWeapon( i, ent->client->ps.stats ) && - weaponType && !BG_FindInfinteAmmoForWeapon( i ) && + !BG_FindInfinteAmmoForWeapon( i ) && !BG_WeaponIsFull( i, ent->client->ps.stats, ent->client->ps.ammo, ent->client->ps.powerups ) ) { BG_FindAmmoForWeapon( i, &maxAmmo, &maxClips ); - if( buyingEnergyAmmo ) + if( buyingEnergyAmmo && isEnergy ) { G_AddEvent( ent, EV_RPTUSE_SOUND, 0 ); if( BG_InventoryContainsUpgrade( UP_BATTPACK, ent->client->ps.stats ) ) maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER ); } + else if( !buyingEnergyAmmo && !isEnergy ) + { + //G_AddEvent( ent, EV_RPTUSE_SOUND, 0 ); + if( BG_InventoryContainsUpgrade( UP_AMMOPACK, ent->client->ps.stats ) ) + maxClips = (int)( 1 + (float)(maxClips) * AMMOPACK_MODIFIER ); + } + + //battlesuit doesnt use buyingEnergyAmmo var + if( BG_InventoryContainsUpgrade( UP_BATTLESUIT, ent->client->ps.stats ) ) + { + if( isEnergy ) + maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER ); + else + maxClips = (int)( 1 + (float)(maxClips) * AMMOPACK_MODIFIER ); + } + BG_PackAmmoArray( i, ent->client->ps.ammo, ent->client->ps.powerups, maxAmmo, maxClips ); restoredAmmo = qtrue; } + if( BG_InventoryContainsWeapon( i, ent->client->ps.stats ) && + i==WP_STASIS_GUN && + !BG_WeaponIsFull( i, ent->client->ps.stats, + ent->client->ps.ammo, ent->client->ps.powerups ) ) + { + BG_FindAmmoForWeapon( i, &maxAmmo, &maxClips ); + BG_PackAmmoArray( i, ent->client->ps.ammo, ent->client->ps.powerups, + maxAmmo, maxClips ); + + restoredAmmo = qtrue; + } } if( restoredAmmo ) @@ -374,8 +399,11 @@ if( traceEnt->takedamage ) { + int damage = MDRIVER_DMG; + if( BG_InventoryContainsUpgrade( UP_SURGE, ent->client->ps.stats ) ) + damage += damage / SURGE_DMG_DIV; G_Damage( traceEnt, ent, ent, forward, tr.endpos, - MDRIVER_DMG, 0, MOD_MDRIVER ); + damage, 0, MOD_MDRIVER ); } } @@ -416,6 +444,24 @@ /* ====================================================================== +EBLOB + +====================================================================== +*/ + +void eBlobFire( gentity_t *ent ) +{ + gentity_t *m; + + m = fire_eBlob( ent, muzzle, forward ); + +// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics +} + + +/* +====================================================================== + BLASTER PISTOL ====================================================================== @@ -450,6 +496,21 @@ /* ====================================================================== +STASIS GUN + +====================================================================== +*/ + +void stasisGunFire( gentity_t *ent ) +{ + gentity_t *m; + + m = fire_stasisGun( ent, muzzle, forward ); +} + +/* +====================================================================== + FLAME THROWER ====================================================================== @@ -477,9 +538,25 @@ m = launch_grenade( ent, muzzle, forward ); } + /* ====================================================================== +SHOTGUN NADE + +====================================================================== +*/ + +void throwShotgunNade( gentity_t *ent ) +{ + gentity_t *m; + + m = launch_shotgunNade( ent, muzzle, forward ); +} + +/* +====================================================================== + LAS GUN ====================================================================== @@ -529,7 +606,13 @@ } if( traceEnt->takedamage ) - G_Damage( traceEnt, ent, ent, forward, tr.endpos, LASGUN_DAMAGE, 0, MOD_LASGUN ); + { + int damage = LASGUN_DAMAGE; + if( BG_InventoryContainsUpgrade( UP_SURGE, ent->client->ps.stats ) ) + damage += damage / SURGE_DMG_DIV; + G_Damage( traceEnt, ent, ent, forward, tr.endpos, + damage, 0, MOD_LASGUN ); + } } /* @@ -624,6 +707,38 @@ /* ====================================================================== +XAEL + +====================================================================== +*/ + +/* +=============== +XChargeFire +=============== +*/ +void XChargeFire( gentity_t *ent, qboolean secondary ) +{ + gentity_t *m; + + if( secondary ) + { + m = fire_xael( ent, muzzle, forward, XAEL_SECONDARY_DAMAGE, + XAEL_SECONDARY_RADIUS ); + ent->client->ps.weaponTime = XAEL_REPEAT; + } + else + { + m = fire_xael( ent, muzzle, forward, ent->client->ps.stats[ STAT_MISC ], XAEL_RADIUS ); + ent->client->ps.weaponTime = XAEL_CHARGEREPEAT; + } + + ent->client->ps.stats[ STAT_MISC ] = 0; +} + +/* +====================================================================== + TESLA GENERATOR ====================================================================== @@ -694,7 +809,7 @@ vec3_t forward, end; trace_t tr; gentity_t *traceEnt; - int bHealth; + int bHealth,hHealth; if( ent->client->ps.stats[ STAT_BUILDABLE ] != BA_NONE ) { @@ -702,7 +817,7 @@ return; } - //repair buildable + //repair/heal buildable/player if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) { AngleVectors( ent->client->ps.viewangles, forward, NULL, NULL ); @@ -712,34 +827,61 @@ traceEnt = &g_entities[ tr.entityNum ]; if( tr.fraction < 1.0 && - ( traceEnt->s.eType == ET_BUILDABLE ) && - ( traceEnt->biteam == ent->client->ps.stats[ STAT_PTEAM ] ) && ( ( ent->client->ps.weapon >= WP_HBUILD2 ) && ( ent->client->ps.weapon <= WP_HBUILD ) ) && - traceEnt->spawned && traceEnt->health > 0 ) - { - if( ent->client->ps.stats[ STAT_MISC ] > 0 ) + traceEnt->health > 0 ) + { + //repair buildable + if(traceEnt->s.eType == ET_BUILDABLE && traceEnt->spawned && + ( traceEnt->biteam == ent->client->ps.stats[ STAT_PTEAM ] )) { - G_AddEvent( ent, EV_BUILD_DELAY, ent->client->ps.clientNum ); - return; + if( ent->client->ps.stats[ STAT_MISC ] > 0 ) + { + G_AddEvent( ent, EV_BUILD_DELAY, ent->client->ps.clientNum ); + return; + } + + bHealth = BG_FindHealthForBuildable( traceEnt->s.modelindex ); + + traceEnt->health += HBUILD_HEALRATE; + + if( traceEnt->health > bHealth ) + traceEnt->health = bHealth; + + if( traceEnt->health == bHealth ) + G_AddEvent( ent, EV_BUILD_REPAIRED, 0 ); + else + G_AddEvent( ent, EV_BUILD_REPAIR, 0 ); } + //heal ANY player + else if( traceEnt->s.eType == ET_PLAYER && traceEnt->client ) + { + if( ent->client->ps.stats[ STAT_MISC ] > 0 ) + { + G_AddEvent( ent, EV_BUILD_DELAY, ent->client->ps.clientNum ); + return; + } - bHealth = BG_FindHealthForBuildable( traceEnt->s.modelindex ); + hHealth = traceEnt->client->ps.stats[ STAT_MAX_HEALTH ]; - traceEnt->health += HBUILD_HEALRATE; + traceEnt->health += HBUILD_HEALRATE/2; - if( traceEnt->health > bHealth ) - traceEnt->health = bHealth; + if( traceEnt->health > hHealth ) + traceEnt->health = hHealth; - if( traceEnt->health == bHealth ) - G_AddEvent( ent, EV_BUILD_REPAIRED, 0 ); - else - G_AddEvent( ent, EV_BUILD_REPAIR, 0 ); + if( traceEnt->health == hHealth ) + G_AddEvent( ent, EV_BUILD_REPAIRED, 0 ); + else + G_AddEvent( ent, EV_BUILD_REPAIR, 0 ); + } } } else if( ent->client->ps.weapon == WP_ABUILD2 ) meleeAttack( ent, ABUILDER_CLAW_RANGE, ABUILDER_CLAW_WIDTH, ABUILDER_CLAW_DMG, MOD_ABUILDER_CLAW ); //melee attack for alien builder + else if( ent->client->ps.weapon == WP_ABUILD ) + meleeAttack( ent, ABUILDER_CLAW_RANGE, ABUILDER_CLAW_WIDTH, + ABUILDER_CLAW_DMG/2, MOD_ABUILDER_CLAW ); //melee attack for alien builder } /* @@ -769,7 +911,8 @@ BG_FindBuildDelayForWeapon( ent->s.weapon ) * 2; } else if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS && !G_IsPowered( muzzle ) && - ( ent->client->ps.stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ) != BA_H_REPEATER ) //hack + ( ent->client->ps.stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ) != BA_H_REPEATER && + ( ent->client->ps.stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ) != BA_H_SPAWN ) //hack { ent->client->ps.stats[ STAT_MISC ] += BG_FindBuildDelayForWeapon( ent->s.weapon ) * 2; @@ -884,6 +1027,83 @@ /* ====================================================================== +LEVEL0 UPG + +====================================================================== +*/ + +/* +=============== +CheckVenomAttack2 +=============== +*/ +qboolean CheckVenomAttack2( gentity_t *ent ) +{ + trace_t tr; + vec3_t end; + gentity_t *tent; + gentity_t *traceEnt; + vec3_t mins, maxs; + int damage = LEVEL0_BITE_DMG; + + VectorSet( mins, -LEVEL0_BITE_WIDTH, -LEVEL0_BITE_WIDTH, -LEVEL0_BITE_WIDTH ); + VectorSet( maxs, LEVEL0_BITE_WIDTH, LEVEL0_BITE_WIDTH, LEVEL0_BITE_WIDTH ); + + // set aiming directions + AngleVectors( ent->client->ps.viewangles, forward, right, up ); + + CalcMuzzlePoint( ent, forward, right, up, muzzle ); + + VectorMA( muzzle, LEVEL0_BITE_RANGE, forward, end ); + + trap_Trace( &tr, muzzle, mins, maxs, end, ent->s.number, MASK_SHOT ); + + if( tr.surfaceFlags & SURF_NOIMPACT ) + return qfalse; + + traceEnt = &g_entities[ tr.entityNum ]; + + if( !traceEnt->takedamage ) + return qfalse; + + if( !traceEnt->client && !traceEnt->s.eType == ET_BUILDABLE ) + return qfalse; + + //allow bites to work against (human) buildables only + if( traceEnt->s.eType == ET_BUILDABLE && traceEnt->health > 0 ) + { + if( BG_FindTeamForBuildable( traceEnt->s.modelindex ) != BIT_HUMANS ) + return qfalse; + //hackery + damage *= 0.3f; + } + + if( traceEnt->client ) + { + if( traceEnt->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) + return qfalse; + if( traceEnt->client->ps.stats[ STAT_HEALTH ] <= 0 ) + return qfalse; + } + + // send blood impact + if( traceEnt->takedamage && traceEnt->client ) + { + tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT ); + tent->s.otherEntityNum = traceEnt->s.number; + tent->s.eventParm = DirToByte( tr.plane.normal ); + tent->s.weapon = ent->s.weapon; + tent->s.generic1 = ent->s.generic1; //weaponMode + } + + G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_NO_KNOCKBACK, MOD_LEVEL0_BITE ); + + return qtrue; +} + +/* +====================================================================== + LEVEL1 ====================================================================== @@ -1368,12 +1588,23 @@ { gentity_t *m; - m = fire_bounceBall( ent, muzzle, forward ); + m = fire_bounceBall( ent, muzzle, forward, + WP_ALEVEL2_UPG, LEVEL2_BOUNCEBALL_DMG, MOD_LEVEL2_BOUNCEBALL, LEVEL2_BOUNCEBALL_SPEED ); // VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics } +void bounceBallFire2( gentity_t *ent ) +{ + gentity_t *m; + m = fire_bounceBall( ent, muzzle, forward, + WP_ALEVEL3_UPG, LEVEL3_BOUNCEBALL_DMG, MOD_LEVEL3_BOUNCEBALL, LEVEL3_BOUNCEBALL_SPEED ); + +// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics +} + + /* ====================================================================== @@ -1461,9 +1692,14 @@ switch( ent->s.weapon ) { case WP_ALEVEL3_UPG: - bounceBallFire( ent ); + bounceBallFire2( ent ); break; + case WP_ALEVEL4_UPG: + eBlobFire( ent ); + break; + + case WP_ABUILD: case WP_ABUILD2: slowBlobFire( ent ); break; @@ -1499,12 +1735,21 @@ poisonCloud( ent ); break; case WP_ALEVEL2_UPG: - areaZapFire( ent ); + bounceBallFire( ent ); break; + case WP_SHOTGUN: + throwShotgunNade( ent ); + break; + case WP_STASIS_GUN: + bulletFire( ent, STASIS_SPREAD, STASIS_DMG, MOD_STASIS ); + break; case WP_LUCIFER_CANNON: LCChargeFire( ent, qtrue ); break; + case WP_XAEL: + XChargeFire( ent, qtrue ); + break; case WP_ABUILD: case WP_ABUILD2: @@ -1554,6 +1799,7 @@ meleeAttack( ent, LEVEL2_CLAW_RANGE, LEVEL2_CLAW_WIDTH, LEVEL2_CLAW_DMG, MOD_LEVEL2_CLAW ); break; case WP_ALEVEL4: + case WP_ALEVEL4_UPG: meleeAttack( ent, LEVEL4_CLAW_RANGE, LEVEL4_CLAW_WIDTH, LEVEL4_CLAW_DMG, MOD_LEVEL4_CLAW ); break; @@ -1575,12 +1821,18 @@ case WP_PULSE_RIFLE: pulseRifleFire( ent ); break; + case WP_STASIS_GUN: + stasisGunFire( ent ); + break; case WP_MASS_DRIVER: massDriverFire( ent ); break; case WP_LUCIFER_CANNON: LCChargeFire( ent, qfalse ); break; + case WP_XAEL: + XChargeFire( ent, qfalse ); + break; case WP_LAS_GUN: lasGunFire( ent ); break; Index: src/game/tremulous.h =================================================================== --- src/game/tremulous.h (revision 894) +++ src/game/tremulous.h (working copy) @@ -54,6 +54,10 @@ #define LEVEL0_BITE_WIDTH 6.0f #define LEVEL0_BITE_REPEAT 500 #define LEVEL0_BITE_K_SCALE 1.0f +#define LEVEL0_DRILL_SPEED_MOD 0.8f +#define LEVEL0_DRILL_SPEED 800 +#define LEVEL0_DRILL_CHARGE_TIME 600 +#define LEVEL0_DRILL_TIME 400 #define LEVEL1_CLAW_DMG ADM(32) #define LEVEL1_CLAW_RANGE 96.0f @@ -85,6 +89,10 @@ #define LEVEL2_AREAZAP_MAX_TARGETS 3 #define LEVEL2_WALLJUMP_MAXSPEED 1000.0f +#define LEVEL2_BOUNCEBALL_DMG ADM(60) +#define LEVEL2_BOUNCEBALL_REPEAT 1000 +#define LEVEL2_BOUNCEBALL_SPEED 2000.0f + #define LEVEL3_CLAW_DMG ADM(80) #define LEVEL3_CLAW_RANGE 96.0f #define LEVEL3_CLAW_WIDTH 16.0f @@ -109,6 +117,7 @@ #define LEVEL4_CLAW_WIDTH 20.0f #define LEVEL4_CLAW_REPEAT 750 #define LEVEL4_CLAW_K_SCALE 1.0f +#define LEVEL4_CLAW_U_K_SCALE 1.1f #define LEVEL4_REGEN_RANGE 200.0f #define LEVEL4_REGEN_MOD 2.0f #define LEVEL4_CHARGE_SPEED 2.0f @@ -118,6 +127,11 @@ #define LEVEL4_CHARGE_CHARGE_RATIO (LEVEL4_CHARGE_TIME/LEVEL4_CHARGE_CHARGE_TIME) #define LEVEL4_CHARGE_REPEAT 1000 #define LEVEL4_CHARGE_DMG ADM(110) +#define LEVEL4_EBLOB_THINK_TIME 5000 +#define LEVEL4_EBLOB_REPEAT 2000 +#define LEVEL4_EBLOB_SPEED 500.0f +#define LEVEL4_EBLOB_RANGE 200.0f +#define LEVEL4_EBLOB_DMG ADM(175) @@ -155,6 +169,12 @@ #define LEVEL0_REGEN 1 #define LEVEL0_COST 0 +#define LEVEL0_UPG_SPEED 1.3f +#define LEVEL0_UPG_VALUE AVM(200) +#define LEVEL0_UPG_HEALTH AHM(45) +#define LEVEL0_UPG_REGEN 2 +#define LEVEL0_UPG_COST 1 + #define LEVEL1_SPEED 1.25f #define LEVEL1_VALUE AVM(225) #define LEVEL1_HEALTH AHM(75) @@ -198,7 +218,14 @@ #define LEVEL4_COST 2 +#define LEVEL4_UPG_SPEED 1.2f +#define LEVEL4_UPG_VALUE AVM(1000) +#define LEVEL4_UPG_HEALTH AHM(500) +#define LEVEL4_UPG_REGEN 8 +#define LEVEL4_UPG_COST 4 + + /* * ALIEN buildables * @@ -213,7 +240,7 @@ * */ -#define ALIEN_BHLTH_MODIFIER 1.0f +#define ALIEN_BHLTH_MODIFIER 1.2f #define ABHM(h) ((int)((float)h*ALIEN_BHLTH_MODIFIER)) #define CREEP_BASESIZE 700 @@ -231,13 +258,16 @@ #define ASPAWN_CREEPSIZE 120 #define ASPAWN_VALUE 150 -#define BARRICADE_BP 10 +#define BARRICADE_BP 6 #define BARRICADE_BT 20000 -#define BARRICADE_HEALTH ABHM(200) +#define BARRICADE_HEALTH ABHM(500)//200 #define BARRICADE_REGEN 14 #define BARRICADE_SPLASHDAMAGE 50 #define BARRICADE_SPLASHRADIUS 50 #define BARRICADE_CREEPSIZE 120 +#define BARRICADE_ATTACK_RANGE 50.0f +#define BARRICADE_ATTACK_DAMAGE 50 +#define BARRICADE_ATTACK_TIMER 1000 #define BOOSTER_BP 12 #define BOOSTER_BT 15000 @@ -380,6 +410,11 @@ #define SHOTGUN_SPREAD 900 #define SHOTGUN_DMG HDM(7) +#define SHOTGUN_NADE_REPEAT 2000 +#define SHOTGUN_NADE_DAMAGE HDM(50) +#define SHOTGUN_NADE_RANGE 100.0f +#define SHOTGUN_NADE_SPEED 600.0f + #define LASGUN_PRICE 250 #define LASGUN_AMMO 200 #define LASGUN_REPEAT 200 @@ -411,6 +446,15 @@ #define PRIFLE_DMG HDM(9) #define PRIFLE_SPEED 1000 +#define STASIS_PRICE 400 +#define STASIS_BULLETS 450 +#define STASIS_REPEAT 1000 +#define STASIS_S_REPEAT 60 +#define STASIS_K_SCALE 1.0f +#define STASIS_SPREAD 1750 +#define STASIS_DMG HDM(2) +#define STASIS_SPEED 1500 + #define FLAMER_PRICE 450 #define FLAMER_GAS 150 #define FLAMER_REPEAT 200 @@ -436,6 +480,21 @@ #define LCANNON_TOTAL_CHARGE 255 #define LCANNON_MIN_CHARGE 50 +#define XAEL_PRICE 800 +#define XAEL_AMMO 120 +#define XAEL_REPEAT 500 +#define XAEL_K_SCALE 1.0f +#define XAEL_CHARGEREPEAT 1000 +#define XAEL_RELOAD 2000 +#define XAEL_DAMAGE HDM(300) +#define XAEL_RADIUS 175 +#define XAEL_SECONDARY_DAMAGE HDM(15) +#define XAEL_SECONDARY_RADIUS 50 +#define XAEL_SPEED 350 +#define XAEL_CHARGE_TIME 2000 +#define XAEL_TOTAL_CHARGE 255 +#define XAEL_MIN_CHARGE 50 + #define HBUILD_PRICE 0 #define HBUILD_REPEAT 1000 #define HBUILD_DELAY 17500 @@ -458,16 +517,26 @@ #define MEDKIT_PRICE 0 +#define REGEN_PRICE 150 +#define REGEN_HEALTH_RATE 3 +#define REGEN_STAMINA_RATE 25 + #define BATTPACK_PRICE 100 #define BATTPACK_MODIFIER 1.5f //modifier for extra energy storage available +#define AMMOPACK_PRICE 100 +#define AMMOPACK_MODIFIER 1.4f //modifier for extra ammo storage available + +#define SURGE_PRICE 200 +#define SURGE_DMG_DIV 5 + #define JETPACK_PRICE 120 #define JETPACK_FLOAT_SPEED 128.0f //up movement speed #define JETPACK_SINK_SPEED 192.0f //down movement speed #define JETPACK_DISABLE_TIME 1000 //time to disable the jetpack when player damaged #define JETPACK_DISABLE_CHANCE 0.3f -#define BSUIT_PRICE 400 +#define BSUIT_PRICE 500 #define MGCLIP_PRICE 0 @@ -494,11 +563,12 @@ * */ -#define HUMAN_BHLTH_MODIFIER 1.0f +#define HUMAN_BHLTH_MODIFIER 1.3f #define HBHM(h) ((int)((float)h*HUMAN_BHLTH_MODIFIER)) #define REACTOR_BASESIZE 1000 #define REPEATER_BASESIZE 500 +#define HSPAWN_BASESIZE 150 #define HUMAN_DETONATION_DELAY 5000 #define HSPAWN_BP 10 @@ -508,6 +578,10 @@ #define HSPAWN_SPLASHRADIUS 100 #define HSPAWN_VALUE 1 +#define HSPAWN_ATTACK_RANGE 50.0f +#define HSPAWN_ATTACK_DAMAGE 50 +#define HSPAWN_ATTACK_TIMER 1000 + #define MEDISTAT_BP 8 #define MEDISTAT_BT 10000 #define MEDISTAT_HEALTH HBHM(190) @@ -517,6 +591,7 @@ #define MGTURRET_BP 8 #define MGTURRET_BT 10000 #define MGTURRET_HEALTH HBHM(190) +#define MGTURRET_DCC_REGEN 8 #define MGTURRET_SPLASHDAMAGE 100 #define MGTURRET_SPLASHRADIUS 100 #define MGTURRET_ANGULARSPEED 8 //degrees/think ~= 200deg/sec @@ -535,6 +610,7 @@ #define TESLAGEN_BP 10 #define TESLAGEN_BT 15000 #define TESLAGEN_HEALTH HBHM(220) +#define TESLAGEN_DCC_REGEN 10 #define TESLAGEN_SPLASHDAMAGE 50 #define TESLAGEN_SPLASHRADIUS 100 #define TESLAGEN_REPEAT 250 @@ -545,6 +621,7 @@ #define DC_BP 8 #define DC_BT 10000 #define DC_HEALTH HBHM(190) +#define DC_DCC_REGEN 10 #define DC_SPLASHDAMAGE 50 #define DC_SPLASHRADIUS 100 @@ -583,10 +660,12 @@ #define STAMINA_STOP_RESTORE 25 #define STAMINA_WALK_RESTORE 15 #define STAMINA_SPRINT_TAKE 8 -#define STAMINA_LARMOUR_TAKE 4 +#define STAMINA_LARMOUR_TAKE 6 #define HUMAN_SPAWN_REPEAT_TIME 10000 +#define HUMAN_REGEN_DAMAGE_TIME 1500 //msec since damage that regen starts again + /* * Misc */ Index: src/ui/ui_main.c =================================================================== --- src/ui/ui_main.c (revision 894) +++ src/ui/ui_main.c (working copy) @@ -3182,11 +3182,11 @@ if( BG_ClassIsAllowed( PCL_ALIEN_LEVEL0 ) ) UI_AddClass( PCL_ALIEN_LEVEL0 ); - if( BG_ClassIsAllowed( PCL_ALIEN_BUILDER0_UPG ) && - BG_FindStagesForClass( PCL_ALIEN_BUILDER0_UPG, UI_GetCurrentAlienStage( ) ) ) - UI_AddClass( PCL_ALIEN_BUILDER0_UPG ); - else if( BG_ClassIsAllowed( PCL_ALIEN_BUILDER0 ) ) - UI_AddClass( PCL_ALIEN_BUILDER0 ); + //if( BG_ClassIsAllowed( PCL_ALIEN_BUILDER0_UPG ) && + // BG_FindStagesForClass( PCL_ALIEN_BUILDER0_UPG, UI_GetCurrentAlienStage( ) ) ) + // UI_AddClass( PCL_ALIEN_BUILDER0_UPG ); + //else if( BG_ClassIsAllowed( PCL_ALIEN_BUILDER0 ) ) + // UI_AddClass( PCL_ALIEN_BUILDER0 ); } /* @@ -5004,6 +5004,7 @@ static char info[MAX_STRING_CHARS]; static char hostname[1024]; static char clientBuff[32]; + static char pingBuff[32]; static int lastColumn = -1; static int lastTime = 0; *handle = -1; @@ -5020,6 +5021,7 @@ } else if (feederID == FEEDER_SERVERS) { if (index >= 0 && index < uiInfo.serverStatus.numDisplayServers) { int ping; + qboolean isConnectable=qfalse; if (lastColumn != column || lastTime > uiInfo.uiDC.realTime + 5000) { trap_LAN_GetServerInfo(ui_netSource.integer, uiInfo.serverStatus.displayServers[index], info, MAX_STRING_CHARS); lastColumn = column; @@ -5031,6 +5033,12 @@ // if we ever see a ping that is out of date, do a server refresh // UI_UpdatePendingPings(); } + if( atoi(Info_ValueForKey(info, "clients")) < atoi(Info_ValueForKey(info, "sv_maxclients")) + && ( atoi(Info_ValueForKey(info, "ping")) < atoi(Info_ValueForKey(info, "maxping")) + || atoi(Info_ValueForKey(info, "maxping")) == 0 ) ) + { + isConnectable = qtrue; + } switch (column) { case SORT_HOST : if (ping <= 0) { @@ -5059,14 +5067,22 @@ case SORT_MAP : return Info_ValueForKey(info, "mapname"); case SORT_CLIENTS : - Com_sprintf( clientBuff, sizeof(clientBuff), "%s (%s)", Info_ValueForKey(info, "clients"), Info_ValueForKey(info, "sv_maxclients")); + if(isConnectable) + Com_sprintf( clientBuff, sizeof(clientBuff), S_COLOR_GREEN "%s/%s", Info_ValueForKey(info, "clients"), Info_ValueForKey(info, "sv_maxclients")); + else + Com_sprintf( clientBuff, sizeof(clientBuff), S_COLOR_RED "%s/%s", Info_ValueForKey(info, "clients"), Info_ValueForKey(info, "sv_maxclients")); return clientBuff; case SORT_PING : if (ping <= 0) { return "..."; - } else { - return Info_ValueForKey(info, "ping"); } + if(isConnectable) + Com_sprintf( pingBuff, sizeof(pingBuff), S_COLOR_GREEN "%s", Info_ValueForKey(info, "ping") ); + else + Com_sprintf( pingBuff, sizeof(pingBuff), S_COLOR_RED "%s", Info_ValueForKey(info, "ping") ); + return pingBuff; + case SORT_GAMETYPE : + return strlen(Info_ValueForKey(info, "game")) ? Info_ValueForKey(info, "game") : "base"; } } } else if (feederID == FEEDER_SERVERSTATUS) { Index: src/ui/ui_public.h =================================================================== --- src/ui/ui_public.h (revision 894) +++ src/ui/ui_public.h (working copy) @@ -148,7 +148,8 @@ SORT_HOST, SORT_MAP, SORT_CLIENTS, - SORT_PING + SORT_PING, + SORT_GAMETYPE } serverSortField_t; typedef enum { Index: src/ui/ui_shared.c =================================================================== --- src/ui/ui_shared.c (revision 894) +++ src/ui/ui_shared.c (working copy) @@ -3821,6 +3821,7 @@ refdef_t refdef; refEntity_t ent; vec3_t mins, maxs, origin; + vec3_t axis[3]; vec3_t angles; modelDef_t *modelPtr = (modelDef_t*)item->typeData; @@ -3884,8 +3885,21 @@ modelPtr->angle = (int)(modelPtr->angle + 1) % 360; } } - VectorSet( angles, 0, modelPtr->angle, 0 ); - AnglesToAxis( angles, ent.axis ); + //VectorSet( angles, 0, modelPtr->angle, 0 ); + //AnglesToAxis( angles, ent.axis ); + if(VectorLengthSquared(modelPtr->axis)) + { + VectorCopy( modelPtr->axis, axis[2] ); + VectorNormalize( axis[2] ); + MakeNormalVectors( modelPtr->axis , axis[0] , axis[1] ); + RotateAroundDirection(axis, modelPtr->angle ); + AxisCopy( axis , ent.axis ); + } + else + { + VectorSet( angles, 0, modelPtr->angle, 0 ); + AnglesToAxis( angles, ent.axis ); + } ent.hModel = item->asset; VectorCopy( origin, ent.origin ); @@ -4794,6 +4808,22 @@ return qtrue; } +// model_axis //::// +qboolean ItemParse_model_axis( itemDef_t *item, int handle ) { + modelDef_t *modelPtr; + Item_ValidateTypeData(item); + modelPtr = (modelDef_t*)item->typeData; + + if (PC_Float_Parse(handle, &modelPtr->axis[0])) { + if (PC_Float_Parse(handle, &modelPtr->axis[1])) { + if (PC_Float_Parse(handle, &modelPtr->axis[2])) { + return qtrue; + } + } + } + return qfalse; +} + // rect qboolean ItemParse_rect( itemDef_t *item, int handle ) { if (!PC_Rect_Parse(handle, &item->window.rectClient)) { @@ -5385,6 +5415,7 @@ {"asset_model", ItemParse_asset_model, NULL}, {"asset_shader", ItemParse_asset_shader, NULL}, {"model_origin", ItemParse_model_origin, NULL}, + {"model_axis", ItemParse_model_axis, NULL}, {"model_fovx", ItemParse_model_fovx, NULL}, {"model_fovy", ItemParse_model_fovy, NULL}, {"model_rotation", ItemParse_model_rotation, NULL}, Index: src/ui/ui_shared.h =================================================================== --- src/ui/ui_shared.h (revision 894) +++ src/ui/ui_shared.h (working copy) @@ -213,6 +213,7 @@ vec3_t origin; float fov_x; float fov_y; + vec3_t axis; int rotationSpeed; } modelDef_t; Index: ui/infopanes.def.h =================================================================== --- ui/infopanes.def.h (revision 894) +++ ui/infopanes.def.h (working copy) @@ -1,16 +1,18 @@ -#include "/home/tma/tremulous/src/game/tremulous.h" +#include "../src/game/tremulous.h" #define CREDITS(X) text "Credits: " text X +#define EVOS(X) text "Evos: " text X #define HUMAN_BCOST(X) text "Power: " text X #define ALIEN_BCOST(X) text "Sentience: " text X + //team menu { name alienteam text "The Alien Team\n\n" text "The Aliens' strengths are in movement " - text "and the ability to quickly construct new bases quickly. They possess a " + text "and the ability to quickly construct new bases. They possess a " text "range of abilities including basic melee attacks, movement-" text "crippling poisons and more." align left @@ -51,15 +53,17 @@ name ckititem text "Construction kit\n\n" text "Used for building all basic structures. This includes " - text "spawns, power and basic defense.\n\n" + text "spawns, power and basic defense.\n" + text "It can be used to heal aliens/humans too.\n\n" text "Credits: Free" } { name ackititem text "Advanced Construction kit\n\n" - text "Used for building advanced structures. This includes " - text "combat computers and advanced defense.\n\n" + text "Used for building/repairing advanced structures. This includes " + text "combat computers and advanced defense.\n" + text "It can be used to heal aliens/humans too.\n\n" text "Credits: Free" } @@ -108,6 +112,13 @@ } { + name stasisitem + text "Stasis Gun\n\n" + text "Unknown weapon.\n\n" + CREDITS( STASIS_PRICE ) +} + +{ name lcannonitem text "Lucifer Cannon\n\n" text "Similar to the pulse rifle, but more powerful. " @@ -117,6 +128,13 @@ } { + name xaelitem + text "Xael\n\n" + text "Unknown weapon.\n\n" + CREDITS( XAEL_PRICE ) +} + +{ name lgunitem text "Las Gun\n\n" text "Slightly more powerful than the basic rifle, but " @@ -167,6 +185,22 @@ } { + name ammopackitem + text "Ammo Pack\n\n" + text "Back-mounted ammo pack that permits storage of extra clips " + text "for non-energy weapons.\n\n" + CREDITS( AMMOPACK_PRICE ) +} + +{ + name surgeitem + text "Surge\n\n" + text "A clip extension that can be only used for lasgun and massdriver. " + text "It doubles the ammo usage and damage.\n\n" + CREDITS( SURGE_PRICE ) +} + +{ name jetpackitem text "Jet Pack\n\n" text "Back-mounted jet pack that enables the user to fly to remote " @@ -191,7 +225,14 @@ text "Credits: Free" } +{ + name regenitem + text "Bio Kit\n\n" + text "An implant that helps its user to regenerate health and stamina.\n\n" + CREDITS( REGEN_PRICE ) +} + //human structures { @@ -261,6 +302,7 @@ text "Repeater\n\n" text "A power distributor that transmits power from the reactor " text "to remote locations, so that bases may be built far from the reactor.\n\n" + HUMAN_BCOST( REPEATER_BP ) } //alien structures @@ -286,7 +328,8 @@ name barricadebuild text "Barricade\n\n" text "Used to obstruct corridors and doorways, " - text "hindering humans from threatening the spawns and Overmind.\n\n" + text "hindering humans from threatening the spawns and Overmind.\n" + text "Damages enemies that are too close.\n\n" ALIEN_BCOST( BARRICADE_BP ) } @@ -324,7 +367,8 @@ text "attacks. In addition to the default attack damage, the victim loses " text "health over time unless they heal themselves with a medkit." text "The booster also increases the rate of health regeneration for " - text "any nearby aliens.\n\n" + text "any nearby aliens.\n" + text "Damages enemies that are too close.\n\n" ALIEN_BCOST( BOOSTER_BP ) } @@ -342,7 +386,8 @@ name builderclass text "Granger\n\n" text "Responsible for building and maintaining all " - text "the alien structures." + text "the alien structures.\n\n" + text "Evos: Free" } { @@ -350,22 +395,33 @@ text "Advanced Granger\n\n" text "Similar to the base Granger, " text "except that in addition to being able to build structures it has a " - text "melee attack and the ability to crawl on walls." + text "melee attack and the ability to crawl on walls.\n\n" + text "Evos: Free" } { name level0class text "Dretch\n\n" text "Has a lethal bite and the ability to crawl " - text "on walls and ceilings." + text "on walls and ceilings.\n\n" + text "Evos: Free" } { + name level0upgclass + text "Advanced Dretch\n\n" + text "The Advanced Dretch has all the abilities of the basic Dretch. " + text "In addition it has drill ability.\n\n" + EVOS( LEVEL0_UPG_COST ) +} + +{ name level1class text "Basilisk\n\n" text "Able to crawl on walls and ceilings. " text "Its melee attack is most effective when combined with the ability to " - text "grab its foe." + text "grab its foe.\n\n" + EVOS( LEVEL1_COST ) } { @@ -373,21 +429,25 @@ text "Advanced Basilisk\n\n" text "In addition to the basic Basilisk abilities, the Advanced " text "Basilisk sprays a poisonous gas which disorientaits any " - text "nearby humans." + text "nearby humans.\n" + text "It becomes invisible if stays still for a while.\n\n" + EVOS( LEVEL1_UPG_COST ) } { name level2class text "Marauder\n\n" text "Has a melee attack and the ability to jump off walls." - text "This allows the Marauder to gather great speed in enclosed areas." + text "This allows the Marauder to gather great speed in enclosed areas.\n\n" + EVOS( LEVEL2_COST ) } { name level2upgclass text "Advanced Marauder\n\n" text "The Advanced Marauder has all the abilities of the base Marauder " - text "including an area effect electric shock attack." + text "including 3 barbs which may be used to attack humans from a distance.\n\n" + EVOS( LEVEL2_UPG_COST ) } { @@ -395,14 +455,16 @@ text "Dragoon\n\n" text "Possesses a melee attack and the pounce ability, which may " text "be used as an attack, or a means to reach a remote location inaccessible " - text "from the ground." + text "from the ground.\n\n" + EVOS( LEVEL3_COST ) } { name level3upgclass text "Advanced Dragoon\n\n" text "In addition to the basic Dragoon abilities, the Dragoon Upgrade has " - text "3 barbs which may be used to attack humans from a distance." + text "an area effect electric shock attack.\n\n" + EVOS( LEVEL3_UPG_COST ) } { @@ -410,8 +472,15 @@ text "Tyrant\n\n" text "Provides a healing aura in which nearby aliens regenerate health " text "faster than usual. As well as a melee attack, this class can charge " - text "at enemy humans and structures, inflicting great damage." + text "at enemy humans and structures, inflicting great damage.\n\n" + EVOS( LEVEL4_COST ) } +{ + name level4upgclass + text "Advanced Tyrant\n\n" + text "It has an acid ball that can be used only once unless it is boosted.\n\n" + EVOS( LEVEL4_UPG_COST ) +} // graphic // graphic left center "gfx/blah" 64 128 Index: ui/joinserver.menu =================================================================== --- ui/joinserver.menu (revision 894) +++ ui/joinserver.menu (working copy) @@ -224,7 +224,7 @@ { name serverColumn group grpColumn - rect 10 130 365 232 + rect 10 130 300 232 style WINDOW_STYLE_FILLED border 1 backcolor 0 0 0 0 @@ -238,7 +238,7 @@ { name mapColumn group grpColumn - rect 375 130 125 232 + rect 310 130 100 232 style WINDOW_STYLE_FILLED border 1 backcolor 0 0 0 0 @@ -252,7 +252,7 @@ { name playerColumn group grpColumn - rect 500 130 60 232 + rect 410 130 60 232 style WINDOW_STYLE_FILLED border 1 backcolor 0 0 0 0 @@ -266,7 +266,7 @@ { name pingColumn group grpColumn - rect 560 130 52 232 + rect 470 130 60 232 style WINDOW_STYLE_FILLED border 1 backcolor 0 0 0 0 @@ -278,6 +278,20 @@ itemDef { + name gameColumn + group grpColumn + rect 530 130 100 232 + style WINDOW_STYLE_FILLED + border 1 + backcolor 0 0 0 0 + bordersize 1 + bordercolor .5 .5 .5 1 + visible 1 + decoration + } + + itemDef + { name serverlist rect 10 130 620 232 type ITEM_TYPE_LISTBOX @@ -293,11 +307,12 @@ backcolor 0.2 0.2 0.2 1 outlinecolor 0.1 0.1 0.1 0.5 visible 1 - columns 4 - 2 40 80 ITEM_ALIGN_LEFT - 375 40 20 ITEM_ALIGN_LEFT - 500 5 10 ITEM_ALIGN_LEFT - 560 20 20 ITEM_ALIGN_LEFT + columns 5 + 2 40 50 ITEM_ALIGN_LEFT + 302 40 20 ITEM_ALIGN_LEFT + 410 5 10 ITEM_ALIGN_LEFT + 470 20 20 ITEM_ALIGN_LEFT + 530 20 20 ITEM_ALIGN_LEFT doubleClick { uiScript JoinServer } } @@ -313,7 +328,7 @@ type ITEM_TYPE_BUTTON textscale .33 style WINDOW_STYLE_EMPTY - rect 10 103 365 26 + rect 10 103 300 26 textalign ITEM_ALIGN_LEFT textalignx 10 textaligny 18 @@ -341,7 +356,7 @@ text "Map Name" textscale .33 style WINDOW_STYLE_EMPTY - rect 375 103 125 26 + rect 310 103 100 26 textalign ITEM_ALIGN_LEFT textalignx 10 textaligny 18 @@ -369,7 +384,7 @@ type ITEM_TYPE_BUTTON textscale .33 style WINDOW_STYLE_EMPTY - rect 500 103 60 26 + rect 410 103 60 26 textalign ITEM_ALIGN_LEFT textalignx 10 textaligny 18 @@ -398,7 +413,7 @@ type ITEM_TYPE_BUTTON textscale .33 style WINDOW_STYLE_EMPTY - rect 560 103 70 26 + rect 470 103 60 26 textalign ITEM_ALIGN_LEFT textalignx 10 textaligny 18 @@ -417,8 +432,35 @@ setitemcolor pingColumn backcolor 0.3 1 1 0.5 } } + + itemDef + { + name game + group grpTabs + text "Game" + type ITEM_TYPE_BUTTON + textscale .33 + style WINDOW_STYLE_EMPTY + rect 530 103 100 26 + textalign ITEM_ALIGN_LEFT + textalignx 10 + textaligny 18 + border 1 + bordercolor 0.5 0.5 0.5 1 + forecolor 1 1 1 1 + backcolor 0.2 0.2 0.2 1 + outlinecolor 0.1 0.1 0.1 0.5 + visible 1 + action + { + play "sound/misc/menu1.wav"; + uiScript ServerSort 4; + + setitemcolor grpColumn backcolor 0 0 0 0; + setitemcolor gameColumn backcolor 0.3 1 1 0.5 + } + } - itemDef { name password Index: ui/main.menu =================================================================== --- ui/main.menu (revision 894) +++ ui/main.menu (working copy) @@ -27,9 +27,9 @@ fullScreen MENU_TRUE rect 0 0 640 480 // Size and position of the menu visible MENU_TRUE // Visible on open - focusColor 1 .75 0 1 // Menu focus color for text and items + focusColor 1 0 0 1 // Menu focus color for text and items - onOpen { uiScript stopRefresh ; playlooped "sound/ui/heartbeat.wav" } + //onOpen { uiScript stopRefresh ; playlooped "ui/assets/beef_rock_8-12-04.ogg" } onESC { open quit_popmenu } itemDef @@ -40,23 +40,79 @@ backcolor 0 0 0 1 visible 1 decoration - background "ui/assets/mainmenu.jpg" + background "ui/tremxbg.jpg" } - itemDef { - name splashmodel + name wormhole rect 0 0 640 480 type ITEM_TYPE_MODEL style WINDOW_STYLE_EMPTY - asset_model "models/splash/splash_screen.md3" - model_fovx 32.0 - model_fovy 24.0 - model_angle 180 + asset_model "ui/assets/wormhole.md3" + model_fovx 36 + model_fovy 36 + //model_angle 180 + //model_rotation 15 + //model_axis 0 0.0 1.0 visible 1 decoration } + /*itemDef + { + name background + rect 0 0 640 480 + style WINDOW_STYLE_SHADER + backcolor 0 0 0 1 + visible 1 + decoration + background "ui/smoke_s" + }*/ + itemDef + { + name logo + rect 160 5 320 155 + style WINDOW_STYLE_SHADER + backcolor 0 0 0 1 + visible 1 + decoration + background "ui/logo_s" + } + //itemDef + //{ + // name nebula + // rect 0 5 640 305 + // style WINDOW_STYLE_SHADER + // backcolor 0 0 0 1 + // visible 1 + // decoration + // background "models/splash/nebula" + //} + //itemDef models/splash/nebula + //{ + // name splashmodel + // rect 40 200 320 240 + // type ITEM_TYPE_MODEL + // style WINDOW_STYLE_EMPTY + // asset_model "ui/assets/planet.md3" + // model_fovx 48 + // model_fovy 36 + // model_angle 180 + // model_rotation 15 + // model_axis 0.2 0.6 0 + // visible 1 + // decoration + //} + //itemDef + //{ + // name backgr + // rect 40 200 320 240 + // style WINDOW_STYLE_SHADER + // visible 1 + // decoration + // background "ui/trcp" + //} + itemDef { name mainmenu @@ -64,12 +120,13 @@ type ITEM_TYPE_BUTTON style WINDOW_STYLE_EMPTY textstyle ITEM_TEXTSTYLE_NORMAL - rect 472 20 128 20 - textalign ITEM_ALIGN_RIGHT - textalignx 128 + rect 256 200 128 20 + textalign ITEM_ALIGN_CENTER + textalignx 64 textaligny 20 - textscale .416 + //textscale .416 forecolor 1 1 1 1 + backcolor 1 0 0 1 visible 1 action { @@ -82,47 +139,47 @@ itemDef { name mainmenu - text "Options" + text "Mods" type ITEM_TYPE_BUTTON style WINDOW_STYLE_EMPTY textstyle ITEM_TEXTSTYLE_NORMAL - textscale .416 - rect 472 40 128 20 - textalignx 128 + //textscale .416 + rect 256 230 128 20 + textalignx 64 textaligny 20 - textalign ITEM_ALIGN_RIGHT - backcolor 0 0 0 0 + textalign ITEM_ALIGN_CENTER + backcolor 0 1 0 1 forecolor 1 1 1 1 visible 1 action { play "sound/misc/menu1.wav"; - open simple_options + open mod } } itemDef { name mainmenu - text "Mods" + text "Options" type ITEM_TYPE_BUTTON - style WINDOW_STYLE_EMPTY + style WINDOW_STYLE_EMPTY textstyle ITEM_TEXTSTYLE_NORMAL - textscale .416 - rect 472 60 128 20 - textalignx 128 + rect 256 260 128 20 + textalignx 64 textaligny 20 - textalign ITEM_ALIGN_RIGHT - backcolor 0 0 0 0 + //textscale .416 + textalign ITEM_ALIGN_CENTER + backcolor 0 0 1 1 forecolor 1 1 1 1 visible 1 action { - play "sound/misc/menu1.wav"; - open mod + play "sound/misc/menu1.wav"; + open simple_options } } - + itemDef { name mainmenu @@ -130,16 +187,17 @@ type ITEM_TYPE_BUTTON style WINDOW_STYLE_EMPTY textstyle ITEM_TEXTSTYLE_NORMAL - rect 472 80 128 20 - textalignx 128 + rect 256 290 128 20 + textalignx 64 textaligny 20 - textscale .416 - textalign ITEM_ALIGN_RIGHT + //textscale .416 + textalign ITEM_ALIGN_CENTER + backcolor 0 0 1 1 forecolor 1 1 1 1 visible 1 action { - play "sound/misc/menu1.wav"; + play "sound/misc/menu1.wav"; open quit_popmenu } }