diff --git a/base/default.cfg b/base/default.cfg new file mode 100644 index 0000000..b8fa8b4 --- /dev/null +++ b/base/default.cfg @@ -0,0 +1,109 @@ +// +// SP JEDI ACADEMY DEFAULT CONFIG +// + +unbindall + +// +// WEAPONS +// +bind 1 "weapon 1" +bind 2 "weapon 2" +bind 3 "weapon 3" +bind 4 "weapon 4" +bind 5 "weapon 5" +bind 6 "weapon 6" +bind 7 "weapon 7" +bind 8 "weapon 8" +bind 9 "weapon 13" +bind 0 "weapon 9" +bind - "weapon 10" +bind = "weapon 0" + +bind \ weapongrabbed +bind [ weapprev +bind ] weapnext +bind mwheelup weapprev +bind mwheeldown weapnext + +// +// CHARACTER CONTROLS +// +bind CTRL +attack +bind ALT +altattack +bind SHIFT +speed +bind v +strafe +bind PGUP +lookup +bind PGDN +lookdown +bind END centerview +bind c +movedown +bind SPACE +moveup +bind ENTER +use +bind r +use + + +bind UPARROW +forward +bind DOWNARROW +back +bind LEFTARROW +left +bind RIGHTARROW +right +bind w +forward +bind a +moveleft +bind s +back +bind d +moveright +bind , +moveleft +bind . +moveright + +// +// FORCE POWERS +// + +bind F1 force_throw +bind F2 force_pull +bind F3 force_speed +bind F4 force_sight + +bind f +useforce +bind e forcenext +bind q forceprev + +bind TAB datapad +bind m datapad +bind p "cg_thirdperson !" +bind l saberAttackCycle + +// +// INVENTORY +// + +// +// QUICK KEYS +// + +//single only +bind F9 "load quick" +bind F10 "uimenu ingameloadmenu" +bind F11 "uimenu ingamesavemenu" +bind F12 "save quick" + +// +// MOUSE OPTIONS +// + +bind / +mlook + +// +// MOUSE BUTTONS +// + +bind MOUSE1 +attack +bind MOUSE2 +altattack +bind MOUSE3 saberAttackCycle + + +// +// CLIENT ENVIRONMENT COMMANDS +// + +bind ~ "toggleconsole" +bind ` "toggleconsole" + diff --git a/base/ext_data/MP/netf_overrides.txt b/base/ext_data/MP/netf_overrides.txt new file mode 100644 index 0000000..79d689f --- /dev/null +++ b/base/ext_data/MP/netf_overrides.txt @@ -0,0 +1,155 @@ +;rww - this file will allow you to override the number of bits any given +;entityState value is sent across the network in for your mod. Do not +;mess with this unless you know what you're doing as it's easily possible +;to mess something up terribly. Just remove the ; in front of any of the +;values that you want to override and use the desired bit num. 0 is a +;special-case value, it means to send across as a float. GENTITYNUM_BITS +;means to send in as many bits as it takes to send the highest possible +;entity number. +; +;pos.trTime, 32 +;pos.trBase[0], 0 +;pos.trBase[1], 0 +;pos.trDelta[0], 0 +;pos.trDelta[1], 0 +;pos.trBase[2], 0 +;apos.trBase[1], 0 +;pos.trDelta[2], 0 +;apos.trBase[0], 0 +;event, 10 +;angles2[1], 0 +;eType, 8 +;torsoAnim, 16 +;forceFrame, 16 +;eventParm, 8 +;legsAnim, 16 +;torsoFlip, 1 +;legsFlip, 1 +;groundEntityNum, GENTITYNUM_BITS +;pos.trType, 8 +;eFlags, 32 +;bolt1, 8 +;bolt2, GENTITYNUM_BITS +;trickedentindex, 16 +;trickedentindex2, 16 +;trickedentindex3, 16 +;trickedentindex4, 16 +;speed, 0 +;fireflag, 2 +;genericenemyindex, 32 +;activeForcePass, 6 +;emplacedOwner, 32 +;otherEntityNum, GENTITYNUM_BITS +;weapon, 32 +;clientNum, GENTITYNUM_BITS +;angles[1], 0 +;pos.trDuration, 32 +;apos.trType, 8 +;origin[0], 0 +;origin[1], 0 +;origin[2], 0 +;solid, 24 +;owner, GENTITYNUM_BITS +;teamowner, 8 +;shouldtarget, 1 +;powerups, 16 +;modelGhoul2, 8 +;g2radius, 8 +;modelindex, -16 +;otherEntityNum2, GENTITYNUM_BITS +;loopSound, 8 +;loopIsSoundset, 1 +;soundSetIndex, 8 +;generic1, 8 +;origin2[2], 0 +;origin2[0], 0 +;origin2[1], 0 +;modelindex2, 8 +;angles[0], 0 +;time, 32 +;apos.trTime, 32 +;apos.trDuration, 32 +;apos.trBase[2], 0 +;apos.trDelta[0], 0 +;apos.trDelta[1], 0 +;apos.trDelta[2], 0 +;time2, 32 +;angles[2], 0 +;angles2[0], 0 +;angles2[2], 0 +;constantLight, 32 +;frame, 16 +;saberInFlight, 1 +;saberEntityNum, GENTITYNUM_BITS +;saberMove, 8 +;forcePowersActive, 32 +;isJediMaster, 1 +;isPortalEnt, 1 +;heldByClient, 6 +;ragAttach, GENTITYNUM_BITS +;iModelScale, 10 +;brokenLimbs, 8 +;boltToPlayer, 6 +;hasLookTarget, 1 +;lookTarget, GENTITYNUM_BITS +; +;customRGBA[0], 8 +;customRGBA[1], 8 +;customRGBA[2], 8 +;customRGBA[3], 8 +; +;health, 10 +;maxhealth, 10 +; +;npcSaber1, 9 +;npcSaber2, 9 +; +;csSounds_Std, 8 +;csSounds_Combat, 8 +;csSounds_Extra, 8 +;csSounds_Jedi, 8 +; +;surfacesOn, 32 +;surfacesOff, 32 +; +;boneIndex1, 6 +;boneIndex2, 6 +;boneIndex3, 6 +;boneIndex4, 6 +; +;boneOrient, 9 +; +;boneAngles1[0], 0 +;boneAngles1[1], 0 +;boneAngles1[2], 0 +; +;boneAngles2[0], 0 +;boneAngles2[1], 0 +;boneAngles2[2], 0 +; +;boneAngles3[0], 0 +;boneAngles3[1], 0 +;boneAngles3[2], 0 +; +;boneAngles4[0], 0 +;boneAngles4[1], 0 +;boneAngles4[2], 0 +; +;NPC_class, 8 +; +;m_iVehicleNum, 10 +; +;eFlags2,10 +; +;userInt1, 1 +;userInt2, 1 +;userInt3, 1 +;userFloat1, 1 +;userFloat2, 1 +;userFloat3, 1 +;userVec1[0], 1 +;userVec1[1], 1 +;userVec1[2], 1 +;userVec2[0], 1 +;userVec2[1], 1 +;userVec2[2], 1 diff --git a/base/ext_data/MP/psf_overrides.txt b/base/ext_data/MP/psf_overrides.txt new file mode 100644 index 0000000..d1d2bb2 --- /dev/null +++ b/base/ext_data/MP/psf_overrides.txt @@ -0,0 +1,181 @@ +;rww - this file will allow you to override the number of bits any given +;playerState value is sent across the network in for your mod. Do not +;mess with this unless you know what you're doing as it's easily possible +;to mess something up terribly. Just remove the ; in front of any of the +;values that you want to override and use the desired bit num. 0 is a +;special-case value, it means to send across as a float. GENTITYNUM_BITS +;means to send in as many bits as it takes to send the highest possible +;entity number. +; +;commandTime, 32 +;origin[0], 0 +;origin[1], 0 +;bobCycle, 8 +;velocity[0], 0 +;velocity[1], 0 +;viewangles[1], 0 +;viewangles[0], 0 +; +;weaponTime, -16 +;weaponChargeTime, 32 +;weaponChargeSubtractTime, 32 +;origin[2], 0 +;velocity[2], 0 +;pm_time, -16 +;eventSequence, 16 +;torsoAnim, 16 +;torsoTimer, 16 +;legsAnim, 16 +;legsTimer, 16 +;legsFlip, 1 +;torsoFlip, 1 +;movementDir, 4 +;events[0], 10 +;events[1], 10 +;pm_flags, 16 +;groundEntityNum, GENTITYNUM_BITS +;weaponstate, 4 +;eFlags, 32 +;externalEvent, 10 +;gravity, 16 +;speed, -16 +;basespeed, -16 +;delta_angles[1], 16 +;externalEventParm, 8 +;viewheight, -8 +;damageEvent, 8 +;damageYaw, 8 +;damagePitch, 8 +;damageCount, 8 +;damageType, 2 +;generic1, 8 +;pm_type, 8 +;delta_angles[0], 16 +;delta_angles[2], 16 +;eventParms[0], -16 +;eventParms[1], 8 +;clientNum, GENTITYNUM_BITS +;weapon, 8 +;viewangles[2], 0 +; +;jumppad_ent, 10 +;loopSound, 16 +;loopIsSoundset, 1 +; +;zoomMode, 2 +;zoomTime, 32 +;zoomLocked, 1 +;zoomFov, 0 +; +;fd.forcePowersActive, 32 +;fd.forceMindtrickTargetIndex, 16 +;fd.forceMindtrickTargetIndex2, 16 +;fd.forceMindtrickTargetIndex3, 16 +;fd.forceMindtrickTargetIndex4, 16 +;fd.forceJumpZStart, 0 +;fd.forcePowerSelected, 8 +;fd.forcePowersKnown, 32 +;fd.forcePower, 8 +;fd.forceSide, 2 +;fd.sentryDeployed, 1 +;fd.forcePowerLevel[FP_LEVITATION], 2 +;fd.forcePowerLevel[FP_SEE], 2 +;fd.forceGripCripple, 1 +;genericEnemyIndex, 32 +;activeForcePass, 6 +;hasDetPackPlanted, 1 +;emplacedIndex, GENTITYNUM_BITS +;fd.forceRageRecoveryTime, 32 +;rocketLockIndex, GENTITYNUM_BITS +;rocketLockTime, 32 +;rocketTargetTime, 32 +;holocronBits, 32 +;isJediMaster, 1 +;forceRestricted, 1 +;trueJedi, 1 +;trueNonJedi, 1 +;fallingToDeath, 32 +;electrifyTime, 32 +; +;fd.forcePowerDebounce[FP_LEVITATION], 32 +; +;saberMove, 32 +;saberActive, 1 +;saberInFlight, 1 +;saberBlocked, 8 +;saberEntityNum, GENTITYNUM_BITS +;saberCanThrow, 1 +;forceHandExtend, 8 +;forceDodgeAnim, 16 +;fd.saberAnimLevel, 4 +;fd.saberDrawAnimLevel, 4 +;saberAttackChainCount, 4 +;saberHolstered, 1 +; +;jetpackFuel, 8 +;cloakFuel, 8 +; +;duelIndex, GENTITYNUM_BITS +;duelTime, 32 +;duelInProgress, 1 +; +;saberLockTime, 32 +;saberLockEnemy, GENTITYNUM_BITS +;saberLockFrame, 16 +;saberLockAdvance, 1 +; +;inAirAnim, 1 +; +;lastHitLoc[2], 0 +;lastHitLoc[0], 0 +;lastHitLoc[1], 0 +; +;heldByClient, 6 +;ragAttach, GENTITYNUM_BITS +;iModelScale, 10 +;brokenLimbs, 8 +;hasLookTarget, 1 +;lookTarget, GENTITYNUM_BITS +; +;customRGBA[0], 8 +;customRGBA[1], 8 +;customRGBA[2], 8 +;customRGBA[3], 8 +; +;standheight, 10 +;crouchheight, 10 +; +;m_iVehicleNum, GENTITYNUM_BITS +; +;vehOrientation[0], 0 +;vehOrientation[1], 0 +;vehOrientation[2], 0 +; +;vehSurfaces, 16 +; +;vehTurnaroundIndex, GENTITYNUM_BITS +;vehTurnaroundTime, 32 +; +;moveDir[0], 0 +;moveDir[1], 0 +;moveDir[2], 0 +; +;vehBoarding, 1 +; +;hackingTime, 32 +;hackingBaseTime, 16 +; +;eFlags2,10 +; +;userInt1, 1 +;userInt2, 1 +;userInt3, 1 +;userFloat1, 1 +;userFloat2, 1 +;userFloat3, 1 +;userVec1[0], 1 +;userVec1[1], 1 +;userVec1[2], 1 +;userVec2[0], 1 +;userVec2[1], 1 +;userVec2[2], 1 diff --git a/base/ext_data/MP/vssver.scc b/base/ext_data/MP/vssver.scc new file mode 100644 index 0000000..fa23a9e Binary files /dev/null and b/base/ext_data/MP/vssver.scc differ diff --git a/base/ext_data/dms.dat b/base/ext_data/dms.dat new file mode 100644 index 0000000..fc5cc9b --- /dev/null +++ b/base/ext_data/dms.dat @@ -0,0 +1,1757 @@ +musicfiles +{ + kejimbase_explore + { + entry + { + marker0 0.000 + marker1 22.070 + marker2 53.723 + marker3 90.926 + } + exit + { + nextfile kejimbase_etr00 + time00 3.337 + time01 5.668 + time02 22.040 + time03 29.889 + time04 50.124 + time05 37.168 + time06 53.473 + time07 65.923 + time08 90.478 + time09 143.233 + time10 156.166 + time11 176.608 + time12 193.505 + } + exit + { + nextfile kejimbase_etr01 + time00 45.555 + time01 81.525 + time02 106.406 + time03 128.648 + time04 185.168 + time05 209.309 + } + } + kejimbase_action + { + entry + { + marker0 0.00 + marker1 42.585 + marker2 87.664 + } + exit + { + nextfile kejimbase_atr00 + nextmark marker0 + time00 69.347 + time01 72.142 + time02 80.444 + time03 87.608 + time04 90.185 + } + exit + { + nextfile kejimbase_atr01 + nextmark marker1 + time00 2.434 + time01 5.667 + time02 20.281 + } + exit + { + nextfile kejimbase_atr02 + nextmark marker2 + time00 62.894 + } + exit + { + nextfile kejimbase_atr03 + nextmark marker3 + time00 12.397 + time01 28.679 + time02 35.492 + time03 45.328 + } + } + ImpBaseB_Explore + { + entry + { + marker0 0 + marker1 37 + marker2 69.81 + marker3 119.97 + } + exit + { + nextfile ImpBaseB_Etr00 + time0 37 + time1 54.0 + time2 62.35 + time3 69.81 + time4 79.85 + time5 119.97 + time6 132.75 + time7 146.88 + } + exit + { + nextfile ImpBaseB_Etr01 + time0 13.67 + time1 26.96 + time2 89.42 + time3 96.92 + time4 107.77 + } + + } + ImpBaseB_Action + { + entry + { + marker0 0 + marker1 30.23 + marker2 45.45 + marker3 104.48 + } + exit + { + nextfile ImpBaseB_Atr00 + nextmark marker3 + time0 38.22 + time1 50.31 + time2 59.23 + time3 64.47 + time4 80.41 + time5 87.69 + time6 92.01 + time7 98.07 + time8 104.48 + } + exit + { + nextfile ImpBaseB_Atr01 + nextmark marker2 + time0 8.91 + time1 20.89 + } + exit + { + nextfile ImpBaseB_Atr02 + nextmark marker1 + time0 25.45 + time1 30.23 + } + exit + { + nextfile ImpBaseB_Atr03 + nextmark marker0 + time0 4.97 + time1 11.33 + time2 16.11 + time3 45.45 + time4 70.61 + time5 74.66 + } + } + ImpBaseC_explore + { + entry + { + marker0 0.000 + marker1 55.831 + marker2 11.160 + marker3 11.160 + + } + exit + { + nextfile ImpBaseC_etr00 + time00 42.904 + time01 71.172 + time02 127.721 + time03 150.290 + time04 171.618 + + } + exit + { + nextfile ImpBaseC_etr01 + time00 19.096 + time01 26.412 + time02 88.211 + time03 101.169 + + } + } + ImpBaseC_action + { + entry + { + marker0 0.00 + marker1 19.468 + marker2 33.480 + } + exit + { + nextfile ImpBaseC_atr00 + nextmark marker0 + time00 2.542 + time01 5.440 + time02 9.470 + time03 19.366 + } + exit + { + nextfile ImpBaseC_atr01 + nextmark marker1 + time00 25.544 + time01 29.140 + } + exit + { + nextfile ImpBaseC_atr02 + nextmark marker2 + time00 44.888 + } + exit + { + nextfile ImpBaseC_atr03 + nextmark marker3 + time00 34.272 + time01 65.224 + } + } + BespinA_Explore + { + entry + { + marker0 6.74 + marker1 17.51 + marker2 95.95 + marker3 149.87 + } + exit + { + nextfile BespinA_Etr00 + time00 42.01 + } + exit + { + nextfile BespinA_Etr01 + time00 165.65 + } + exit + { + nextfile BespinA_Etr02 + time00 17.51 + time01 29.50 + time02 54.80 + time03 70.21 + time04 90.25 + time05 106.40 + time06 120.53 + time07 149.87 + time08 178.36 + } + } + BespinA_Action + { + entry + { + marker0 0.00 + marker1 42.585 + marker2 87.664 + } + exit + { + nextfile BespinA_Atr00 + nextmark marker0 + time00 3.08 + time01 6.19 + time02 35.26 + } + exit + { + nextfile BespinA_Atr01 + nextmark marker1 + time00 8.98 + time01 14.76 + time02 20.65 + time03 44.34 + time04 47.28 + } + exit + { + nextfile BespinA_Atr02 + nextmark marker2 + time00 51.82 + time01 58.00 + } + exit + { + nextfile BespinA_Atr03 + nextmark marker3 + time00 28.90 + time01 64.78 + } + } + + besplat_explore + { + entry + { + marker0 46.78 + marker1 69.05 + marker2 85.85 + } + exit + { + nextfile besplat_etr00 + time0 6.89 + time1 21.26 + time3 55.52 + time4 69.75 + time5 85.87 + time6 98.12 + time7 119.44 + time8 131.95 + time9 157.58 + } + exit + { + nextfile besplat_etr01 + time0 34.15 + time1 141.84 + time2 174.72 + time3 183.05 + } + } + + besplat_action + { + entry + { + marker0 0 + marker1 16.56 + marker2 24.86 + marker3 62.37 + } + exit + { + nextfile besplat_atr00 + nextmark marker1 + time0 2.82 + time1 68.46 + } + exit + { + nextfile besplat_atr01 + nextmark marker2 + time0 41.23 + time1 54.20 + time2 59.31 + time3 76.51 + } + exit + { + nextfile besplat_atr02 + nextmark marker0 + time0 13.47 + time1 21.19 + time2 24.65 + time3 28.82 + time4 83.53 + } + } + + besplat_boss + { + } + + yavtrial_explore + { + entry + { + marker0 124.126 + marker1 102.326 + marker2 24.853 + marker3 0.00 + } + exit + { + nextfile yavtrial_etr00 + time00 3.095 + time01 23.931 + time02 24.937 + time03 46.905 + time04 61.268 + time05 79.042 + time06 101.750 + time07 118.136 + time08 147.951 + } + exit + { + nextfile yavtrial_etr01 + time00 161.783 + } + } + yavtrial_action + { + entry + { + marker0 0.00 + marker1 60.145 + marker2 85.922 + } + exit + { + nextfile yavtrial_atr00 + nextmark marker0 + time00 3.553 + time01 6.118 + time02 8.718 + time03 41.152 + time04 103.559 + } + exit + { + nextfile yavtrial_atr01 + nextmark marker1 + time00 9.307 + time01 12.310 + time02 16.719 + time03 20.045 + time04 26.229 + time05 35.160 + } + exit + { + nextfile yavtrial_atr02 + nextmark marker2 + time00 59.302 + time01 65.837 + time02 74.429 + } + exit + { + nextfile yavtrial_atr03 + nextmark marker3 + time00 38.325 + time01 49.857 + } + } + alienha_explore + { + entry + { + marker0 0 + marker1 65.84 + marker2 93.63 + } + exit + { + nextfile alienha_etr00 + time0 5.80 + time1 33.04 + time3 67.61 + } + exit + { + nextfile alienha_etr01 + time0 94.47 + time1 103.06 + time2 115.75 + time3 127.32 + time4 138.36 + time5 152.10 + time6 166.11 + time7 180.29 + } + } + alienha_action + { + entry + { + marker0 0 + marker1 40.96 + marker2 63.33 + } + exit + { + nextfile alienha_atr00 + nextmark marker2 + time0 3.35 + time1 6.85 + time3 15.70 + time4 22.61 + } + exit + { + nextfile alienha_atr01 + nextmark marker0 + time0 31.85 + time1 41.42 + time2 47.06 + } + exit + { + nextfile alienha_atr03 + nextmark marker1 + time0 53.01 + time1 58.57 + time2 62.87 + time3 72.03 + time4 89.64 + time5 96.94 + } + } + tunnels_explore + { + entry + { + marker0 0 + marker1 64.20 + marker2 96.47 + } + exit + { + nextfile tunnels_etr00 + time0 6.06 + time1 18.26 + time3 35.01 + time4 42.98 + time5 69.73 + time6 84.16 + } + exit + { + nextfile tunnels_etr01 + time0 94.81 + time1 111.25 + time2 121.77 + time3 134.68 + } + } + tunnels_action + { + entry + { + marker0 0 + marker1 22.39 + } + exit + { + nextfile tunnels_atr00 + nextmark marker0 + time0 0.29 + } + exit + { + nextfile tunnels_atr01 + nextmark marker2 + time0 15.62 + time1 22.94 + } + exit + { + nextfile tunnels_atr02 + nextmark marker2 + time0 29.14 + time1 35.63 + time2 45.33 + time3 51.78 + time4 58.67 + } + exit + { + nextfile tunnels_atr03 + nextmark marker1 + time0 64.81 + time1 68.53 + time2 72.28 + time3 75.89 + } + } + IMPBaseD_explore + { + entry + { + marker0 0.000 + marker1 66.790 + marker2 102.874 + marker3 150.554 + } + exit + { + nextfile IMPBaseD_etr00 + time00 7.997 + time01 16.678 + time02 44.664 + time03 70.836 + + } + exit + { + nextfile IMPBaseD_etr01 + time00 89.986 + time01 111.971 + time02 130.629 + time03 166.389 + time04 172.530 + } + } + IMPBaseD_action + { + entry + { + marker0 6.607 + marker1 60.118 + marker2 140.053 + } + exit + { + nextfile IMPBaseD_atr00 + nextmark marker0 + time00 6.457 + time01 13.265 + time02 18.757 + time03 25.194 + time04 152.772 + } + exit + { + nextfile IMPBaseD_atr01 + nextmark marker1 + time00 30.336 + time01 37.883 + time02 46.802 + time03 61.122 + } + exit + { + nextfile IMPBaseD_atr02 + nextmark marker2 + time00 78.257 + time01 85.312 + time02 92.170 + time03 140.866 + time04 149.597 + } + exit + { + nextfile IMPBaseD_atr03 + nextmark marker3 + time00 105.982 + time01 115.569 + time02 128.476 + } + } + swamp_explore + { + entry + { + marker0 0.000 + marker1 16.916 + marker2 80.714 + marker3 31.761 + + } + exit + { + nextfile swamp_etr00 + time00 11.185 + time01 20.989 + time02 51.408 + time03 63.196 + time04 71.293 + + } + exit + { + nextfile swamp_etr01 + time00 42.044 + time01 78.362 + time02 95.485 + time03 113.023 + + } + } + swamp_action + { + entry + { + marker0 0.00 + marker1 36.318 + marker2 45.982 + } + exit + { + nextfile swamp_atr00 + nextmark marker0 + time00 1.035 + } + exit + { + nextfile swamp_atr01 + nextmark marker1 + time00 6.835 + time01 11.323 + time02 18.592 + time03 36.230 + time04 59.793 + } + exit + { + nextfile swamp_atr02 + nextmark marker2 + time00 34.108 + time01 79.955 + time02 89.847 + time03 126.994 + + } + exit + { + nextfile swamp_atr03 + nextmark marker3 + time00 102.414 + time01 115.382 + time02 120.039 + } + } + yavtemp2_explore + { + entry + { + marker0 88.28 + marker1 48.10 + marker2 117.47 + marker3 0 + } + exit + { + nextfile yavtemp2_etr00 + time0 46.23 + time1 53.44 + time2 62.08 + time3 69.09 + time4 77.08 + time5 87.03 + time6 96.49 + } + exit + { + nextfile yavtemp2_etr01 + time0 15.24 + time1 31.79 + time2 42.78 + time3 114.18 + time4 134.25 + time5 144.89 + time6 160.03 + time7 168.03 + } + } + yavtemp2_action + { + entry + { + marker0 0 + marker1 17.35 + marker2 43.31 + marker3 60.39 + } + exit + { + nextfile yavtemp2_atr00 + nextmark marker0 + time0 0 + time1 8.78 + time2 13.47 + } + exit + { + nextfile yavtemp2_atr01 + nextmark marker1 + time0 23.89 + time1 28.62 + time2 41.11 + time3 46.73 + } + exit + { + nextfile yavtemp2_atr02 + nextmark marker2 + time0 48.95 + time1 60.59 + time2 69.13 + time3 97.63 + } + exit + { + nextfile yavtemp2_atr03 + nextmark marker3 + time0 91.11 + } + } + ImpBaseE_explore + { + entry + { + marker0 0.000 + marker1 13.805 + marker2 29.265 + marker3 137.915 + + } + exit + { + nextfile ImpBaseE_etr00 + time00 13.712 + time01 37.872 + time02 52.541 + time03 131.875 + time04 232.256 + + } + exit + { + nextfile ImpBaseE_etr01 + time00 120.057 + time01 157.080 + time02 176.388 + + } + } + ImpBaseE_action + { + entry + { + marker0 0.00 + marker1 18.336 + marker2 52.491 + } + exit + { + nextfile ImpBaseE_atr00 + nextmark marker0 + time00 22.012 + time01 32.861 + time02 73.853 + time03 77.808 + } + exit + { + nextfile ImpBaseE_atr01 + nextmark marker1 + time00 5.824 + time01 18.457 + time02 81.088 + time03 114.805 + } + exit + { + nextfile ImpBaseE_atr02 + nextmark marker2 + time00 1.923 + time01 26.892 + time02 30.703 + time03 59.294 + time04 65.331 + time05 88.803 + time06 91.876 + + } + exit + { + nextfile ImpBaseE_atr03 + nextmark marker3 + time00 11.958 + time01 43.027 + time02 48.014 + time04 96.757 + time05 107.858 + time06 130.437 + } + } + alienhb_explore + { + entry + { + marker0 127.71 + marker1 36.56 + marker2 89.94 + } + exit + { + nextfile alienhb_etr00 + time0 13.60 + time1 22.58 + time3 31.69 + time4 41.08 + time5 53.08 + time6 67.91 + time7 89.29 + time8 181.41 + } + exit + { + nextfile alienhb_etr01 + time0 109.08 + time1 123.18 + time2 134.76 + time3 149.54 + time4 160.53 + time5 174.10 + } + } + alienhb_action + { + entry + { + marker0 0 + marker1 6.85 + marker2 31.84 + marker3 66.77 + } + exit + { + nextfile alienhb_atr00 + nextmark marker0 + time0 5.29 + time1 21.54 + time3 26.21 + time4 120.30 + } + exit + { + nextfile alienhb_atr01 + nextmark marker1 + time0 10.35 + time1 17.03 + } + exit + { + nextfile alienhb_atr02 + nextmark marker2 + time0 60.27 + time1 70.21 + time2 80.36 + time3 93.55 + time4 100.47 + time5 111.75 + } + } + yavfinal_explore + { + entry + { + marker0 0.000 + marker1 18.664 + marker2 53.390 + marker3 97.161 + + } + exit + { + nextfile yavfinal_etr00 + time00 53.434 + time01 83.935 + + } + exit + { + nextfile yavfinal_etr01 + time00 9.852 + time01 94.171 + time02 104.106 + + } + } + yavfinal_action + { + entry + { + marker0 0.00 + marker1 43.094 + marker2 73.785 + } + exit + { + nextfile yavfinal_atr00 + nextmark marker0 + time00 53.502 + time01 61.386 + } + exit + { + nextfile yavfinal_atr01 + nextmark marker1 + time00 3.623 + time01 96.341 + } + exit + { + nextfile yavfinal_atr02 + nextmark marker2 + time00 9.019 + time01 11.707 + time02 15.535 + time03 29.107 + time04 35.847 + time05 75.327 + time06 101.992 + + } + exit + { + nextfile yavfinal_atr03 + nextmark marker3 + time00 21.257 + time01 25.167 + time02 43.800 + time03 106.249 + time04 113.638 + + } + } + yavfinal_boss + { + } + narshaada_explore + { + entry + { + marker0 123.18 + marker1 0 + marker2 43.30 + marker3 12.27 + } + exit + { + nextfile narshaada_etr00 + time0 55.86 + time1 70.17 + time2 78.63 + time3 88.61 + time4 106.57 + + } + exit + { + nextfile narshaada_etr01 + time0 13.75 + time1 31.29 + time2 43.84 + time4 123.91 + time5 134.92 + time6 149.29 + time7 168.16 + time8 184.19 + } + } + narshaada_action + { + entry + { + marker0 0 + marker1 15.65 + marker2 47.07 + } + exit + { + nextfile narshaada_atr00 + nextmark marker0 + time0 2.72 + time1 59.84 + time2 63.90 + time3 74.16 + time4 82.37 + } + exit + { + nextfile narshaada_atr01 + nextmark marker1 + time0 10.89 + time1 20.59 + time2 28.15 + time3 39.65 + time4 46.35 + } + exit + { + nextfile narshaada_atr02 + nextmark marker2 + time0 48.98 + time1 69.05 + } + exit + { + nextfile narshaada_atr03 + nextmark marker3 + time0 86.14 + time1 90.73 + time2 96.40 + time3 101.09 + } + } + tusken_explore + { + entry + { + marker0 0.000 + marker1 10.583 + marker2 71.039 + marker3 135.541 + } + exit + { + nextfile tusken_etr00 + time00 10.861 + time01 71.150 + time02 90.767 + time03 120.357 + } + exit + { + nextfile tusken_etr01 + time00 37.902 + time01 54.526 + time02 83.563 + } + } + tusken_action + { + entry + { + marker0 0.00 + marker1 12.897 + marker2 43.0 + marker3 91.709 + } + exit + { + nextfile tusken_atr00 + nextmark marker0 + time00 6.123 + time01 8.034 + time02 16.540 + time03 23.633 + time04 104.980 + } + exit + { + nextfile tusken_atr01 + nextmark marker1 + time00 57.368 + time01 63.503 + time02 66.717 + time03 77.926 + time04 90.472 + time05 93.797 + time06 98.102 + time07 108.327 + } + exit + { + nextfile tusken_atr02 + nextmark marker2 + time00 32.583 + } + exit + { + nextfile tusken_atr03 + nextmark marker3 + time00 31.374 + time01 40.811 + time02 43.581 + time03 46.745 + time04 53.173 + time05 71.815 + time06 74.780 + time07 82.316 + time08 87.553 + } + } + hoth2_explore + { + entry + { + marker0 0 + marker1 43.374 + marker2 101.295 + marker3 128 + } + exit + { + nextfile hoth2_etr00 + time00 0.6 + time01 68.013 + time02 102.813 + time03 140.937 + } + exit + { + nextfile hoth2_etr01 + time00 39.663 + time01 53.196 + time02 96.547 + time03 119.562 + time04 142.523 + } + + } + hoth2_action + { + entry + { + marker0 0 + marker1 27.263 + marker2 87.276 + marker3 117.919 + } + exit + { + nextfile hoth2_atr00 + nextmark marker0 + time00 7.092 + time01 14.241 + time02 20.347 + time03 67.703 + time04 69.517 + time05 71.844 + time06 75.125 + time07 78 + time08 82.965 + time09 129.589 + time10 158.426 + } + exit + { + nextfile hoth2_atr01 + nextmark marker1 + time00 25.993 + time01 29.983 + time02 35.6 + time03 38.318 + time04 40.995 + time05 42.335 + time06 52.587 + time07 57.297 + time08 60.622 + time09 62.617 + time10 84.422 + time11 96.308 + time12 98.358 + time13 102.459 + time14 104.409 + time15 109.8 + time16 118.721 + time17 141.128 + time18 145.861 + time19 150.9 + } + exit + { + nextfile hoth2_atr02 + nextmark marker2 + time00 32.915 + + } + exit + { + nextfile hoth2_atr03 + nextmark marker3 + time00 42.924 + time01 46.027 + time02 48.611 + time03 50.384 + time04 52.047 + time05 86.486 + time06 90.032 + time07 94.786 + time08 124.69 + time09 153.883 + } + } + dealsour_explore + { + entry + { + marker0 0.000 + marker1 100.492 + marker2 126.154 + + } + exit + { + nextfile dealsour_etr00 + time00 5.153 + time01 26.487 + time02 64.556 + time03 93.205 + time04 108.166 + time05 138.145 + } + exit + { + nextfile dealsour_etr01 + time00 9.143 + time01 21.223 + time02 43.388 + time03 87.830 + time04 116.589 + } + } + dealsour_action + { + entry + { + marker0 0.00 + marker1 65.166 + marker2 100.575 + } + exit + { + nextfile dealsour_atr00 + nextmark marker0 + time00 4.765 + time01 17.278 + time02 26.365 + time03 53.352 + time04 57.175 + time05 82.776 + } + exit + { + nextfile dealsour_atr01 + nextmark marker1 + time00 13.321 + time01 91.953 + time02 104.975 + } + exit + { + nextfile dealsour_atr02 + nextmark marker2 + time00 36.351 + time01 44.386 + time02 59.624 + time03 70.075 + time04 79.435 + time05 95.511 + } + } + rancor_explore + { + entry + { + marker0 0 + marker1 46.103 + marker2 88.328 + + } + exit + { + nextfile rancor_etr00 + time00 0.775 + time01 5.319 + time02 16.291 + time03 43.222 + time04 49.539 + time05 63.725 + time06 84.0 + time07 103.623 + + + } + exit + { + nextfile rancor_etr01 + time00 10.08 + time01 26.820 + time02 51.645 + time03 68.213 + time04 129.279 + } + + } + rancor_action + { + entry + { + marker0 0 + marker1 54.928 + marker2 88.315 + } + exit + { + nextfile rancor_atr00 + nextmark marker0 + time00 0.05 + time01 2.737 + time02 7.918 + time03 10.079 + time04 84.256 + time05 90.440 + time06 95.759 + time07 105.562 + time08 105.562 + time09 111.159 + time10 113.985 + time11 118.03 + } + exit + { + nextfile rancor_atr01 + nextmark marker1 + time00 8.921 + time01 24.975 + time02 31.458 + time03 35.586 + time04 38.523 + time05 56.3 + time06 60 + time07 65.549 + time08 73.223 + time09 77.467 + time10 102.791 + time11 123.9 + time12 141.193 + time13 144.02 + time14 146.296 + time15 151.234 + time16 155.057 + time17 157.329 + } + exit + { + nextfile rancor_atr02 + nextmark marker2 + time00 5.098 + time01 9.309 + time02 19.508 + time03 74.323 + time04 80.898 + time05 86.123 + time06 99.754 + time07 132.448 + time08 136.504 + time09 148.230 + time10 161.263 + } + } + korrib_lite_explore + { + entry + { + marker0 0.000 + marker1 20.170 + marker2 51.645 + marker3 73.201 + } + exit + { + nextfile korrib_lite_etr00 + time00 40.866 + time01 55.635 + time02 68.222 + } + exit + { + nextfile korrib_lite_etr01 + time00 0.200 + time01 15.472 + time02 77.914 + time03 80.977 + } + } + korrib_dark_explore + { + entry + { + marker0 0.000 + marker1 56.300 + marker2 81.901 + marker3 97.970 + } + exit + { + nextfile korrib_dark_etr00 + time00 0.100 + time01 55.719 + time02 69.607 + time03 105.397 + } + exit + { + nextfile korrib_dark_etr01 + time00 29.202 + time01 82.004 + } + } + korrib_action + { + entry + { + marker0 0.00 + marker1 41.495 + marker2 63.586 + marker3 96.124 + } + exit + { + nextfile korrib_atr00 + nextmark marker0 + time00 0.100 + time01 2.769 + time02 7.929 + time03 35.142 + time04 41.429 + time05 66.838 + time06 101.731 + time07 115.125 + } + exit + { + nextfile korrib_atr01 + nextmark marker1 + time00 10.161 + time01 31.271 + time02 33.499 + time03 45.925 + time04 48.117 + time05 53.043 + time06 63.397 + time07 105.512 + time08 108.174 + } + exit + { + nextfile korrib_atr02 + nextmark marker2 + time00 6.125 + time01 15.027 + time02 18.225 + time03 38.181 + time04 59.245 + time05 76.386 + time06 80.120 + time07 92.516 + } + exit + { + nextfile korrib_atr03 + nextmark marker3 + time00 20.844 + time01 24.075 + time02 74.372 + time03 85.475 + time04 89.990 + time05 117.480 + } + } + final_battle + { + } + vjun3_explore + { + + entry + { + marker0 0.000 + marker1 41.670 + marker2 146.402 + } + exit + { + nextfile vjun3_etr00 + time00 132.271 + time01 144.739 + } + exit + { + nextfile vjun3_etr01 + time00 13.138 + time01 25.994 + time02 85.175 + } + } + vjun3_action + { + entry + { + marker0 0.00 + marker1 8.256 + marker2 65.554 + } + exit + { + nextfile vjun3_atr00 + nextmark marker0 + time00 7.785 + time01 32.66 + time02 47.516 + time03 51.710 + time04 65.674 + time05 87.719 + time06 105.684 + time07 119.798 + time08 125.561 + time09 128.004 + } + exit + { + nextfile vjun3_atr01 + nextmark marker1 + time00 13.243 + time01 20.037 + time02 23.944 + time03 36.96 + time04 39.62 + time05 54.14 + time06 57.372 + time07 81.623 + time08 99.91 + } + exit + { + nextfile vjun3_atr02 + nextmark marker2 + time00 2.271 + time01 15.017 + time02 28.210 + time03 42.557 + time04 45.80 + time05 69.571 + time06 73.505 + time07 93.482 + time08 115.814 + } + } +} +levelmusic +{ + yavin1 + { + explore swamp_explore + action swamp_action + } + yavin1b + { + uses yavin1 + } + yavin2 + { + explore yavtemp2_explore + action yavtemp2_action + } + t1_fatal + { + explore tunnels_explore + action tunnels_action + } + t1_sour + { + explore dealsour_explore + action dealsour_action + } + t1_surprise + { + explore tusken_explore + action tusken_action + } + t1_danger + { + uses t1_surprise + } + hoth2 + { + explore hoth2_explore + action hoth2_action + } + hoth3 + { + uses hoth2 + } + t2_dpred + { + explore ImpBaseB_Explore + action ImpBaseB_Action + } + t2_wedge + { + explore besplat_explore + action besplat_action + boss besplat_boss + } + t2_rancor + { + explore rancor_explore + action rancor_action + } + t2_rogue + { + explore narshaada_explore + action narshaada_action + } + vjun1 + { + uses yavin2 + } + vjun2 + { + explore ImpBaseE_explore + action ImpBaseE_action + } + vjun3 + { + explore vjun3_explore + action vjun3_action + } + t3_bounty + { + uses t1_sour + } + t3_byss + { + explore alienhb_explore + action alienhb_action + } + t3_hevil + { + uses t2_wedge + } + t3_rift + { + uses yavin2 + } + taspir1 + { + uses vjun2 + } + taspir2 + { + uses vjun2 + } + kor_lite + { + explore korrib_lite_explore + action korrib_action + boss final_battle + } + kor_dark + { + explore korrib_dark_explore + action korrib_action + boss final_battle + } +} diff --git a/base/ext_data/items.dat b/base/ext_data/items.dat new file mode 100644 index 0000000..0b28718 --- /dev/null +++ b/base/ext_data/items.dat @@ -0,0 +1,782 @@ +// EXTERNAL ITEM DATA +// + +//Fields +//pickupsound STRING; DEFAULT = sound/weapons/w_pkup.wav +//itemname STRING; +//classname STRING; +//count INT; ammount of ammo or health given with item +//icon STRING; +//min VECTOR; item bounds min, DEFAULT = -16 -16 -2 +//max VECTOR; item bounds max, DEFAULT = 16 16 16 +//pickupname STRING; name to show in inventory +//tag ENUM; WP_, or AMMO_ +//type ENUM; IT_WEAPON, IT_AMMO, IT_ARMOR, IT_HEALTH +//worldmodel STRING; model to show on ground or in hand + +{ +itemname ITM_SABER_PICKUP + +classname weapon_saber +worldmodel models/weapons2/saber/saber_w.md3 +icon gfx/hud/w_icon_lightsaber +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_SABER +min -16 -16 -8 +max 16 16 16 +} + + +{ +itemname ITM_BRYAR_PISTOL_PICKUP + +classname weapon_bryar_pistol +worldmodel models/weapons2/briar_pistol/briar_pistol_w.glm +icon gfx/hud/w_icon_briar +// Amount of ammo given with weapon +count 10 +type IT_WEAPON +tag WP_BRYAR_PISTOL +min -10 -10 -2 +max 10 10 12 +} + +{ +itemname ITM_BLASTER_PISTOL_PICKUP + +classname weapon_blaster_pistol +worldmodel models/weapons2/blaster_pistol/blaster_pistol_w.glm +icon gfx/hud/w_icon_blaster_pistol +// Amount of ammo given with weapon +count 10 +type IT_WEAPON +tag WP_BLASTER_PISTOL +min -10 -10 -2 +max 10 10 12 +} + +{ +itemname ITM_BLASTER_PICKUP + +classname weapon_blaster +worldmodel models/weapons2/blaster_r/blaster_w.glm +icon gfx/hud/w_icon_blaster +// Amount of ammo given with weapon +count 10 +type IT_WEAPON +tag WP_BLASTER +min -10 -10 -2 +max 10 10 12 +} + +{ +itemname ITM_DISRUPTOR_PICKUP + +classname weapon_disruptor +worldmodel models/weapons2/disruptor/disruptor_w.glm +icon gfx/hud/w_icon_disruptor +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_DISRUPTOR +min -10 -10 -2 +max 10 10 12 +} + +{ +itemname ITM_BOWCASTER_PICKUP + +classname weapon_bowcaster +worldmodel models/weapons2/bowcaster/bowcaster_w.glm +icon gfx/hud/w_icon_bowcaster +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_BOWCASTER +min -10 -10 -2 +max 10 10 12 +} + +{ +itemname ITM_REPEATER_PICKUP + +classname weapon_repeater +worldmodel models/weapons2/heavy_repeater/heavy_repeater_w.glm +icon gfx/hud/w_icon_repeater +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_REPEATER +min -10 -10 -2 +max 10 10 12 +} + +{ +itemname ITM_DEMP2_PICKUP + +classname weapon_demp2 +worldmodel models/weapons2/demp2/demp2_w.glm +icon gfx/hud/w_icon_demp2 +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_DEMP2 +min -10 -10 -2 +max 10 10 12 +} + + +{ +itemname ITM_FLECHETTE_PICKUP + +classname weapon_flechette +worldmodel models/weapons2/golan_arms/golan_arms_w.glm +icon gfx/hud/w_icon_flechette +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_FLECHETTE +min -10 -10 -2 +max 10 10 12 +} + +{ +itemname ITM_CONCUSSION_RIFLE_PICKUP + +classname weapon_concussion_rifle +worldmodel models/weapons2/concussion/c_rifle_w.glm +icon gfx/hud/w_icon_c_rifle +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_CONCUSSION +min -10 -10 -2 +max 10 10 12 +} + +{ +itemname ITM_ROCKET_LAUNCHER_PICKUP + +classname weapon_rocket_launcher +worldmodel models/weapons2/merr_sonn/merr_sonn_w.glm +icon gfx/hud/w_icon_merrsonn +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_ROCKET_LAUNCHER +min -10 -10 -2 +max 10 10 12 +} + + +{ +itemname ITM_THERMAL_DET_PICKUP + +classname weapon_thermal +worldmodel models/weapons2/thermal/thermal_pu.md3 +icon gfx/hud/w_icon_thermal +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_THERMAL +min -10 -10 -2 +max 10 10 12 +} + +{ +itemname ITM_TRIP_MINE_PICKUP + +classname weapon_trip_mine +worldmodel models/weapons2/laser_trap/laser_trap_pu.md3 +icon gfx/hud/w_icon_tripmine +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_TRIP_MINE +min -10 -10 -2 +max 10 10 12 +} + +{ +itemname ITM_DET_PACK_PICKUP + +classname weapon_det_pack +worldmodel models/weapons2/detpack/det_pack_pu.md3 +icon gfx/hud/w_icon_detpack +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_DET_PACK +min -10 -10 -2 +max 10 10 12 +} + +{ +itemname ITM_STUN_BATON_PICKUP + +classname weapon_stun_baton +worldmodel models/weapons2/stun_baton/stunbaton_w.glm +icon gfx/hud/w_icon_stunbaton +// Amount of ammo given with weapon +count 50 +type IT_WEAPON +tag WP_STUN_BATON +} + + +{ +itemname ITM_BOT_LASER_PICKUP + +classname weapon_botwelder +worldmodel models/weapons2/noweap/noweap.md3 +// Amount of ammo given with weapon +count 400 +type IT_WEAPON +tag WP_BOT_LASER +} + +{ +itemname ITM_MELEE + +classname weapon_melee +worldmodel models/weapons2/noweap/noweap.md3 +icon gfx/hud/w_icon_melee +// Amount of ammo given with weapon +count 400 +type IT_WEAPON +tag WP_MELEE +min -16 -16 -2 +max 16 16 16 +} + +{ +itemname ITM_EMPLACED_GUN_PICKUP + +classname weapon_emplaced_gun +worldmodel models/weapons2/noweap/noweap.md3 +// Amount of ammo given with weapon +count 800 +type IT_WEAPON +tag WP_EMPLACED_GUN +} + +{ +itemname ITM_TURRET_PICKUP + +classname weapon_turret +worldmodel models/weapons2/noweap/noweap.md3 +// Amount of ammo given with weapon +count 400 +type IT_WEAPON +tag WP_TURRET +} + +{ +itemname ITM_ATST_MAIN_PICKUP + +classname weapon_atst_main +worldmodel models/weapons2/noweap/noweap.md3 +icon gfx/hud/w_icon_atst +// Amount of ammo given with weapon +count 400 +type IT_WEAPON +tag WP_ATST_MAIN +} + +{ +itemname ITM_ATST_SIDE_PICKUP + +classname weapon_atst_side +worldmodel models/weapons2/noweap/noweap.md3 +icon gfx/hud/w_icon_atstside +// Amount of ammo given with weapon +count 400 +type IT_WEAPON +tag WP_ATST_SIDE +} + +{ +itemname ITM_TIE_FIGHTER_PICKUP + +classname weapon_tie_fighter +worldmodel models/weapons2/noweap/noweap.md3 +// Amount of ammo given with weapon +count 400 +type IT_WEAPON +tag WP_TIE_FIGHTER +} + +{ +itemname ITM_RAPID_FIRE_CONC_PICKUP + +classname weapon_rapid_concussion +worldmodel models/weapons2/noweap/noweap.md3 +// Amount of ammo given with weapon +count 400 +type IT_WEAPON +tag WP_RAPID_FIRE_CONC +} + +{ +itemname ITM_JAWA_PICKUP + +classname weapon_jawa +worldmodel models/weapons2/jawa/jawa_gun.md3 +// Amount of ammo given with weapon +count 400 +type IT_WEAPON +tag WP_JAWA +} + +{ +itemname ITM_TUSKEN_RIFLE_PICKUP + +classname weapon_tusken_rifle +worldmodel models/weapons2/tusken_rifle/tusken_rifle.md3 +// Amount of ammo given with weapon +count 400 +type IT_WEAPON +tag WP_TUSKEN_RIFLE +} + +{ +itemname ITM_TUSKEN_STAFF_PICKUP + +classname weapon_tusken_staff +worldmodel models/weapons2/tusken_staff/tusken_staff.md3 +// Amount of ammo given with weapon +count 400 +type IT_WEAPON +tag WP_TUSKEN_STAFF +} + +{ +itemname ITM_SCEPTER_PICKUP + +classname weapon_scepter +worldmodel models/weapons2/sith_scepter/sith_scepter.md3 +// Amount of ammo given with weapon +count 400 +type IT_WEAPON +tag WP_SCEPTER +} + +{ +itemname ITM_NOGHRI_STICK_PICKUP + +classname weapon_noghri_stick +worldmodel models/weapons2/noghri_stick/noghri_stick.md3 +// Amount of ammo given with weapon +count 400 +type IT_WEAPON +tag WP_NOGHRI_STICK +} +// +//Items +// + +// AMMO Items +//------------- +{ +itemname ITM_AMMO_FORCE_PICKUP + +classname ammo_force +worldmodel models/items/forcegem.md3 +pickupsound sound/player/enlightenment.wav +icon gfx/hud/forcegem_icon2 +count 100 +type IT_AMMO +tag AMMO_FORCE +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_AMMO_BLASTER_PICKUP + +classname ammo_blaster +worldmodel models/items/energy_cell.md3 +icon gfx/hud/energy_cell +count 25 +type IT_AMMO +tag AMMO_BLASTER +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_AMMO_POWERCELL_PICKUP + +classname ammo_powercell +worldmodel models/items/power_cell.md3 +icon gfx/hud/power_cell +count 100 +type IT_AMMO +tag AMMO_POWERCELL +max 8 8 16 +min -8 -8 -0 +} + + +{ +itemname ITM_AMMO_METAL_BOLTS_PICKUP + +classname ammo_metallic_bolts +worldmodel models/items/metallic_bolts.md3 +icon gfx/hud/metallic_bolts +count 100 +type IT_AMMO +tag AMMO_METAL_BOLTS +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_AMMO_ROCKETS_PICKUP + +classname ammo_rockets +worldmodel models/items/rockets.md3 +icon gfx/hud/rockets +count 3 +type IT_AMMO +tag AMMO_ROCKETS +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_AMMO_EMPLACED_PICKUP + +classname ammo_emplaced +worldmodel models/weapons2/noweap/noweap.md3 +count 100 +type IT_AMMO +tag AMMO_EMPLACED +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_AMMO_THERMAL_PICKUP + +classname ammo_thermal +worldmodel models/weapons2/thermal/thermal_pu.md3 +icon gfx/hud/w_icon_thermal +count 4 +type IT_AMMO +tag AMMO_THERMAL +max 16 16 16 +min -16 -16 -0 +} + +{ +itemname ITM_AMMO_TRIPMINE_PICKUP + +classname ammo_tripmine +worldmodel models/weapons2/laser_trap/laser_trap_pu.md3 +icon gfx/hud/w_icon_tripmine +count 3 +type IT_AMMO +tag AMMO_TRIPMINE +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_AMMO_DETPACK_PICKUP + +classname ammo_detpack +worldmodel models/weapons2/detpack/det_pack_pu.md3 +icon gfx/hud/w_icon_detpack +count 3 +type IT_AMMO +tag AMMO_DETPACK +max 8 8 16 +min -8 -8 -0 +} + + + +{ +itemname ITM_BATTERY_PICKUP + +classname item_battery +worldmodel models/items/battery.md3 +icon gfx/hud/battery +count 1000 +type IT_BATTERY +tag ITM_BATTERY_PICKUP +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_SEEKER_PICKUP +classname item_seeker +worldmodel models/items/remote.md3 +icon gfx/hud/i_icon_seeker +count 120 +type IT_HOLDABLE +tag INV_SEEKER +max 8 8 16 +min -8 -8 -4 +} + +{ +itemname ITM_SHIELD_PICKUP +classname item_enviro +worldmodel models/items/shield.md3 +icon gfx/hud/i_icon_shieldwall +count 100 +type IT_HOLDABLE +tag ITM_SHIELD_PICKUP +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_BACTA_PICKUP +classname item_bacta +worldmodel models/items/bacta.md3 +icon gfx/hud/i_icon_bacta +count 25 +type IT_HEALTH +tag ITM_MEDPAK_PICKUP +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_DATAPAD_PICKUP +classname item_datapad +worldmodel models/items/datapad.md3 +count 1 +type IT_HOLDABLE +tag ITM_DATAPAD_PICKUP +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_BINOCULARS_PICKUP +classname item_binoculars +worldmodel models/items/binoculars.md3 +icon gfx/hud/i_icon_zoom +count 1 +type IT_HOLDABLE +tag INV_ELECTROBINOCULARS +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_SENTRY_GUN_PICKUP +classname item_sentry_gun +worldmodel models/items/psgun.glm +icon gfx/hud/i_icon_sentrygun +count 120 +type IT_HOLDABLE +tag INV_SENTRY +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_LA_GOGGLES_PICKUP +classname item_la_goggles +worldmodel models/items/binoculars.md3 +icon gfx/hud/i_icon_goggles +count 30 +type IT_HOLDABLE +tag INV_LIGHTAMP_GOGGLES +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_MEDPAK_PICKUP +classname item_medpak_instant +worldmodel models/items/medpac.md3 +icon gfx/hud/i_icon_medkit +count 20 +type IT_HEALTH +tag ITM_MEDPAK_PICKUP +max 8 8 16 +min -8 -8 -3 +} + +{ +itemname ITM_SHIELD_SM_PICKUP +classname item_shield_sm_instant +worldmodel models/items/psd_sm.md3 +icon gfx/hud/psd_small +count 25 +type IT_ARMOR +tag ITM_SHIELD_SM_PICKUP +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_SHIELD_LRG_PICKUP +classname item_shield_lrg_instant +worldmodel models/items/psd.md3 +icon gfx/hud/psd_medium +count 50 +type IT_ARMOR +tag ITM_SHIELD_LRG_PICKUP +max 8 8 16 +min -8 -8 -4 +} + + +{ +itemname ITM_GOODIE_KEY_PICKUP +classname item_goodie_key +worldmodel models/items/key.md3 +icon gfx/hud/i_icon_goodie_key +type IT_HOLDABLE +tag INV_GOODIE_KEY +max 8 8 16 +min -8 -8 -0 +} + + +{ +itemname ITM_SECURITY_KEY_PICKUP +classname item_security_key +worldmodel models/items/key.md3 +icon gfx/hud/i_icon_security_key +type IT_HOLDABLE +tag INV_SECURITY_KEY +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_FORCE_HEAL_PICKUP + +classname holocron_force_heal +worldmodel models/map_objects/force_holocrons/heal.md3 +pickupsound sound/player/holocron.wav +icon gfx/hud/f_icon_heal +count 1 +type IT_HOLOCRON +tag FP_HEAL +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_FORCE_LEVITATION_PICKUP + +classname holocron_force_levitation +worldmodel models/map_objects/force_holocrons/jump.md3 +pickupsound sound/player/holocron.wav +icon gfx/hud/f_icon_levitation +count 1 +type IT_HOLOCRON +tag FP_LEVITATION +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_FORCE_SPEED_PICKUP + +classname holocron_force_speed +worldmodel models/map_objects/force_holocrons/speed.md3 +pickupsound sound/player/holocron.wav +icon gfx/hud/f_icon_speed +count 1 +type IT_HOLOCRON +tag FP_SPEED +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_FORCE_PUSH_PICKUP + +classname holocron_force_push +worldmodel models/map_objects/force_holocrons/push.md3 +pickupsound sound/player/holocron.wav +icon gfx/hud/f_icon_push +count 1 +type IT_HOLOCRON +tag FP_PUSH +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_FORCE_PULL_PICKUP + +classname holocron_force_pull +worldmodel models/map_objects/force_holocrons/pull.md3 +pickupsound sound/player/holocron.wav +icon gfx/hud/f_icon_pull +count 1 +type IT_HOLOCRON +tag FP_PULL +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_FORCE_TELEPATHY_PICKUP + +classname holocron_force_telepathy +worldmodel models/map_objects/force_holocrons/telepathy.md3 +pickupsound sound/player/holocron.wav +icon gfx/hud/f_icon_telepathy +count 1 +type IT_HOLOCRON +tag FP_TELEPATHY +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_FORCE_GRIP_PICKUP + +classname holocron_force_grip +worldmodel models/map_objects/force_holocrons/grip.md3 +pickupsound sound/player/holocron.wav +icon gfx/hud/f_icon_grip +count 1 +type IT_HOLOCRON +tag FP_GRIP +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_FORCE_LIGHTNING_PICKUP + +classname holocron_force_lightning +worldmodel models/map_objects/force_holocrons/lightning.md3 +pickupsound sound/player/holocron.wav +icon gfx/hud/f_icon_lightning +count 1 +type IT_HOLOCRON +tag FP_LIGHTNING +max 8 8 16 +min -8 -8 -0 +} + +{ +itemname ITM_FORCE_SABERTHROW_PICKUP + +classname holocron_force_saberthrow +worldmodel models/map_objects/force_holocrons/saberthrow.md3 +pickupsound sound/player/holocron.wav +icon gfx/hud/f_icon_saberthrow +count 1 +type IT_HOLOCRON +tag FP_SABERTHROW +max 8 8 16 +min -8 -8 -0 +} diff --git a/base/ext_data/npcs/Bartender.npc b/base/ext_data/npcs/Bartender.npc new file mode 100644 index 0000000..4b0db4a --- /dev/null +++ b/base/ext_data/npcs/Bartender.npc @@ -0,0 +1,25 @@ +Bartender +{ + playerModel chiss + weapon WP_NONE + snd bartender + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL +// race human + class CLASS_BARTENDER + walkSpeed 55 + runSpeed 200 + yawspeed 90 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbLegs 0 + dismemberProbHands 0 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/BespinCop.npc b/base/ext_data/npcs/BespinCop.npc new file mode 100644 index 0000000..f022f1c --- /dev/null +++ b/base/ext_data/npcs/BespinCop.npc @@ -0,0 +1,57 @@ +BespinCop +{ + playerModel bespin_cop + weapon WP_BLASTER_PISTOL + health 40 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + walkSpeed 55 + runSpeed 200 + yawspeed 120 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +// race bespincop + class CLASS_BESPIN_COP + snd bespincop1 + sndcombat bespincop1 + sndextra bespincop1 +} + +BespinCop2 +{ + playerModel bespin_cop + weapon WP_BLASTER_PISTOL + health 40 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + walkSpeed 55 + runSpeed 200 + yawspeed 120 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +// race bespincop + class CLASS_BESPIN_COP + snd bespincop2 + sndcombat bespincop2 + sndextra bespincop2 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Desann.npc b/base/ext_data/npcs/Desann.npc new file mode 100644 index 0000000..646ea2f --- /dev/null +++ b/base/ext_data/npcs/Desann.npc @@ -0,0 +1,53 @@ +Desann +{ + playerModel desann + saber desann + weapon WP_SABER + saberStyle 4 + FP_HEAL 0 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 3 + FP_PULL 3 + FP_TELEPATHY 0 + FP_GRIP 3 + FP_LIGHTNING 3 + FP_RAGE 3 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 3 + FP_SEE 3 + FP_SABERTHROW 3 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + forceRegenRate 50 + rank captain + reactions 3 + aim 3 + move 5 + aggression 3 + evasion 5 + intelligence 5 + hfov 160 + vfov 160 + scale 135 + height 78 + crouchheight 42 + width 18 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race human + class CLASS_DESANN + yawSpeed 120 + walkSpeed 55 + runSpeed 200 + snd desann + sndcombat desann + sndjedi desann + health 500 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbLegs 0 + dismemberProbHands 0 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Elder.npc b/base/ext_data/npcs/Elder.npc new file mode 100644 index 0000000..0c0fd3c --- /dev/null +++ b/base/ext_data/npcs/Elder.npc @@ -0,0 +1,55 @@ +Elder +{ + playerModel prisoner + weapon WP_NONE + customSkin elder + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_PRISONER + snd prisoner1 + sndcombat prisoner1 + sndextra prisoner1 + walkSpeed 55 + runSpeed 200 + yawspeed 110 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + +Elder2 +{ + playerModel prisoner + weapon WP_NONE + customSkin elder2 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_PRISONER + snd prisoner2 + sndcombat prisoner2 + sndextra prisoner2 + walkSpeed 55 + runSpeed 200 + yawspeed 110 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Galak.npc b/base/ext_data/npcs/Galak.npc new file mode 100644 index 0000000..4b5ab60 --- /dev/null +++ b/base/ext_data/npcs/Galak.npc @@ -0,0 +1,22 @@ +Galak +{ + playerModel galak + weapon WP_BLASTER + altFire 1 + rank commander + snd galak + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank captain + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race klingon + class CLASS_IMPERIAL + yawspeed 90 + walkSpeed 55 + runSpeed 200 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Galak_Mech.npc b/base/ext_data/npcs/Galak_Mech.npc new file mode 100644 index 0000000..76d00f8 --- /dev/null +++ b/base/ext_data/npcs/Galak_Mech.npc @@ -0,0 +1,36 @@ +Galak_Mech +{ + playerModel galak_mech + weapon WP_REPEATER + health 1000 + width 20 + height 88 + crouchheight 88 + snd galak_mech + reactions 3 + aim 5 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race klingon + class CLASS_GALAK_MECH + snd galak + sndcombat galak + sndextra galak + yawSpeed 50 + walkSpeed 45 + runSpeed 150 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbHands 0 + dismemberProbLegs 0 + dismemberProbWaist 0 + headPitchRangeUp 60 + headPitchRangeDown 60 + torsoPitchRangeUp 60 + torsoPitchRangeDown 60 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Glider.npc b/base/ext_data/npcs/Glider.npc new file mode 100644 index 0000000..f133bb7 --- /dev/null +++ b/base/ext_data/npcs/Glider.npc @@ -0,0 +1,21 @@ +Glider +{ + playerModel glider + weapon WP_MELEE + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL +// race harvester + class CLASS_GLIDER + yawSpeed 60 + runSpeed 150 + walkSpeed 50 + hFOV 120 + vfov 45 + snd glider +} \ No newline at end of file diff --git a/base/ext_data/npcs/Gran.npc b/base/ext_data/npcs/Gran.npc new file mode 100644 index 0000000..52ca56c --- /dev/null +++ b/base/ext_data/npcs/Gran.npc @@ -0,0 +1,125 @@ +Gran +{ + playerModel gran + customSkin sp + customRGBA random1 + weapon WP_THERMAL + weapon WP_MELEE + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + health 30 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_GRAN + snd gran1 + sndcombat gran1 + sndextra gran1 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +Gran2 +{ + playerModel gran + customSkin sp + customRGBA random1 + weapon WP_THERMAL + weapon WP_MELEE + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + health 30 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_GRAN + snd gran2 + sndcombat gran2 + sndextra gran2 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +GranBoxer +{ + playerModel gran + customSkin sp + customRGBA random1 + weapon WP_MELEE + surfOff "l_leg_kneeguard r_leg_kneeguard" + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + health 50 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race klingon + class CLASS_GRAN + snd gran2 + sndcombat gran2 + sndextra gran2 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +GranShooter +{ + playerModel gran + customSkin sp + customRGBA random1 + weapon WP_BLASTER + surfOff "l_leg_kneeguard" + reactions 3 + aim 5 + move 3 + aggression 3 + evasion 1 + intelligence 5 + health 40 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race klingon + class CLASS_GRAN + snd gran1 + sndcombat gran1 + sndextra gran1 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/HazardTrooper.npc b/base/ext_data/npcs/HazardTrooper.npc new file mode 100644 index 0000000..45a307a --- /dev/null +++ b/base/ext_data/npcs/HazardTrooper.npc @@ -0,0 +1,92 @@ +hazardtrooper +{ + playerModel hazardtrooper + weapon WP_REPEATER + health 150 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_HAZARD_TROOPER + height 80 + crouchheight 48 + snd st1 + sndcombat st1 + sndextra st1 + yawspeed 100 + walkSpeed 55 + runSpeed 65 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +hazardtrooperconcussion +{ + playerModel hazardtrooper + weapon WP_CONCUSSION + health 150 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_HAZARD_TROOPER + height 80 + crouchheight 48 + snd st1 + sndcombat st1 + sndextra st1 + yawspeed 100 + walkSpeed 55 + runSpeed 65 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +hazardtrooperofficer +{ + playerModel hazardtrooper + weapon WP_FLECHETTE + health 150 + headPitchRangeDown 30 + reactions 4 + aim 3 + move 4 + aggression 5 + evasion 2 + intelligence 5 + rank lt + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_HAZARD_TROOPER + height 64 + crouchheight 48 + snd stofficer1 + sndcombat stofficer1 + sndextra stofficer1 + yawspeed 100 + walkSpeed 55 + runSpeed 65 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} diff --git a/base/ext_data/npcs/Howler.npc b/base/ext_data/npcs/Howler.npc new file mode 100644 index 0000000..eb03c94 --- /dev/null +++ b/base/ext_data/npcs/Howler.npc @@ -0,0 +1,23 @@ +Howler +{ + playerModel howler + weapon WP_MELEE + height 32 + crouchheight 32 + reactions 4 + aim 1 + move 5 + aggression 3 + evasion 5 + intelligence 2 + playerTeam TEAM_FREE + enemyTeam TEAM_FREE + class CLASS_HOWLER + yawSpeed 60 + runSpeed 300 + walkSpeed 100 + hFOV 120 + vfov 45 + snd howler + health 60 +} \ No newline at end of file diff --git a/base/ext_data/npcs/ImpCommander.npc b/base/ext_data/npcs/ImpCommander.npc new file mode 100644 index 0000000..585f3f0 --- /dev/null +++ b/base/ext_data/npcs/ImpCommander.npc @@ -0,0 +1,34 @@ +ImpCommander +{ + playerModel imperial + weapon WP_BLASTER + altFire 1 + surfOff l_arm_key + customSkin commander + health 80 + reactions 4 + aim 4 + move 4 + aggression 4 + evasion 4 + intelligence 4 + rank commander + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race klingon + class CLASS_IMPERIAL +// snd io3 +// sndcombat io3 +// sndextra io3 + snd io1 + sndcombat io1 + sndextra io1 + yawspeed 110 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/ImpOfficer.npc b/base/ext_data/npcs/ImpOfficer.npc new file mode 100644 index 0000000..dd408f0 --- /dev/null +++ b/base/ext_data/npcs/ImpOfficer.npc @@ -0,0 +1,30 @@ +ImpOfficer +{ + playerModel imperial + weapon WP_BLASTER + surfOff l_arm_key + customSkin officer + health 40 + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 3 + intelligence 3 + rank ltcomm + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race klingon + class CLASS_IMPERIAL + snd io1 + sndcombat io1 + sndextra io1 + yawspeed 110 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/ImpWorker.npc b/base/ext_data/npcs/ImpWorker.npc new file mode 100644 index 0000000..7b9ad15 --- /dev/null +++ b/base/ext_data/npcs/ImpWorker.npc @@ -0,0 +1,101 @@ +ImpWorker +{ + playerModel imperial_worker + weapon WP_BLASTER_PISTOL + headPitchRangeDown 30 + health 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race imperial + class CLASS_IMPWORKER + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd worker1 + sndcombat worker1 + sndextra worker1 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +ImpWorker2 +{ + playerModel imperial_worker + weapon WP_BLASTER_PISTOL + headPitchRangeDown 30 + health 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race imperial + class CLASS_IMPWORKER + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd worker2 + sndcombat worker2 + sndextra worker2 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +ImpWorker3 +{ + playerModel imperial_worker + weapon WP_BLASTER_PISTOL + headPitchRangeDown 30 + health 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race imperial + class CLASS_IMPWORKER + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd worker3 + sndcombat worker3 + sndextra worker3 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} diff --git a/base/ext_data/npcs/Imperial.npc b/base/ext_data/npcs/Imperial.npc new file mode 100644 index 0000000..2e1ea9e --- /dev/null +++ b/base/ext_data/npcs/Imperial.npc @@ -0,0 +1,29 @@ +Imperial +{ + playerModel imperial + weapon WP_BLASTER_PISTOL + surfOff l_arm_key + health 20 + reactions 2 + aim 2 + move 2 + aggression 2 + evasion 2 + intelligence 2 + rank lt + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race klingon + class CLASS_IMPERIAL + snd io2 + sndcombat io2 + sndextra io2 + yawspeed 110 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Jan.npc b/base/ext_data/npcs/Jan.npc new file mode 100644 index 0000000..ceb7499 --- /dev/null +++ b/base/ext_data/npcs/Jan.npc @@ -0,0 +1,30 @@ +Jan +{ + playerModel jan + weapon WP_BLASTER + altFire 1 + rank lt + reactions 3 + aim 5 + move 3 + aggression 3 + evasion 3 + intelligence 3 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_JAN + sex female + snd jan + sndcombat jan + sndextra jan + yawSpeed 140 + walkSpeed 55 + runSpeed 200 +// race human + snd jan + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbHands 1 + dismemberProbLegs 0 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Jedi.npc b/base/ext_data/npcs/Jedi.npc new file mode 100644 index 0000000..41a62dc --- /dev/null +++ b/base/ext_data/npcs/Jedi.npc @@ -0,0 +1,102 @@ +Jedi +{ + playerModel jedi + saber single_2 + saberColor yellow + weapon WP_SABER + saberStyle 1 + saberStyle 3 + saberStyle 2 + FP_HEAL 1 + FP_LEVITATION 2 + FP_SPEED 2 + FP_PUSH 2 + FP_PULL 1 + FP_TELEPATHY 1 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 1 + FP_ABSORB 1 + FP_DRAIN 0 + FP_SEE 1 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + forceRegenRate 150 + forcePowerMax 90 + rank lt + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 2 + intelligence 3 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_JEDI + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + snd jedi1 + sndcombat jedi1 + sndjedi jedi1 + health 200 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + +Jedi2 +{ + playerModel jedi + saber single_7 + saberColor orange + weapon WP_SABER + saberStyle 1 + saberStyle 2 + saberStyle 3 + FP_HEAL 1 + FP_LEVITATION 2 + FP_SPEED 2 + FP_PUSH 2 + FP_PULL 1 + FP_TELEPATHY 1 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 1 + FP_ABSORB 1 + FP_DRAIN 0 + FP_SEE 1 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + forceRegenRate 200 + forcePowerMax 75 + rank lt + customSkin j2 + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 2 + intelligence 3 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_JEDI + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + snd jedi2 + sndcombat jedi2 + sndjedi jedi2 + health 200 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/JediF.npc b/base/ext_data/npcs/JediF.npc new file mode 100644 index 0000000..673b974 --- /dev/null +++ b/base/ext_data/npcs/JediF.npc @@ -0,0 +1,49 @@ +JediF +{ + playerModel jan + surfOff "torso_vest hips_chaps torso_computer head_goggles torso_comp hips_belt" + surfOn "torso_augment hips_augment hips_torso" + saber dual_3 + saberColor random + weapon WP_SABER + saberStyle 7 + FP_HEAL 1 + FP_LEVITATION 2 + FP_SPEED 2 + FP_PUSH 2 + FP_PULL 1 + FP_TELEPATHY 1 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 1 + FP_ABSORB 1 + FP_DRAIN 0 + FP_SEE 2 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + rank lt + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 2 + intelligence 3 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_JEDI + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + sex female + snd jan + sndcombat jan + sndjedi jan + health 200 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/JediMaster.npc b/base/ext_data/npcs/JediMaster.npc new file mode 100644 index 0000000..10dabd7 --- /dev/null +++ b/base/ext_data/npcs/JediMaster.npc @@ -0,0 +1,47 @@ +JediMaster +{ + playerModel jedi + customSkin master + saber dual_3 + saberColor green + weapon WP_SABER + saberStyle 7 + FP_HEAL 2 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 3 + FP_PULL 2 + FP_TELEPATHY 2 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 2 + FP_ABSORB 2 + FP_DRAIN 0 + FP_SEE 2 + FP_SABERTHROW 3 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + rank commander + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_JEDI + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + snd jedi2 + sndcombat jedi2 + sndjedi jedi2 + health 400 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/JediTrainer.npc b/base/ext_data/npcs/JediTrainer.npc new file mode 100644 index 0000000..0fd02f6 --- /dev/null +++ b/base/ext_data/npcs/JediTrainer.npc @@ -0,0 +1,48 @@ +JediTrainer +{ + playerModel jeditrainer + saber jedi + saber2 jedi + saberColor purple + saber2Color purple + weapon WP_SABER + saberStyle 6 + FP_HEAL 2 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 3 + FP_PULL 2 + FP_TELEPATHY 2 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 2 + FP_ABSORB 2 + FP_DRAIN 0 + FP_SEE 2 + FP_SABERTHROW 3 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + rank commander + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_JEDI + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + snd jedi2 + sndcombat jedi2 + sndjedi jedi2 + health 400 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Kyle.npc b/base/ext_data/npcs/Kyle.npc new file mode 100644 index 0000000..c522636 --- /dev/null +++ b/base/ext_data/npcs/Kyle.npc @@ -0,0 +1,91 @@ +Kyle +{ + playerModel kyle + saber kyle + rank commander + health 1000 + weapon WP_BRYAR_PISTOL + weapon WP_SABER + saberStyle 1 + saberStyle 3 + saberStyle 2 + FP_HEAL 3 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 3 + FP_PULL 3 + FP_TELEPATHY 3 + FP_GRIP 3 + FP_LIGHTNING 2 + FP_SABERTHROW 3 + FP_RAGE 0 + FP_PROTECT 3 + FP_ABSORB 3 + FP_DRAIN 0 + FP_SEE 3 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + forcePowerMax 200 + reactions 4 + aim 5 + move 3 + aggression 5 + evasion 5 + intelligence 5 + playerTeam TEAM_PLAYER + class CLASS_KYLE + snd kyle + sndcombat kyle + sndjedi kyle + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbHands 0 + dismemberProbLegs 0 + dismemberProbWaist 0 +} + +Kyle_boss +{ + playerModel kyle + saber kyle_boss + rank captain + health 300 + weapon WP_SABER + saberStyle 1 + saberStyle 2 + saberStyle 3 + FP_HEAL 3 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 3 + FP_PULL 3 + FP_TELEPATHY 3 + FP_GRIP 3 + FP_LIGHTNING 0 +// FP_SABERTHROW 3 + FP_SABERTHROW 0 + FP_RAGE 0 + FP_PROTECT 3 + FP_ABSORB 3 + FP_DRAIN 0 + FP_SEE 3 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + reactions 4 + aim 5 + move 3 + aggression 5 + evasion 5 + intelligence 5 + playerTeam TEAM_PLAYER + class CLASS_KYLE + snd kyle_boss + sndcombat kyle_boss + sndjedi kyle_boss + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbHands 0 + dismemberProbLegs 0 + dismemberProbWaist 0 +} + diff --git a/base/ext_data/npcs/Lando.npc b/base/ext_data/npcs/Lando.npc new file mode 100644 index 0000000..360aa72 --- /dev/null +++ b/base/ext_data/npcs/Lando.npc @@ -0,0 +1,62 @@ +Lando +{ + playerModel lando + weapon WP_BLASTER + rank captain + altFire 1 + snd lando + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY +// race human + class CLASS_LANDO + snd lando + sndcombat lando + sndextra lando + sndjedi lando + walkSpeed 55 + runSpeed 200 + yawspeed 120 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbHands 0 + dismemberProbLegs 0 + dismemberProbWaist 0 +} + +Lando_cin +{ + playerModel lando + rank captain + altFire 1 + snd lando + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY +// race human + class CLASS_LANDO + snd lando + sndcombat lando + sndextra lando + sndjedi lando + walkSpeed 52 + runSpeed 200 + yawspeed 120 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbHands 0 + dismemberProbLegs 0 + dismemberProbWaist 0 +} diff --git a/base/ext_data/npcs/Luke.npc b/base/ext_data/npcs/Luke.npc new file mode 100644 index 0000000..b6c1176 --- /dev/null +++ b/base/ext_data/npcs/Luke.npc @@ -0,0 +1,49 @@ +Luke +{ + playerModel luke + saber luke + weapon WP_SABER + saberStyle 1 + saberStyle 3 + saberStyle 2 + FP_HEAL 3 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 3 + FP_PULL 3 + FP_TELEPATHY 3 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_SABERTHROW 3 + FP_RAGE 0 + FP_PROTECT 3 + FP_ABSORB 3 + FP_DRAIN 0 + FP_SEE 3 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + forcePowerMax 200 + rank captain + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 5 + intelligence 3 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_LUKE + yawSpeed 140 + walkSpeed 55 + runSpeed 200 +// race human + snd luke + sndcombat luke + sndjedi luke + health 200 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbLegs 0 + dismemberProbHands 0 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Merchant.npc b/base/ext_data/npcs/Merchant.npc new file mode 100644 index 0000000..ec2a7f5 --- /dev/null +++ b/base/ext_data/npcs/Merchant.npc @@ -0,0 +1,27 @@ +Merchant +{ + playerModel prisoner + weapon WP_NONE + customSkin merchant + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_PRISONER + snd prisoner2 + sndcombat prisoner2 + sndextra prisoner2 + walkSpeed 55 + runSpeed 200 + yawspeed 110 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Minemonster.npc b/base/ext_data/npcs/Minemonster.npc new file mode 100644 index 0000000..6782dfe --- /dev/null +++ b/base/ext_data/npcs/Minemonster.npc @@ -0,0 +1,24 @@ +Minemonster +{ + playerModel minemonster + weapon WP_MELEE + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_MINEMONSTER + snd mine + yawSpeed 160 + runSpeed 210 + walkSpeed 50 + hFOV 120 + vfov 45 + height 30 + width 9 + snd mine + health 40 +} \ No newline at end of file diff --git a/base/ext_data/npcs/MonMothma.npc b/base/ext_data/npcs/MonMothma.npc new file mode 100644 index 0000000..a8ab731 --- /dev/null +++ b/base/ext_data/npcs/MonMothma.npc @@ -0,0 +1,25 @@ +MonMothma +{ + playerModel monmothma + weapon WP_NONE + snd monmothma + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY +// race human + class CLASS_MONMOTHMA + walkSpeed 55 + runSpeed 200 + yawspeed 90 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbLegs 0 + dismemberProbHands 0 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/MorganKatarn.npc b/base/ext_data/npcs/MorganKatarn.npc new file mode 100644 index 0000000..13e025b --- /dev/null +++ b/base/ext_data/npcs/MorganKatarn.npc @@ -0,0 +1,25 @@ +MorganKatarn +{ + playerModel morgan + weapon WP_NONE + snd morgan + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL +// race human + class CLASS_MORGAN + walkSpeed 55 + runSpeed 200 + yawspeed 90 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbLegs 0 + dismemberProbHands 0 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Noghri.npc b/base/ext_data/npcs/Noghri.npc new file mode 100644 index 0000000..5306e84 --- /dev/null +++ b/base/ext_data/npcs/Noghri.npc @@ -0,0 +1,27 @@ +Noghri +{ + playerModel noghri + weapon WP_NOGHRI_STICK + reactions 4 + aim 2 + move 5 + aggression 3 + evasion 5 + intelligence 3 + rank crewman + health 100 + playerTeam TEAM_FREE + enemyTeam TEAM_FREE + class CLASS_NOGHRI + snd noghri1 + sndcombat noghri1 + sndextra noghri1 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Prisoner.npc b/base/ext_data/npcs/Prisoner.npc new file mode 100644 index 0000000..1ff30d6 --- /dev/null +++ b/base/ext_data/npcs/Prisoner.npc @@ -0,0 +1,54 @@ +Prisoner +{ + playerModel prisoner + weapon WP_NONE + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_PRISONER + snd prisoner1 + sndcombat prisoner1 + sndextra prisoner1 + walkSpeed 55 + runSpeed 200 + yawspeed 110 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + +Prisoner2 +{ + playerModel prisoner + weapon WP_NONE + customSkin prisoner2 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_PRISONER + snd prisoner2 + sndcombat prisoner2 + sndextra prisoner2 + walkSpeed 55 + runSpeed 200 + yawspeed 110 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Ragnos.npc b/base/ext_data/npcs/Ragnos.npc new file mode 100644 index 0000000..16709ca --- /dev/null +++ b/base/ext_data/npcs/Ragnos.npc @@ -0,0 +1,20 @@ +Ragnos +{ + playerModel marka_ragnos + weapon WP_NONE + rank captain + snd ragnos + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + rank captain + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_GRAN + yawspeed 90 + walkSpeed 55 + runSpeed 200 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Rax.npc b/base/ext_data/npcs/Rax.npc new file mode 100644 index 0000000..b6d4231 --- /dev/null +++ b/base/ext_data/npcs/Rax.npc @@ -0,0 +1,25 @@ +Rax +{ + playerModel rax_joris + weapon WP_CONCUSSION + altFire 1 + rank commander + snd rax + sndcombat rax + sndextra rax + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 4 + rank captain + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_IMPERIAL + yawspeed 90 + walkSpeed 55 + runSpeed 200 + health 300 + visrange 3000 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Rebel.npc b/base/ext_data/npcs/Rebel.npc new file mode 100644 index 0000000..3ecc94a --- /dev/null +++ b/base/ext_data/npcs/Rebel.npc @@ -0,0 +1,61 @@ +Rebel +{ + playerModel rebel + weapon WP_BLASTER + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY +// race human + class CLASS_REBEL +// snd rebel1 +// sndcombat rebel1 +// sndextra rebel1 + snd rebel_pilot1 + sndcombat rebel_pilot1 + sndextra rebel_pilot1 + yawspeed 120 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +Rebel2 +{ + playerModel rebel + weapon WP_BLASTER + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY +// race human + class CLASS_REBEL +// snd rebel2 +// sndcombat rebel2 +// sndextra rebel2 + snd rebel_pilot1 + sndcombat rebel_pilot1 + sndextra rebel_pilot1 + yawspeed 120 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Rebel2.npc b/base/ext_data/npcs/Rebel2.npc new file mode 100644 index 0000000..c163ffa --- /dev/null +++ b/base/ext_data/npcs/Rebel2.npc @@ -0,0 +1,27 @@ +Rebel2 +{ + playerModel rebel + weapon WP_BLASTER + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY +// race human + class CLASS_REBEL + snd rebel_pilot1 + sndcombat rebel_pilot1 + sndextra rebel_pilot1 + yawspeed 120 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Reborn.npc b/base/ext_data/npcs/Reborn.npc new file mode 100644 index 0000000..b29fc1f --- /dev/null +++ b/base/ext_data/npcs/Reborn.npc @@ -0,0 +1,50 @@ +Reborn +{ + playerModel reborn + saber reborn + weapon WP_SABER + saberStyle 1 + FP_HEAL 0 + FP_LEVITATION 1 + FP_SPEED 1 + FP_PUSH 0 + FP_PULL 0 + FP_TELEPATHY 0 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 0 + FP_SEE 0 + FP_SABERTHROW 0 + FP_SABER_DEFENSE 1 + FP_SABER_OFFENSE 1 + forcePowerMax 50 + forceRegenRate 200 + reactions 1 + aim 1 + move 1 + aggression 1 + evasion 1 + intelligence 1 + hfov 120 + vfov 120 + scale 94 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race human + class CLASS_REBORN + snd reborn1 + sndcombat reborn1 + sndjedi reborn1 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 40 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/RebornAcrobat.npc b/base/ext_data/npcs/RebornAcrobat.npc new file mode 100644 index 0000000..1f82848 --- /dev/null +++ b/base/ext_data/npcs/RebornAcrobat.npc @@ -0,0 +1,51 @@ +RebornAcrobat +{ + playerModel reborn + customSkin acrobat + saber reborn + saberColor red + weapon WP_SABER + saberStyle 2 + FP_HEAL 0 + FP_LEVITATION 2 + FP_SPEED 1 + FP_PUSH 0 + FP_PULL 0 + FP_TELEPATHY 0 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 0 + FP_SEE 0 + FP_SABERTHROW 0 + FP_SABER_DEFENSE 1 + FP_SABER_OFFENSE 1 + rank crewman + reactions 3 + aim 3 + move 5 + aggression 3 + evasion 3 + intelligence 5 + hfov 160 + vfov 160 + scale 96 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race human + class CLASS_REBORN + snd reborn1 + sndcombat reborn1 + sndjedi reborn1 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 100 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/RebornBoss.npc b/base/ext_data/npcs/RebornBoss.npc new file mode 100644 index 0000000..61488eb --- /dev/null +++ b/base/ext_data/npcs/RebornBoss.npc @@ -0,0 +1,51 @@ +RebornBoss +{ + playerModel reborn + customSkin boss + saber shadowtrooper + weapon WP_SABER + saberStyle 1 + saberStyle 2 + saberStyle 3 + FP_HEAL 0 + FP_LEVITATION 2 + FP_SPEED 2 + FP_PUSH 2 + FP_PULL 1 + FP_TELEPATHY 0 + FP_GRIP 2 + FP_LIGHTNING 0 + FP_RAGE 1 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 1 + FP_SEE 1 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + rank lt + reactions 3 + aim 3 + move 5 + aggression 4 + evasion 3 + intelligence 5 + hfov 160 + vfov 160 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race human + class CLASS_REBORN + snd reborn3 + sndcombat reborn3 + sndjedi reborn3 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 150 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/RebornChiss.npc b/base/ext_data/npcs/RebornChiss.npc new file mode 100644 index 0000000..dbc1c2e --- /dev/null +++ b/base/ext_data/npcs/RebornChiss.npc @@ -0,0 +1,54 @@ +RebornChiss +{ + playerModel chiss + saber reborn + saber2 sabersai + saber2color red + weapon WP_SABER + saberStyle 6 + FP_HEAL 0 + FP_LEVITATION 0 + FP_SPEED 1 + FP_PUSH 2 + FP_PULL 0 + FP_TELEPATHY 0 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 1 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 0 + FP_SEE 1 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 2 + rank ltjg + reactions 3 + aim 3 + move 5 + aggression 4 + evasion 2 + intelligence 5 + hfov 160 + vfov 160 + scale 96 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race human + class CLASS_REBORN + snd bartender + sndcombat bartender + sndjedi bartender +// snd reborn2 +// sndcombat reborn2 +// sndjedi reborn2 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 100 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/RebornFencer.npc b/base/ext_data/npcs/RebornFencer.npc new file mode 100644 index 0000000..9d49e8e --- /dev/null +++ b/base/ext_data/npcs/RebornFencer.npc @@ -0,0 +1,52 @@ +RebornFencer +{ + playerModel reborn + customSkin fencer + saber reborn + weapon WP_SABER + saberStyle 1 + FP_HEAL 0 + FP_LEVITATION 0 + FP_SPEED 1 + FP_PUSH 2 + FP_PULL 0 + FP_TELEPATHY 0 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 1 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 0 + FP_SEE 0 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 2 + forcePowerMax 75 + forceRegenRate 200 + rank ltjg + reactions 3 + aim 3 + move 5 + aggression 4 + evasion 2 + intelligence 5 + hfov 160 + vfov 160 + scale 96 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race human + class CLASS_REBORN + snd reborn2 + sndcombat reborn2 + sndjedi reborn2 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 100 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/RebornForceUser.npc b/base/ext_data/npcs/RebornForceUser.npc new file mode 100644 index 0000000..76859ce --- /dev/null +++ b/base/ext_data/npcs/RebornForceUser.npc @@ -0,0 +1,51 @@ +RebornForceUser +{ + playerModel reborn + customSkin forceuser + saber reborn + weapon WP_SABER + saberStyle 2 + FP_HEAL 0 + FP_LEVITATION 1 + FP_SPEED 1 + FP_PUSH 2 + FP_PULL 1 + FP_TELEPATHY 0 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 0 + FP_SEE 1 + FP_SABERTHROW 0 + FP_SABER_DEFENSE 1 + FP_SABER_OFFENSE 1 + forceRegenRate 150 + rank ensign + reactions 3 + aim 3 + move 5 + aggression 2 + evasion 2 + intelligence 5 + hfov 160 + vfov 160 + scale 96 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race human + class CLASS_REBORN + snd reborn2 + sndcombat reborn2 + sndjedi reborn2 + yawSpeed 80 + walkSpeed 55 + runSpeed 200 + health 100 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/RebornRodian.npc b/base/ext_data/npcs/RebornRodian.npc new file mode 100644 index 0000000..13e7127 --- /dev/null +++ b/base/ext_data/npcs/RebornRodian.npc @@ -0,0 +1,52 @@ +RebornRodian +{ + playerModel rodian + weapon WP_SABER + saber saberstar2 + saber2 saberstar2 + saberColor red + saber2Color red + saberStyle 6 + FP_HEAL 0 + FP_LEVITATION 3 + FP_SPEED 2 + FP_PUSH 1 + FP_PULL 1 + FP_TELEPATHY 0 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 0 + FP_SEE 1 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 2 + rank lt + reactions 3 + aim 3 + move 5 + aggression 3 + evasion 3 + intelligence 5 + hfov 160 + vfov 160 + scale 96 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race human + class CLASS_REBORN + snd rodian1 + sndcombat rodian1 + sndjedi rodian1 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 100 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/RebornTrandoshan.npc b/base/ext_data/npcs/RebornTrandoshan.npc new file mode 100644 index 0000000..cdc99e5 --- /dev/null +++ b/base/ext_data/npcs/RebornTrandoshan.npc @@ -0,0 +1,50 @@ +RebornTrandoshan +{ + playerModel trandoshan + weapon WP_SABER + saber sabertrident + saberColor red + saberColor2 red + saberColor3 red + saberColor4 red + FP_HEAL 0 + FP_LEVITATION 2 + FP_SPEED 0 + FP_PUSH 2 + FP_PULL 2 + FP_TELEPATHY 0 + FP_GRIP 1 + FP_LIGHTNING 0 + FP_RAGE 1 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 1 + FP_SEE 0 + FP_SABERTHROW 0 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 2 + rank lt + reactions 3 + aim 3 + move 5 + aggression 4 + evasion 3 + intelligence 5 + hfov 160 + vfov 160 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd trandoshan1 + sndcombat trandoshan1 + sndjedi trandoshan1 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 150 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/RebornWeequay.npc b/base/ext_data/npcs/RebornWeequay.npc new file mode 100644 index 0000000..cf4e5b4 --- /dev/null +++ b/base/ext_data/npcs/RebornWeequay.npc @@ -0,0 +1,49 @@ +RebornWeequay +{ + playerModel weequay + weapon WP_SABER + saber saberbroad + saberColor red + saberColor2 red + saberStyle 3 + FP_HEAL 0 + FP_LEVITATION 2 + FP_SPEED 0 + FP_PUSH 3 + FP_PULL 3 + FP_TELEPATHY 0 + FP_GRIP 1 + FP_LIGHTNING 0 + FP_RAGE 2 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 1 + FP_SEE 0 + FP_SABERTHROW 1 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 2 + rank lt + reactions 3 + aim 3 + move 5 + aggression 4 + evasion 3 + intelligence 5 + hfov 160 + vfov 160 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd weequay + sndcombat weequay + sndjedi weequay + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 150 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Reborn_dual.npc b/base/ext_data/npcs/Reborn_dual.npc new file mode 100644 index 0000000..95b5330 --- /dev/null +++ b/base/ext_data/npcs/Reborn_dual.npc @@ -0,0 +1,103 @@ +reborn_dual +{ + playerModel reborn_new + customSkin red + saber reborn + saber2 reborn + weapon WP_SABER + saberStyle 6 + FP_HEAL 0 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 3 + FP_PULL 2 + FP_TELEPATHY 0 + FP_GRIP 2 + FP_LIGHTNING 1 + FP_RAGE 2 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 2 + FP_SEE 2 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + rank ltcomm + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + hfov 160 + vfov 160 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd reborn2 + sndcombat reborn2 + sndjedi reborn2 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 300 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +reborn_dual2 +{ + playerModel reborn_new + customSkin blue + saber reborn + saber2 reborn + weapon WP_SABER + saberStyle 6 + FP_HEAL 0 + FP_LEVITATION 3 + FP_SPEED 1 + FP_PUSH 2 + FP_PULL 1 + FP_TELEPATHY 0 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 1 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 0 + FP_SEE 0 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 2 + FP_SABER_OFFENSE 3 + rank lt + reactions 5 + aim 5 + move 5 + aggression 4 + evasion 4 + intelligence 5 + hfov 160 + vfov 160 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd reborn2 + sndcombat reborn2 + sndjedi reborn2 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 175 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} diff --git a/base/ext_data/npcs/Reborn_new.npc b/base/ext_data/npcs/Reborn_new.npc new file mode 100644 index 0000000..901a6a3 --- /dev/null +++ b/base/ext_data/npcs/Reborn_new.npc @@ -0,0 +1,104 @@ +reborn_new +{ + playerModel reborn_new + saber reborn_new + weapon WP_SABER + saberStyle 1 + saberStyle 3 + saberStyle 2 + FP_HEAL 0 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 3 + FP_PULL 2 + FP_TELEPATHY 0 + FP_GRIP 3 + FP_LIGHTNING 1 + FP_RAGE 2 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 2 + FP_SEE 2 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + rank ltcomm + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + hfov 160 + vfov 160 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd reborn2 + sndcombat reborn2 + sndjedi reborn2 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 300 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +reborn_new2 +{ + playerModel reborn_new + customSkin blue + saber shadowtrooper + weapon WP_SABER + saberStyle 1 + saberStyle 3 + saberStyle 2 + FP_HEAL 0 + FP_LEVITATION 3 + FP_SPEED 1 + FP_PUSH 2 + FP_PULL 1 + FP_TELEPATHY 0 + FP_GRIP 2 + FP_LIGHTNING 0 + FP_RAGE 1 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 0 + FP_SEE 0 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 2 + FP_SABER_OFFENSE 3 + rank lt + reactions 5 + aim 5 + move 5 + aggression 4 + evasion 4 + intelligence 5 + hfov 160 + vfov 160 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd reborn2 + sndcombat reborn2 + sndjedi reborn2 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 175 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} diff --git a/base/ext_data/npcs/Reborn_staff.npc b/base/ext_data/npcs/Reborn_staff.npc new file mode 100644 index 0000000..4413232 --- /dev/null +++ b/base/ext_data/npcs/Reborn_staff.npc @@ -0,0 +1,103 @@ +reborn_staff +{ + playerModel reborn_new + customSkin red + saber dual_1 + saberColor red + weapon WP_SABER + saberStyle 7 + FP_HEAL 0 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 3 + FP_PULL 2 + FP_TELEPATHY 0 + FP_GRIP 2 + FP_LIGHTNING 1 + FP_RAGE 2 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 2 + FP_SEE 2 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + rank ltcomm + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + hfov 160 + vfov 160 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd reborn1 + sndcombat reborn1 + sndjedi reborn1 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 300 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +reborn_staff2 +{ + playerModel reborn_new + customSkin blue + saber dual_1 + saberColor red + weapon WP_SABER + saberStyle 7 + FP_HEAL 0 + FP_LEVITATION 3 + FP_SPEED 1 + FP_PUSH 2 + FP_PULL 1 + FP_TELEPATHY 0 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 1 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 0 + FP_SEE 0 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 2 + FP_SABER_OFFENSE 3 + rank lt + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 4 + intelligence 5 + hfov 160 + vfov 160 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd reborn1 + sndcombat reborn1 + sndjedi reborn1 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 175 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} diff --git a/base/ext_data/npcs/Reborn_twin.npc b/base/ext_data/npcs/Reborn_twin.npc new file mode 100644 index 0000000..781110b --- /dev/null +++ b/base/ext_data/npcs/Reborn_twin.npc @@ -0,0 +1,275 @@ +DKothos +{ + playerModel reborn_twin +// customSkin ? + weapon WP_MELEE + health 500 + FP_HEAL 0 + FP_LEVITATION 3 + FP_SPEED 2 + FP_PUSH 3 + FP_PULL 0 + FP_TELEPATHY 0 + FP_GRIP 2 + FP_LIGHTNING 2 + FP_RAGE 0 + FP_PROTECT 2 + FP_ABSORB 2 + FP_DRAIN 2 + FP_SEE 0 + FP_SABERTHROW 0 + FP_SABER_DEFENSE 0 + FP_SABER_OFFENSE 0 + forcePowerMax 200 + forceRegenRate 50 + forceRegenAmount 2 + rank captain + reactions 5 + aim 5 + move 5 + aggression 1 + evasion 5 + intelligence 5 + hfov 160 + vfov 160 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd kothos + sndcombat kothos + sndjedi kothos + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +VKothos +{ + playerModel reborn_twin +// customSkin ? + weapon WP_MELEE + health 500 + FP_HEAL 0 + FP_LEVITATION 3 + FP_SPEED 2 + FP_PUSH 3 + FP_PULL 0 + FP_TELEPATHY 0 + FP_GRIP 2 + FP_LIGHTNING 2 + FP_RAGE 0 + FP_PROTECT 2 + FP_ABSORB 2 + FP_DRAIN 2 + FP_SEE 0 + FP_SABERTHROW 0 + FP_SABER_DEFENSE 0 + FP_SABER_OFFENSE 0 + forcePowerMax 200 + forceRegenRate 50 + forceRegenAmount 2 + rank captain + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 4 + intelligence 5 + hfov 160 + vfov 160 + hfov 120 + vfov 120 + scale 100 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd kothos + sndcombat kothos + sndjedi kothos + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +RebornMaster +{ + playerModel reborn_twin + customSkin boss + saber rebornmaster + weapon WP_SABER + saberStyle 1 + saberStyle 2 + saberStyle 3 + health 200 + FP_HEAL 3 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 3 + FP_PULL 3 + FP_TELEPATHY 0 + FP_GRIP 3 + FP_LIGHTNING 3 + FP_RAGE 3 + FP_PROTECT 2 + FP_ABSORB 2 + FP_DRAIN 2 + FP_SEE 0 + FP_SABERTHROW 3 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + forcePowerMax 200 + forceRegenRate 50 + forceRegenAmount 2 + rank captain + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + hfov 160 + vfov 160 + hfov 120 + vfov 120 + scale 100 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_SHADOWTROOPER + snd reborn1 + sndcombat reborn1 + sndjedi reborn1 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +RebornMasterDual +{ + playerModel reborn_twin + customSkin boss + saber shadowtrooper + saber2 shadowtrooper + weapon WP_SABER + saberStyle 6 + health 200 + FP_HEAL 3 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 3 + FP_PULL 3 + FP_TELEPATHY 0 + FP_GRIP 3 + FP_LIGHTNING 3 + FP_RAGE 3 + FP_PROTECT 2 + FP_ABSORB 2 + FP_DRAIN 2 + FP_SEE 0 + FP_SABERTHROW 3 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + forcePowerMax 200 + forceRegenRate 50 + forceRegenAmount 2 + rank captain + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + hfov 160 + vfov 160 + hfov 120 + vfov 120 + scale 100 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_SHADOWTROOPER + snd reborn2 + sndcombat reborn2 + sndjedi reborn2 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + + +RebornMasterStaff +{ + playerModel reborn_twin + customSkin boss + saber dual_1 + saberColor red + weapon WP_SABER + saberStyle 7 + health 200 + FP_HEAL 3 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 3 + FP_PULL 3 + FP_TELEPATHY 0 + FP_GRIP 3 + FP_LIGHTNING 3 + FP_RAGE 3 + FP_PROTECT 2 + FP_ABSORB 2 + FP_DRAIN 2 + FP_SEE 0 + FP_SABERTHROW 3 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + forcePowerMax 200 + forceRegenRate 50 + forceRegenAmount 2 + rank captain + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + hfov 160 + vfov 160 + hfov 120 + vfov 120 + scale 100 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_SHADOWTROOPER + snd reborn2 + sndcombat reborn2 + sndjedi reborn2 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + diff --git a/base/ext_data/npcs/Reelo.npc b/base/ext_data/npcs/Reelo.npc new file mode 100644 index 0000000..f27c47d --- /dev/null +++ b/base/ext_data/npcs/Reelo.npc @@ -0,0 +1,30 @@ +Reelo +{ + playerModel reelo + weapon WP_BLASTER + rank commander + altFire 1 + snd reelo + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race klingon + class CLASS_REELO + snd reelo + sndcombat reelo + sndextra reelo + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbHands 0 + dismemberProbLegs 0 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/RocketTrooper.npc b/base/ext_data/npcs/RocketTrooper.npc new file mode 100644 index 0000000..8dad542 --- /dev/null +++ b/base/ext_data/npcs/RocketTrooper.npc @@ -0,0 +1,37 @@ +RocketTrooper +{ + playerModel stormtrooper +// surfOn torso_pauldron +// surfOff "torso_armor_neck_augment torso_body_neck_augment" + customSkin officer + weapon WP_ROCKET_LAUNCHER + health 60 + headPitchRangeDown 30 + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + rank ensign + scale 110 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race klingon + class CLASS_STORMTROOPER + height 68 + crouchheight 52 + walkSpeed 51 + runSpeed 200 + snd stofficer1 + sndcombat stofficer1 + sndextra stofficer1 + yawspeed 100 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Rodian.npc b/base/ext_data/npcs/Rodian.npc new file mode 100644 index 0000000..c20d435 --- /dev/null +++ b/base/ext_data/npcs/Rodian.npc @@ -0,0 +1,66 @@ +Rodian +{ + playerModel rodian + customSkin sp + customRGBA random1 + weapon WP_DISRUPTOR + altFire 1 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + health 25 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race klingon + class CLASS_RODIAN + snd rodian1 + sndcombat rodian1 + sndextra rodian1 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + visrange 8192 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +Rodian2 +{ + playerModel rodian + customSkin sp + customRGBA random1 + weapon WP_BLASTER + altFire 1 + surfOff "hips_belt torso_vest" + surfOn "torso_augment" + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + health 20 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race klingon + class CLASS_RODIAN + snd rodian2 + sndcombat rodian2 + sndextra rodian2 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/STCommander.npc b/base/ext_data/npcs/STCommander.npc new file mode 100644 index 0000000..788081a --- /dev/null +++ b/base/ext_data/npcs/STCommander.npc @@ -0,0 +1,37 @@ +STCommander +{ + playerModel stormtrooper +// surfOn torso_pauldron +// surfOff "torso_armor_neck_augment torso_body_neck_augment" + customSkin officer + weapon WP_REPEATER + health 60 + headPitchRangeDown 30 + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + rank ensign + scale 105 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race klingon + class CLASS_STORMTROOPER + height 68 + crouchheight 52 + walkSpeed 51 + runSpeed 200 + snd stofficer1 + sndcombat stofficer1 + sndextra stofficer1 + yawspeed 110 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/STOfficer.npc b/base/ext_data/npcs/STOfficer.npc new file mode 100644 index 0000000..822e5ae --- /dev/null +++ b/base/ext_data/npcs/STOfficer.npc @@ -0,0 +1,74 @@ +STOfficer +{ + playerModel stormtrooper +// surfOn torso_pauldron +// surfOff "torso_armor_neck_augment torso_body_neck_augment" + customSkin officer + weapon WP_FLECHETTE + health 60 + headPitchRangeDown 30 + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + rank ensign + scale 105 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_STORMTROOPER + height 68 + crouchheight 52 + walkSpeed 51 + runSpeed 200 + snd stofficer1 + sndcombat stofficer1 + sndextra stofficer1 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +STOfficerAlt +{ + playerModel stormtrooper +// surfOn torso_pauldron +// surfOff "torso_armor_neck_augment torso_body_neck_augment" + customSkin officer + weapon WP_FLECHETTE + altFire 1 + health 60 + headPitchRangeDown 30 + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + rank ensign + scale 105 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_STORMTROOPER + height 68 + crouchheight 52 + walkSpeed 51 + runSpeed 200 + snd stofficer1 + sndcombat stofficer1 + sndextra stofficer1 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/STOfficerAlt.npc b/base/ext_data/npcs/STOfficerAlt.npc new file mode 100644 index 0000000..6524cb4 --- /dev/null +++ b/base/ext_data/npcs/STOfficerAlt.npc @@ -0,0 +1,37 @@ +STOfficerAlt +{ + playerModel stormtrooper + weapon WP_FLECHETTE + altFire 1 + surfOn torso_pauldron + surfOff "torso_armor_neck_augment torso_body_neck_augment" + health 60 + headPitchRangeDown 30 + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + rank ensign + scale 105 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race klingon + class CLASS_STORMTROOPER + height 68 + crouchheight 52 + walkSpeed 51 + runSpeed 200 + snd stofficer1 + sndcombat stofficer1 + sndextra stofficer1 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/ShadowTrooper.npc b/base/ext_data/npcs/ShadowTrooper.npc new file mode 100644 index 0000000..5c99019 --- /dev/null +++ b/base/ext_data/npcs/ShadowTrooper.npc @@ -0,0 +1,100 @@ +ShadowTrooper +{ + playerModel shadowtrooper + saber shadowtrooper + weapon WP_SABER + saberStyle 1 + saberStyle 3 + saberStyle 2 + FP_HEAL 0 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 3 + FP_PULL 2 + FP_TELEPATHY 0 + FP_GRIP 2 + FP_LIGHTNING 1 + FP_RAGE 2 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 2 + FP_SEE 2 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + rank ltcomm + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 4 + intelligence 5 + hfov 160 + vfov 160 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race human + class CLASS_SHADOWTROOPER + snd shadow1 + sndcombat shadow1 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +ShadowTrooper2 +{ + playerModel shadowtrooper + saber shadowtrooper + saberColor red + weapon WP_SABER + saberStyle 3 + saberStyle 2 + saberStyle 1 + FP_HEAL 0 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 3 + FP_PULL 2 + FP_TELEPATHY 0 + FP_GRIP 2 + FP_LIGHTNING 1 + FP_RAGE 2 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 2 + FP_SEE 2 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + rank lt + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 4 + intelligence 5 + hfov 160 + vfov 160 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race human + class CLASS_SHADOWTROOPER + snd shadow2 + sndcombat shadow2 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} diff --git a/base/ext_data/npcs/StormPilot.npc b/base/ext_data/npcs/StormPilot.npc new file mode 100644 index 0000000..463abe7 --- /dev/null +++ b/base/ext_data/npcs/StormPilot.npc @@ -0,0 +1,35 @@ +StormPilot +{ + playerModel stormpilot + weapon WP_BLASTER_PISTOL + health 30 + headPitchRangeDown 30 + reactions 3 + aim 5 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_STORMTROOPER + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 +// snd stofficer1 +// sndcombat stofficer1 +// sndextra stofficer1 + snd worker2 + sndcombat worker2 + sndextra worker2 + yawspeed 80 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/StormTrooper.npc b/base/ext_data/npcs/StormTrooper.npc new file mode 100644 index 0000000..efa850d --- /dev/null +++ b/base/ext_data/npcs/StormTrooper.npc @@ -0,0 +1,67 @@ +StormTrooper +{ + playerModel stormtrooper + weapon WP_BLASTER + health 30 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race klingon + class CLASS_STORMTROOPER + height 64 + crouchheight 38 + walkSpeed 51 + runSpeed 200 + snd st1 + sndcombat st1 + sndextra st1 + yawspeed 70 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +StormTrooper2 +{ + playerModel stormtrooper + weapon WP_BLASTER + health 30 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race klingon + class CLASS_STORMTROOPER + height 64 + crouchheight 38 + walkSpeed 51 + runSpeed 200 + snd st2 + sndcombat st2 + sndextra st2 + yawspeed 70 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} diff --git a/base/ext_data/npcs/SwampTrooper.npc b/base/ext_data/npcs/SwampTrooper.npc new file mode 100644 index 0000000..763336e --- /dev/null +++ b/base/ext_data/npcs/SwampTrooper.npc @@ -0,0 +1,63 @@ +SwampTrooper +{ + playerModel swamptrooper + weapon WP_FLECHETTE + headPitchRangeDown 30 + health 70 + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 3 + intelligence 3 + scale 110 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race klingon + class CLASS_SWAMPTROOPER + height 68 + crouchheight 52 + snd swamp1 + sndcombat swamp1 + sndextra swamp1 + yawspeed 100 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +SwampTrooper2 +{ + playerModel swamptrooper + weapon WP_REPEATER + headPitchRangeDown 30 + health 70 + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 3 + intelligence 3 + scale 110 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race klingon + class CLASS_SWAMPTROOPER + height 68 + crouchheight 52 + snd swamp2 + sndcombat swamp2 + sndextra swamp2 + yawspeed 100 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Tavion.npc b/base/ext_data/npcs/Tavion.npc new file mode 100644 index 0000000..f0f3c9e --- /dev/null +++ b/base/ext_data/npcs/Tavion.npc @@ -0,0 +1,50 @@ +Tavion +{ + playerModel tavion + rank commander + saber tavion + saberColor red + weapon WP_SABER + saberStyle 5 + FP_HEAL 0 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 3 + FP_PULL 2 + FP_TELEPATHY 0 + FP_GRIP 2 + FP_LIGHTNING 2 + FP_RAGE 2 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 1 + FP_SEE 1 + FP_SABERTHROW 3 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + reactions 3 + aim 3 + move 5 + aggression 3 + evasion 4 + intelligence 5 + hfov 160 + vfov 160 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race human + class CLASS_TAVION + sex female + snd tavion + sndcombat tavion + sndjedi tavion + yawSpeed 120 + walkSpeed 55 + runSpeed 200 + health 300 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbLegs 0 + dismemberProbHands 0 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Tavion_new.npc b/base/ext_data/npcs/Tavion_new.npc new file mode 100644 index 0000000..91233ea --- /dev/null +++ b/base/ext_data/npcs/Tavion_new.npc @@ -0,0 +1,152 @@ +Tavion_new +{ + playerModel tavion_new + rank commander + saber tavion + saberColor red + weapon WP_SABER + saberStyle 5 + FP_HEAL 0 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 3 + FP_PULL 2 + FP_TELEPATHY 0 + FP_GRIP 3 + FP_LIGHTNING 2 + FP_RAGE 2 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 2 + FP_SEE 1 + FP_SABERTHROW 3 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + reactions 3 + aim 3 + move 5 + aggression 3 + evasion 4 + intelligence 5 + hfov 160 + vfov 160 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race human + class CLASS_TAVION + sex female + snd tavion + sndcombat tavion + sndjedi tavion + yawSpeed 120 + walkSpeed 55 + runSpeed 200 + health 300 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbLegs 0 + dismemberProbHands 0 + dismemberProbWaist 0 +} + +Tavion_scepter +{ + playerModel tavion_new + rank commander + saber tavion + saberColor red + weapon WP_SCEPTER + weapon WP_SABER + saberStyle 6 + health 400 + FP_HEAL 0 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 3 + FP_PULL 3 + FP_TELEPATHY 0 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 0 + FP_SEE 0 + FP_SABERTHROW 3 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + hfov 160 + vfov 160 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + sex female + snd tavion + sndcombat tavion + sndjedi tavion + yawSpeed 120 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbLegs 0 + dismemberProbHands 0 + dismemberProbWaist 0 +} + +Tavion_sith_sword +{ + playerModel tavion_new + customSkin possessed + rank captain + weapon WP_SABER + saber sith_sword + saberStyle 4 + health 250 + FP_HEAL 0 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 3 + FP_PULL 3 + FP_TELEPATHY 0 + FP_GRIP 3 + FP_LIGHTNING 3 + FP_RAGE 3 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 3 + FP_SEE 0 + FP_SABERTHROW 3 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + hfov 160 + vfov 160 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_DESANN + sex female + snd tavion + sndcombat tavion + sndjedi tavion + yawSpeed 120 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbLegs 0 + dismemberProbHands 0 + dismemberProbWaist 0 +} + diff --git a/base/ext_data/npcs/Trandoshan.npc b/base/ext_data/npcs/Trandoshan.npc new file mode 100644 index 0000000..8065257 --- /dev/null +++ b/base/ext_data/npcs/Trandoshan.npc @@ -0,0 +1,30 @@ +Trandoshan +{ + playerModel trandoshan + customSkin sp + customRGBA random1 + weapon WP_REPEATER + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + health 40 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race klingon + class CLASS_TRANDOSHAN + snd trandoshan1 + sndcombat trandoshan1 + sndextra trandoshan1 + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/Ugnaught.npc b/base/ext_data/npcs/Ugnaught.npc new file mode 100644 index 0000000..855c228 --- /dev/null +++ b/base/ext_data/npcs/Ugnaught.npc @@ -0,0 +1,55 @@ +Ugnaught +{ + playerModel ugnaught + weapon WP_NONE + scale 75 + health 10 + snd ugnaught + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_PLAYER + class CLASS_UGNAUGHT + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +Ugnaught2 +{ + playerModel ugnaught + weapon WP_NONE + surfOff "l_hand_purse" + surfOn "r_hand_tool" + scale 75 + health 10 + snd ugnaught + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_PLAYER + class CLASS_UGNAUGHT + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} diff --git a/base/ext_data/npcs/alora.npc b/base/ext_data/npcs/alora.npc new file mode 100644 index 0000000..a599c9d --- /dev/null +++ b/base/ext_data/npcs/alora.npc @@ -0,0 +1,103 @@ +alora +{ + playerModel alora + rank lt + saber single_4 + saberColor red + weapon WP_SABER + saberStyle 2 + saberStyle 1 + health 300 + FP_HEAL 0 + FP_LEVITATION 2 + FP_SPEED 2 + FP_PUSH 2 + FP_PULL 2 + FP_TELEPATHY 0 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 0 + FP_SEE 0 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 2 + FP_SABER_OFFENSE 2 + reactions 3 + aim 3 + move 5 + aggression 3 + evasion 4 + intelligence 5 + hfov 160 + vfov 160 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + sex female + snd alora + sndcombat alora + sndjedi alora + yawSpeed 120 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbLegs 0 + dismemberProbHands 0 + dismemberProbWaist 0 +} + +alora_dual +{ +// playerModel alora2 + playerModel alora + rank commander + saber single_4 + saberColor red + saber2 single_4 + saber2Color red + weapon WP_SABER + saberStyle 6 + health 500 + FP_HEAL 0 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 3 + FP_PULL 3 + FP_TELEPATHY 0 + FP_GRIP 2 + FP_LIGHTNING 2 + FP_RAGE 3 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 0 + FP_SEE 0 + FP_SABERTHROW 3 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + hfov 160 + vfov 160 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_ALORA + sex female + snd alora + sndcombat alora + sndjedi alora + yawSpeed 120 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbLegs 0 + dismemberProbHands 0 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/assassin_droid.npc b/base/ext_data/npcs/assassin_droid.npc new file mode 100644 index 0000000..5996821 --- /dev/null +++ b/base/ext_data/npcs/assassin_droid.npc @@ -0,0 +1,32 @@ +assassin_droid +{ + playerModel assassin_droid + weapon WP_BLASTER + health 150 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_ASSASSIN_DROID + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd shadowtrooper1 + sndcombat shadowtrooper1 + sndextra shadowtrooper1 + yawspeed 70 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 100 + dismemberProbArms 100 + dismemberProbLegs 100 + dismemberProbHands 100 + dismemberProbWaist 100 +} \ No newline at end of file diff --git a/base/ext_data/npcs/atst.npc b/base/ext_data/npcs/atst.npc new file mode 100644 index 0000000..ecb1273 --- /dev/null +++ b/base/ext_data/npcs/atst.npc @@ -0,0 +1,36 @@ +atst +{ + playerModel atst + weapon WP_ATST_MAIN + weapon WP_ATST_SIDE +// headModel atst + //torsoModel atst + //legsModel atst + headYawRangeLeft 80 + headYawRangeRight 80 + headPitchRangeUp 30 + headPitchRangeDown 30 + torsoYawRangeLeft 0 + torsoYawRangeRight 0 + torsoPitchRangeUp 0 + torsoPitchRangeDown 0 + health 200 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + height 272 + width 80 +// race bot + class CLASS_ATST + yawSpeed 60 + runSpeed 150 + walkSpeed 150 + hFOV 120 + vfov 45 + snd atst +} \ No newline at end of file diff --git a/base/ext_data/npcs/atst_vehicle.npc b/base/ext_data/npcs/atst_vehicle.npc new file mode 100644 index 0000000..ba9998b --- /dev/null +++ b/base/ext_data/npcs/atst_vehicle.npc @@ -0,0 +1,13 @@ +ATST_vehicle +{ + weapon WP_BOWCASTER + weapon WP_ROCKET_LAUNCHER + weapon WP_EMPLACED_GUN + playerModel atst + playerTeam TEAM_FREE + enemyTeam TEAM_FREE + class CLASS_VEHICLE + height 272 + width 80 + health 3000 +} \ No newline at end of file diff --git a/base/ext_data/npcs/boba_fett.npc b/base/ext_data/npcs/boba_fett.npc new file mode 100644 index 0000000..36d6257 --- /dev/null +++ b/base/ext_data/npcs/boba_fett.npc @@ -0,0 +1,44 @@ + +boba_fett +{ + playerModel boba_fett + altFire 1 + weapon WP_MELEE + weapon WP_DISRUPTOR + weapon WP_ROCKET_LAUNCHER + weapon WP_BLASTER + FP_HEAL 0 + FP_LEVITATION 3 + FP_SPEED 0 + FP_PUSH 0 + FP_PULL 0 + FP_TELEPATHY 0 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_SABERTHROW 0 + FP_SABER_DEFENSE 0 + FP_SABER_OFFENSE 0 + health 400 + headPitchRangeDown 30 + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + earshot 2048 + visrange 4096 + hfov 120 + vfov 100 + rank captain + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_BOBAFETT + walkSpeed 80 + runSpeed 250 + snd boba + sndcombat boba + sndextra boba + yawspeed 180 +} + diff --git a/base/ext_data/npcs/chewie.npc b/base/ext_data/npcs/chewie.npc new file mode 100644 index 0000000..52a9d2d --- /dev/null +++ b/base/ext_data/npcs/chewie.npc @@ -0,0 +1,86 @@ +chewie +{ + playerModel chewbacca + altFire 0 + weapon WP_BOWCASTER + FP_HEAL 0 + FP_LEVITATION 0 + FP_SPEED 0 + FP_PUSH 0 + FP_PULL 0 + FP_TELEPATHY 0 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_SABERTHROW 0 + FP_SABER_DEFENSE 0 + FP_SABER_OFFENSE 0 + health 400 + scale 122 + width 18 + height 78 + crouchheight 42 + headPitchRangeDown 30 + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + earshot 1024 + visrange 2048 + hfov 120 + vfov 100 + rank captain + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_REBEL + walkSpeed 60 + runSpeed 160 + snd chewbacca + sndcombat chewbacca + sndextra chewbacca + yawspeed 90 +} + +chewie_cin +{ + playerModel chewbacca + altFire 0 + FP_HEAL 0 + FP_LEVITATION 0 + FP_SPEED 0 + FP_PUSH 0 + FP_PULL 0 + FP_TELEPATHY 0 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_SABERTHROW 0 + FP_SABER_DEFENSE 0 + FP_SABER_OFFENSE 0 + health 400 + scale 122 + width 18 + height 78 + crouchheight 42 + headPitchRangeDown 30 + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + earshot 1024 + visrange 2048 + hfov 120 + vfov 100 + rank captain + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_REBEL + walkSpeed 60 + runSpeed 160 + snd chewbacca + sndcombat chewbacca + sndextra chewbacca + yawspeed 90 +} \ No newline at end of file diff --git a/base/ext_data/npcs/cultist.npc b/base/ext_data/npcs/cultist.npc new file mode 100644 index 0000000..e269d7e --- /dev/null +++ b/base/ext_data/npcs/cultist.npc @@ -0,0 +1,38 @@ +cultist +{ + playerModel cultist + weapon WP_BLASTER + altfire 1 + FP_LEVITATION 3 + FP_SPEED 2 + FP_PUSH 2 + FP_PULL 2 + FP_GRIP 1 + FP_LIGHTNING 1 + FP_DRAIN 1 + rank ltcomm + reactions 1 + aim 1 + move 1 + aggression 1 + evasion 1 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race human + class CLASS_REBORN + snd cultist1 + sndcombat cultist1 + sndjedi cultist1 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 50 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/cultist_destroyer.npc b/base/ext_data/npcs/cultist_destroyer.npc new file mode 100644 index 0000000..4e2fd66 --- /dev/null +++ b/base/ext_data/npcs/cultist_destroyer.npc @@ -0,0 +1,31 @@ +cultist_destroyer +{ + playerModel cultist + customSkin red + weapon WP_MELEE + FP_LEVITATION 3 + rank ltcomm + reactions 1 + aim 1 + move 1 + aggression 5 + evasion 1 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd cultist3 + sndcombat cultist3 + sndjedi cultist3 + yawSpeed 60 + walkSpeed 72 + runSpeed 230 + health 100 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/cultist_drain.npc b/base/ext_data/npcs/cultist_drain.npc new file mode 100644 index 0000000..4b39936 --- /dev/null +++ b/base/ext_data/npcs/cultist_drain.npc @@ -0,0 +1,37 @@ +cultist_drain +{ + playerModel cultist + customSkin red + weapon WP_MELEE + FP_LEVITATION 1 + FP_PUSH 3 + FP_DRAIN 3 + forcePowerMax 200 + forceRegenRate 50 + forceRegenAmount 2 + rank captain + reactions 1 + aim 1 + move 1 + aggression 5 + evasion 3 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race human + class CLASS_REBORN + snd cultist3 + sndcombat cultist3 + sndjedi cultist3 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 100 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/cultist_grip.npc b/base/ext_data/npcs/cultist_grip.npc new file mode 100644 index 0000000..ad77d26 --- /dev/null +++ b/base/ext_data/npcs/cultist_grip.npc @@ -0,0 +1,38 @@ +cultist_grip +{ + playerModel cultist + weapon WP_MELEE + FP_LEVITATION 1 + FP_PUSH 3 + FP_PULL 2 +// FP_GRIP 3 + FP_GRIP 2 + forcePowerMax 200 + forceRegenRate 50 + forceRegenAmount 2 + rank captain + reactions 1 + aim 1 + move 1 + aggression 5 + evasion 3 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race human + class CLASS_REBORN + snd cultist3 + sndcombat cultist3 + sndjedi cultist3 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 100 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/cultist_lightning.npc b/base/ext_data/npcs/cultist_lightning.npc new file mode 100644 index 0000000..4f5283d --- /dev/null +++ b/base/ext_data/npcs/cultist_lightning.npc @@ -0,0 +1,37 @@ +cultist_lightning +{ + playerModel cultist + customSkin blue + weapon WP_MELEE + FP_LEVITATION 1 + FP_PUSH 3 + FP_LIGHTNING 3 + forcePowerMax 200 + forceRegenRate 50 + forceRegenAmount 2 + rank captain + reactions 1 + aim 1 + move 1 + aggression 5 + evasion 3 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race human + class CLASS_REBORN + snd cultist3 + sndcombat cultist3 + sndjedi cultist3 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 100 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/cultist_saber.npc b/base/ext_data/npcs/cultist_saber.npc new file mode 100644 index 0000000..fcce37e --- /dev/null +++ b/base/ext_data/npcs/cultist_saber.npc @@ -0,0 +1,294 @@ +cultist_saber +{ + playerModel cultist + customSkin brown + saber reborn + weapon WP_SABER + saberStyle 1 + FP_LEVITATION 1 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 1 + reactions 1 + aim 1 + move 1 + aggression 3 + evasion 1 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd cultist1 + sndcombat cultist1 + sndjedi cultist1 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 100 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +cultist_saber_throw +{ + playerModel cultist + customSkin brown + saber reborn + weapon WP_SABER + saberStyle 1 + FP_LEVITATION 1 + FP_SABER_DEFENSE 2 + FP_SABER_OFFENSE 1 + FP_SABERTHROW 1 + reactions 1 + aim 1 + move 1 + aggression 2 + evasion 1 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd cultist1 + sndcombat cultist1 + sndjedi cultist1 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 100 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +cultist_saber_med +{ + playerModel cultist + customSkin brown + saber reborn + weapon WP_SABER + saberStyle 2 + FP_LEVITATION 1 + FP_SABER_DEFENSE 2 + FP_SABER_OFFENSE 2 + rank crewman + reactions 1 + aim 1 + move 1 + aggression 3 + evasion 1 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd cultist1 + sndcombat cultist1 + sndjedi cultist1 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 100 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +cultist_saber_med_throw +{ + playerModel cultist + customSkin brown + saber reborn + weapon WP_SABER + saberStyle 2 + FP_LEVITATION 1 + FP_SABER_DEFENSE 1 + FP_SABER_OFFENSE 2 + FP_SABERTHROW 2 + rank crewman + reactions 1 + aim 1 + move 1 + aggression 2 + evasion 1 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd cultist1 + sndcombat cultist1 + sndjedi cultist1 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 100 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +cultist_saber_strong +{ + playerModel cultist + customSkin brown + saber reborn + weapon WP_SABER + saberStyle 3 + FP_LEVITATION 1 + FP_SABER_DEFENSE 1 + FP_SABER_OFFENSE 3 + rank ensign + reactions 1 + aim 1 + move 1 + aggression 3 + evasion 1 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd cultist1 + sndcombat cultist1 + sndjedi cultist1 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 100 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +cultist_saber_strong_throw +{ + playerModel cultist + customSkin brown + saber reborn + weapon WP_SABER + saberStyle 3 + FP_LEVITATION 1 + FP_SABER_DEFENSE 1 + FP_SABER_OFFENSE 3 + FP_SABERTHROW 2 + rank ensign + reactions 1 + aim 1 + move 1 + aggression 2 + evasion 1 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd cultist1 + sndcombat cultist1 + sndjedi cultist1 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 100 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +cultist_saber_all +{ + playerModel cultist + customSkin brown + saber reborn + weapon WP_SABER + saberStyle 1 + saberStyle 3 + saberStyle 2 + FP_LEVITATION 1 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + rank crewman + reactions 1 + aim 1 + move 1 + aggression 4 + evasion 1 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd cultist1 + sndcombat cultist1 + sndjedi cultist1 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 100 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +cultist_saber_all_throw +{ + playerModel cultist + customSkin brown + saber reborn + weapon WP_SABER + saberStyle 1 + saberStyle 3 + saberStyle 2 + FP_LEVITATION 1 + FP_SABER_DEFENSE 2 + FP_SABER_OFFENSE 3 + FP_SABERTHROW 2 + rank crewman + reactions 1 + aim 1 + move 1 + aggression 3 + evasion 1 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd cultist1 + sndcombat cultist1 + sndjedi cultist1 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 100 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + diff --git a/base/ext_data/npcs/cultist_saber_powers.npc b/base/ext_data/npcs/cultist_saber_powers.npc new file mode 100644 index 0000000..41f7182 --- /dev/null +++ b/base/ext_data/npcs/cultist_saber_powers.npc @@ -0,0 +1,305 @@ +cultist_saber2 +{ + playerModel cultist + customSkin brown + saber reborn + weapon WP_SABER + saberStyle 1 + rank ltjg + FP_PUSH 1 + FP_LEVITATION 1 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 2 + reactions 1 + aim 1 + move 1 + aggression 3 + evasion 2 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd cultist1 + sndcombat cultist1 + sndjedi cultist1 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 150 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +cultist_saber_throw2 +{ + playerModel cultist + customSkin brown + saber reborn + weapon WP_SABER + saberStyle 1 + rank ltjg + FP_PUSH 1 + FP_LEVITATION 1 + FP_SABER_DEFENSE 2 + FP_SABER_OFFENSE 2 + FP_SABERTHROW 1 + reactions 1 + aim 1 + move 1 + aggression 2 + evasion 2 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd cultist1 + sndcombat cultist1 + sndjedi cultist1 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 150 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +cultist_saber_med2 +{ + playerModel cultist + customSkin brown + saber reborn + weapon WP_SABER + saberStyle 2 + rank ensign + FP_PUSH 1 + FP_LEVITATION 1 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + reactions 1 + aim 1 + move 1 + aggression 3 + evasion 2 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd cultist1 + sndcombat cultist1 + sndjedi cultist1 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 150 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +cultist_saber_med_throw2 +{ + playerModel cultist + customSkin brown + saber reborn + weapon WP_SABER + saberStyle 2 + rank ensign + FP_PUSH 1 + FP_LEVITATION 1 + FP_SABER_DEFENSE 2 + FP_SABER_OFFENSE 2 + FP_SABERTHROW 2 + reactions 1 + aim 1 + move 1 + aggression 2 + evasion 2 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd cultist1 + sndcombat cultist1 + sndjedi cultist1 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 150 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +cultist_saber_strong2 +{ + playerModel cultist + customSkin brown + saber reborn + weapon WP_SABER + saberStyle 3 + rank ltjg + FP_PUSH 1 + FP_LEVITATION 1 + FP_SABER_DEFENSE 2 + FP_SABER_OFFENSE 3 + reactions 1 + aim 1 + move 1 + aggression 3 + evasion 2 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd cultist1 + sndcombat cultist1 + sndjedi cultist1 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 150 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +cultist_saber_strong_throw2 +{ + playerModel cultist + customSkin brown + saber reborn + weapon WP_SABER + saberStyle 3 + rank ltjg + FP_PUSH 1 + FP_LEVITATION 1 + FP_SABER_DEFENSE 2 + FP_SABER_OFFENSE 3 + FP_SABERTHROW 2 + reactions 1 + aim 1 + move 1 + aggression 2 + evasion 2 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd cultist1 + sndcombat cultist1 + sndjedi cultist1 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 150 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +cultist_saber_all2 +{ + playerModel cultist + customSkin brown + saber reborn + weapon WP_SABER + saberStyle 1 + saberStyle 3 + saberStyle 2 + rank ltjg + FP_PUSH 1 + FP_LEVITATION 1 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + rank crewman + reactions 1 + aim 1 + move 1 + aggression 4 + evasion 2 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd cultist1 + sndcombat cultist1 + sndjedi cultist1 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 150 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + +cultist_saber_all_throw2 +{ + playerModel cultist + customSkin brown + saber reborn + weapon WP_SABER + saberStyle 1 + saberStyle 3 + saberStyle 2 + rank ltjg + FP_PUSH 1 + FP_LEVITATION 1 + FP_SABER_DEFENSE 2 + FP_SABER_OFFENSE 3 + FP_SABERTHROW 2 + reactions 1 + aim 1 + move 1 + aggression 3 + evasion 2 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd cultist1 + sndcombat cultist1 + sndjedi cultist1 + yawSpeed 60 + walkSpeed 45 + runSpeed 180 + health 150 + dismemberProbHead 0 + dismemberProbArms 20 + dismemberProbLegs 0 + dismemberProbHands 30 + dismemberProbWaist 0 +} + diff --git a/base/ext_data/npcs/cultistcommando.npc b/base/ext_data/npcs/cultistcommando.npc new file mode 100644 index 0000000..dee5f3b --- /dev/null +++ b/base/ext_data/npcs/cultistcommando.npc @@ -0,0 +1,31 @@ +cultistcommando +{ + playerModel cultist + weapon WP_BLASTER_PISTOL + FP_LEVITATION 2 + rank ltcomm + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 4 + intelligence 5 + hfov 160 + vfov 160 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// class CLASS_COMMANDO + class CLASS_REBORN + snd cultist3 + sndcombat cultist3 + sndextra cultist3 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 250 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/gonk.npc b/base/ext_data/npcs/gonk.npc new file mode 100644 index 0000000..42f224a --- /dev/null +++ b/base/ext_data/npcs/gonk.npc @@ -0,0 +1,23 @@ +gonk +{ + playerModel gonk + weapon WP_NONE + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL +// race bot + class CLASS_GONK + yawSpeed 60 + runSpeed 40 + walkSpeed 30 + height 32 + width 12 + hFOV 120 + vfov 45 + snd gonk +} \ No newline at end of file diff --git a/base/ext_data/npcs/human_merc.npc b/base/ext_data/npcs/human_merc.npc new file mode 100644 index 0000000..19ba1a7 --- /dev/null +++ b/base/ext_data/npcs/human_merc.npc @@ -0,0 +1,372 @@ +human_merc +{ + playerModel human_merc + weapon WP_BLASTER + surfOff "l_arm_pocket l_arm_key" + health 100 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_STORMTROOPER + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd humanmerc1 + sndcombat humanmerc1 + sndextra humanmerc1 + yawspeed 70 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +human_merc_bow +{ + playerModel human_merc + surfOff "l_arm_pocket l_arm_key" + weapon WP_BOWCASTER + health 100 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_STORMTROOPER + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd humanmerc2 + sndcombat humanmerc2 + sndextra humanmerc2 + yawspeed 70 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +human_merc_rep +{ + playerModel human_merc + surfOff "l_arm_pocket l_arm_key" + weapon WP_REPEATER + health 100 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_STORMTROOPER + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd humanmerc2 + sndcombat humanmerc2 + sndextra humanmerc2 + yawspeed 70 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +human_merc_flc +{ + playerModel human_merc + surfOff "l_arm_pocket l_arm_key" + weapon WP_FLECHETTE + health 100 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_STORMTROOPER + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd humanmerc1 + sndcombat humanmerc1 + sndextra humanmerc1 + yawspeed 70 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +human_merc_cnc +{ + playerModel human_merc + surfOff "l_arm_pocket l_arm_key" + weapon WP_CONCUSSION + health 100 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_STORMTROOPER + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd humanmerc2 + sndcombat humanmerc2 + sndextra humanmerc2 + yawspeed 70 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +human_merc +{ + playerModel human_merc + surfOff "l_arm_pocket l_arm_key" + weapon WP_BLASTER + health 100 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_STORMTROOPER + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd st1 + sndcombat st1 + sndextra st1 + yawspeed 70 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +human_merc_bow +{ + playerModel human_merc + surfOff "l_arm_pocket l_arm_key" + weapon WP_BOWCASTER + health 100 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_STORMTROOPER + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd st1 + sndcombat st1 + sndextra st1 + yawspeed 70 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +human_merc_rep +{ + playerModel human_merc + surfOff "l_arm_pocket l_arm_key" + weapon WP_REPEATER + health 100 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_STORMTROOPER + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd st1 + sndcombat st1 + sndextra st1 + yawspeed 70 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +human_merc_flc +{ + playerModel human_merc + surfOff "l_arm_pocket l_arm_key" + weapon WP_FLECHETTE + health 100 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_STORMTROOPER + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd st1 + sndcombat st1 + sndextra st1 + yawspeed 70 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +lannik_racto +{ + playerModel human_merc + customSkin racto + surfOff "l_arm_pocket l_arm_key" + weapon WP_CONCUSSION + health 300 + headPitchRangeDown 30 + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 5 + intelligence 5 + rank captain + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_STORMTROOPER + height 64 + crouchheight 48 + snd lannik + sndcombat lannik + sndextra lannik + yawspeed 70 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +human_merc_key +{ + playerModel human_merc + customSkin key_carrier + weapon WP_BLASTER + health 100 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_STORMTROOPER + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd st1 + sndcombat st1 + sndextra st1 + yawspeed 70 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} diff --git a/base/ext_data/npcs/interrogator.npc b/base/ext_data/npcs/interrogator.npc new file mode 100644 index 0000000..5d98daf --- /dev/null +++ b/base/ext_data/npcs/interrogator.npc @@ -0,0 +1,24 @@ +interrogator +{ + playermodel interrogator + weapon WP_NONE + health 100 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race bot + class CLASS_INTERROGATOR + yawSpeed 120 + runSpeed 150 + walkSpeed 50 + height 24 + width 12 + hFOV 120 + vfov 45 + snd interrogator +} \ No newline at end of file diff --git a/base/ext_data/npcs/jawa.npc b/base/ext_data/npcs/jawa.npc new file mode 100644 index 0000000..2264294 --- /dev/null +++ b/base/ext_data/npcs/jawa.npc @@ -0,0 +1,54 @@ +jawa +{ + playerModel jawa + weapon WP_NONE + scale 75 + health 10 + snd jawa + sndcombat jawa + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_FREE + class CLASS_JAWA + yawspeed 90 + walkSpeed 55 + runSpeed 150 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +jawa_armed +{ + playerModel jawa + weapon WP_JAWA + scale 75 + health 10 + snd jawa + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_FREE + class CLASS_JAWA + yawspeed 90 + walkSpeed 55 + runSpeed 100 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} diff --git a/base/ext_data/npcs/jedi_random.npc b/base/ext_data/npcs/jedi_random.npc new file mode 100644 index 0000000..582a3f8 --- /dev/null +++ b/base/ext_data/npcs/jedi_random.npc @@ -0,0 +1,648 @@ + +jedi_hf1 +{ + playerModel jedi_hf + customSkin head_B1|torso_C1|lower_D1 +// customRGBA 255 157 114 + customRGBA jedi_hf + saber single_1 + saberColor random + weapon WP_SABER + saberStyle 1 + saberStyle 3 + saberStyle 2 + FP_HEAL 1 + FP_LEVITATION 2 + FP_SPEED 2 + FP_PUSH 2 + FP_PULL 1 + FP_TELEPATHY 1 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 1 + FP_ABSORB 1 + FP_DRAIN 0 + FP_SEE 1 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + forceRegenRate 150 + forcePowerMax 90 + rank lt + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 2 + intelligence 3 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_JEDI + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + sex female + snd female_jedi1 + sndcombat female_jedi1 + sndjedi female_jedi1 + health 200 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + +jedi_hf2 +{ + playerModel jedi_hf + customSkin head_C1|torso_A1|lower_B1 +// customRGBA 233 183 208 + customRGBA jedi_hf + saber single_2 + saberColor random + weapon WP_SABER + saberStyle 1 + saberStyle 3 + saberStyle 2 + FP_HEAL 1 + FP_LEVITATION 2 + FP_SPEED 2 + FP_PUSH 2 + FP_PULL 1 + FP_TELEPATHY 1 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 1 + FP_ABSORB 1 + FP_DRAIN 0 + FP_SEE 1 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + forceRegenRate 150 + forcePowerMax 90 + rank lt + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 2 + intelligence 3 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_JEDI + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + sex female + snd female_jedi1 + sndcombat female_jedi1 + sndjedi female_jedi1 + health 200 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + +jedi_hm1 +{ + playerModel jedi_hm + customSkin head_A1|torso_A1|lower_B1 +// customRGBA 112 153 161 + customRGBA jedi_hm + saber single_3 + saberColor random + weapon WP_SABER + saberStyle 1 + saberStyle 3 + saberStyle 2 + FP_HEAL 1 + FP_LEVITATION 2 + FP_SPEED 2 + FP_PUSH 2 + FP_PULL 1 + FP_TELEPATHY 1 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 1 + FP_ABSORB 1 + FP_DRAIN 0 + FP_SEE 1 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + forceRegenRate 150 + forcePowerMax 90 + rank lt + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 2 + intelligence 3 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_JEDI + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + snd jedi1 + sndcombat jedi1 + sndjedi jedi1 + health 200 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + +jedi_hm2 +{ + playerModel jedi_hm + customSkin head_B1|torso_C1|lower_A1 +// customRGBA 254 197 73 + customRGBA jedi_hm + saber single_4 + saberColor random + weapon WP_SABER + saberStyle 1 + saberStyle 3 + saberStyle 2 + FP_HEAL 1 + FP_LEVITATION 2 + FP_SPEED 2 + FP_PUSH 2 + FP_PULL 1 + FP_TELEPATHY 1 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 1 + FP_ABSORB 1 + FP_DRAIN 0 + FP_SEE 1 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + forceRegenRate 150 + forcePowerMax 90 + rank lt + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 2 + intelligence 3 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_JEDI + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + snd jedi2 + sndcombat jedi2 + sndjedi jedi2 + health 200 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + +jedi_kdm1 +{ + playerModel jedi_kdm + customSkin head_B1|torso_D1|lower_C1 +// customRGBA 138 83 0 + customRGBA jedi_kdm + saber dual_3 + saberColor random + weapon WP_SABER + saberStyle 7 + FP_HEAL 1 + FP_LEVITATION 2 + FP_SPEED 1 + FP_PUSH 2 + FP_PULL 1 + FP_TELEPATHY 1 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 1 + FP_ABSORB 1 + FP_DRAIN 0 + FP_SEE 1 + FP_SABERTHROW 0 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + forceRegenRate 150 + forcePowerMax 90 + rank lt + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 2 + intelligence 3 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_JEDI + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + snd jedi2 + sndcombat jedi2 + sndjedi jedi2 + health 200 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + +jedi_kdm2 +{ + playerModel jedi_kdm + customSkin head_C1|torso_B1|lower_B1 +// customRGBA 225 226 144 + customRGBA jedi_kdm + saber single_5 + saberColor random + weapon WP_SABER + saberStyle 2 + saberStyle 3 + FP_HEAL 2 + FP_LEVITATION 2 + FP_SPEED 2 + FP_PUSH 2 + FP_PULL 3 + FP_TELEPATHY 1 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 2 + FP_ABSORB 2 + FP_DRAIN 0 + FP_SEE 1 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + forceRegenRate 150 + forcePowerMax 90 + rank lt + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 2 + intelligence 3 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_JEDI + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + snd jedi2 + sndcombat jedi2 + sndjedi jedi2 + health 200 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + +jedi_rm1 +{ + playerModel jedi_rm + customSkin head_A1|torso_A1|lower_A1 +// customRGBA 163 79 17 + customRGBA jedi_rm + saber single_6 + saberColor random + weapon WP_SABER + saberStyle 2 + saberStyle 1 + FP_HEAL 1 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 2 + FP_PULL 1 + FP_TELEPATHY 1 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 1 + FP_ABSORB 2 + FP_DRAIN 0 + FP_SEE 1 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + forceRegenRate 150 + forcePowerMax 90 + rank lt + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 2 + intelligence 3 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_JEDI + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + snd jedi1 + sndcombat jedi1 + sndjedi jedi1 + health 200 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + +jedi_rm2 +{ + playerModel jedi_rm + customSkin head_B1|torso_B1|lower_C1 +// customRGBA 49 155 131 + customRGBA jedi_rm + saber single_7 + saberColor random + weapon WP_SABER + saberStyle 2 + saberStyle 1 + FP_HEAL 2 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 2 + FP_PULL 1 + FP_TELEPATHY 1 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 2 + FP_ABSORB 1 + FP_DRAIN 0 + FP_SEE 1 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + forceRegenRate 150 + forcePowerMax 90 + rank lt + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 2 + intelligence 3 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_JEDI + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + snd jedi1 + sndcombat jedi1 + sndjedi jedi1 + health 200 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + +jedi_tf1 +{ + playerModel jedi_tf + customSkin head_A1|torso_A1|lower_D1 +// customRGBA 255 200 212 + customRGBA jedi_tf + saber dual_5 + saberColor random + weapon WP_SABER + saberStyle 7 + FP_HEAL 1 + FP_LEVITATION 2 + FP_SPEED 2 + FP_PUSH 2 + FP_PULL 1 + FP_TELEPATHY 1 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 1 + FP_ABSORB 1 + FP_DRAIN 0 + FP_SEE 1 + FP_SABERTHROW 0 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + forceRegenRate 150 + forcePowerMax 90 + rank lt + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 2 + intelligence 3 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_JEDI + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + sex female + snd female_jedi2 + sndcombat female_jedi2 + sndjedi female_jedi2 + health 200 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + +jedi_tf2 +{ + playerModel jedi_tf + customSkin head_B2|torso_C1|lower_C1 +// customRGBA 255 255 255 + customRGBA jedi_tf + saber single_8 + saberColor random + weapon WP_SABER + saberStyle 1 + saberStyle 2 + FP_HEAL 2 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 2 + FP_PULL 2 + FP_TELEPATHY 1 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 2 + FP_ABSORB 1 + FP_DRAIN 0 + FP_SEE 1 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + forceRegenRate 150 + forcePowerMax 90 + rank lt + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 2 + intelligence 3 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_JEDI + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + sex female + snd female_jedi2 + sndcombat female_jedi2 + sndjedi female_jedi2 + health 200 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + +jedi_zf1 +{ + playerModel jedi_zf + customSkin head_B1|torso_A1|lower_D1 +// customRGBA 255 164 59 + customRGBA jedi_zf + saber single_9 + saberColor random + weapon WP_SABER + saberStyle 1 + saberStyle 3 + saberStyle 2 + FP_HEAL 1 + FP_LEVITATION 2 + FP_SPEED 2 + FP_PUSH 2 + FP_PULL 1 + FP_TELEPATHY 1 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 1 + FP_ABSORB 1 + FP_DRAIN 0 + FP_SEE 1 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + forceRegenRate 150 + forcePowerMax 90 + rank lt + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 2 + intelligence 3 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_JEDI + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + sex female + snd female_jedi2 + sndcombat female_jedi2 + sndjedi female_jedi2 + health 200 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + +jedi_zf2 +{ + playerModel jedi_zf + customSkin head_C1|torso_C1|lower_B1 +// customRGBA 161 226 240 + customRGBA jedi_zf + saber single_9 + saber2 single_1 + saberColor random + saber2Color random + weapon WP_SABER + saberStyle 6 + FP_HEAL 1 + FP_LEVITATION 2 + FP_SPEED 2 + FP_PUSH 2 + FP_PULL 1 + FP_TELEPATHY 1 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 1 + FP_ABSORB 1 + FP_DRAIN 0 + FP_SEE 1 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + forceRegenRate 150 + forcePowerMax 90 + rank lt + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 2 + intelligence 3 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_JEDI + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + sex female + snd female_jedi1 + sndcombat female_jedi1 + sndjedi female_jedi1 + health 200 + dismemberProbHead 0 + dismemberProbArms 5 + dismemberProbLegs 0 + dismemberProbHands 10 + dismemberProbWaist 0 +} + + diff --git a/base/ext_data/npcs/lambdashuttle.npc b/base/ext_data/npcs/lambdashuttle.npc new file mode 100644 index 0000000..12cfa65 --- /dev/null +++ b/base/ext_data/npcs/lambdashuttle.npc @@ -0,0 +1,12 @@ + +//NOTE: for vehicle-class NPCs, the playerModel key is actually their entry in the vehicles.dat + +LambdaShuttle +{ + weapon WP_NONE + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL + class CLASS_VEHICLE + width 250 + height 248 +} diff --git a/base/ext_data/npcs/mark1.npc b/base/ext_data/npcs/mark1.npc new file mode 100644 index 0000000..8dbdfea --- /dev/null +++ b/base/ext_data/npcs/mark1.npc @@ -0,0 +1,24 @@ +mark1 +{ + playerModel mark1 + weapon WP_BOT_LASER + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + height 120 + width 36 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + health 300 +// race bot + class CLASS_MARK1 + yawSpeed 60 + runSpeed 150 + walkSpeed 70 + hFOV 120 + vfov 45 + snd mark1 +} \ No newline at end of file diff --git a/base/ext_data/npcs/mark2.npc b/base/ext_data/npcs/mark2.npc new file mode 100644 index 0000000..3d84444 --- /dev/null +++ b/base/ext_data/npcs/mark2.npc @@ -0,0 +1,21 @@ +mark2 +{ + playerModel mark2 + weapon WP_BOT_LASER + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race bot + class CLASS_MARK2 + yawSpeed 60 + runSpeed 150 + walkSpeed 75 + hFOV 120 + vfov 45 + snd mark2 +} \ No newline at end of file diff --git a/base/ext_data/npcs/mouse.npc b/base/ext_data/npcs/mouse.npc new file mode 100644 index 0000000..9e2d696 --- /dev/null +++ b/base/ext_data/npcs/mouse.npc @@ -0,0 +1,25 @@ +mouse +{ + headmodel none + torsomodel none + legsmodel mouse + weapon WP_NONE + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL +// race bot + class CLASS_MOUSE + yawSpeed 120 + runSpeed 500 + walkSpeed 150 + height 16 + width 8 + hFOV 120 + vfov 45 + snd mouse +} \ No newline at end of file diff --git a/base/ext_data/npcs/nullDriver.npc b/base/ext_data/npcs/nullDriver.npc new file mode 100644 index 0000000..417e1e8 --- /dev/null +++ b/base/ext_data/npcs/nullDriver.npc @@ -0,0 +1,10 @@ + +nullDriver +{ + playerModel kyle + weapon WP_NONE + playerTeam neutral + enemyTeam neutral + class kyle +} + diff --git a/base/ext_data/npcs/player.npc b/base/ext_data/npcs/player.npc new file mode 100644 index 0000000..f89aae7 --- /dev/null +++ b/base/ext_data/npcs/player.npc @@ -0,0 +1,7 @@ + +Player +{ + playerModel player + class CLASS_PLAYER +} + diff --git a/base/ext_data/npcs/probe.npc b/base/ext_data/npcs/probe.npc new file mode 100644 index 0000000..9e2e686 --- /dev/null +++ b/base/ext_data/npcs/probe.npc @@ -0,0 +1,33 @@ +probe +{ + playerModel probe + weapon WP_BOT_LASER + health 200 + headYawRangeLeft 180 + headYawRangeRight 180 + headPitchRangeUp 0 + headPitchRangeDown 0 + torsoYawRangeLeft 0 + torsoYawRangeRight 0 + torsoPitchRangeUp 10 + torsoPitchRangeDown 10 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race bot + class CLASS_PROBE + yawSpeed 60 + runSpeed 150 + walkSpeed 50 + height 110 + width 24 + hFOV 120 + vfov 45 + snd probe + moveType "flyswim" +} \ No newline at end of file diff --git a/base/ext_data/npcs/protocol.npc b/base/ext_data/npcs/protocol.npc new file mode 100644 index 0000000..efbd072 --- /dev/null +++ b/base/ext_data/npcs/protocol.npc @@ -0,0 +1,24 @@ +protocol +{ + playerModel protocol + weapon WP_NONE + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL +// race bot + class CLASS_PROTOCOL + snd protocol + yawSpeed 60 + runSpeed 150 + walkSpeed 50 + height 65 + width 12 + hFOV 120 + vfov 45 + snd protocol +} \ No newline at end of file diff --git a/base/ext_data/npcs/protocol_imp.npc b/base/ext_data/npcs/protocol_imp.npc new file mode 100644 index 0000000..2244423 --- /dev/null +++ b/base/ext_data/npcs/protocol_imp.npc @@ -0,0 +1,27 @@ +protocol_imp +{ + playerModel protocol + weapon WP_NONE + surfOn head_off + surfOff head + customSkin imp + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL +// race bot + class CLASS_PROTOCOL + snd protocol + yawSpeed 60 + runSpeed 150 + walkSpeed 50 + height 65 + width 12 + hFOV 120 + vfov 45 + snd protocol +} \ No newline at end of file diff --git a/base/ext_data/npcs/r2d2.npc b/base/ext_data/npcs/r2d2.npc new file mode 100644 index 0000000..018298c --- /dev/null +++ b/base/ext_data/npcs/r2d2.npc @@ -0,0 +1,31 @@ +r2d2 +{ + playermodel r2d2 + weapon WP_NONE + headYawRangeLeft 180 + headYawRangeRight 180 + headPitchRangeUp 0 + headPitchRangeDown 0 + torsoYawRangeLeft 0 + torsoYawRangeRight 0 + torsoPitchRangeUp 10 + torsoPitchRangeDown 10 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL +// race bot + class CLASS_R2D2 + yawSpeed 120 + runSpeed 150 + walkSpeed 50 + height 40 + width 12 + hFOV 120 + vfov 45 + snd r2d2 +} \ No newline at end of file diff --git a/base/ext_data/npcs/r2d2_imp.npc b/base/ext_data/npcs/r2d2_imp.npc new file mode 100644 index 0000000..07076b2 --- /dev/null +++ b/base/ext_data/npcs/r2d2_imp.npc @@ -0,0 +1,32 @@ +r2d2_imp +{ + playermodel r2d2 + weapon WP_NONE + customSkin imp + headYawRangeLeft 180 + headYawRangeRight 180 + headPitchRangeUp 0 + headPitchRangeDown 0 + torsoYawRangeLeft 0 + torsoYawRangeRight 0 + torsoPitchRangeUp 10 + torsoPitchRangeDown 10 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL +// race bot + class CLASS_R2D2 + yawSpeed 120 + runSpeed 150 + walkSpeed 50 + height 40 + width 12 + hFOV 120 + vfov 45 + snd r2d2 +} \ No newline at end of file diff --git a/base/ext_data/npcs/r5d2.npc b/base/ext_data/npcs/r5d2.npc new file mode 100644 index 0000000..1c484c2 --- /dev/null +++ b/base/ext_data/npcs/r5d2.npc @@ -0,0 +1,31 @@ +r5d2 +{ + playerModel r5d2 + weapon WP_NONE + headYawRangeLeft 180 + headYawRangeRight 180 + headPitchRangeUp 0 + headPitchRangeDown 0 + torsoYawRangeLeft 0 + torsoYawRangeRight 0 + torsoPitchRangeUp 10 + torsoPitchRangeDown 10 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL +// race bot + class CLASS_R5D2 + yawSpeed 60 + runSpeed 150 + walkSpeed 50 + height 40 + width 12 + hFOV 120 + vfov 45 + snd r5d2 +} \ No newline at end of file diff --git a/base/ext_data/npcs/r5d2_imp.npc b/base/ext_data/npcs/r5d2_imp.npc new file mode 100644 index 0000000..cf20703 --- /dev/null +++ b/base/ext_data/npcs/r5d2_imp.npc @@ -0,0 +1,33 @@ +r5d2_imp +{ + playerModel r5d2 + weapon WP_NONE +//oops, guess they never made this skin... +// customSkin imp + headYawRangeLeft 180 + headYawRangeRight 180 + headPitchRangeUp 0 + headPitchRangeDown 0 + torsoYawRangeLeft 0 + torsoYawRangeRight 0 + torsoPitchRangeUp 10 + torsoPitchRangeDown 10 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL +// race bot + class CLASS_R5D2 + yawSpeed 60 + runSpeed 150 + walkSpeed 50 + height 40 + width 12 + hFOV 120 + vfov 45 + snd r5d2 +} \ No newline at end of file diff --git a/base/ext_data/npcs/rancor.npc b/base/ext_data/npcs/rancor.npc new file mode 100644 index 0000000..c96dd7e --- /dev/null +++ b/base/ext_data/npcs/rancor.npc @@ -0,0 +1,70 @@ + +rancor +{ + playerModel rancor + weapon WP_MELEE + health 2000 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_FREE + enemyTeam TEAM_FREE + class CLASS_RANCOR + height 160 + crouchheight 128 + width 60 + snd rancor + sndcombat rancor + sndextra rancor + yawspeed 40 +// walkSpeed 173 +// runSpeed 173 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbLegs 0 + dismemberProbHands 0 + dismemberProbWaist 0 +} + +mutant_rancor +{ + playerModel mutant_rancor + weapon WP_MELEE + health 10000 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_FREE + enemyTeam TEAM_FREE + class CLASS_RANCOR + scale 200 + height 350 + crouchheight 350 + width 120 + snd mutant_rancor + sndcombat mutant_rancor + sndextra mutant_rancor + yawspeed 40 +// walkSpeed 173 +// runSpeed 173 + walkSpeed 110 + runSpeed 400 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbLegs 0 + dismemberProbHands 0 + dismemberProbWaist 0 +} + diff --git a/base/ext_data/npcs/rancor_vehicle.npc b/base/ext_data/npcs/rancor_vehicle.npc new file mode 100644 index 0000000..3f172ca --- /dev/null +++ b/base/ext_data/npcs/rancor_vehicle.npc @@ -0,0 +1,14 @@ + +//NOTE: for vehicle-class NPCs, the playerModel key is actually their entry in the vehicles.dat + +Rancor_vehicle +{ + weapon WP_NONE + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL + class CLASS_VEHICLE + snd rancor + height 128 + crouchheight 128 + width 60 +} diff --git a/base/ext_data/npcs/remote.npc b/base/ext_data/npcs/remote.npc new file mode 100644 index 0000000..312aa67 --- /dev/null +++ b/base/ext_data/npcs/remote.npc @@ -0,0 +1,53 @@ +remote +{ +// headmodel none +// torsomodel none +// legsmodel remote + playerModel remote + weapon WP_BOT_LASER + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 3 + intelligence 5 + playerTeam TEAM_FREE + enemyTeam TEAM_FREE + class CLASS_SEEKER + yawSpeed 120 + runSpeed 500 + walkSpeed 150 + height 32 + width 8 + hFOV 160 + vfov 45 + snd remote + moveType "flyswim" +} + +remote_sp +{ + headmodel none + torsomodel none + legsmodel remote_sp + weapon WP_BOT_LASER + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 3 + intelligence 5 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race bot + class CLASS_REMOTE + yawSpeed 120 + runSpeed 500 + walkSpeed 150 + height 32 + width 8 + hFOV 160 + vfov 45 + snd remote + moveType "flyswim" +} diff --git a/base/ext_data/npcs/rockettrooper2.npc b/base/ext_data/npcs/rockettrooper2.npc new file mode 100644 index 0000000..103264e --- /dev/null +++ b/base/ext_data/npcs/rockettrooper2.npc @@ -0,0 +1,71 @@ +RocketTrooper2 +{ + playerModel rockettrooper + weapon WP_ROCKET_LAUNCHER + health 200 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_ROCKETTROOPER + height 72 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd st1 + sndcombat st1 + sndextra st1 + walkSpeed 55 + runSpeed 150 + yawspeed 50 + visrange 2048 + earshot 2048 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +RocketTrooper2Officer +{ + playerModel rockettrooper + weapon WP_REPEATER + health 400 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank lt + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_ROCKETTROOPER + height 72 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd st1 + sndcombat st1 + sndextra st1 + walkSpeed 55 + runSpeed 200 + yawspeed 50 + hfov 60 + vfov 80 + visrange 2048 + earshot 2048 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} diff --git a/base/ext_data/npcs/rockettrooper_w.npc b/base/ext_data/npcs/rockettrooper_w.npc new file mode 100644 index 0000000..d2deb6b --- /dev/null +++ b/base/ext_data/npcs/rockettrooper_w.npc @@ -0,0 +1,35 @@ + +RocketTrooper_ver1 +{ + playerModel stormtrooper + weapon WP_BLASTER + health 30 + headPitchRangeDown 30 + reactions 3 + aim 5 + move 3 + aggression 3 + scaley 130 + scalex 120 + evasion 1 + intelligence 5 + rank crewman + playerTeam enemy + enemyTeam player + class stormtrooper + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd st1 + sndcombat st1 + sndextra st1 + yawspeed 70 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} diff --git a/base/ext_data/npcs/rocks.npc b/base/ext_data/npcs/rocks.npc new file mode 100644 index 0000000..236d4e6 --- /dev/null +++ b/base/ext_data/npcs/rocks.npc @@ -0,0 +1,28 @@ +rocks +{ + playerModel rocks + weapon WP_NONE + scale 100 + health 100 + snd jawa + sndcombat jawa + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_FREE + class CLASS_KYLE + yawspeed 90 + walkSpeed 55 + runSpeed 150 + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbLegs 0 + dismemberProbHands 0 + dismemberProbWaist 0 +} + diff --git a/base/ext_data/npcs/rosh_penin.npc b/base/ext_data/npcs/rosh_penin.npc new file mode 100644 index 0000000..bf35238 --- /dev/null +++ b/base/ext_data/npcs/rosh_penin.npc @@ -0,0 +1,124 @@ +rosh_penin_noforce +{ + playerModel rosh_penin + weapon WP_MELEE + FP_HEAL 0 + FP_LEVITATION 0 + FP_SPEED 0 + FP_PUSH 0 + FP_PULL 1 + FP_TELEPATHY 0 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 0 + FP_SEE 0 + FP_SABERTHROW 0 + FP_SABER_DEFENSE 0 + FP_SABER_OFFENSE 0 + rank crewman + reactions 1 + aim 1 + move 1 + aggression 1 + evasion 1 + intelligence 1 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_REBEL + snd rosh + sndcombat rosh + sndjedi rosh + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbHands 0 + dismemberProbLegs 0 + dismemberProbWaist 0 +} + +rosh_penin +{ + playerModel rosh_penin + saber training + weapon WP_SABER + saberStyle 3 + FP_HEAL 0 + FP_LEVITATION 3 + FP_SPEED 3 + FP_PUSH 2 + FP_PULL 3 + FP_TELEPATHY 0 + FP_GRIP 0 + FP_LIGHTNING 0 + FP_RAGE 0 + FP_PROTECT 0 + FP_ABSORB 0 + FP_DRAIN 0 + FP_SEE 0 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + rank lt + reactions 2 + aim 2 + move 3 + aggression 5 + evasion 3 + intelligence 2 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY + class CLASS_JEDI + snd rosh + sndcombat rosh + sndjedi rosh + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbHands 0 + dismemberProbLegs 0 + dismemberProbWaist 0 +} + +rosh_dark +{ + playerModel rosh_penin + saber shadowtrooper + weapon WP_SABER + saberStyle 3 + health 500 + FP_HEAL 0 + FP_LEVITATION 2 + FP_SPEED 2 + FP_PUSH 2 + FP_PULL 2 + FP_TELEPATHY 0 + FP_GRIP 2 + FP_LIGHTNING 1 + FP_RAGE 1 + FP_PROTECT 1 + FP_ABSORB 1 + FP_DRAIN 0 + FP_SEE 0 + FP_SABERTHROW 2 + FP_SABER_DEFENSE 2 + FP_SABER_OFFENSE 2 + rank lt + reactions 2 + aim 2 + move 3 + aggression 5 + evasion 3 + intelligence 2 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_REBORN + snd rosh_boss + sndcombat rosh_boss + sndjedi rosh_boss + dismemberProbHead 0 + dismemberProbArms 0 + dismemberProbHands 0 + dismemberProbLegs 0 + dismemberProbWaist 0 +} diff --git a/base/ext_data/npcs/saber_droid.npc b/base/ext_data/npcs/saber_droid.npc new file mode 100644 index 0000000..a567be5 --- /dev/null +++ b/base/ext_data/npcs/saber_droid.npc @@ -0,0 +1,66 @@ +saber_droid_training +{ + playerModel saber_droid + saber droid + weapon WP_SABER + saberStyle 1 + FP_SABER_DEFENSE 1 + FP_SABER_OFFENSE 1 + reactions 1 + aim 1 + move 1 + aggression 1 + evasion 1 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_SABER_DROID + snd saber_droid + sndcombat saber_droid + sndjedi saber_droid + yawSpeed 100 + walkSpeed 60 + runSpeed 200 + health 50 + dismemberProbHead 100 + dismemberProbArms 100 + dismemberProbLegs 100 + dismemberProbHands 100 + dismemberProbWaist 100 +} + +saber_droid +{ + playerModel saber_droid + saber droid + weapon WP_SABER + saberStyle 1 + FP_SABER_DEFENSE 3 + FP_SABER_OFFENSE 3 + rank ensign + reactions 1 + aim 1 + move 1 + aggression 1 + evasion 1 + intelligence 1 + hfov 120 + vfov 120 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_SABER_DROID + snd saber_droid + sndcombat saber_droid + sndjedi saber_droid + yawSpeed 100 + walkSpeed 60 + runSpeed 200 + health 300 + dismemberProbHead 100 + dismemberProbArms 100 + dismemberProbLegs 100 + dismemberProbHands 100 + dismemberProbWaist 100 +} diff --git a/base/ext_data/npcs/saboteur.npc b/base/ext_data/npcs/saboteur.npc new file mode 100644 index 0000000..0a8bc00 --- /dev/null +++ b/base/ext_data/npcs/saboteur.npc @@ -0,0 +1,61 @@ +saboteur +{ + playerModel saboteur + weapon WP_BLASTER_RIFLE + altFire 1 + rank crewman + reactions 5 + aim 3 + move 5 + aggression 5 + evasion 4 + intelligence 5 + hfov 160 + vfov 160 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_SABOTEUR + snd sab1 + sndcombat sab1 + sndextra sab1 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} + +saboteurcommando +{ + playerModel saboteur + weapon WP_BLASTER_RIFLE + altFire 1 + rank crewman + reactions 5 + aim 3 + move 5 + aggression 5 + evasion 4 + intelligence 5 + hfov 160 + vfov 160 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_SABOTEUR + snd sab2 + sndcombat sab2 + sndextra sab2 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} diff --git a/base/ext_data/npcs/saboteurpistol.npc b/base/ext_data/npcs/saboteurpistol.npc new file mode 100644 index 0000000..27be4ff --- /dev/null +++ b/base/ext_data/npcs/saboteurpistol.npc @@ -0,0 +1,29 @@ +saboteurpistol +{ + playerModel saboteur + weapon WP_BLASTER_PISTOL + rank ltjg + reactions 5 + aim 4 + move 5 + aggression 5 + evasion 4 + intelligence 5 + hfov 160 + vfov 160 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_SABOTEUR + snd sab1 + sndcombat sab1 + sndextra sab1 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 100 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/saboteursniper.npc b/base/ext_data/npcs/saboteursniper.npc new file mode 100644 index 0000000..3ad8891 --- /dev/null +++ b/base/ext_data/npcs/saboteursniper.npc @@ -0,0 +1,30 @@ +saboteursniper +{ + playerModel saboteur + weapon WP_DISRUPTOR + altFire 1 + rank crewman + reactions 5 + aim 5 + move 5 + aggression 5 + evasion 4 + intelligence 5 + hfov 160 + vfov 160 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_SABOTEUR + snd sab2 + sndcombat sab2 + sndextra sab2 + yawSpeed 140 + walkSpeed 55 + runSpeed 200 + health 100 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/sand_creature.npc b/base/ext_data/npcs/sand_creature.npc new file mode 100644 index 0000000..e55b83f --- /dev/null +++ b/base/ext_data/npcs/sand_creature.npc @@ -0,0 +1,48 @@ +sand_creature +{ + playermodel sand_creature + weapon WP_NONE +// health 500 + health 150 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam TEAM_FREE + enemyTeam TEAM_FREE + class CLASS_SAND_CREATURE + yawSpeed 120 + runSpeed 300 + walkSpeed 125 + height 24 + width 48 + hFOV 120 + vfov 45 + snd sand_creature +} + +sand_creature_fast +{ + playermodel sand_creature + weapon WP_NONE + health 500 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam TEAM_FREE + enemyTeam TEAM_FREE + class CLASS_SAND_CREATURE + yawSpeed 120 + runSpeed 400 + walkSpeed 400 + height 24 + width 48 + hFOV 120 + vfov 45 + snd sand_creature +} diff --git a/base/ext_data/npcs/seeker.npc b/base/ext_data/npcs/seeker.npc new file mode 100644 index 0000000..dd8b25c --- /dev/null +++ b/base/ext_data/npcs/seeker.npc @@ -0,0 +1,26 @@ +seeker +{ + headmodel none + torsomodel none + legsmodel remote + weapon WP_BOT_LASER + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 3 + intelligence 5 + playerTeam TEAM_PLAYER + enemyTeam TEAM_ENEMY +// race bot + class CLASS_SEEKER + yawSpeed 120 + runSpeed 500 + walkSpeed 150 + height 32 + width 8 + hFOV 160 + vfov 45 + snd remote + moveType "flyswim" +} \ No newline at end of file diff --git a/base/ext_data/npcs/sentry.npc b/base/ext_data/npcs/sentry.npc new file mode 100644 index 0000000..f999092 --- /dev/null +++ b/base/ext_data/npcs/sentry.npc @@ -0,0 +1,25 @@ +sentry +{ + playermodel sentry + weapon WP_NONE + health 100 + reactions 3 + aim 3 + move 3 + aggression 3 + evasion 1 + intelligence 5 + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER +// race bot + class CLASS_SENTRY + health 150 + yawSpeed 120 + runSpeed 400 + walkSpeed 250 + height 48 + width 24 + hFOV 120 + vfov 160 + snd sentry +} \ No newline at end of file diff --git a/base/ext_data/npcs/snowtrooper.npc b/base/ext_data/npcs/snowtrooper.npc new file mode 100644 index 0000000..ebdad7b --- /dev/null +++ b/base/ext_data/npcs/snowtrooper.npc @@ -0,0 +1,33 @@ + +SnowTrooper +{ + playerModel snowtrooper + weapon WP_BLASTER + health 30 + headPitchRangeDown 30 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_STORMTROOPER + height 64 + crouchheight 48 + walkSpeed 51 + runSpeed 200 + snd st1 + sndcombat st1 + sndextra st1 + yawspeed 70 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 0 + dismemberProbHands 20 + dismemberProbWaist 0 +} diff --git a/base/ext_data/npcs/swoop.npc b/base/ext_data/npcs/swoop.npc new file mode 100644 index 0000000..37058e3 --- /dev/null +++ b/base/ext_data/npcs/swoop.npc @@ -0,0 +1,115 @@ + +//NOTE: for vehicle-class NPCs, the playerModel key is actually their entry in the vehicles.dat + +Swoop +{ + weapon WP_BLASTER + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL + class CLASS_VEHICLE + width 24 + height 32 +} + +Swoop_black +{ + weapon WP_BLASTER + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL + class CLASS_VEHICLE + width 24 + height 32 +} + +Swoop_blue +{ + weapon WP_BLASTER + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL + class CLASS_VEHICLE + width 24 + height 32 +} + +Swoop_gold +{ + weapon WP_BLASTER + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL + class CLASS_VEHICLE + width 24 + height 32 +} + +Swoop_green +{ + weapon WP_BLASTER + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL + class CLASS_VEHICLE + width 24 + height 32 +} + +Swoop_purple +{ + weapon WP_BLASTER + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL + class CLASS_VEHICLE + width 24 + height 32 +} + +Swoop_red +{ + weapon WP_BLASTER + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL + class CLASS_VEHICLE + width 24 + height 32 +} + +Swoop_silver +{ + weapon WP_BLASTER + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL + class CLASS_VEHICLE + width 24 + height 32 +} + +Swoop_cin +{ + weapon WP_BLASTER + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL + class CLASS_VEHICLE + width 24 + height 32 +} + +swoop_mp +{ + weapon WP_BLASTER + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL + class CLASS_VEHICLE + width 24 + height 32 +} + +swoop_mp2 +{ + weapon WP_BLASTER + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL + class CLASS_VEHICLE + width 24 + height 32 +} + + + diff --git a/base/ext_data/npcs/tauntaun.npc b/base/ext_data/npcs/tauntaun.npc new file mode 100644 index 0000000..55a1a13 --- /dev/null +++ b/base/ext_data/npcs/tauntaun.npc @@ -0,0 +1,11 @@ + +//NOTE: for vehicle-class NPCs, the playerModel key is actually their entry in the vehicles.dat + +Tauntaun +{ + weapon WP_NONE + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL + class CLASS_VEHICLE + snd tauntaun +} diff --git a/base/ext_data/npcs/test.npc b/base/ext_data/npcs/test.npc new file mode 100644 index 0000000..47b491f --- /dev/null +++ b/base/ext_data/npcs/test.npc @@ -0,0 +1,8 @@ +test +{ + playerModel test + weapon WP_NONE + playerTeam TEAM_PLAYER + enemyTeam TEAM_NEUTRAL + class CLASS_KYLE +} \ No newline at end of file diff --git a/base/ext_data/npcs/tie-bomber.npc b/base/ext_data/npcs/tie-bomber.npc new file mode 100644 index 0000000..549e519 --- /dev/null +++ b/base/ext_data/npcs/tie-bomber.npc @@ -0,0 +1,19 @@ +//NOTE: for vehicle-class NPCs, the playerModel key is actually their entry in the vehicles.dat + +tie-bomber +{ + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL + class CLASS_VEHICLE + width 200 + height 256 +} + +tie-bomber2 +{ + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL + class CLASS_VEHICLE + width 200 + height 256 +} diff --git a/base/ext_data/npcs/tie-fighter.npc b/base/ext_data/npcs/tie-fighter.npc new file mode 100644 index 0000000..ed9585a --- /dev/null +++ b/base/ext_data/npcs/tie-fighter.npc @@ -0,0 +1,11 @@ + +//NOTE: for vehicle-class NPCs, the playerModel key is actually their entry in the vehicles.dat + +tie-fighter +{ + playerTeam TEAM_NEUTRAL + enemyTeam TEAM_NEUTRAL + class CLASS_VEHICLE + width 140 + height 300 +} diff --git a/base/ext_data/npcs/tusken.npc b/base/ext_data/npcs/tusken.npc new file mode 100644 index 0000000..1102616 --- /dev/null +++ b/base/ext_data/npcs/tusken.npc @@ -0,0 +1,27 @@ +tusken +{ + playerModel tusken + weapon WP_TUSKEN_STAFF + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + health 50 + rank crewman + playerTeam TEAM_FREE + enemyTeam TEAM_FREE + class CLASS_TUSKEN + snd tusken + sndcombat tusken + sndextra tusken + yawspeed 90 + walkSpeed 55 + runSpeed 200 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/tuskensniper.npc b/base/ext_data/npcs/tuskensniper.npc new file mode 100644 index 0000000..13cf30f --- /dev/null +++ b/base/ext_data/npcs/tuskensniper.npc @@ -0,0 +1,29 @@ +tuskensniper +{ + playerModel tusken + weapon WP_TUSKEN_RIFLE + altFire 1 + reactions 3 + aim 1 + move 3 + aggression 3 + evasion 1 + intelligence 5 + health 50 + rank crewman + playerTeam TEAM_ENEMY + enemyTeam TEAM_PLAYER + class CLASS_TUSKEN + snd tusken + sndcombat tusken + sndextra tusken + yawspeed 90 + walkSpeed 55 + runSpeed 200 + visRange 3000 + dismemberProbHead 0 + dismemberProbArms 10 + dismemberProbLegs 1 + dismemberProbHands 20 + dismemberProbWaist 0 +} \ No newline at end of file diff --git a/base/ext_data/npcs/vssver.scc b/base/ext_data/npcs/vssver.scc new file mode 100644 index 0000000..0f9234b Binary files /dev/null and b/base/ext_data/npcs/vssver.scc differ diff --git a/base/ext_data/vssver.scc b/base/ext_data/vssver.scc new file mode 100644 index 0000000..aaa219a Binary files /dev/null and b/base/ext_data/vssver.scc differ diff --git a/base/ext_data/weapons.dat b/base/ext_data/weapons.dat new file mode 100644 index 0000000..944dd0f --- /dev/null +++ b/base/ext_data/weapons.dat @@ -0,0 +1,744 @@ +// EXTERNAL WEAPON & AMMO DATA +// +// NOTE!!!!!!!!! Weapontype must start the block of weapon data. +// NOTE!!!!!!!!! Ammo must start the block of ammo data. +// +// Weapontype - weapon data is associated with which weapon (must be first) +// WP_SABER, // player and NPC weapon +// WP_BLASTER_PISTOL, // player and NPC weapon +// WP_BLASTER, // player and NPC weapon +// WP_DISRUPTOR, // player and NPC weapon +// WP_BOWCASTER, // NPC weapon - player can pick this up, but never starts with them +// WP_REPEATER, // NPC weapon - player can pick this up, but never starts with them +// WP_DEMP2, // NPC weapon - player can pick this up, but never starts with them +// WP_FLECHETTE, // NPC weapon - player can pick this up, but never starts with them +// WP_ROCKET_LAUNCHER, // NPC weapon - player can pick this up, but never starts with them +// WP_THERMAL, // player and NPC weapon +// WP_TRIP_MINE, // NPC weapon - player can pick this up, but never starts with them +// WP_DET_PACK, // NPC weapon - player can pick this up, but never starts with them +// WP_CONCUSSION, // NPC weapon - player can pick this up, but never starts with them +//extras +// WP_STUN_BATON, // NPC weapon - player can pick this up, but never starts with them +// WP_MELEE, // player and NPC weapon - Any ol' melee attack +// These can never be gotten directly by the player +//NPC weapons +// WP_BRYAR_PISTOL, // NPC weapon - player can pick this up, but never starts with them +// WP_EMPLACED_GUN, +// WP_BOT_LASER, // Probe droid - Laser blast +// WP_TURRET, // turret guns +// WP_ATST_MAIN, +// WP_ATST_SIDE, +// WP_TIE_FIGHTER, +// WP_RAPID_FIRE_CONC, +// WP_JAWA, +// WP_TUSKEN_RIFLE, +// WP_TUSKEN_STAFF, +// WP_SCEPTER, +// WP_NOGHRI_STICK, +// +// Weaponclass - weapon name +// Weaponmodel - weapon model used in game +// weaponicon - interface image +// Ammotype - type of power weapon needs to fire +// 0 - No power +// 1 - Star Fleet power +// 2 - Alien Crystal power +// 3 - Phaser power +// Ammolowcount - amount when "Low ammo" warning appears on screen +// Flashcolor - color generate by weapon flash (R,G,B) +// Firingsound - sound file used when _idling_! +// altfiringsound - sound file used when alt-firing +// flashsound - sound file used by flash +// altflashsound - sound file used by an alt-fire flash +// stopsound - sound file used when a firing sound stops +// Firetime - amount of time between firings +// altfireTime - for alt fire +// Range - range of weapon +// energyPerShot - amount of energy used per shot +// altenergypershot- for alt fire +// barrelcount - number of barrels the model has (weaponname_b?.md3) +// missileModel - missile .md3 +// altmissileModel - alternate missile .md3 +// missileSound - played while flying +// altmissileSound - alternate missile launch sound +// missileLight - intensity of lightsource for missile - if 0.0 then none (float) +// altmissileLight - alternate missile light +// missileLightColor - color in three float style R, G, B (0.0 to 1.0) - NOTE - if you have a light, you MUST HAVE THESE +// altmissileLightColor - alternate color in three float style R, G, B (0.0 to 1.0) +// missileHitSound - played on impact +// altmissileHitSound - for alt fire +// missileFuncName - missile fly function +// altmissileFuncName - for alt fire +// +// FUNCTION NAMES +// borgfunc +// scavengerfunc +// altscavengerfunc +// stasisfunc +// grenadefunc +// altgrenadefunc +// tetrionfunc +// dreadnoughtfunc +// quantumfunc +// quantumaltfunc +// botrocketfunc +// forgeprojfunc +// forgeprojfunc2 +// forgepsychfunc +// parasiteacidfunc +// stasisattackfunc +// loaderlaserfunc +// botprojfunc + +// +// For AMMO Types +// ammoicon - STRING +// ammomax - INT + + +// WP_NULL +{ +WEAPONTYPE WP_NONE +} + +// WP_STUN_BATON +{ +weapontype WP_STUN_BATON +weaponclass weapon_stun_baton +weaponmodel models/weapons2/stun_baton/baton.md3 +weaponIcon gfx/hud/w_icon_stunbaton +firingsound sound/weapons/baton/idle.wav +firingforce fffx/weapons/baton/idle +barrelcount 3 +ammotype 1 +ammolowcount 5 +energypershot 0 +firetime 400 +range 8192 +altenergypershot 0 +altfiretime 400 +altrange 8192 +} + +// WP_SABER +{ +weapontype WP_SABER +weaponclass weapon_saber +weaponmodel models/weapons2/saber/saber_w.md3 +weaponIcon gfx/hud/w_icon_lightsaber +firingsound sound/weapons/saber/saberhum1.wav +ammotype 1 +ammolowcount 5 +energypershot 1 +firetime 100 +range 8192 +altenergypershot 3 +altfiretime 100 +altrange 8192 +missilemodel models/weapons2/saber/saber_w.md3 +} + + +// WP_BRYAR_PISTOL +{ +weapontype WP_BRYAR_PISTOL +weaponclass weapon_bryar_pistol +weaponmodel models/weapons2/briar_pistol/briar_pistol.md3 +weaponIcon gfx/hud/w_icon_briar +missileFuncName bryar_func +altmissileFuncName bryar_alt_func +ammotype 2 +ammolowcount 15 +energypershot 1 +firetime 400 +range 8192 +altenergypershot 1 +altfiretime 400 +altrange 8192 +muzzleEffect bryar/muzzle_flash +altmuzzleEffect bryar/altmuzzle_flash +altchargesound sound/weapons/bryar/altcharge.wav +altchargeforce fffx/weapons/bryar/altcharge +selectSound sound/weapons/bryar/select.wav +selectforce fffx/weapons/bryar/select +} + +// WP_BLASTER +{ +weapontype WP_BLASTER +weaponclass weapon_blaster +weaponmodel models/weapons2/blaster_r/blaster.md3 +weaponIcon gfx/hud/w_icon_blaster +ammotype 2 +ammolowcount 15 +energypershot 1 +firetime 350 +range 8192 +altenergypershot 2 +altfiretime 150 +altrange 8192 +missileFuncName blaster_func +altmissileFuncName blaster_alt_func +muzzleEffect blaster/muzzle_flash +altmuzzleEffect blaster/altmuzzle_flash +selectSound sound/weapons/blaster/select.wav +selectforce fffx/weapons/blaster/select +} + +// WP_DISRUPTOR +{ +weapontype WP_DISRUPTOR +weaponclass weapon_disruptor +weaponmodel models/weapons2/disruptor/disruptor.md3 +weaponIcon gfx/hud/w_icon_disruptor +ammotype 3 +ammolowcount 15 +energypershot 3 +barrelcount 1 +firetime 600 +range 8192 +altenergypershot 3 +altfiretime 1300 +altrange 8192 +muzzleEffect disruptor/muzzle_flash +altmuzzleEffect disruptor/altmuzzle_flash +selectSound sound/weapons/disruptor/select.wav +selectforce fffx/weapons/disruptor/select +altchargesound sound/weapons/disruptor/altCharge.wav +altchargeforce fffx/weapons/disruptor/altcharge +} + +// WP_BOWCASTER +{ +weapontype WP_BOWCASTER +weaponclass weapon_bowcaster +weaponmodel models/weapons2/bowcaster/bowcaster.md3 +weaponIcon gfx/hud/w_icon_bowcaster +altchargesound sound/weapons/bowcaster/altcharge.wav +altchargeforce fffx/weapons/bowcaster/altcharge +ammotype 3 +ammolowcount 15 +energypershot 5 +firetime 750 +range 8192 +altenergypershot 5 +altfiretime 400 +altrange 8192 +missileFuncName bowcaster_func +altmissileFuncName bowcaster_func +muzzleEffect bowcaster/muzzle_flash +altmuzzleEffect bowcaster/altmuzzle_flash +selectSound sound/weapons/bowcaster/select.wav +selectforce fffx/weapons/bowcaster/select +chargesound sound/weapons/bowcaster/altcharge.wav +chargeforce fffx/weapons/bowcaster/altcharge +} + +// WP_REPEATER +{ +weapontype WP_REPEATER +weaponclass weapon_repeater +weaponmodel models/weapons2/heavy_repeater/heavy_repeater.md3 +weaponIcon gfx/hud/w_icon_repeater +ammotype 4 +ammolowcount 25 +energypershot 1 +firetime 50 +range 8192 +altenergypershot 8 +altfiretime 800 +altrange 8192 +barrelcount 1 +missileFuncName repeater_func +altmissileFuncName repeater_alt_func +muzzleEffect repeater/muzzle_flash +altmuzzleEffect repeater/altmuzzle_flash +selectSound sound/weapons/repeater/select.wav +selectforce fffx/weapons/repeater/select +} + +// WP_DEMP2 +{ +weapontype WP_DEMP2 +weaponclass weapon_demp2 +weaponmodel models/weapons2/demp2/demp2.md3 +weaponIcon gfx/hud/w_icon_demp2 +ammotype 3 +ammolowcount 15 +energypershot 8 +firetime 450 +range 8192 +altenergypershot 10 +altfiretime 1200 +altrange 8192 +missileFuncName demp2_func +muzzleEffect demp2/muzzle_flash +altmissileFuncName demp2_alt_func +altmuzzleEffect demp2/altmuzzle_flash +selectSound sound/weapons/demp2/select.wav +selectforce fffx/weapons/demp2/select +altchargesound sound/weapons/demp2/altCharge.wav +altchargeforce fffx/weapons/demp2/altcharge +} + + +// WP_FLECHETTE +{ +weapontype WP_FLECHETTE +weaponclass weapon_flechette +weaponmodel models/weapons2/golan_arms/golan_arms.md3 +barrelcount 1 +ammotype 4 +ammolowcount 15 +firetime 550 +energypershot 8 +range 8192 +weaponIcon gfx/hud/w_icon_flechette +altenergypershot 8 +altfiretime 400 +altrange 8192 +missileFuncName flechette_func +missileModel models/weapons2/golan_arms/projectileMain.md3 +altmissileFuncName flechette_alt_func +muzzleEffect flechette/muzzle_flash +altmuzzleEffect flechette/altmuzzle_flash +altmissileModel models/weapons2/golan_arms/projectile.md3 +selectSound sound/weapons/flechette/select.wav +selectforce fffx/weapons/flechette/select +} + +// WP_ROCKET_LAUNCHER +{ +weapontype WP_ROCKET_LAUNCHER +weaponclass weapon_rocket_launcher +weaponmodel models/weapons2/merr_sonn/merr_sonn.md3 +ammotype 5 +ammolowcount 1 +firetime 600 +energypershot 1 +range 8192 +weaponIcon gfx/hud/w_icon_merrsonn +barrelcount 1 +altenergypershot 1 +altfiretime 1000 +altrange 8192 +missileLight 125 +missileLightColor 1.0 1.0 0.5 +altmissileLight 125 +altmissileLightColor 1.0 1.0 0.5 +missileFuncName rocket_func +altmissileFuncName rocket_alt_func +muzzleEffect rocket/muzzle_flash2 +altmuzzleEffect rocket/altmuzzle_flash +missileModel models/weapons2/merr_sonn/projectile.md3 +altmissileModel models/weapons2/merr_sonn/projectile.md3 +missilesound sound/weapons/rocket/missleloop.wav +altmissilesound sound/weapons/rocket/missleloop.wav +selectSound sound/weapons/rocket/select.wav +selectforce fffx/weapons/rocket/select +} + +// WP_CONCUSSION +{ +weapontype WP_CONCUSSION +weaponclass weapon_concussion_rifle +weaponmodel models/weapons2/concussion/c_rifle.md3 +weaponIcon gfx/hud/w_icon_c_rifle +ammotype 4 +ammolowcount 120 +energypershot 40 +firingsound sound/weapons/concussion/idle_lp.wav +firetime 800 +range 8192 +missileFuncName conc_func +muzzleEffect concussion/muzzle_flash +missileLight 125 +missileLightColor 0.75 0.25 1.0 +missilesound sound/weapons/concussion/missleloop.wav +altenergypershot 50 +altfiretime 1200 +altrange 8192 +barrelcount 1 +altmuzzleEffect concussion/altmuzzle_flash +selectSound sound/weapons/concussion/select.wav +selectforce fffx/weapons/concussion/select +} + +// WP_THERMAL +{ +weapontype WP_THERMAL +weaponclass weapon_thermal +weaponmodel models/weapons2/thermal/thermal.md3 +weaponIcon gfx/hud/w_icon_thermal +ammotype 7 +ammolowcount 1 +energypershot 1 +firetime 800 +range 8192 +altenergypershot 1 +altfiretime 400 +altrange 8192 +missileModel models/weapons2/thermal/thermal_proj.md3 +altmissileModel models/weapons2/thermal/thermal_proj.md3 +barrelcount 0 +chargesound sound/weapons/thermal/charge.wav +chargeforce fffx/weapons/thermal/charge +altchargesound sound/weapons/thermal/charge.wav +altchargeforce fffx/weapons/thermal/charge +selectSound sound/weapons/thermal/select.wav +selectforce fffx/weapons/thermal/select +muzzleEffect thermal/muzzle_flash +} + +// WP_TRIP_MINE +{ +weapontype WP_TRIP_MINE +weaponclass weapon_trip_mine +weaponmodel models/weapons2/laser_trap/laser_trap.md3 +weaponIcon gfx/hud/w_icon_tripmine +ammotype 8 +ammolowcount 1 +energypershot 1 +firetime 800 +range 8192 +altenergypershot 1 +altfiretime 400 +altrange 8192 +missileModel models/weapons2/laser_trap/laser_trap_w.glm +altmissileModel models/weapons2/laser_trap/laser_trap_w.glm +selectSound sound/weapons/detpack/select.wav +selectforce fffx/weapons/detpack/select +muzzleEffect tripmine/muzzle_flash + +} + +// WP_DET_PACK +{ +weapontype WP_DET_PACK +weaponclass weapon_det_pack +weaponmodel models/weapons2/detpack/det_pack.md3 +weaponIcon gfx/hud/w_icon_detpack +ammotype 9 +ammolowcount 1 +energypershot 1 +firetime 800 +range 8192 +altenergypershot 0 +altfiretime 400 +altrange 8192 +missileModel models/weapons2/detpack/det_pack_proj.glm +selectSound sound/weapons/detpack/select.wav +selectforce fffx/weapons/detpack/select +muzzleEffect detpack/muzzle_flash +} + +// WP_EMPLACED_GUN +{ +weapontype WP_EMPLACED_GUN +weaponclass weapon_emplaced_gun +weaponmodel models/weapons2/noweap/noweap.md3 + +altenergypershot 1 +altrange 8192 +missileFuncName emplaced_func +altmissileFuncName emplaced_func +ammotype 6 +ammolowcount 15 +energypershot 1 +firetime 150 +altfiretime 150 +range 8192 +muzzleEffect emplaced/muzzle_flash +muzzleEffect eweb/muzzle_flash +} + +// WP_BOT_LASER +{ +weapontype WP_BOT_LASER +weaponclass weapon_bryar_pistol +weaponmodel models/weapons2/noweap/noweap.md3 + +//flashsound sound/weapons/probe/fire.wav +//altflashsound sound/weapons/probe/alt_fire.wav +altenergypershot 0 +altrange 8192 +missileFuncName bryar_func +ammotype 1 +ammolowcount 15 +energypershot 2 +firetime 1600 +range 8192 +} + +// WP_MELEE +{ +weapontype WP_MELEE +weaponclass weapon_melee +weaponmodel models/weapons2/noweap/noweap.md3 +weaponIcon gfx/hud/w_icon_melee +ammotype 3 +ammolowcount 5 +energypershot 0 +firetime 1000 +range 1024 +} + +// WP_ATST_MAIN +{ +weapontype WP_ATST_MAIN +weaponclass weapon_atst_main +weaponmodel models/weapons2/noweap/noweap.md3 +weaponIcon gfx/hud/w_icon_atst +//flashsound sound/weapons/atst/ATSTfire1.wav +//altflashsound sound/weapons/atst/ATSTfire2.wav +altenergypershot 1 +altrange 8192 +missileFuncName atstmain_func +altmissileFuncName atstmain_func +ammotype 6 +ammolowcount 15 +energypershot 1 +firetime 200 +altfiretime 150 +range 8192 +muzzleEffect emplaced/muzzle_flash +} + +// WP_ATST_SIDE +{ +weapontype WP_ATST_SIDE +weaponclass weapon_atst_side +weaponmodel models/weapons2/noweap/noweap.md3 +weaponIcon gfx/hud/w_icon_atstside +altenergypershot 1 +altrange 8192 + +altmissileModel models/weapons2/merr_sonn/projectile.md3 + +missileFuncName atst_side_main_func +altmissileFuncName atst_side_alt_func +muzzleEffect emplaced/muzzle_flash +altmuzzleEffect emplaced/muzzle_flash + +ammotype 6 +ammolowcount 15 +energypershot 1 +firetime 400 +altfiretime 1000 +range 8192 +} + +// WP_TIE_FIGHTER +{ +weapontype WP_TIE_FIGHTER +weaponclass weapon_tie_fighter +weaponmodel models/weapons2/noweap/noweap.md3 +altenergypershot 1 +altrange 8192 +missileFuncName emplaced_func +altmissileFuncName emplaced_func +ammotype 6 +ammolowcount 15 +energypershot 1 +firetime 400 +altfiretime 400 +range 8192 +muzzleEffect emplaced/muzzle_flash +} + +// WP_RAPID_FIRE_CONC +{ +weapontype WP_RAPID_FIRE_CONC +weaponclass weapon_radid_concussion +weaponmodel models/weapons2/noweap/noweap.md3 +altenergypershot 1 +altrange 8192 +missileFuncName emplaced_func +altmissileFuncName repeater_alt_func +ammotype 6 +ammolowcount 15 +energypershot 1 +firetime 400 +altfiretime 1000 +range 8192 +muzzleEffect emplaced/muzzle_flash +} + +// WP_BLASTER_PISTOL +{ +weapontype WP_BLASTER_PISTOL +weaponclass weapon_blaster_pistol +weaponmodel models/weapons2/blaster_pistol/blaster_pistol.md3 +weaponIcon gfx/hud/w_icon_blaster_pistol +missileFuncName bryar_func +altmissileFuncName bryar_alt_func +ammotype 2 +ammolowcount 15 +energypershot 1 +firetime 400 +range 8192 +altenergypershot 1 +altfiretime 400 +altrange 8192 +muzzleEffect bryar/muzzle_flash +altmuzzleEffect bryar/altmuzzle_flash +altchargesound sound/weapons/bryar/altcharge.wav +selectSound sound/weapons/bryar/select.wav +selectforce fffx/weapons/bryar/select +} + +// WP_TURRET +{ +weapontype WP_TURRET +weaponclass weapon_turret +weaponmodel models/weapons2/noweap/noweap.md3 +altenergypershot 1 +altrange 8192 +missileFuncName turret_func +ammotype 6 +ammolowcount 15 +energypershot 1 +firetime 400 +altfiretime 400 +range 8192 +muzzleEffect turret/muzzle_flash +} + +// WP_JAWA +{ +weapontype WP_JAWA +weaponclass weapon_jawa +weaponmodel models/weapons2/jawa/jawa_gun.md3 +missileFuncName bryar_func +altmissileFuncName bryar_alt_func +ammotype 2 +ammolowcount 15 +energypershot 2 +firetime 400 +range 8192 +altenergypershot 2 +altfiretime 400 +altrange 8192 +muzzleEffect bryar/muzzle_flash +} + +// WP_TUSKEN_RIFLE +{ +weapontype WP_TUSKEN_RIFLE +weaponclass weapon_tusken_rifle +weaponmodel models/weapons2/tusken_rifle/tusken_rifle.md3 +ammotype 3 +ammolowcount 15 +firetime 1000 +energypershot 3 +firetime 600 +missileFuncName tusk_shot_func +missileLight 50 +missileLightColor 1.0 0.75 0.25 +muzzleEffect tusken/muzzle_flash +altenergypershot 3 +altfiretime 1000 +altmissileFuncName tusk_shot_func +altmissileLight 50 +altmissileLightColor 1.0 0.75 0.25 +altmuzzleEffect tusken/muzzle_flash +selectSound sound/weapons/disruptor/select.wav +selectforce fffx/weapons/disruptor/select +} + +// WP_TUSKEN_STAFF +{ +weapontype WP_TUSKEN_STAFF +weaponclass weapon_tusken_staff +weaponmodel models/weapons2/tusken_staff/tusken_staff.md3 +ammotype 3 +ammolowcount 5 +energypershot 0 +firetime 1000 +range 1024 +} + +//WP_SCEPTER +{ +weapontype WP_SCEPTER +weaponclass weapon_scepter +weaponmodel models/weapons2/sith_scepter/sith_scepter.md3 +ammotype 3 +ammolowcount 5 +energypershot 0 +firetime 1000 +range 1024 +} + +//WP_NOGHRI_STICK +{ +weapontype WP_NOGHRI_STICK +weaponclass weapon_noghri_stick +weaponmodel models/weapons2/noghri_stick/noghri_stick.md3 +ammotype 3 +ammolowcount 5 +energypershot 1 +firetime 600 +missileFuncName noghri_shot_func +muzzleEffect noghri_stick/muzzle_flash +} + +// AMMO_NONE +{ +AMMO AMMO_NONE +AMMOMAX 0 +} + +// AMMO_FORCE +{ +AMMO AMMO_FORCE +AMMOMAX 100 +} + +// AMMO_BLASTER +{ +AMMO AMMO_BLASTER +AMMOMAX 300 +} + +// AMMO_POWERCELL +{ +AMMO AMMO_POWERCELL +AMMOMAX 300 +} + +// AMMO_METAL_BOLTS +{ +AMMO AMMO_METAL_BOLTS +AMMOMAX 400 +} + +// AMMO_ROCKETS +{ +AMMO AMMO_ROCKETS +AMMOMAX 10 +} + +// AMMO_EMPLACED +{ +AMMO AMMO_EMPLACED +AMMOMAX 999 +} + +// AMMO_THERMAL +{ +AMMO AMMO_THERMAL +AMMOMAX 10 +} + +// AMMO_TRIPMINE +{ +AMMO AMMO_TRIPMINE +AMMOMAX 5 +} + +// AMMO_DETPACK +{ +AMMO AMMO_DETPACK +AMMOMAX 5 +} \ No newline at end of file diff --git a/base/high.cfg b/base/high.cfg new file mode 100644 index 0000000..9e899b8 --- /dev/null +++ b/base/high.cfg @@ -0,0 +1,18 @@ +set r_picmip 0 +set r_lodbias 0 +set r_detailtextures 1 +set r_dynamiclight 1 +set r_flares 1 +set r_subdivisions 4 +set r_lodcurveError 250 +set r_lodscale 10 +set cg_shadows 2 +set r_texturebitslm 32 +set r_texturebits 32 +set r_colorbits 32 +set r_depthbits 32 + +set r_surfaceSprites 1 +set r_weatherScale 1 + +set r_noportals 0 \ No newline at end of file diff --git a/base/low.cfg b/base/low.cfg new file mode 100644 index 0000000..9fc46d8 --- /dev/null +++ b/base/low.cfg @@ -0,0 +1,22 @@ +set s_khz 11 +set cg_VariantSoundCap 2 + +set r_picmip 2 +set r_lodbias 2 +set r_detailtextures 0 +set r_dynamiclight 0 +set r_flares 0 +set r_subdivisions 20 +set r_lodcurveError 500 +set r_lodscale 4 +set cg_shadows 0 +set cg_marks 0 + +set r_texturebits 16 +set r_colorbits 16 +set r_depthbits 16 + +set r_surfaceSprites 0 +set r_weatherScale 0 + +set r_noportals 1 \ No newline at end of file diff --git a/base/med.cfg b/base/med.cfg new file mode 100644 index 0000000..35bbba4 --- /dev/null +++ b/base/med.cfg @@ -0,0 +1,18 @@ +set sys_lowmem 0 +set r_picmip 1 +set r_lodbias 1 +set r_detailtextures 1 +set r_dynamiclight 1 +set r_flares 1 +set r_subdivisions 12 +set r_lodcurveError 250 +set r_lodscale 6 +set cg_shadows 1 +set r_texturebits 0 +set r_colorbits 0 +set r_depthbits 0 + +set r_surfaceSprites 1 +set r_weatherScale 1 + +set r_noportals 0 diff --git a/base/mpdefault.cfg b/base/mpdefault.cfg new file mode 100644 index 0000000..d10938b --- /dev/null +++ b/base/mpdefault.cfg @@ -0,0 +1,141 @@ +// +// MP JEDI ACADEMY DEFAULT CONFIG +// + +unbindall + +// +// weapons +// +bind 1 "weapon 1" +bind 2 "weapon 2" +bind 3 "weapon 3" +bind 4 "weapon 4" +bind 5 "weapon 5" +bind 6 "weapon 6" +bind 7 "weapon 7" +bind 8 "weapon 8" +bind 9 "weapon 13" +bind 0 "weapon 9" +bind - "weapon 10" +bind = "weapon 0" + + +// +// CHARACTER CONTROLS +// + +bind CTRL +attack +bind ALT +altattack +bind SHIFT +speed +bind z +strafe +bind PGUP +lookup +bind PGDN +lookdown +bind END centerview +bind c +movedown +bind SPACE +moveup +bind ENTER +use +bind r +use + + +bind UPARROW +forward +bind DOWNARROW +back +bind LEFTARROW +left +bind RIGHTARROW +right +bind w +forward +bind a +moveleft +bind s +back +bind d +moveright +bind , +moveleft +bind . +moveright + +// +// FORCE POWERS +// + +bind F1 force_throw +bind F2 force_pull +bind F3 force_speed +bind F4 force_seeing +bind F5 force_heal +bind F6 force_protect +bind F7 force_absorb +bind F8 force_distract +bind F9 +force_grip +bind F10 +force_lightning +bind F11 force_rage +bind F12 +force_drain +bind \ force_forcepowerother +bind ] force_healother + + +bind f +useforce +bind e forcenext +bind q forceprev + +bind TAB +scores +bind INS scoresUp +bind DEL scoresDown +bind p "cg_thirdperson !" +bind l saberAttackCycle + +// +// QUICK KEYS +// + + +//multi only +bind KP_HOME use_field + +//bind KP_RIGHTARROW use_field +//bind KP_UPARROW use_field +//bind KP_DOWNARROW use_field +//bind KP_END use_field +//bind KP_PGDN use_field +//bind KP_INS use_field +//bind KP_DEL use_field +//bind KP_ENTER use_field +// + + +// +// MOUSE OPTIONS +// + +bind / +mlook + +// +// MOUSE BUTTONS +// + +bind MOUSE1 +attack +bind MOUSE2 +altattack +bind MOUSE3 saberAttackCycle +bind mwheelup weapprev +bind mwheeldown weapnext + +// +// CLIENT ENVIRONMENT COMMANDS +// + +bind ~ "toggleconsole" +bind ` "toggleconsole" + + +//yell to all +bind y messagemode +//team talk +bind t messagemode2 +//target +bind u messagemode3 +//attacker +bind i messagemode4 +//voicechat +bind v voicechat +//Automap toggle +bind m automap_toggle +//Objectives menu +bind o "ui_opensiegemenu ingame_objectives" + +// Saber Challenge +bind k engage_duel diff --git a/base/noMotion.cfg b/base/noMotion.cfg new file mode 100644 index 0000000..b9c92df --- /dev/null +++ b/base/noMotion.cfg @@ -0,0 +1,5 @@ +cg_runpitch 0 +cg_runroll 0 +cg_bobup 0 +cg_bobpitch 0 +cg_bobroll 0 \ No newline at end of file diff --git a/base/productid.txt b/base/productid.txt new file mode 100644 index 0000000..9e1663b --- /dev/null +++ b/base/productid.txt @@ -0,0 +1 @@ +This file is copyright 2003 Raven Software, and may not be duplicated except during a licensed installation of the full commercial version of Star Wars: Jedi Academy \ No newline at end of file diff --git a/base/restoreMotion.cfg b/base/restoreMotion.cfg new file mode 100644 index 0000000..b786388 --- /dev/null +++ b/base/restoreMotion.cfg @@ -0,0 +1,5 @@ +reset cg_runpitch +reset cg_runroll +reset cg_bobup +reset cg_bobpitch +reset cg_bobroll \ No newline at end of file diff --git a/base/vssver.scc b/base/vssver.scc new file mode 100644 index 0000000..95c651a Binary files /dev/null and b/base/vssver.scc differ diff --git a/code/0_compiled_first/vssver.scc b/code/0_compiled_first/vssver.scc index bbe8e58..56bb212 100644 Binary files a/code/0_compiled_first/vssver.scc and b/code/0_compiled_first/vssver.scc differ diff --git a/code/RMG/vssver.scc b/code/RMG/vssver.scc index 2f374f9..c7c6ca2 100644 Binary files a/code/RMG/vssver.scc and b/code/RMG/vssver.scc differ diff --git a/code/Ragl/vssver.scc b/code/Ragl/vssver.scc index 45055c3..2677bd4 100644 Binary files a/code/Ragl/vssver.scc and b/code/Ragl/vssver.scc differ diff --git a/code/Ratl/vssver.scc b/code/Ratl/vssver.scc index 715da81..9e2d713 100644 Binary files a/code/Ratl/vssver.scc and b/code/Ratl/vssver.scc differ diff --git a/code/Ravl/vssver.scc b/code/Ravl/vssver.scc index e182a3e..fad942c 100644 Binary files a/code/Ravl/vssver.scc and b/code/Ravl/vssver.scc differ diff --git a/code/Rufl/vssver.scc b/code/Rufl/vssver.scc index f5c7800..e985dfd 100644 Binary files a/code/Rufl/vssver.scc and b/code/Rufl/vssver.scc differ diff --git a/code/SHDebug/vssver.scc b/code/SHDebug/vssver.scc index 1209876..6cb0102 100644 Binary files a/code/SHDebug/vssver.scc and b/code/SHDebug/vssver.scc differ diff --git a/code/cgame/FxScheduler.cpp b/code/cgame/FxScheduler.cpp index c89a905..33db076 100644 --- a/code/cgame/FxScheduler.cpp +++ b/code/cgame/FxScheduler.cpp @@ -1950,9 +1950,45 @@ void CFxScheduler::CreateEffect( CPrimitiveTemplate *fx, const vec3_t origin, ve { gentity_t *ent = &g_entities[tr.entityNum]; - CG_AddGhoul2Mark(fx->mMediaHandles.GetHandle(), fx->mSizeStart.GetVal(), tr.endpos, tr.plane.normal, - tr.entityNum, ent->client->ps.origin, ent->client->ps.viewangles[YAW], - ent->ghoul2, ent->s.modelScale, Q_irand(40000, 60000)); + if ( ent != NULL ) + { + vec3_t entOrg, hitDir; + float entYaw; + float firstModel = 0; + if ( !(ent->s.eFlags&EF_NODRAW) ) + {//not drawn, no marks + if ( ent->client ) + { + VectorCopy( ent->client->ps.origin, entOrg ); + } + else + { + VectorCopy( ent->currentOrigin, entOrg ); + } + if ( ent->client ) + { + entYaw = ent->client->ps.viewangles[YAW]; + } + else + { + entYaw = ent->currentAngles[YAW]; + } + //if ( VectorCompare( tr.plane.normal, vec3_origin ) ) + {//hunh, no plane? Use trace dir + VectorCopy( ax[0], hitDir ); + } + /* + else + { + VectorCopy( tr.plane.normal, hitDir ); + } + */ + + CG_AddGhoul2Mark(fx->mMediaHandles.GetHandle(), fx->mSizeStart.GetVal(), tr.endpos, tr.plane.normal, + tr.entityNum, entOrg, entYaw, + ent->ghoul2, ent->s.modelScale, Q_irand(40000, 60000), firstModel); + } + } } } break; diff --git a/code/cgame/cg_ents.cpp b/code/cgame/cg_ents.cpp index 026e753..0d1463b 100644 --- a/code/cgame/cg_ents.cpp +++ b/code/cgame/cg_ents.cpp @@ -12,10 +12,11 @@ #include "..\game\g_vehicles.h" extern void CG_AddSaberBlade( centity_t *cent, centity_t *scent, refEntity_t *saber, int renderfx, int modelIndex, vec3_t origin, vec3_t angles); -extern void CG_CheckSaberInWater( centity_t *cent, centity_t *scent, int modelIndex, vec3_t origin, vec3_t angles ); +extern void CG_CheckSaberInWater( centity_t *cent, centity_t *scent, int saberNum, int modelIndex, vec3_t origin, vec3_t angles ); extern void CG_ForcePushBlur( const vec3_t org, qboolean darkSide = qfalse ); extern void CG_AddForceSightShell( refEntity_t *ent, centity_t *cent ); extern qboolean CG_PlayerCanSeeCent( centity_t *cent ); +extern cvar_t *debug_subdivision; /* ====================== @@ -562,7 +563,7 @@ const weaponData_t *wData = NULL; else if ( cent->gent->owner->client->ps.saberEventFlags & SEF_INWATER ) { CG_CheckSaberInWater( &cg_entities[cent->gent->owner->s.number], - &cg_entities[cent->gent->s.number], cent->gent->weaponModel[0], + &cg_entities[cent->gent->s.number], 0, cent->gent->weaponModel[0], cent->lerpOrigin, cent->lerpAngles ); } } @@ -582,7 +583,12 @@ const weaponData_t *wData = NULL; else { int spinSound; - if ( cent->gent->owner->client->ps.saber[0].type == SABER_SITH_SWORD ) + if ( cent->gent->owner->client->ps.saber[0].spinSound + && cgs.sound_precache[cent->gent->owner->client->ps.saber[0].spinSound] ) + { + spinSound = cgs.sound_precache[cent->gent->owner->client->ps.saber[0].spinSound]; + } + else if ( cent->gent->owner->client->ps.saber[0].type == SABER_SITH_SWORD ) { spinSound = cgi_S_RegisterSound( "sound/weapons/saber/saberspinoff.wav" ); } @@ -623,7 +629,7 @@ const weaponData_t *wData = NULL; else if ( cent->gent->owner->client->ps.saberEventFlags & SEF_INWATER ) { CG_CheckSaberInWater( &cg_entities[cent->gent->owner->s.number], - &cg_entities[cent->gent->s.number], 0, cent->lerpOrigin, + &cg_entities[cent->gent->s.number], 0, 0, cent->lerpOrigin, cent->lerpAngles ); } } @@ -654,7 +660,12 @@ const weaponData_t *wData = NULL; else { int spinSound; - if ( cent->gent->owner->client->ps.saber[0].type == SABER_SITH_SWORD ) + if ( cent->gent->owner->client->ps.saber[0].spinSound + && cgs.sound_precache[cent->gent->owner->client->ps.saber[0].spinSound] ) + { + spinSound = cgs.sound_precache[cent->gent->owner->client->ps.saber[0].spinSound]; + } + else if ( cent->gent->owner->client->ps.saber[0].type == SABER_SITH_SWORD ) { spinSound = cgi_S_RegisterSound( "sound/weapons/saber/saberspinoff.wav" ); } @@ -986,7 +997,22 @@ Ghoul2 Insert End // lovely...this is for weapons that should be oriented vertically. For weapons lockers and such. if ( cent->gent->spawnflags & 16 ) { //VectorClear( spinAngles ); - spinAngles[PITCH] -= 75; + if ( item->giType == IT_WEAPON + && item->giTag == WP_SABER ) + { + if ( cent->gent->random ) + {//pitch specified + spinAngles[PITCH] += cent->gent->random; + } + else + { + spinAngles[PITCH] -= 20; + } + } + else + { + spinAngles[PITCH] -= 75; + } } if( item->giType != IT_HOLOCRON ) @@ -1997,7 +2023,7 @@ extern cvar_t *g_saberRealisticCombat; if ( newBolt != -1 ) { cent->gent->delay = cg.time + 50; - CG_PlayEffectBolted( "blaster/smoke_bolton", owner->playerModel, newBolt, owner->s.number, owner->s.origin ); //ent origin used to make FX culling work + CG_PlayEffectBolted( "saber/limb_bolton", owner->playerModel, newBolt, owner->s.number, owner->s.origin ); //ent origin used to make FX culling work } } } @@ -2019,7 +2045,7 @@ extern cvar_t *g_saberRealisticCombat; } } if ( owner->client->NPC_class == CLASS_PROTOCOL - || g_dismemberment->integer == 113811381138 + || debug_subdivision->integer || g_saberRealisticCombat->integer ) { //wait 100ms before allowing owner to be dismembered again diff --git a/code/cgame/cg_info.cpp b/code/cgame/cg_info.cpp index 911b737..0be77c1 100644 --- a/code/cgame/cg_info.cpp +++ b/code/cgame/cg_info.cpp @@ -52,8 +52,14 @@ static void ObjectivePrint_Line(const int color, const int objectIndex, int &mis int iYPixelsPerLine = cgi_R_Font_HeightPixels(cgs.media.qhFontMedium, 1.0f); - cgi_SP_GetStringTextString( va("OBJECTIVES_%s",objectiveTable[objectIndex].name) , finalText, sizeof(finalText) ); - + if( gi.Cvar_VariableIntegerValue("com_demo") ) + { + cgi_SP_GetStringTextString( va("OBJECTIVES_DEMO_%s",objectiveTable[objectIndex].name) , finalText, sizeof(finalText) ); + } + else + { + cgi_SP_GetStringTextString( va("OBJECTIVES_%s",objectiveTable[objectIndex].name) , finalText, sizeof(finalText) ); + } // A hack to be able to count prisoners if (objectIndex==T2_RANCOR_OBJ5) { @@ -672,18 +678,57 @@ static void CG_GetLoadScreenInfo(int *weaponBits,int *forceBits) ); } - - // the new JK2 stuff - force powers, etc... - // - gi.Cvar_VariableStringBuffer( "playerfplvl", s, sizeof(s) ); - i=0; - var = strtok( s, " " ); - while( var != NULL ) + else { - /* While there are tokens in "s" */ - loadForcePowerLevel[i++] = atoi(var); - /* Get next token: */ - var = strtok( NULL, " " ); + // will also need to do this for weapons + if( gi.Cvar_VariableIntegerValue("com_demo") ) + { + gi.Cvar_VariableStringBuffer( "demo_playerwpns", s, sizeof(s) ); + + *weaponBits = atoi(s); + + } + + } + + if( gi.Cvar_VariableIntegerValue("com_demo") ) + { + // le Demo stuff... + // the new JK2 stuff - force powers, etc... + // + *forceBits = 0; // need to zero it out it might have already been set above if coming from a true + // map transition in the demo + gi.Cvar_VariableStringBuffer( "demo_playerfplvl", s, sizeof(s) ); + int j=0; + var = strtok( s, " " ); + while( var != NULL ) + { + /* While there are tokens in "s" */ + loadForcePowerLevel[j] = atoi(var); + if( loadForcePowerLevel[j] ) + { + *forceBits |= (1<ps.weapon ); + if ( g_entities[i].client->ps.saber[0].g2MarksShader[0] ) + { + cgi_R_RegisterShader( g_entities[i].client->ps.saber[0].g2MarksShader ); + } + if ( g_entities[i].client->ps.saber[0].g2MarksShader2[0] ) + { + cgi_R_RegisterShader( g_entities[i].client->ps.saber[0].g2MarksShader2 ); + } + if ( g_entities[i].client->ps.saber[0].g2WeaponMarkShader[0] ) + { + cgi_R_RegisterShader( g_entities[i].client->ps.saber[0].g2WeaponMarkShader ); + } + if ( g_entities[i].client->ps.saber[0].g2WeaponMarkShader2[0] ) + { + cgi_R_RegisterShader( g_entities[i].client->ps.saber[0].g2WeaponMarkShader2 ); + } + if ( g_entities[i].client->ps.saber[1].g2MarksShader[0] ) + { + cgi_R_RegisterShader( g_entities[i].client->ps.saber[1].g2MarksShader ); + } + if ( g_entities[i].client->ps.saber[1].g2MarksShader2[0] ) + { + cgi_R_RegisterShader( g_entities[i].client->ps.saber[1].g2MarksShader2 ); + } + if ( g_entities[i].client->ps.saber[1].g2WeaponMarkShader[0] ) + { + cgi_R_RegisterShader( g_entities[i].client->ps.saber[1].g2WeaponMarkShader ); + } + if ( g_entities[i].client->ps.saber[1].g2WeaponMarkShader2[0] ) + { + cgi_R_RegisterShader( g_entities[i].client->ps.saber[1].g2WeaponMarkShader2 ); + } CG_RegisterNPCCustomSounds( &g_entities[i].client->clientInfo ); //CG_RegisterNPCEffects( g_entities[i].client->playerTeam ); } @@ -1768,7 +1800,7 @@ Ghoul2 Insert End else */ { - NPC_Precache( &g_entities[i] ); + CG_NPC_Precache( &g_entities[i] ); } } } diff --git a/code/cgame/cg_players.cpp b/code/cgame/cg_players.cpp index 3187121..4c231fe 100644 --- a/code/cgame/cg_players.cpp +++ b/code/cgame/cg_players.cpp @@ -17,6 +17,9 @@ #include "animtable.h" +extern qboolean WP_SaberBladeUseSecondBladeStyle( saberInfo_t *saber, int bladeNum ); +extern void WP_SaberSwingSound( gentity_t *ent, int saberNum, swingType_t swingType ); + extern vmCvar_t cg_debugHealthBars; /* @@ -28,7 +31,7 @@ taken from the entityState_t //rww - generic function for applying a shader to the skin. extern vmCvar_t cg_g2Marks; void CG_AddGhoul2Mark(int type, float size, vec3_t hitloc, vec3_t hitdirection, - int entnum, vec3_t entposition, float entangle, CGhoul2Info_v &ghoul2, vec3_t modelScale, int lifeTime, vec3_t uaxis ) + int entnum, vec3_t entposition, float entangle, CGhoul2Info_v &ghoul2, vec3_t modelScale, int lifeTime, int firstModel, vec3_t uaxis ) { if ( !cg_g2Marks.integer ) {//don't want these @@ -44,11 +47,15 @@ void CG_AddGhoul2Mark(int type, float size, vec3_t hitloc, vec3_t hitdirection, goreSkin.frontFaces = true; // yes front goreSkin.backFaces = false; // no back goreSkin.lifeTime = lifeTime; + goreSkin.firstModel = firstModel; + /* + //NOTE: sorry, have to disable fade-out of marks, causes sorting issues if (lifeTime > 0) { goreSkin.fadeOutTime = lifeTime*0.1; //use whatever you want here -rww } goreSkin.fadeRGB = true; //fade on RGB and alpha instead of just alpha (not needed for all shaders, but whatever) + */ goreSkin.currentTime = cg.time; goreSkin.entNum = entnum; @@ -79,7 +86,15 @@ void CG_AddGhoul2Mark(int type, float size, vec3_t hitloc, vec3_t hitdirection, } VectorCopy(modelScale, goreSkin.scale); - VectorCopy ( hitdirection, goreSkin.rayDirection); + if ( VectorCompare( hitdirection, vec3_origin ) ) + {//wtf, no dir? Make one up + VectorSubtract( entposition, hitloc, goreSkin.rayDirection); + VectorNormalize( goreSkin.rayDirection ); + } + else + {//use passed in value + VectorCopy ( hitdirection, goreSkin.rayDirection); + } VectorCopy ( hitloc, goreSkin.hitLocation ); VectorCopy ( entposition, goreSkin.position ); @@ -982,6 +997,56 @@ static void CG_PlayerAnimEventDo( centity_t *cent, animevent_t *animEvent ) } } break; + case AEV_SABER_SWING: + if ( cent->gent ) + {//cheat over to game side and play sound from there... + WP_SaberSwingSound( cent->gent, animEvent->eventData[AED_SABER_SWING_SABERNUM], (swingType_t)animEvent->eventData[AED_SABER_SWING_TYPE] ); + } + break; + case AEV_SABER_SPIN: + if ( cent->gent + && cent->gent->client ) + { + saberInfo_t *saber = ¢->gent->client->ps.saber[animEvent->eventData[AED_SABER_SPIN_SABERNUM]]; + if ( saber ) + { + int spinSound = 0; + if ( saber->spinSound + && cgs.sound_precache[saber->spinSound] ) + {//use override + spinSound = cgs.sound_precache[saber->spinSound]; + } + else + { + switch ( animEvent->eventData[AED_SABER_SPIN_TYPE] ) + { + case 0://saberspinoff + spinSound = cgi_S_RegisterSound( "sound/weapons/saber/saberspinoff.wav" ); + break; + case 1://saberspin + spinSound = cgi_S_RegisterSound( "sound/weapons/saber/saberspin.wav" ); + break; + case 2://saberspin1 + spinSound = cgi_S_RegisterSound( "sound/weapons/saber/saberspin1.wav" ); + break; + case 3://saberspin2 + spinSound = cgi_S_RegisterSound( "sound/weapons/saber/saberspin2.wav" ); + break; + case 4://saberspin3 + spinSound = cgi_S_RegisterSound( "sound/weapons/saber/saberspin3.wav" ); + break; + default://random saberspin1-3 + spinSound = cgi_S_RegisterSound( va( "sound/weapons/saber/saberspin%d.wav", Q_irand(1,3)) ); + break; + } + } + if ( spinSound ) + { + cgi_S_StartSound( NULL, cent->currentState.clientNum, CHAN_AUTO, spinSound ); + } + } + } + break; case AEV_FOOTSTEP: CG_PlayerFootsteps( cent, (footstepType_t)animEvent->eventData[AED_FOOTSTEP_TYPE] ); break; @@ -1251,6 +1316,28 @@ static void CG_PlayerAnimEvents( int animFileIndex, qboolean torso, int oldFrame doEvent = qtrue; } break; + case AEV_SABER_SWING: + // Determine probability of playing sound + if (!animEvents[i].eventData[AED_SABER_SWING_PROBABILITY]) // 100% + { + doEvent = qtrue; + } + else if (animEvents[i].eventData[AED_SABER_SWING_PROBABILITY] > Q_irand(0, 99) ) + { + doEvent = qtrue; + } + break; + case AEV_SABER_SPIN: + // Determine probability of playing sound + if (!animEvents[i].eventData[AED_SABER_SPIN_PROBABILITY]) // 100% + { + doEvent = qtrue; + } + else if (animEvents[i].eventData[AED_SABER_SPIN_PROBABILITY] > Q_irand(0, 99) ) + { + doEvent = qtrue; + } + break; case AEV_FOOTSTEP: // Determine probability of playing sound //Com_Printf( "Footstep event on frame %d, even should be on frame %d, off by %d\n", frame, animEvents[i].keyFrame, frame-animEvents[i].keyFrame ); @@ -5490,6 +5577,90 @@ static void CG_StopWeaponSounds( centity_t *cent ) //--------------- SABER STUFF -------- extern void CG_Smoke( vec3_t origin, vec3_t dir, float radius, float speed, qhandle_t shader, int flags); +void CG_SaberDoWeaponHitMarks( gclient_t *client, gentity_t *saberEnt, gentity_t *hitEnt, int saberNum, int bladeNum, vec3_t hitPos, vec3_t hitDir, vec3_t uaxis, vec3_t splashBackDir, float sizeTimeScale ) +{ + if ( client + && sizeTimeScale > 0.0f + && hitEnt + && hitEnt->client + && hitEnt->ghoul2.size() ) + {//burn mark with glow + //FIXME: set the correct angle based on direction of swing + //FIXME: keep a count of these on the ent and don't add too many + int lifeTime = (1.01-(float)(hitEnt->health)/hitEnt->max_health) * (float)Q_irand( 5000, 10000 ); + float size = 0.0f; + int weaponMarkShader = 0, markShader = cgs.media.bdecal_saberglowmark; + + //First: do mark decal on hitEnt + if ( WP_SaberBladeUseSecondBladeStyle( &client->ps.saber[saberNum], bladeNum ) ) + { + if ( client->ps.saber[saberNum].g2MarksShader2[0] ) + {//we have a shader to use instead of the standard mark shader + markShader = cgi_R_RegisterShader( client->ps.saber[saberNum].g2MarksShader2 ); + lifeTime = Q_irand( 20000, 30000 );//last longer if overridden + } + } + else + { + if ( client->ps.saber[saberNum].g2MarksShader[0] ) + {//we have a shader to use instead of the standard mark shader + markShader = cgi_R_RegisterShader( client->ps.saber[saberNum].g2MarksShader ); + lifeTime = Q_irand( 20000, 30000 );//last longer if overridden + } + } + + if ( markShader ) + { + lifeTime = ceil( (float)lifeTime * sizeTimeScale ); + size = Q_flrand( 2.0f, 3.0f ) * sizeTimeScale; + CG_AddGhoul2Mark( markShader, size, hitPos, hitDir, hitEnt->s.number, + hitEnt->client->ps.origin, hitEnt->client->renderInfo.legsYaw, hitEnt->ghoul2, hitEnt->s.modelScale, + lifeTime, 0, uaxis ); + } + + //now do weaponMarkShader - splashback decal on weapon + if ( WP_SaberBladeUseSecondBladeStyle( &client->ps.saber[saberNum], bladeNum ) ) + { + if ( client->ps.saber[saberNum].g2WeaponMarkShader2[0] ) + {//we have a shader to use instead of the standard mark shader + weaponMarkShader = cgi_R_RegisterShader( client->ps.saber[saberNum].g2WeaponMarkShader2 ); + lifeTime = Q_irand( 7000, 12000 );//last longer if overridden + } + } + else + { + if ( client->ps.saber[saberNum].g2WeaponMarkShader[0] ) + {//we have a shader to use instead of the standard mark shader + weaponMarkShader = cgi_R_RegisterShader( client->ps.saber[saberNum].g2WeaponMarkShader ); + lifeTime = Q_irand( 7000, 12000 );//last longer if overridden + } + } + + if ( weaponMarkShader ) + { + centity_t *splatterOnCent = (saberEnt&&client->ps.saberInFlight?&cg_entities[saberEnt->s.number]:&cg_entities[client->ps.clientNum]); + float yawAngle = 0; + vec3_t backDir; + VectorScale( hitDir, -1, backDir ); + if ( !splatterOnCent->gent->client ) + { + yawAngle = splatterOnCent->lerpAngles[YAW]; + } + else + { + yawAngle = splatterOnCent->gent->client->renderInfo.legsYaw; + } + lifeTime = ceil( (float)lifeTime * sizeTimeScale ); + size = Q_flrand( 1.0f, 3.0f ) * sizeTimeScale; + if ( splatterOnCent->gent->ghoul2.size() > saberNum+1 ) + { + CG_AddGhoul2Mark( weaponMarkShader, size, hitPos, backDir, splatterOnCent->currentState.number, + splatterOnCent->lerpOrigin, yawAngle, splatterOnCent->gent->ghoul2, splatterOnCent->currentState.modelScale, + lifeTime, saberNum+1, uaxis/*splashBackDir*/ ); + } + } + } +} static void CG_RGBForSaberColor( saber_colors_t color, vec3_t rgb ) { @@ -5518,19 +5689,49 @@ static void CG_RGBForSaberColor( saber_colors_t color, vec3_t rgb ) static void CG_DoSaberLight( saberInfo_t *saber ) { + int firstBlade = 0; + int lastBlade; //RGB combine all the colors of the sabers you're using into one averaged color! if ( !saber ) { return; } + lastBlade = saber->numBlades - 1; + + if ( (saber->saberFlags2&SFL2_NO_DLIGHT) ) + { + if ( saber->bladeStyle2Start > 0 ) + { + if ( (saber->saberFlags2&SFL2_NO_DLIGHT2) ) + { + return; + } + else + { + firstBlade = saber->bladeStyle2Start; + } + } + else + { + return; + } + } + else if ( saber->bladeStyle2Start > 0 ) + { + if ( (saber->saberFlags2&SFL2_NO_DLIGHT2) ) + { + lastBlade = saber->bladeStyle2Start; + } + } + vec3_t positions[MAX_BLADES*2], mid={0}, rgbs[MAX_BLADES*2], rgb={0}; float lengths[MAX_BLADES*2]={0}, totallength = 0, numpositions = 0, dist, diameter = 0; int i, j; if ( saber ) { - for ( i = 0; i < saber->numBlades; i++ ) + for ( i = firstBlade; i <= lastBlade; i++ ) { if ( saber->blade[i].length >= MIN_SABERBLADE_DRAW_LENGTH ) { @@ -5787,7 +5988,7 @@ static void CG_CreateSaberMarks( vec3_t start, vec3_t end, vec3_t normal ) extern void FX_AddPrimitive( CEffect **effect, int killTime ); //------------------------------------------------------- -void CG_CheckSaberInWater( centity_t *cent, centity_t *scent, int modelIndex, vec3_t origin, vec3_t angles ) +void CG_CheckSaberInWater( centity_t *cent, centity_t *scent, int saberNum, int modelIndex, vec3_t origin, vec3_t angles ) { gclient_s *client = cent->gent->client; if ( !client ) @@ -5802,7 +6003,11 @@ void CG_CheckSaberInWater( centity_t *cent, centity_t *scent, int modelIndex, ve { return; } - + if ( cent && cent->gent && cent->gent->client + && (cent->gent->client->ps.saber[saberNum].saberFlags&SFL_ON_IN_WATER) ) + {//saber can stay on underwater + return; + } if (gi.totalMapContents() & (CONTENTS_WATER|CONTENTS_SLIME)) { vec3_t saberOrg; @@ -5855,6 +6060,7 @@ Ghoul2 Insert Start return; } + /* if ( cent->gent->client->ps.saber[saberNum].type == SABER_CLAW ) {//hack - come off the forearm int fwdAxis = POSITIVE_Y; @@ -5892,6 +6098,7 @@ Ghoul2 Insert Start gi.G2API_GiveMeVectorFromMatrix(boltMatrix, (Eorientations)upAxis, axis_[2]);//up } else + */ { // figure out where the actual model muzzle is @@ -5912,6 +6119,19 @@ Ghoul2 Insert Start bolt = 0; } } + + //if there is an effect on this blade, play it + if ( !WP_SaberBladeUseSecondBladeStyle( ¢->gent->client->ps.saber[saberNum], bladeNum ) + && cent->gent->client->ps.saber[saberNum].bladeEffect ) + { + CG_PlayEffectIDBolted( cent->gent->client->ps.saber[saberNum].bladeEffect, modelIndex, bolt, scent->currentState.clientNum, scent->lerpOrigin, -1, qfalse ); + } + else if ( WP_SaberBladeUseSecondBladeStyle( ¢->gent->client->ps.saber[saberNum], bladeNum ) + && cent->gent->client->ps.saber[saberNum].bladeEffect2 ) + { + CG_PlayEffectIDBolted( cent->gent->client->ps.saber[saberNum].bladeEffect2, modelIndex, bolt, scent->currentState.clientNum, scent->lerpOrigin, -1, qfalse ); + } + //get the boltMatrix gi.G2API_GetBoltMatrix(scent->gent->ghoul2, modelIndex, bolt, &boltMatrix, angles, origin, cg.time, cgs.model_draw, scent->currentState.modelScale); // work the matrix axis stuff into the original axis and origins used. @@ -6232,7 +6452,22 @@ Ghoul2 Insert End { extern vmCvar_t cg_saberEntMarks; int traceMask = MASK_SOLID; + qboolean noMarks = qfalse; + if ( (!WP_SaberBladeUseSecondBladeStyle( ¢->gent->client->ps.saber[saberNum], bladeNum ) + && (cent->gent->client->ps.saber[saberNum].saberFlags2&SFL2_NO_IDLE_EFFECT) ) + || ( WP_SaberBladeUseSecondBladeStyle( ¢->gent->client->ps.saber[saberNum], bladeNum ) + && (cent->gent->client->ps.saber[saberNum].saberFlags2&SFL2_NO_IDLE_EFFECT2) ) + ) + {//do no effects when idle + if ( !cent->gent->client->ps.saberInFlight + && !PM_SaberInAttack( cent->gent->client->ps.saberMove ) + && !PM_SaberInTransitionAny( cent->gent->client->ps.saberMove ) + && !PM_SaberInSpecialAttack( cent->gent->client->ps.torsoAnim ) ) + {//idle, do no marks + noMarks = qtrue; + } + } if ( cg_saberEntMarks.integer ) { if ( cent->gent->client->ps.saberInFlight @@ -6259,92 +6494,104 @@ Ghoul2 Insert End { if ( (trace.contents&CONTENTS_WATER) || (trace.contents&CONTENTS_SLIME) ) { - /* - if ( !(cent->gent->client->ps.saberEventFlags&SEF_INWATER) ) + if ( !noMarks ) { - } - */ - if ( !Q_irand( 0, 10 ) ) - {//FIXME: don't do this this way.... :) + /* + if ( !(cent->gent->client->ps.saberEventFlags&SEF_INWATER) ) + { + } + */ + if ( !Q_irand( 0, 10 ) ) + {//FIXME: don't do this this way.... :) #ifdef _IMMERSION - if ( !cent->gent->client->ps.saberInFlight || saberNum != 0 ) - { - cgi_FF_Start( cgi_FF_Register( "fffx/weapons/saber/hitwater", FF_CHANNEL_WEAPON ), cent->currentState.number ); - } + if ( !cent->gent->client->ps.saberInFlight || saberNum != 0 ) + { + cgi_FF_Start( cgi_FF_Register( "fffx/weapons/saber/hitwater", FF_CHANNEL_WEAPON ), cent->currentState.number ); + } #endif // _IMMERSION - vec3_t spot; - VectorCopy( trace.endpos, spot ); - spot[2] += 4; - if ( Q_irand( 1, client->ps.saber[saberNum].numBlades ) == 1 ) - { - theFxScheduler.PlayEffect( "saber/boil", spot ); - cgi_S_StartSound ( spot, -1, CHAN_AUTO, cgi_S_RegisterSound( "sound/weapons/saber/hitwater.wav" ) ); + vec3_t spot; + VectorCopy( trace.endpos, spot ); + spot[2] += 4; + if ( Q_irand( 1, client->ps.saber[saberNum].numBlades ) == 1 ) + { + theFxScheduler.PlayEffect( "saber/boil", spot ); + cgi_S_StartSound ( spot, -1, CHAN_AUTO, cgi_S_RegisterSound( "sound/weapons/saber/hitwater.wav" ) ); + } } + //cent->gent->client->ps.saberEventFlags |= SEF_INWATER; + //don't do other trace } - //cent->gent->client->ps.saberEventFlags |= SEF_INWATER; - //don't do other trace i = 1; } else { - if ( !(trace.surfaceFlags & SURF_NOIMPACT) // never spark on sky - && (trace.entityNum == ENTITYNUM_WORLD || cg_entities[trace.entityNum].currentState.solid == SOLID_BMODEL) - && Q_irand( 1, client->ps.saber[saberNum].numBlades ) == 1 ) + if ( !noMarks ) { - //was "sparks/spark" - theFxScheduler.PlayEffect( "sparks/spark_nosnd", trace.endpos, trace.plane.normal ); - } - // All I need is a bool to mark whether I have a previous point to work with. - //....come up with something better.. - if ( client->ps.saber[saberNum].blade[bladeNum].trail.haveOldPos[i] ) - { - if ( trace.entityNum == ENTITYNUM_WORLD || (cg_entities[trace.entityNum].currentState.eFlags & EF_PERMANENT) || cg_entities[trace.entityNum].currentState.eType == ET_TERRAIN ) - {//only put marks on architecture - // Let's do some cool burn/glowing mark bits!!! - CG_CreateSaberMarks( client->ps.saber[saberNum].blade[bladeNum].trail.oldPos[i], trace.endpos, trace.plane.normal ); - - if ( Q_irand( 1, client->ps.saber[saberNum].numBlades ) == 1 ) + if ( ( !WP_SaberBladeUseSecondBladeStyle( &client->ps.saber[saberNum], bladeNum ) && !(client->ps.saber[saberNum].saberFlags2&SFL2_NO_WALL_MARKS) ) + || ( WP_SaberBladeUseSecondBladeStyle( &client->ps.saber[saberNum], bladeNum ) && !(client->ps.saber[saberNum].saberFlags2&SFL2_NO_WALL_MARKS2) ) ) + { + if ( !(trace.surfaceFlags & SURF_NOIMPACT) // never spark on sky + && (trace.entityNum == ENTITYNUM_WORLD || cg_entities[trace.entityNum].currentState.solid == SOLID_BMODEL) + && Q_irand( 1, client->ps.saber[saberNum].numBlades ) == 1 ) { - //make a sound - if ( cg.time - cent->gent->client->ps.saberHitWallSoundDebounceTime >= 100 ) - {//ugh, need to have a real sound debouncer... or do this game-side - cent->gent->client->ps.saberHitWallSoundDebounceTime = cg.time; - #ifdef _IMMERSION - int index = Q_irand( 1, 3 ); - cgi_S_StartSound ( cent->lerpOrigin, cent->currentState.clientNum, CHAN_WEAPON, cgi_S_RegisterSound( va ( "sound/weapons/saber/saberhitwall%d.wav", index ) ) ); - if ( !cent->gent->client->ps.saberInFlight || saberNum == 1 ) + //was "sparks/spark" + theFxScheduler.PlayEffect( "sparks/spark_nosnd", trace.endpos, trace.plane.normal ); + } + } + // All I need is a bool to mark whether I have a previous point to work with. + //....come up with something better.. + if ( client->ps.saber[saberNum].blade[bladeNum].trail.haveOldPos[i] ) + { + if ( trace.entityNum == ENTITYNUM_WORLD || (cg_entities[trace.entityNum].currentState.eFlags & EF_PERMANENT) || cg_entities[trace.entityNum].currentState.eType == ET_TERRAIN ) + {//only put marks on architecture + if ( (!WP_SaberBladeUseSecondBladeStyle( &client->ps.saber[saberNum], bladeNum ) && !(client->ps.saber[saberNum].saberFlags2&SFL2_NO_WALL_MARKS)) + || (WP_SaberBladeUseSecondBladeStyle( &client->ps.saber[saberNum], bladeNum ) && !(client->ps.saber[saberNum].saberFlags2&SFL2_NO_WALL_MARKS2)) ) + { + // Let's do some cool burn/glowing mark bits!!! + CG_CreateSaberMarks( client->ps.saber[saberNum].blade[bladeNum].trail.oldPos[i], trace.endpos, trace.plane.normal ); + + if ( Q_irand( 1, client->ps.saber[saberNum].numBlades ) == 1 ) { - cgi_FF_Start( cgi_FF_Register( va( "fffx/weapons/saber/saberhitwall%d", index ), FF_CHANNEL_WEAPON ), cent->currentState.clientNum ); + //make a sound + if ( cg.time - cent->gent->client->ps.saberHitWallSoundDebounceTime >= 100 ) + {//ugh, need to have a real sound debouncer... or do this game-side + cent->gent->client->ps.saberHitWallSoundDebounceTime = cg.time; +#ifdef _IMMERSION + int index = Q_irand( 1, 3 ); + cgi_S_StartSound ( cent->lerpOrigin, cent->currentState.clientNum, CHAN_WEAPON, cgi_S_RegisterSound( va ( "sound/weapons/saber/saberhitwall%d.wav", index ) ) ); + if ( !cent->gent->client->ps.saberInFlight || saberNum == 1 ) + { + cgi_FF_Start( cgi_FF_Register( va( "fffx/weapons/saber/saberhitwall%d", index ), FF_CHANNEL_WEAPON ), cent->currentState.clientNum ); + } +#else + cgi_S_StartSound ( cent->lerpOrigin, cent->currentState.clientNum, CHAN_ITEM, cgi_S_RegisterSound( va ( "sound/weapons/saber/saberhitwall%d.wav", Q_irand( 1, 3 ) ) ) ); +#endif // _IMMERSION + } } - #else - cgi_S_StartSound ( cent->lerpOrigin, cent->currentState.clientNum, CHAN_ITEM, cgi_S_RegisterSound( va ( "sound/weapons/saber/saberhitwall%d.wav", Q_irand( 1, 3 ) ) ) ); - #endif // _IMMERSION } } - } - else if ( !i ) - {//can put marks on G2 clients (but only on base to tip trace) - gentity_t *hitEnt = &g_entities[trace.entityNum]; - if ( hitEnt && hitEnt->client && hitEnt->ghoul2.size() ) - {//burn mark with glow - //FIXME: set the correct angle based on direction of swing - //FIXME: keep a count of these on the ent and don't add too many - int lifeTime = (1.01-(float)(hitEnt->health)/hitEnt->max_health) * (float)Q_irand( 5000, 10000 ); - vec3_t uaxis; + else if ( !i ) + {//can put marks on G2 clients (but only on base to tip trace) + gentity_t *hitEnt = &g_entities[trace.entityNum]; + vec3_t uaxis, splashBackDir; VectorSubtract(client->ps.saber[saberNum].blade[bladeNum].trail.oldPos[i], trace.endpos, uaxis); - CG_AddGhoul2Mark( cgs.media.bdecal_saberglowmark, Q_flrand(3.0, 4.0), trace.endpos, axis_[0], hitEnt->s.number, - hitEnt->client->ps.origin, hitEnt->client->renderInfo.legsYaw, hitEnt->ghoul2, hitEnt->s.modelScale, - lifeTime, uaxis ); + VectorScale( axis_[0], -1, splashBackDir ); + //FIXME: if not hitting the first model on the enemy, don't do this! + CG_SaberDoWeaponHitMarks( client, (scent!=NULL?scent->gent:NULL), hitEnt, saberNum, bladeNum, trace.endpos, axis_[0], uaxis, splashBackDir, 0.25f ); + } + } + else + { + // if we impact next frame, we'll mark a slash mark + client->ps.saber[saberNum].blade[bladeNum].trail.haveOldPos[i] = qtrue; + if ( (!WP_SaberBladeUseSecondBladeStyle( &client->ps.saber[saberNum], bladeNum ) && !(client->ps.saber[saberNum].saberFlags2&SFL2_NO_WALL_MARKS)) + || (WP_SaberBladeUseSecondBladeStyle( &client->ps.saber[saberNum], bladeNum ) && !(client->ps.saber[saberNum].saberFlags2&SFL2_NO_WALL_MARKS2)) ) + { + CG_ImpactMark( cgs.media.rivetMarkShader, client->ps.saber[saberNum].blade[bladeNum].trail.oldPos[i], client->ps.saber[saberNum].blade[bladeNum].trail.oldNormal[i], + 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, qfalse, 1.1f, qfalse ); } } } - else - { - // if we impact next frame, we'll mark a slash mark - client->ps.saber[saberNum].blade[bladeNum].trail.haveOldPos[i] = qtrue; - CG_ImpactMark( cgs.media.rivetMarkShader, client->ps.saber[saberNum].blade[bladeNum].trail.oldPos[i], client->ps.saber[saberNum].blade[bladeNum].trail.oldNormal[i], - 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, qfalse, 1.1f, qfalse ); - } } // stash point so we can connect-the-dots later @@ -6366,11 +6613,18 @@ Ghoul2 Insert End cent->gent->client->ps.saberEventFlags &= ~SEF_INWATER; if ( client->ps.saber[saberNum].blade[bladeNum].trail.haveOldPos[i] ) { - // Hmmm, no impact this frame, but we have an old point - // Let's put the mark there, we should use an endcap mark to close the line, but we - // can probably just get away with a round mark - CG_ImpactMark( cgs.media.rivetMarkShader, client->ps.saber[saberNum].blade[bladeNum].trail.oldPos[i], client->ps.saber[saberNum].blade[bladeNum].trail.oldNormal[i], - 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, qfalse, 1.1f, qfalse ); + if ( !noMarks ) + { + if ( (!WP_SaberBladeUseSecondBladeStyle( &client->ps.saber[saberNum], bladeNum ) && !(client->ps.saber[saberNum].saberFlags2&SFL2_NO_WALL_MARKS)) + || (WP_SaberBladeUseSecondBladeStyle( &client->ps.saber[saberNum], bladeNum ) && !(client->ps.saber[saberNum].saberFlags2&SFL2_NO_WALL_MARKS2)) ) + { + // Hmmm, no impact this frame, but we have an old point + // Let's put the mark there, we should use an endcap mark to close the line, but we + // can probably just get away with a round mark + CG_ImpactMark( cgs.media.rivetMarkShader, client->ps.saber[saberNum].blade[bladeNum].trail.oldPos[i], client->ps.saber[saberNum].blade[bladeNum].trail.oldNormal[i], + 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, qfalse, 1.1f, qfalse ); + } + } } // we aren't impacting, so turn off our mark tracking mechanism @@ -6392,127 +6646,137 @@ Ghoul2 Insert End return; } - saberTrail_t *saberTrail = &client->ps.saber[saberNum].blade[bladeNum].trail; + if ( (!WP_SaberBladeUseSecondBladeStyle( &client->ps.saber[saberNum], bladeNum ) && client->ps.saber[saberNum].trailStyle < 2 ) + || ( WP_SaberBladeUseSecondBladeStyle( &client->ps.saber[saberNum], bladeNum ) && client->ps.saber[saberNum].trailStyle2 < 2 ) ) + {//okay to draw the trail + saberTrail_t *saberTrail = &client->ps.saber[saberNum].blade[bladeNum].trail; #define SABER_TRAIL_TIME 40.0f - // if we happen to be timescaled or running in a high framerate situation, we don't want to flood - // the system with very small trail slices...but perhaps doing it by distance would yield better results? - if ( saberTrail->lastTime > cg.time ) - {//after a pause, cg.time jumps ahead in time for one frame - //and lastTime gets set to that and will freak out, so, since - //it's never valid for saberTrail->lastTime to be > cg.time, - //cap it to cg.time here - saberTrail->lastTime = cg.time; - } - if ( cg.time > saberTrail->lastTime + 2 && saberTrail->inAction ) // 2ms - { - if ( saberTrail->inAction && cg.time < saberTrail->lastTime + 300 ) // if we have a stale segment, don't draw until we have a fresh one + // if we happen to be timescaled or running in a high framerate situation, we don't want to flood + // the system with very small trail slices...but perhaps doing it by distance would yield better results? + if ( saberTrail->lastTime > cg.time ) + {//after a pause, cg.time jumps ahead in time for one frame + //and lastTime gets set to that and will freak out, so, since + //it's never valid for saberTrail->lastTime to be > cg.time, + //cap it to cg.time here + saberTrail->lastTime = cg.time; + } + if ( cg.time > saberTrail->lastTime + 2 && saberTrail->inAction ) // 2ms { - vec3_t rgb1={255,255,255}; - - if ( cent->gent->client->ps.saber[saberNum].type != SABER_SITH_SWORD ) + if ( saberTrail->inAction && cg.time < saberTrail->lastTime + 300 ) // if we have a stale segment, don't draw until we have a fresh one { - switch( client->ps.saber[saberNum].blade[bladeNum].color ) - { - case SABER_RED: - VectorSet( rgb1, 255.0f, 0.0f, 0.0f ); - break; - case SABER_ORANGE: - VectorSet( rgb1, 255.0f, 64.0f, 0.0f ); - break; - case SABER_YELLOW: - VectorSet( rgb1, 255.0f, 255.0f, 0.0f ); - break; - case SABER_GREEN: - VectorSet( rgb1, 0.0f, 255.0f, 0.0f ); - break; - case SABER_BLUE: - VectorSet( rgb1, 0.0f, 64.0f, 255.0f ); - break; - case SABER_PURPLE: - VectorSet( rgb1, 220.0f, 0.0f, 255.0f ); - break; - } - } + vec3_t rgb1={255,255,255}; - float diff = cg.time - saberTrail->lastTime; - - // I'm not sure that clipping this is really the best idea - if ( diff <= SABER_TRAIL_TIME * 2 ) - { - // build a quad - CTrail *fx = new CTrail; - - float duration; - - if ( cent->gent->client->ps.saber[saberNum].type == SABER_SITH_SWORD) + if ( cent->gent->client->ps.saber[saberNum].type != SABER_SITH_SWORD + && ( WP_SaberBladeUseSecondBladeStyle( &client->ps.saber[saberNum], bladeNum ) || client->ps.saber[saberNum].trailStyle != 1 ) + && ( !WP_SaberBladeUseSecondBladeStyle( &client->ps.saber[saberNum], bladeNum ) || client->ps.saber[saberNum].trailStyle2 != 1 ) + ) { - fx->mShader = cgs.media.swordTrailShader; - duration = saberTrail->duration/2.0f; // stay around twice as long - VectorSet( rgb1, 32.0f, 32.0f, 32.0f ); // make the sith sword trail pretty faint - } - else - { - fx->mShader = cgs.media.saberBlurShader; - duration = saberTrail->duration/5.0f; + switch( client->ps.saber[saberNum].blade[bladeNum].color ) + { + case SABER_RED: + VectorSet( rgb1, 255.0f, 0.0f, 0.0f ); + break; + case SABER_ORANGE: + VectorSet( rgb1, 255.0f, 64.0f, 0.0f ); + break; + case SABER_YELLOW: + VectorSet( rgb1, 255.0f, 255.0f, 0.0f ); + break; + case SABER_GREEN: + VectorSet( rgb1, 0.0f, 255.0f, 0.0f ); + break; + case SABER_BLUE: + VectorSet( rgb1, 0.0f, 64.0f, 255.0f ); + break; + case SABER_PURPLE: + VectorSet( rgb1, 220.0f, 0.0f, 255.0f ); + break; + } } - float oldAlpha = 1.0f - ( diff / duration ); + float diff = cg.time - saberTrail->lastTime; - // Go from new muzzle to new end...then to old end...back down to old muzzle...finally - // connect back to the new muzzle...this is our trail quad - VectorCopy( org_, fx->mVerts[0].origin ); - VectorMA( end, 3.0f, axis_[0], fx->mVerts[1].origin ); + // I'm not sure that clipping this is really the best idea + if ( diff <= SABER_TRAIL_TIME * 2 ) + { + // build a quad + CTrail *fx = new CTrail; - VectorCopy( saberTrail->tip, fx->mVerts[2].origin ); - VectorCopy( saberTrail->base, fx->mVerts[3].origin ); + float duration; - // New muzzle - VectorCopy( rgb1, fx->mVerts[0].rgb ); - fx->mVerts[0].alpha = 255.0f; + if ( cent->gent->client->ps.saber[saberNum].type == SABER_SITH_SWORD + || (!WP_SaberBladeUseSecondBladeStyle( &client->ps.saber[saberNum], bladeNum ) && client->ps.saber[saberNum].trailStyle == 1 ) + || ( WP_SaberBladeUseSecondBladeStyle( &client->ps.saber[saberNum], bladeNum ) && client->ps.saber[saberNum].trailStyle2 == 1 ) + ) + { + fx->mShader = cgs.media.swordTrailShader; + duration = saberTrail->duration/2.0f; // stay around twice as long + VectorSet( rgb1, 32.0f, 32.0f, 32.0f ); // make the sith sword trail pretty faint + } + else + { + fx->mShader = cgs.media.saberBlurShader; + duration = saberTrail->duration/5.0f; + } - fx->mVerts[0].ST[0] = 0.0f; - fx->mVerts[0].ST[1] = 0.99f; - fx->mVerts[0].destST[0] = 0.99f; - fx->mVerts[0].destST[1] = 0.99f; + float oldAlpha = 1.0f - ( diff / duration ); - // new tip - VectorCopy( rgb1, fx->mVerts[1].rgb ); - fx->mVerts[1].alpha = 255.0f; - - fx->mVerts[1].ST[0] = 0.0f; - fx->mVerts[1].ST[1] = 0.0f; - fx->mVerts[1].destST[0] = 0.99f; - fx->mVerts[1].destST[1] = 0.0f; + // Go from new muzzle to new end...then to old end...back down to old muzzle...finally + // connect back to the new muzzle...this is our trail quad + VectorCopy( org_, fx->mVerts[0].origin ); + VectorMA( end, 3.0f, axis_[0], fx->mVerts[1].origin ); - // old tip - VectorCopy( rgb1, fx->mVerts[2].rgb ); - fx->mVerts[2].alpha = 255.0f; + VectorCopy( saberTrail->tip, fx->mVerts[2].origin ); + VectorCopy( saberTrail->base, fx->mVerts[3].origin ); - fx->mVerts[2].ST[0] = 0.99f - oldAlpha; // NOTE: this just happens to contain the value I want - fx->mVerts[2].ST[1] = 0.0f; - fx->mVerts[2].destST[0] = 0.99f + fx->mVerts[2].ST[0]; - fx->mVerts[2].destST[1] = 0.0f; + // New muzzle + VectorCopy( rgb1, fx->mVerts[0].rgb ); + fx->mVerts[0].alpha = 255.0f; - // old muzzle - VectorCopy( rgb1, fx->mVerts[3].rgb ); - fx->mVerts[3].alpha = 255.0f; + fx->mVerts[0].ST[0] = 0.0f; + fx->mVerts[0].ST[1] = 0.99f; + fx->mVerts[0].destST[0] = 0.99f; + fx->mVerts[0].destST[1] = 0.99f; - fx->mVerts[3].ST[0] = 0.99f - oldAlpha; // NOTE: this just happens to contain the value I want - fx->mVerts[3].ST[1] = 0.99f; - fx->mVerts[3].destST[0] = 0.99f + fx->mVerts[2].ST[0]; - fx->mVerts[3].destST[1] = 0.99f; - -// fx->SetFlags( FX_USE_ALPHA ); - FX_AddPrimitive( (CEffect**)&fx, duration );//SABER_TRAIL_TIME ); - } - } + // new tip + VectorCopy( rgb1, fx->mVerts[1].rgb ); + fx->mVerts[1].alpha = 255.0f; + + fx->mVerts[1].ST[0] = 0.0f; + fx->mVerts[1].ST[1] = 0.0f; + fx->mVerts[1].destST[0] = 0.99f; + fx->mVerts[1].destST[1] = 0.0f; - // we must always do this, even if we aren't active..otherwise we won't know where to pick up from - VectorCopy( org_, saberTrail->base ); - VectorMA( end, 3.0f, axis_[0], saberTrail->tip ); - saberTrail->lastTime = cg.time; + // old tip + VectorCopy( rgb1, fx->mVerts[2].rgb ); + fx->mVerts[2].alpha = 255.0f; + + fx->mVerts[2].ST[0] = 0.99f - oldAlpha; // NOTE: this just happens to contain the value I want + fx->mVerts[2].ST[1] = 0.0f; + fx->mVerts[2].destST[0] = 0.99f + fx->mVerts[2].ST[0]; + fx->mVerts[2].destST[1] = 0.0f; + + // old muzzle + VectorCopy( rgb1, fx->mVerts[3].rgb ); + fx->mVerts[3].alpha = 255.0f; + + fx->mVerts[3].ST[0] = 0.99f - oldAlpha; // NOTE: this just happens to contain the value I want + fx->mVerts[3].ST[1] = 0.99f; + fx->mVerts[3].destST[0] = 0.99f + fx->mVerts[2].ST[0]; + fx->mVerts[3].destST[1] = 0.99f; + + // fx->SetFlags( FX_USE_ALPHA ); + FX_AddPrimitive( (CEffect**)&fx, duration );//SABER_TRAIL_TIME ); + } + } + + // we must always do this, even if we aren't active..otherwise we won't know where to pick up from + VectorCopy( org_, saberTrail->base ); + VectorMA( end, 3.0f, axis_[0], saberTrail->tip ); + saberTrail->lastTime = cg.time; + } } if ( cent->gent->client->ps.saber[saberNum].type == SABER_SITH_SWORD) @@ -6521,9 +6785,27 @@ Ghoul2 Insert End return; } + qboolean noDlight = qfalse; + if ( client->ps.saber[saberNum].numBlades >= 3 + || (!WP_SaberBladeUseSecondBladeStyle( &client->ps.saber[saberNum], bladeNum ) && (client->ps.saber[saberNum].saberFlags2&SFL2_NO_DLIGHT) ) + || ( WP_SaberBladeUseSecondBladeStyle( &client->ps.saber[saberNum], bladeNum ) && (client->ps.saber[saberNum].saberFlags2&SFL2_NO_DLIGHT2) ) + ) + { + noDlight = qtrue; + } + + if ( (!WP_SaberBladeUseSecondBladeStyle( &client->ps.saber[saberNum], bladeNum ) && (client->ps.saber[saberNum].saberFlags2&SFL2_NO_BLADE) ) + || ( WP_SaberBladeUseSecondBladeStyle( &client->ps.saber[saberNum], bladeNum ) && (client->ps.saber[saberNum].saberFlags2&SFL2_NO_BLADE2) ) ) + {//don't draw a blade + if ( !noDlight ) + {//but still do dlight + CG_DoSaberLight( &client->ps.saber[saberNum] ); + } + return; + } // Pass in the renderfx flags attached to the saber weapon model...this is done so that saber glows // will get rendered properly in a mirror...not sure if this is necessary?? - CG_DoSaber( org_, axis_[0], length, client->ps.saber[saberNum].blade[bladeNum].lengthMax, client->ps.saber[saberNum].blade[bladeNum].radius, client->ps.saber[saberNum].blade[bladeNum].color, renderfx, (qboolean)(client->ps.saber[saberNum].numBlades<3) ); + CG_DoSaber( org_, axis_[0], length, client->ps.saber[saberNum].blade[bladeNum].lengthMax, client->ps.saber[saberNum].blade[bladeNum].radius, client->ps.saber[saberNum].blade[bladeNum].color, renderfx, (noDlight==qfalse) ); } void CG_AddSaberBlade( centity_t *cent, centity_t *scent, refEntity_t *saber, int renderfx, int modelIndex, vec3_t origin, vec3_t angles ) @@ -7230,7 +7512,7 @@ extern vmCvar_t cg_thirdPersonAlpha; } //if ( cent->gent->client->ps.saberEventFlags&SEF_INWATER ) { - CG_CheckSaberInWater( cent, cent, cent->gent->weaponModel[saberNum], ent.origin, tempAngles ); + CG_CheckSaberInWater( cent, cent, saberNum, cent->gent->weaponModel[saberNum], ent.origin, tempAngles ); } } if ( cent->currentState.weapon == WP_SABER @@ -8050,7 +8332,7 @@ Ghoul2 Insert End { //if ( cent->gent->client->ps.saberEventFlags&SEF_INWATER ) { - CG_CheckSaberInWater( cent, cent, 0, NULL, NULL ); + CG_CheckSaberInWater( cent, cent, 0, 0, NULL, NULL ); } } } diff --git a/code/cgame/cg_weapons.cpp b/code/cgame/cg_weapons.cpp index 6b36a94..8b7d87a 100644 --- a/code/cgame/cg_weapons.cpp +++ b/code/cgame/cg_weapons.cpp @@ -242,9 +242,10 @@ void CG_RegisterWeapon( int weaponNum ) { theFxScheduler.RegisterEffect( "force/force_touch" ); theFxScheduler.RegisterEffect( "saber/saber_block" ); theFxScheduler.RegisterEffect( "saber/saber_cut" ); - theFxScheduler.RegisterEffect( "blaster/smoke_bolton" ); + theFxScheduler.RegisterEffect( "saber/limb_bolton" ); theFxScheduler.RegisterEffect( "saber/fizz" ); theFxScheduler.RegisterEffect( "saber/boil" ); + theFxScheduler.RegisterEffect( "saber/fire" );//was "sparks/spark" cgs.effects.forceHeal = theFxScheduler.RegisterEffect( "force/heal" ); //cgs.effects.forceInvincibility = theFxScheduler.RegisterEffect( "force/invin" ); @@ -2609,11 +2610,6 @@ void CG_Weapon_f( void ) return; } - if (!CG_WeaponSelectable(num, cg.snap->ps.weapon, qfalse)) - { - return; - } - if ( num == WP_SABER ) {//lightsaber if ( ! ( cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << num ) ) ) @@ -2700,8 +2696,9 @@ void CG_Weapon_f( void ) } } - if ( ! ( cg.snap->ps.stats[STAT_WEAPONS] & ( 1 << num ) ) ) { - return; // don't have the weapon + if (!CG_WeaponSelectable(num, cg.snap->ps.weapon, qfalse)) + { + return; } SetWeaponSelectTime(); diff --git a/code/cgame/vssver.scc b/code/cgame/vssver.scc index f161c9e..5be511a 100644 Binary files a/code/cgame/vssver.scc and b/code/cgame/vssver.scc differ diff --git a/code/client/OpenAL/vssver.scc b/code/client/OpenAL/vssver.scc index ad643b9..ab392e3 100644 Binary files a/code/client/OpenAL/vssver.scc and b/code/client/OpenAL/vssver.scc differ diff --git a/code/client/cl_input.cpp b/code/client/cl_input.cpp index 57bdec4..b17b227 100644 --- a/code/client/cl_input.cpp +++ b/code/client/cl_input.cpp @@ -1079,6 +1079,8 @@ void CL_InitInput( void ) { Cmd_AddCommand ("-altattack", IN_Button7Up); Cmd_AddCommand ("+forcefocus", IN_Button8Down);//special saber attacks Cmd_AddCommand ("-forcefocus", IN_Button8Up); + Cmd_AddCommand ("+block", IN_Button8Down);//manual blocking + Cmd_AddCommand ("-block", IN_Button8Up); //end buttons Cmd_AddCommand ("+mlook", IN_MLookDown); Cmd_AddCommand ("-mlook", IN_MLookUp); diff --git a/code/client/cl_main.cpp b/code/client/cl_main.cpp index 1de19da..62e1ec3 100644 --- a/code/client/cl_main.cpp +++ b/code/client/cl_main.cpp @@ -1269,9 +1269,9 @@ void CL_Init( void ) { Cvar_Get ("name", "Jaden", CVAR_USERINFO | CVAR_ARCHIVE ); Cvar_Get ("snaps", "20", CVAR_USERINFO | CVAR_ARCHIVE ); - Cvar_Get ("sex", "f", CVAR_USERINFO | CVAR_ARCHIVE | CVAR_SAVEGAME ); + Cvar_Get ("sex", "f", CVAR_USERINFO | CVAR_ARCHIVE | CVAR_SAVEGAME | CVAR_NORESTART ); Cvar_Get ("snd", "jaden_fmle", CVAR_USERINFO | CVAR_ARCHIVE | CVAR_SAVEGAME | CVAR_NORESTART );//UI_SetSexandSoundForModel changes to match sounds.cfg for model - Cvar_Get ("handicap", "100", CVAR_USERINFO | CVAR_ARCHIVE | CVAR_SAVEGAME ); + Cvar_Get ("handicap", "100", CVAR_USERINFO | CVAR_SAVEGAME | CVAR_NORESTART); // // register our commands diff --git a/code/client/eax/vssver.scc b/code/client/eax/vssver.scc index aab29e7..67b2a05 100644 Binary files a/code/client/eax/vssver.scc and b/code/client/eax/vssver.scc differ diff --git a/code/client/snd_dma.cpp b/code/client/snd_dma.cpp index 2975307..c009f91 100644 --- a/code/client/snd_dma.cpp +++ b/code/client/snd_dma.cpp @@ -531,6 +531,20 @@ void S_Init( void ) { // Sources / Channels are not sending to any Slots (other than the Listener / Primary FX Slot) s_channels[i].lSlotID = -1; + if (s_bEAX) + { + // Remove the RoomAuto flag from each Source (to remove Reverb Engine Statistical + // model that is assuming units are in metres) + // Without this call reverb sends from the sources will attenuate too quickly + // with distance, especially for the non-primary reverb zones. + + unsigned long ulFlags = 0; + + if (s_eaxSet(&EAXPROPERTYID_EAX40_Source, EAXSOURCE_FLAGS, + s_channels[i].alSource, &ulFlags, sizeof(ulFlags))!=AL_NO_ERROR) + OutputDebugString("Failed to to remove Source flags\n"); + } + s_numChannels++; } @@ -6110,21 +6124,11 @@ static void UpdateEAXListener() } } + lVolume = 0; for (i = 0; i < s_NumFXSlots; i++) { - if (s_FXSlotInfo[i].lEnvID == s_EnvironmentID) - { - lVolume = 0; - if (s_eaxSet(&s_FXSlotInfo[i].FXSlotGuid, EAXFXSLOT_VOLUME, NULL, &lVolume, sizeof(long))!=AL_NO_ERROR) - OutputDebugString("Failed to set Listener's FX Slot Volume to 0\n"); - } - else - { - // This will change to lower the volume based on distance from aperture ... - lVolume = -600; - if (s_eaxSet(&s_FXSlotInfo[i].FXSlotGuid, EAXFXSLOT_VOLUME, NULL, &lVolume, sizeof(long))!=AL_NO_ERROR) - OutputDebugString("Failed to set FX Slot Volume to 0\n"); - } + if (s_eaxSet(&s_FXSlotInfo[i].FXSlotGuid, EAXFXSLOT_VOLUME, NULL, &lVolume, sizeof(long))!=AL_NO_ERROR) + OutputDebugString("Failed to set FX Slot Volume to 0\n"); } } diff --git a/code/client/vssver.scc b/code/client/vssver.scc index a1696a0..445e561 100644 Binary files a/code/client/vssver.scc and b/code/client/vssver.scc differ diff --git a/code/ff/IFC/vssver.scc b/code/ff/IFC/vssver.scc index 00bae12..bad959c 100644 Binary files a/code/ff/IFC/vssver.scc and b/code/ff/IFC/vssver.scc differ diff --git a/code/ff/cl_ff.cpp b/code/ff/cl_ff.cpp index 6becc34..6eadb64 100644 --- a/code/ff/cl_ff.cpp +++ b/code/ff/cl_ff.cpp @@ -11,7 +11,7 @@ extern clientActive_t cl; void CL_InitFF( void ) { - cvar_t *use_ff = Cvar_Get( "use_ff", "1", CVAR_ARCHIVE ); + cvar_t *use_ff = Cvar_Get( "use_ff", "0", CVAR_ARCHIVE ); if (!use_ff || !use_ff->integer diff --git a/code/ff/ff.cpp b/code/ff/ff.cpp index fefab0a..e672df6 100644 --- a/code/ff/ff.cpp +++ b/code/ff/ff.cpp @@ -113,7 +113,7 @@ qboolean FF_Init( void ) Cmd_AddCommand( "ff_stopall", CMD_FF_StopAll ); Cmd_AddCommand( "ff_info", CMD_FF_Info ); #endif - use_ff = Cvar_Get( "use_ff", "1", CVAR_ARCHIVE /*| CVAR_LATCH*/); + use_ff = Cvar_Get( "use_ff", "0", CVAR_ARCHIVE /*| CVAR_LATCH*/); ensureShake = Cvar_Get( "ff_ensureShake", "1", CVAR_TEMP); ff_developer = Cvar_Get( "ff_developer", "0", CVAR_TEMP); ff_channels = Cvar_Get( "ff_channels", FF_CHANNEL, CVAR_ARCHIVE); diff --git a/code/ff/vssver.scc b/code/ff/vssver.scc index 5fadef8..4a498e4 100644 Binary files a/code/ff/vssver.scc and b/code/ff/vssver.scc differ diff --git a/code/game/AI_BobaFett.cpp b/code/game/AI_BobaFett.cpp index b462a5e..443a0a2 100644 --- a/code/game/AI_BobaFett.cpp +++ b/code/game/AI_BobaFett.cpp @@ -345,7 +345,7 @@ qboolean Boba_StopKnockdown( gentity_t *self, gentity_t *pusher, const vec3_t pu //////////////////////////////////////////////////////////////////////////////////////// qboolean Boba_Flying( gentity_t *self ) { - assert(self && self->NPC && self->client && self->client->NPC_class==CLASS_BOBAFETT); + assert(self && self->client && self->client->NPC_class==CLASS_BOBAFETT);//self->NPC && return ((qboolean)(self->client->moveType==MT_FLYSWIM)); } @@ -482,6 +482,12 @@ void Boba_FireFlameThrower( gentity_t *self ) //////////////////////////////////////////////////////////////////////////////////////// void Boba_StopFlameThrower( gentity_t *self ) { + if ( self->s.number < MAX_CLIENTS ) + { + self->client->ps.torsoAnimTimer = 0; + G_StopEffect( G_EffectIndex("boba/fthrw"), self->playerModel, self->genericBolt3, self->s.number); + return; + } if ((NPCInfo->aiFlags&NPCAI_FLAMETHROW)) { self->NPC->aiFlags &= ~NPCAI_FLAMETHROW; @@ -527,6 +533,22 @@ void Boba_StartFlameThrower( gentity_t *self ) //////////////////////////////////////////////////////////////////////////////////////// void Boba_DoFlameThrower( gentity_t *self ) { + if ( self->s.number < MAX_CLIENTS ) + { + if ( self->client ) + { + if ( !self->client->ps.forcePowerDuration[FP_LIGHTNING] ) + { + NPC_SetAnim( self, SETANIM_TORSO, BOTH_FORCELIGHTNING_HOLD, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + self->client->ps.torsoAnimTimer = BOBA_FLAMEDURATION; + G_SoundOnEnt( self, CHAN_WEAPON, "sound/weapons/boba/bf_flame.mp3" ); + G_PlayEffect( G_EffectIndex("boba/fthrw"), self->playerModel, self->genericBolt3, self->s.number, self->s.origin, 1 ); + self->client->ps.forcePowerDuration[FP_LIGHTNING] = 1; + } + Boba_FireFlameThrower( self ); + } + return; + } if (!(NPCInfo->aiFlags&NPCAI_FLAMETHROW) && TIMER_Done(self, "nextAttackDelay")) { Boba_StartFlameThrower( self ); diff --git a/code/game/AI_Jedi.cpp b/code/game/AI_Jedi.cpp index ec59a0b..b7eccd2 100644 --- a/code/game/AI_Jedi.cpp +++ b/code/game/AI_Jedi.cpp @@ -1258,6 +1258,18 @@ static qboolean Jedi_DecideKick( void ) {//just did one return qfalse; } + if ( NPC->client->ps.weapon == WP_SABER ) + { + if ( (NPC->client->ps.saber[0].saberFlags&SFL_NO_KICKS) ) + { + return qfalse; + } + else if ( NPC->client->ps.dualSabers + && (NPC->client->ps.saber[1].saberFlags&SFL_NO_KICKS) ) + { + return qfalse; + } + } //go for it! return qtrue; } @@ -2373,6 +2385,20 @@ evasionType_t Jedi_CheckFlipEvasions( gentity_t *self, float rightdot, float zdi int parts = SETANIM_BOTH, anim; float speed, checkDist; + qboolean allowCartWheels = qtrue; + + if ( self->client->ps.weapon == WP_SABER ) + { + if ( (self->client->ps.saber[0].saberFlags&SFL_NO_CARTWHEELS) ) + { + allowCartWheels = qfalse; + } + else if ( self->client->ps.dualSabers + && (self->client->ps.saber[1].saberFlags&SFL_NO_CARTWHEELS) ) + { + allowCartWheels = qfalse; + } + } if ( PM_SaberInAttack( self->client->ps.saberMove ) || PM_SaberInStart( self->client->ps.saberMove ) ) @@ -2408,7 +2434,7 @@ evasionType_t Jedi_CheckFlipEvasions( gentity_t *self, float rightdot, float zdi //trace in the dir that we want to go VectorMA( self->currentOrigin, checkDist, right, traceto ); gi.trace( &trace, self->currentOrigin, mins, maxs, traceto, self->s.number, CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP ); - if ( trace.fraction >= 1.0f ) + if ( trace.fraction >= 1.0f && allowCartWheels ) {//it's clear, let's do it //FIXME: check for drops? NPC_SetAnim( self, parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); @@ -2459,40 +2485,56 @@ evasionType_t Jedi_CheckFlipEvasions( gentity_t *self, float rightdot, float zdi gi.trace( &trace, self->currentOrigin, mins, maxs, traceto, self->s.number, CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP ); if ( trace.fraction >= 1.0f ) {//it's clear, let's do it - //FIXME: check for drops? - //turn the cartwheel into a wallflip in the other dir - if ( rightdot > 0 ) + qboolean allowWallFlips = qtrue; + if ( self->client->ps.weapon == WP_SABER ) { - anim = BOTH_WALL_FLIP_LEFT; - self->client->ps.velocity[0] = self->client->ps.velocity[1] = 0; - VectorMA( self->client->ps.velocity, 150, right, self->client->ps.velocity ); + if ( (self->client->ps.saber[0].saberFlags&SFL_NO_WALL_FLIPS) ) + { + allowWallFlips = qfalse; + } + else if ( self->client->ps.dualSabers + && (self->client->ps.saber[1].saberFlags&SFL_NO_WALL_FLIPS) ) + { + allowWallFlips = qfalse; + } } - else - { - anim = BOTH_WALL_FLIP_RIGHT; - self->client->ps.velocity[0] = self->client->ps.velocity[1] = 0; - VectorMA( self->client->ps.velocity, -150, right, self->client->ps.velocity ); + if ( allowWallFlips ) + {//okay to do wall-flips with this saber + //FIXME: check for drops? + //turn the cartwheel into a wallflip in the other dir + if ( rightdot > 0 ) + { + anim = BOTH_WALL_FLIP_LEFT; + self->client->ps.velocity[0] = self->client->ps.velocity[1] = 0; + VectorMA( self->client->ps.velocity, 150, right, self->client->ps.velocity ); + } + else + { + anim = BOTH_WALL_FLIP_RIGHT; + self->client->ps.velocity[0] = self->client->ps.velocity[1] = 0; + VectorMA( self->client->ps.velocity, -150, right, self->client->ps.velocity ); + } + self->client->ps.velocity[2] = forceJumpStrength[FORCE_LEVEL_2]/2.25f; + //animate me + int parts = SETANIM_LEGS; + if ( !self->client->ps.weaponTime ) + { + parts = SETANIM_BOTH; + } + NPC_SetAnim( self, parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + self->client->ps.forceJumpZStart = self->currentOrigin[2];//so we don't take damage if we land at same height + self->client->ps.pm_flags |= (PMF_JUMPING|PMF_SLOW_MO_FALL); + if ( self->client->NPC_class == CLASS_BOBAFETT + || (self->client->NPC_class == CLASS_REBORN && self->s.weapon != WP_SABER)) + { + G_AddEvent( self, EV_JUMP, 0 ); + } + else + { + G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/jump.wav" ); + } + return EVASION_OTHER; } - self->client->ps.velocity[2] = forceJumpStrength[FORCE_LEVEL_2]/2.25f; - //animate me - int parts = SETANIM_LEGS; - if ( !self->client->ps.weaponTime ) - { - parts = SETANIM_BOTH; - } - NPC_SetAnim( self, parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); - self->client->ps.forceJumpZStart = self->currentOrigin[2];//so we don't take damage if we land at same height - self->client->ps.pm_flags |= (PMF_JUMPING|PMF_SLOW_MO_FALL); - if ( self->client->NPC_class == CLASS_BOBAFETT - || (self->client->NPC_class == CLASS_REBORN && self->s.weapon != WP_SABER)) - { - G_AddEvent( self, EV_JUMP, 0 ); - } - else - { - G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/jump.wav" ); - } - return EVASION_OTHER; } else {//boxed in on both sides @@ -2525,35 +2567,51 @@ evasionType_t Jedi_CheckFlipEvasions( gentity_t *self, float rightdot, float zdi //Try wall run? if ( bestCheckDist ) {//one of the walls was close enough to wall-run on - //FIXME: check for long enough wall and a drop at the end? - if ( bestCheckDist > 0 ) - {//it was to the right - anim = BOTH_WALL_RUN_RIGHT; - } - else - {//it was to the left - anim = BOTH_WALL_RUN_LEFT; - } - self->client->ps.velocity[2] = forceJumpStrength[FORCE_LEVEL_2]/2.25f; - //animate me - int parts = SETANIM_LEGS; - if ( !self->client->ps.weaponTime ) + qboolean allowWallRuns = qtrue; + if ( self->client->ps.weapon == WP_SABER ) { - parts = SETANIM_BOTH; + if ( (self->client->ps.saber[0].saberFlags&SFL_NO_WALL_RUNS) ) + { + allowWallRuns = qfalse; + } + else if ( self->client->ps.dualSabers + && (self->client->ps.saber[1].saberFlags&SFL_NO_WALL_RUNS) ) + { + allowWallRuns = qfalse; + } } - NPC_SetAnim( self, parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); - self->client->ps.forceJumpZStart = self->currentOrigin[2];//so we don't take damage if we land at same height - self->client->ps.pm_flags |= (PMF_JUMPING|PMF_SLOW_MO_FALL); - if ( self->client->NPC_class == CLASS_BOBAFETT - || (self->client->NPC_class == CLASS_REBORN && self->s.weapon != WP_SABER)) - { - G_AddEvent( self, EV_JUMP, 0 ); + if ( allowWallRuns ) + {//okay to do wallruns with this saber + //FIXME: check for long enough wall and a drop at the end? + if ( bestCheckDist > 0 ) + {//it was to the right + anim = BOTH_WALL_RUN_RIGHT; + } + else + {//it was to the left + anim = BOTH_WALL_RUN_LEFT; + } + self->client->ps.velocity[2] = forceJumpStrength[FORCE_LEVEL_2]/2.25f; + //animate me + int parts = SETANIM_LEGS; + if ( !self->client->ps.weaponTime ) + { + parts = SETANIM_BOTH; + } + NPC_SetAnim( self, parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + self->client->ps.forceJumpZStart = self->currentOrigin[2];//so we don't take damage if we land at same height + self->client->ps.pm_flags |= (PMF_JUMPING|PMF_SLOW_MO_FALL); + if ( self->client->NPC_class == CLASS_BOBAFETT + || (self->client->NPC_class == CLASS_REBORN && self->s.weapon != WP_SABER)) + { + G_AddEvent( self, EV_JUMP, 0 ); + } + else + { + G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/jump.wav" ); + } + return EVASION_OTHER; } - else - { - G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/jump.wav" ); - } - return EVASION_OTHER; } //else check for wall in front, do backflip off wall } diff --git a/code/game/AI_Rancor.cpp b/code/game/AI_Rancor.cpp index fea3c4f..075ee2e 100644 --- a/code/game/AI_Rancor.cpp +++ b/code/game/AI_Rancor.cpp @@ -715,9 +715,9 @@ void Rancor_Bite( void ) if ( !Q_irand( 0, 1 ) ) {//bite something off int hitLoc = HL_WAIST; - if ( g_dismemberment->integer != 113811381138 ) + if ( g_dismemberment->integer < 3 ) { - hitLoc = Q_irand( HL_WAIST, HL_HAND_LT ); + hitLoc = Q_irand( HL_BACK_RT, HL_HAND_LT ); } else { @@ -961,7 +961,7 @@ void Rancor_Attack( float distance, qboolean doCharge, qboolean aimAtBlockedEnti } if ( NPC->activator->health <= 0 ) {//killed him - if ( g_dismemberment->integer == 113811381138 ) + if ( g_dismemberment->integer >= 3 ) {//make it look like we bit his head off NPC->activator->client->dismembered = false; G_DoDismemberment( NPC->activator, NPC->activator->currentOrigin, MOD_SABER, 1000, HL_HEAD, qtrue ); diff --git a/code/game/AI_Wampa.cpp b/code/game/AI_Wampa.cpp index 1c2b1a1..eab70de 100644 --- a/code/game/AI_Wampa.cpp +++ b/code/game/AI_Wampa.cpp @@ -224,9 +224,9 @@ void Wampa_Slash( int boltIndex, qboolean backhand ) if ( !Q_irand( 0, 1 ) ) {//bite something off int hitLoc = HL_WAIST; - if ( g_dismemberment->integer != 113811381138 ) + if ( g_dismemberment->integer < 4 ) { - hitLoc = Q_irand( HL_WAIST, HL_HAND_LT ); + hitLoc = Q_irand( HL_BACK_RT, HL_HAND_LT ); } else { @@ -763,9 +763,9 @@ void NPC_BSWampa_Default( void ) if ( NPC->activator->health <= 0 ) {//killed them, chance of dismembering int hitLoc = HL_WAIST; - if ( g_dismemberment->integer != 113811381138 ) + if ( g_dismemberment->integer < 4 ) { - hitLoc = Q_irand( HL_WAIST, HL_HAND_LT ); + hitLoc = Q_irand( HL_BACK_RT, HL_HAND_LT ); } else { diff --git a/code/game/NPC.cpp b/code/game/NPC.cpp index a51a1f2..29be6be 100644 --- a/code/game/NPC.cpp +++ b/code/game/NPC.cpp @@ -44,6 +44,7 @@ extern qboolean PM_LockedAnim( int anim ); extern cvar_t *g_dismemberment; extern cvar_t *g_saberRealisticCombat; extern cvar_t *g_corpseRemovalTime; +extern cvar_t *debug_subdivision; //Local Variables // ai debug cvars @@ -93,7 +94,7 @@ void CorpsePhysics( gentity_t *self ) if ( level.time - self->s.time > 3000 ) {//been dead for 3 seconds - if ( g_dismemberment->integer != 113811381138 && !g_saberRealisticCombat->integer ) + if ( !debug_subdivision->integer && !g_saberRealisticCombat->integer ) {//can't be dismembered once dead if ( self->client->NPC_class != CLASS_PROTOCOL ) { @@ -463,7 +464,7 @@ and returns. ==================================================================== */ -void pitch_roll_for_slope( gentity_t *forwhom, vec3_t pass_slope, vec3_t storeAngles ) +void pitch_roll_for_slope( gentity_t *forwhom, vec3_t pass_slope, vec3_t storeAngles, qboolean keepPitch ) { vec3_t slope; vec3_t nvf, ovf, ovr, startspot, endspot, new_angles = { 0, 0, 0 }; @@ -498,6 +499,7 @@ void pitch_roll_for_slope( gentity_t *forwhom, vec3_t pass_slope, vec3_t storeAn VectorCopy( pass_slope, slope ); } + float oldPitch = 0; if ( forwhom->client && forwhom->client->NPC_class == CLASS_VEHICLE ) {//special code for vehicles Vehicle_t *pVeh = forwhom->m_pVehicle; @@ -509,11 +511,16 @@ void pitch_roll_for_slope( gentity_t *forwhom, vec3_t pass_slope, vec3_t storeAn } else { + oldPitch = forwhom->currentAngles[PITCH]; AngleVectors( forwhom->currentAngles, ovf, ovr, NULL ); } vectoangles( slope, new_angles ); pitch = new_angles[PITCH] + 90; + if ( keepPitch ) + { + pitch += oldPitch; + } new_angles[ROLL] = new_angles[PITCH] = 0; AngleVectors( new_angles, nvf, NULL, NULL ); diff --git a/code/game/NPC_stats.cpp b/code/game/NPC_stats.cpp index 47e8c2e..9abbe27 100644 --- a/code/game/NPC_stats.cpp +++ b/code/game/NPC_stats.cpp @@ -36,6 +36,8 @@ stringID_table_t animEventTypeTable[] = ENUM2STRING(AEV_FIRE), //# animID AEV_FIRE framenum altfire chancetofire ENUM2STRING(AEV_MOVE), //# animID AEV_MOVE framenum forwardpush rightpush uppush ENUM2STRING(AEV_SOUNDCHAN), //# animID AEV_SOUNDCHAN framenum CHANNEL soundpath randomlow randomhi chancetoplay + ENUM2STRING(AEV_SABER_SWING), //# animID AEV_SABER_SWING framenum CHANNEL randomlow randomhi chancetoplay + ENUM2STRING(AEV_SABER_SPIN), //# animID AEV_SABER_SPIN framenum CHANNEL chancetoplay //must be terminated NULL,-1 }; @@ -600,6 +602,56 @@ static void ParseAnimationEvtBlock(int glaIndex, unsigned short modelIndex, cons break; } animEvents[curAnimEvent].eventData[AED_SOUND_PROBABILITY] = atoi( token ); + + //last part - cheat and check and see if it's a special overridable saber sound we know of... + if ( !Q_stricmpn( "sound/weapons/saber/saberhup", stringData, 28 ) ) + {//a saber swing + animEvents[curAnimEvent].eventType = AEV_SABER_SWING; + animEvents[curAnimEvent].eventData[AED_SABER_SWING_SABERNUM] = 0;//since we don't know which one they meant if we're hacking this, always use first saber + animEvents[curAnimEvent].eventData[AED_SABER_SWING_PROBABILITY] = animEvents[curAnimEvent].eventData[AED_SOUND_PROBABILITY]; + if ( lowestVal < 4 ) + {//fast swing + animEvents[curAnimEvent].eventData[AED_SABER_SWING_TYPE] = SWING_FAST; + } + else if ( lowestVal < 7 ) + {//medium swing + animEvents[curAnimEvent].eventData[AED_SABER_SWING_TYPE] = SWING_MEDIUM; + } + else + {//strong swing + animEvents[curAnimEvent].eventData[AED_SABER_SWING_TYPE] = SWING_STRONG; + } + } + else if ( !Q_stricmpn( "sound/weapons/saber/saberspin", stringData, 29 ) ) + {//a saber spin + animEvents[curAnimEvent].eventType = AEV_SABER_SPIN; + animEvents[curAnimEvent].eventData[AED_SABER_SPIN_SABERNUM] = 0;//since we don't know which one they meant if we're hacking this, always use first saber + animEvents[curAnimEvent].eventData[AED_SABER_SPIN_PROBABILITY] = animEvents[curAnimEvent].eventData[AED_SOUND_PROBABILITY]; + if ( stringData[29] == 'o' ) + {//saberspinoff + animEvents[curAnimEvent].eventData[AED_SABER_SPIN_TYPE] = 0; + } + else if ( stringData[29] == '1' ) + {//saberspin1 + animEvents[curAnimEvent].eventData[AED_SABER_SPIN_TYPE] = 2; + } + else if ( stringData[29] == '2' ) + {//saberspin2 + animEvents[curAnimEvent].eventData[AED_SABER_SPIN_TYPE] = 3; + } + else if ( stringData[29] == '3' ) + {//saberspin3 + animEvents[curAnimEvent].eventData[AED_SABER_SPIN_TYPE] = 4; + } + else if ( stringData[29] == '%' ) + {//saberspin%d + animEvents[curAnimEvent].eventData[AED_SABER_SPIN_TYPE] = 5; + } + else + {//just plain saberspin + animEvents[curAnimEvent].eventData[AED_SABER_SPIN_TYPE] = 1; + } + } break; case AEV_FOOTSTEP: //# animID AEV_FOOTSTEP framenum footstepType //get footstep type @@ -1509,7 +1561,7 @@ void NPC_Precache ( char *NPCName ) Precaches NPC skins, tgas and md3s. */ -void NPC_Precache ( gentity_t *spawner ) +void CG_NPC_Precache ( gentity_t *spawner ) { clientInfo_t ci={0}; renderInfo_t ri={0}; @@ -1771,6 +1823,22 @@ void NPC_Precache ( gentity_t *spawner ) gi.RE_RegisterSkin( saber.skin ); G_SkinIndex( saber.skin ); } + if ( saber.g2MarksShader[0] ) + { + cgi_R_RegisterShader( saber.g2MarksShader ); + } + if ( saber.g2MarksShader2[0] ) + { + cgi_R_RegisterShader( saber.g2MarksShader2 ); + } + if ( saber.g2WeaponMarkShader[0] ) + { + cgi_R_RegisterShader( saber.g2WeaponMarkShader ); + } + if ( saber.g2WeaponMarkShader2[0] ) + { + cgi_R_RegisterShader( saber.g2WeaponMarkShader2 ); + } continue; } @@ -3530,9 +3598,13 @@ qboolean NPC_ParseParms( const char *NPCName, gentity_t *NPC ) char *saberName = G_NewString( value ); WP_SaberParseParms( saberName, &NPC->client->ps.saber[0] ); //if it requires a specific style, make sure we know how to use it - if ( NPC->client->ps.saber[0].style ) + if ( NPC->client->ps.saber[0].stylesLearned ) { - NPC->client->ps.saberStylesKnown |= (1<client->ps.saber[0].style); + NPC->client->ps.saberStylesKnown |= NPC->client->ps.saber[0].stylesLearned; + } + if ( NPC->client->ps.saber[0].singleBladeStyle ) + { + NPC->client->ps.saberStylesKnown |= NPC->client->ps.saber[0].singleBladeStyle; } continue; } @@ -3545,15 +3617,19 @@ qboolean NPC_ParseParms( const char *NPCName, gentity_t *NPC ) continue; } - if ( !NPC->client->ps.saber[0].twoHanded ) + if ( !(NPC->client->ps.saber[0].saberFlags&SFL_TWO_HANDED) ) {//can't use a second saber if first one is a two-handed saber...? char *saberName = G_NewString( value ); WP_SaberParseParms( saberName, &NPC->client->ps.saber[1] ); - if ( NPC->client->ps.saber[1].style ) + if ( NPC->client->ps.saber[1].stylesLearned ) { - NPC->client->ps.saberStylesKnown |= (1<client->ps.saber[1].style); + NPC->client->ps.saberStylesKnown |= NPC->client->ps.saber[1].stylesLearned; } - if ( NPC->client->ps.saber[1].twoHanded ) + if ( NPC->client->ps.saber[1].singleBladeStyle ) + { + NPC->client->ps.saberStylesKnown |= NPC->client->ps.saber[1].singleBladeStyle; + } + if ( (NPC->client->ps.saber[1].saberFlags&SFL_TWO_HANDED) ) {//tsk tsk, can't use a twoHanded saber as second saber WP_RemoveSaber( NPC, 1 ); } diff --git a/code/game/Q3_Interface.cpp b/code/game/Q3_Interface.cpp index a153a03..fd4d000 100644 --- a/code/game/Q3_Interface.cpp +++ b/code/game/Q3_Interface.cpp @@ -803,7 +803,7 @@ static void Q3_SetMissionFailed(const char *TextEnum) { gentity_t *ent = &g_entities[0]; - if ( ent->health >= 0 ) + if ( ent->health > 0 ) { G_PlayerGuiltDeath(); } diff --git a/code/game/b_local.h b/code/game/b_local.h index 4adec3b..ef7f4d8 100644 --- a/code/game/b_local.h +++ b/code/game/b_local.h @@ -41,7 +41,7 @@ extern cvar_t *debugNPCName; extern cvar_t *d_JediAI; extern cvar_t *d_saberCombat; extern void NPC_Think ( gentity_t *self); -extern void pitch_roll_for_slope( gentity_t *forwhom, vec3_t pass_slope = NULL, vec3_t storeAngles = NULL ); +extern void pitch_roll_for_slope( gentity_t *forwhom, vec3_t pass_slope = NULL, vec3_t storeAngles = NULL, qboolean keepPitch = qfalse ); //NPC_reactions.cpp extern void NPC_Pain( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, vec3_t point, int damage, int mod ,int hitLoc); diff --git a/code/game/bg_misc.cpp b/code/game/bg_misc.cpp index 6f52773..03380ba 100644 --- a/code/game/bg_misc.cpp +++ b/code/game/bg_misc.cpp @@ -16,11 +16,13 @@ extern ammoData_t ammoData[AMMO_MAX]; #define PICKUPSOUND "sound/weapons/w_pkup.wav" -/*QUAKED weapon_***** ( 0 0 0 ) (-16 -16 -16) (16 16 16) suspended +/*QUAKED weapon_***** ( 0 0 0 ) (-16 -16 -16) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE NOGLOW USEPICKUP STATIONARY DO NOT USE THIS CLASS, IT JUST HOLDS GENERAL INFORMATION for weapons, ammo, and item pickups. The suspended flag will allow items to hang in the air, otherwise they are dropped to the next surface. The NOPLAYER flag makes it so player cannot pick it up. The ALLOWNPC flag allows only NPCs to pick it up, too +USEPICKUP - Player must be holding "use" to pick it up +STATIONARY - Cannot be moved around by force push/pull, radius damage, knockback, etc... If an item is the target of another entity, it will spawn as normal, use INVISIBLE to hide it. @@ -35,58 +37,69 @@ An item fires all of its targets when it is picked up. If the toucher can't car "enemy" */ -/*QUAKED weapon_stun_baton (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE +/*QUAKED weapon_stun_baton (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE NOGLOW USEPICKUP STATIONARY NOGLOW USEPICKUP STATIONARY model="/models/weapons2/stun_baton/baton.md3" */ -/*QUAKED weapon_saber (.3 .3 1) (-16 -16 -8) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE NOGLOW +/*QUAKED weapon_saber (.3 .3 1) (-16 -16 -8) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID LEANING INVISIBLE NOGLOW USEPICKUP STATIONARY +SUSPENDED - allow items to hang in the air, otherwise they are dropped to the next surface. +NOPLAYER - makes it so player cannot pick it up. +ALLOWNPC - allows only NPCs to pick it up, too +LEANING - lean back against wall +NOGLOW - No Glow +USEPICKUP - Player must be holding "use" to pick it up +STATIONARY - Cannot be moved around by force push/pull, radius damage, knockback, etc... + model="/models/weapons2/saber/saber_w.md3" When picked up, will be used as a second saber unless: 1) It's a two-handed saber 2) The old saber was two-handed - OR 3) You set "saberSolo" to "1" + 4) You have 2 sabers and the saber pickup is on your right when you touch it saberType - entry name from sabers.cfg - which kind of saber this is - use "player" to make it so that the saber will be whatever saber the player is configured to use saberColor - red, orange, yellow, green, blue, and purple +saberLeftHand - always be added as a left-hand saber saberSolo - set to "1" and this will be the only saber the person who picks this up will be holding +saberPitch - if set "LEANING" flag, you can specify the exact pitch to lean forward/back +count - how many you can pick up before it's removed (default is 1, -1 is infinite) */ -/*QUAKED weapon_bryar_pistol (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE +/*QUAKED weapon_bryar_pistol (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE NOGLOW USEPICKUP STATIONARY model="/models/weapons2/briar_pistol/briar_pistol.md3" */ -/*QUAKED weapon_blaster_pistol (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE +/*QUAKED weapon_blaster_pistol (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE NOGLOW USEPICKUP STATIONARY model="/models/weapons2/blaster_pistol/blaster_pistol.md3" */ -/*QUAKED weapon_blaster (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE +/*QUAKED weapon_blaster (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE NOGLOW USEPICKUP STATIONARY model="/models/weapons2/blaster_r/blaster.md3" */ -/*QUAKED weapon_disruptor (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE +/*QUAKED weapon_disruptor (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE NOGLOW USEPICKUP STATIONARY model="/models/weapons2/disruptor/disruptor.md3" */ -/*QUAKED weapon_bowcaster (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE +/*QUAKED weapon_bowcaster (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE NOGLOW USEPICKUP STATIONARY model="/models/weapons2/bowcaster/bowcaster.md3" */ -/*QUAKED weapon_repeater (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE +/*QUAKED weapon_repeater (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE NOGLOW USEPICKUP STATIONARY model="/models/weapons2/heavy_repeater/heavy_repeater.md3" */ -/*QUAKED weapon_demp2 (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE +/*QUAKED weapon_demp2 (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE NOGLOW USEPICKUP STATIONARY model="/models/weapons2/demp2/demp2.md3" */ -/*QUAKED weapon_flechette (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE +/*QUAKED weapon_flechette (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE NOGLOW USEPICKUP STATIONARY model="/models/weapons2/golan_arms/golan_arms.md3" */ -/*QUAKED weapon_concussion_rifle (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE +/*QUAKED weapon_concussion_rifle (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE NOGLOW USEPICKUP STATIONARY model="/models/weapons2/c_rifle/c_rifle.md3" */ -/*QUAKED weapon_rocket_launcher (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE +/*QUAKED weapon_rocket_launcher (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE NOGLOW USEPICKUP STATIONARY model="/models/weapons2/merr_sonn/merr_sonn.md3" */ -/*QUAKED weapon_thermal (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE +/*QUAKED weapon_thermal (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE NOGLOW USEPICKUP STATIONARY model="/models/weapons2/thermal/thermal.md3" */ -/*QUAKED weapon_trip_mine (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE +/*QUAKED weapon_trip_mine (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE NOGLOW USEPICKUP STATIONARY model="/models/weapons2/laser_trap/laser_trap.md3" */ -/*QUAKED weapon_det_pack (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE +/*QUAKED weapon_det_pack (.3 .3 1) (-16 -16 -2) (16 16 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE NOGLOW USEPICKUP STATIONARY model="/models/weapons2/detpack/det_pack.md3" */ @@ -131,13 +144,13 @@ Belt of thermal detonators 3 pack of detpacks */ -/*QUAKED item_medpak_instant (.3 .3 1) (-8 -8 -4) (8 8 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE +/*QUAKED item_medpak_instant (.3 .3 1) (-8 -8 -4) (8 8 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE NOGLOW USEPICKUP STATIONARY */ -/*QUAKED item_shield_sm_instant (.3 .3 1) (-8 -8 -4) (8 8 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE +/*QUAKED item_shield_sm_instant (.3 .3 1) (-8 -8 -4) (8 8 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE NOGLOW USEPICKUP STATIONARY */ -/*QUAKED item_shield_lrg_instant (.3 .3 1) (-8 -8 -4) (8 8 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE +/*QUAKED item_shield_lrg_instant (.3 .3 1) (-8 -8 -4) (8 8 16) SUSPEND NOPLAYER ALLOWNPC NOTSOLID VERTICAL INVISIBLE NOGLOW USEPICKUP STATIONARY */ /*QUAKED item_goodie_key (.3 .3 1) (-8 -8 0) (8 8 16) suspended */ diff --git a/code/game/bg_panimate.cpp b/code/game/bg_panimate.cpp index 266101a..0f9dd88 100644 --- a/code/game/bg_panimate.cpp +++ b/code/game/bg_panimate.cpp @@ -1251,6 +1251,14 @@ qboolean PM_SaberInSpecialAttack( int anim ) return qfalse; } +qboolean PM_SaberInAttackPure( int move ) +{ + if ( move >= LS_A_TL2BR && move <= LS_A_T2B ) + { + return qtrue; + } + return qfalse; +} qboolean PM_SaberInAttack( int move ) { if ( move >= LS_A_TL2BR && move <= LS_A_T2B ) @@ -1493,6 +1501,160 @@ qboolean PM_KickMove( int move ) return qfalse; } +qboolean PM_SaberCanInterruptMove( int move, int anim ) +{ + if ( PM_InAnimForSaberMove( anim, move ) ) + { + switch( move ) + { + case LS_A_BACK: + case LS_A_BACK_CR: + case LS_A_BACKSTAB: + case LS_ROLL_STAB: + case LS_A_LUNGE: + case LS_A_JUMP_T__B_: + case LS_A_FLIP_STAB: + case LS_A_FLIP_SLASH: + case LS_JUMPATTACK_DUAL: + case LS_JUMPATTACK_CART_LEFT: + case LS_JUMPATTACK_CART_RIGHT: + case LS_JUMPATTACK_STAFF_LEFT: + case LS_JUMPATTACK_STAFF_RIGHT: + case LS_BUTTERFLY_LEFT: + case LS_BUTTERFLY_RIGHT: + case LS_A_BACKFLIP_ATK: + case LS_SPINATTACK_DUAL: + case LS_SPINATTACK: + case LS_LEAP_ATTACK: + case LS_SWOOP_ATTACK_RIGHT: + case LS_SWOOP_ATTACK_LEFT: + case LS_TAUNTAUN_ATTACK_RIGHT: + case LS_TAUNTAUN_ATTACK_LEFT: + case LS_KICK_S: + case LS_KICK_BF: + case LS_KICK_RL: + case LS_STABDOWN: + case LS_STABDOWN_STAFF: + case LS_STABDOWN_DUAL: + case LS_DUAL_SPIN_PROTECT: + case LS_STAFF_SOULCAL: + case LS_A1_SPECIAL: + case LS_A2_SPECIAL: + case LS_A3_SPECIAL: + case LS_UPSIDE_DOWN_ATTACK: + case LS_PULL_ATTACK_STAB: + case LS_PULL_ATTACK_SWING: + case LS_SPINATTACK_ALORA: + case LS_DUAL_FB: + case LS_DUAL_LR: + case LS_HILT_BASH: + return qfalse; + } + + if ( PM_SaberInAttackPure( move ) ) + { + return qfalse; + } + if ( PM_SaberInStart( move ) ) + { + return qfalse; + } + if ( PM_SaberInTransition( move ) ) + { + return qfalse; + } + if ( PM_SaberInBounce( move ) ) + { + return qfalse; + } + if ( PM_SaberInBrokenParry( move ) ) + { + return qfalse; + } + if ( PM_SaberInDeflect( move ) ) + { + return qfalse; + } + if ( PM_SaberInParry( move ) ) + { + return qfalse; + } + if ( PM_SaberInKnockaway( move ) ) + { + return qfalse; + } + if ( PM_SaberInReflect( move ) ) + { + return qfalse; + } + } + switch ( anim ) + { + case BOTH_A2_STABBACK1: + case BOTH_ATTACK_BACK: + case BOTH_CROUCHATTACKBACK1: + case BOTH_ROLL_STAB: + case BOTH_BUTTERFLY_LEFT: + case BOTH_BUTTERFLY_RIGHT: + case BOTH_BUTTERFLY_FL1: + case BOTH_BUTTERFLY_FR1: + case BOTH_FJSS_TR_BL: + case BOTH_FJSS_TL_BR: + case BOTH_LUNGE2_B__T_: + case BOTH_FORCELEAP2_T__B_: + case BOTH_JUMPFLIPSLASHDOWN1://# + case BOTH_JUMPFLIPSTABDOWN://# + case BOTH_JUMPATTACK6: + case BOTH_JUMPATTACK7: + case BOTH_SPINATTACK6: + case BOTH_SPINATTACK7: + case BOTH_FORCELONGLEAP_ATTACK: + case BOTH_VS_ATR_S: + case BOTH_VS_ATL_S: + case BOTH_VT_ATR_S: + case BOTH_VT_ATL_S: + case BOTH_A7_KICK_S: + case BOTH_A7_KICK_BF: + case BOTH_A7_KICK_RL: + case BOTH_STABDOWN: + case BOTH_STABDOWN_STAFF: + case BOTH_STABDOWN_DUAL: + case BOTH_A6_SABERPROTECT: + case BOTH_A7_SOULCAL: + case BOTH_A1_SPECIAL: + case BOTH_A2_SPECIAL: + case BOTH_A3_SPECIAL: + case BOTH_FLIP_ATTACK7: + case BOTH_PULL_IMPALE_STAB: + case BOTH_PULL_IMPALE_SWING: + case BOTH_ALORA_SPIN_SLASH: + case BOTH_A6_FB: + case BOTH_A6_LR: + case BOTH_A7_HILT: + case BOTH_LK_S_DL_S_SB_1_W: + case BOTH_LK_S_DL_T_SB_1_W: + case BOTH_LK_S_ST_S_SB_1_W: + case BOTH_LK_S_ST_T_SB_1_W: + case BOTH_LK_S_S_S_SB_1_W: + case BOTH_LK_S_S_T_SB_1_W: + case BOTH_LK_DL_DL_S_SB_1_W: + case BOTH_LK_DL_DL_T_SB_1_W: + case BOTH_LK_DL_ST_S_SB_1_W: + case BOTH_LK_DL_ST_T_SB_1_W: + case BOTH_LK_DL_S_S_SB_1_W: + case BOTH_LK_DL_S_T_SB_1_W: + case BOTH_LK_ST_DL_S_SB_1_W: + case BOTH_LK_ST_DL_T_SB_1_W: + case BOTH_LK_ST_ST_S_SB_1_W: + case BOTH_LK_ST_ST_T_SB_1_W: + case BOTH_LK_ST_S_S_SB_1_W: + case BOTH_LK_ST_S_T_SB_1_W: + case BOTH_HANG_ATTACK: + return qfalse; + } + return qtrue; +} + saberMoveName_t PM_BrokenParryForAttack( int move ) { //Our attack was knocked away by a knockaway parry @@ -1961,6 +2123,15 @@ saberMoveName_t PM_CheckStabDown( void ) { return LS_NONE; } + if ( (pm->ps->saber[0].saberFlags&SFL_NO_STABDOWN) ) + { + return LS_NONE; + } + if ( pm->ps->dualSabers + && (pm->ps->saber[1].saberFlags&SFL_NO_STABDOWN) ) + { + return LS_NONE; + } if ( pm->ps->clientNum < MAX_CLIENTS || PM_ControlledByPlayer() ) //PLAYER ONLY {//player if ( G_TryingKataAttack( pm->gent, &pm->cmd ) )//(pm->cmd.buttons&BUTTON_FORCE_FOCUS) )//Holding focus @@ -2118,17 +2289,21 @@ saberMoveName_t PM_AttackForEnemyPos( qboolean allowFB, qboolean allowStabDown ) } if ( allowFB ) {//directly in front anim allowed - if ( enemyDist > 200 || pm->gent->enemy->health <= 0 ) - {//hmm, look in back for an enemy - if ( pm->ps->clientNum && !PM_ControlledByPlayer() ) - {//player should never do this automatically - if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) - {//only when on ground - if ( pm->gent && pm->gent->client && pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG && Q_irand( 0, pm->gent->NPC->rank ) > RANK_ENSIGN ) - {//only fencers and higher can do this, higher rank does it more - if ( PM_CheckEnemyInBack( 100 ) ) - { - return PM_PickBackStab(); + if ( !(pm->ps->saber[0].saberFlags&SFL_NO_BACK_ATTACK) + && (!pm->ps->dualSabers || !(pm->ps->saber[1].saberFlags&SFL_NO_BACK_ATTACK)) ) + {//okay to do backstabs with this saber + if ( enemyDist > 200 || pm->gent->enemy->health <= 0 ) + {//hmm, look in back for an enemy + if ( pm->ps->clientNum && !PM_ControlledByPlayer() ) + {//player should never do this automatically + if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) + {//only when on ground + if ( pm->gent && pm->gent->client && pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG && Q_irand( 0, pm->gent->NPC->rank ) > RANK_ENSIGN ) + {//only fencers and higher can do this, higher rank does it more + if ( PM_CheckEnemyInBack( 100 ) ) + { + return PM_PickBackStab(); + } } } } @@ -2195,34 +2370,38 @@ saberMoveName_t PM_AttackForEnemyPos( qboolean allowFB, qboolean allowStabDown ) else if ( allowFB ) {//back attack allowed //if ( !PM_InKnockDown( pm->ps ) ) - if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) - {//only when on ground - if ( !pm->gent->enemy->client || pm->gent->enemy->client->ps.groundEntityNum != ENTITYNUM_NONE ) - {//enemy not a client or is a client and on ground - if ( dot < -0.75f - && enemyDist < 128 - && (pm->ps->saberAnimLevel == SS_FAST || pm->ps->saberAnimLevel == SS_STAFF || (pm->gent->client &&(pm->gent->client->NPC_class == CLASS_TAVION||pm->gent->client->NPC_class == CLASS_ALORA)&&Q_irand(0,2))) ) - {//fast back-stab - if ( !(pm->ps->pm_flags&PMF_DUCKED) && pm->cmd.upmove >= 0 ) - {//can't do it while ducked? - if ( (pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer()) || (pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG) ) - {//only fencers and above can do this - autoMove = LS_A_BACKSTAB; + if ( !(pm->ps->saber[0].saberFlags&SFL_NO_BACK_ATTACK) + && (!pm->ps->dualSabers || !(pm->ps->saber[1].saberFlags&SFL_NO_BACK_ATTACK)) ) + {//okay to do backstabs with this saber + if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) + {//only when on ground + if ( !pm->gent->enemy->client || pm->gent->enemy->client->ps.groundEntityNum != ENTITYNUM_NONE ) + {//enemy not a client or is a client and on ground + if ( dot < -0.75f + && enemyDist < 128 + && (pm->ps->saberAnimLevel == SS_FAST || pm->ps->saberAnimLevel == SS_STAFF || (pm->gent->client &&(pm->gent->client->NPC_class == CLASS_TAVION||pm->gent->client->NPC_class == CLASS_ALORA)&&Q_irand(0,2))) ) + {//fast back-stab + if ( !(pm->ps->pm_flags&PMF_DUCKED) && pm->cmd.upmove >= 0 ) + {//can't do it while ducked? + if ( (pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer()) || (pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG) ) + {//only fencers and above can do this + autoMove = LS_A_BACKSTAB; + } } } - } - else if ( pm->ps->saberAnimLevel != SS_FAST - && pm->ps->saberAnimLevel != SS_STAFF ) - {//higher level back spin-attacks - if ( (pm->ps->clientNum&&!PM_ControlledByPlayer()) || ((pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer()) && cg.renderingThirdPerson && !cg.zoomMode) ) - { - if ( (pm->ps->pm_flags&PMF_DUCKED) || pm->cmd.upmove < 0 ) + else if ( pm->ps->saberAnimLevel != SS_FAST + && pm->ps->saberAnimLevel != SS_STAFF ) + {//higher level back spin-attacks + if ( (pm->ps->clientNum&&!PM_ControlledByPlayer()) || ((pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer()) && cg.renderingThirdPerson && !cg.zoomMode) ) { - autoMove = LS_A_BACK_CR; - } - else - { - autoMove = LS_A_BACK; + if ( (pm->ps->pm_flags&PMF_DUCKED) || pm->cmd.upmove < 0 ) + { + autoMove = LS_A_BACK_CR; + } + else + { + autoMove = LS_A_BACK; + } } } } @@ -2236,7 +2415,7 @@ qboolean PM_InSecondaryStyle( void ) { if ( pm->ps->saber[0].numBlades > 1 && pm->ps->saber[0].singleBladeStyle - && pm->ps->saber[0].singleBladeStyle != pm->ps->saber[0].style + && (pm->ps->saber[0].stylesForbidden&(1<ps->saber[0].singleBladeStyle)) && pm->ps->saberAnimLevel == pm->ps->saber[0].singleBladeStyle ) { return qtrue; @@ -2253,6 +2432,38 @@ qboolean PM_InSecondaryStyle( void ) saberMoveName_t PM_SaberLungeAttackMove( qboolean fallbackToNormalLunge ) { G_DrainPowerForSpecialMove( pm->gent, FP_SABER_OFFENSE, SABER_ALT_ATTACK_POWER_FB ); + + //see if we have an overridden (or cancelled) lunge move + if ( pm->ps->saber[0].lungeAtkMove != LS_INVALID ) + { + if ( pm->ps->saber[0].lungeAtkMove != LS_NONE ) + { + return (saberMoveName_t)pm->ps->saber[0].lungeAtkMove; + } + } + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].lungeAtkMove != LS_INVALID ) + { + if ( pm->ps->saber[1].lungeAtkMove != LS_NONE ) + { + return (saberMoveName_t)pm->ps->saber[1].lungeAtkMove; + } + } + } + //no overrides, cancelled? + if ( pm->ps->saber[0].lungeAtkMove == LS_NONE ) + { + return LS_NONE; + } + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].lungeAtkMove == LS_NONE ) + { + return LS_NONE; + } + } + //do normal checks if ( pm->gent->client->NPC_class == CLASS_ALORA && !Q_irand( 0, 3 ) ) {//alora NPC return LS_SPINATTACK_ALORA; @@ -2294,6 +2505,34 @@ saberMoveName_t PM_SaberLungeAttackMove( qboolean fallbackToNormalLunge ) qboolean PM_CheckLungeAttackMove( void ) { + //check to see if it's cancelled? + if ( pm->ps->saber[0].lungeAtkMove == LS_NONE ) + { + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].lungeAtkMove == LS_NONE + || pm->ps->saber[1].lungeAtkMove == LS_INVALID ) + { + return qfalse; + } + } + else + { + return qfalse; + } + } + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].lungeAtkMove == LS_NONE ) + { + if ( pm->ps->saber[0].lungeAtkMove == LS_NONE + || pm->ps->saber[0].lungeAtkMove == LS_INVALID ) + { + return qfalse; + } + } + } + //do normal checks if ( pm->ps->saberAnimLevel == SS_FAST//fast || pm->ps->saberAnimLevel == SS_DUAL//dual || pm->ps->saberAnimLevel == SS_STAFF //staff @@ -2349,6 +2588,36 @@ saberMoveName_t PM_SaberJumpForwardAttackMove( void ) { G_DrainPowerForSpecialMove( pm->gent, FP_LEVITATION, SABER_ALT_ATTACK_POWER_FB ); + //see if we have an overridden (or cancelled) kata move + if ( pm->ps->saber[0].jumpAtkFwdMove != LS_INVALID ) + { + if ( pm->ps->saber[0].jumpAtkFwdMove != LS_NONE ) + { + return (saberMoveName_t)pm->ps->saber[0].jumpAtkFwdMove; + } + } + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].jumpAtkFwdMove != LS_INVALID ) + { + if ( pm->ps->saber[1].jumpAtkFwdMove != LS_NONE ) + { + return (saberMoveName_t)pm->ps->saber[1].jumpAtkFwdMove; + } + } + } + //no overrides, cancelled? + if ( pm->ps->saber[0].jumpAtkFwdMove == LS_NONE ) + { + return LS_NONE; + } + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].jumpAtkFwdMove == LS_NONE ) + { + return LS_NONE; + } + } if ( pm->ps->saberAnimLevel == SS_DUAL || pm->ps->saberAnimLevel == SS_STAFF ) { @@ -2397,6 +2666,35 @@ qboolean PM_CheckJumpForwardAttackMove( void ) return qfalse; } + //check to see if it's cancelled? + if ( pm->ps->saber[0].jumpAtkFwdMove == LS_NONE ) + { + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].jumpAtkFwdMove == LS_NONE + || pm->ps->saber[1].jumpAtkFwdMove == LS_INVALID ) + { + return qfalse; + } + } + else + { + return qfalse; + } + } + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].jumpAtkFwdMove == LS_NONE ) + { + if ( pm->ps->saber[0].jumpAtkFwdMove == LS_NONE + || pm->ps->saber[0].jumpAtkFwdMove == LS_INVALID ) + { + return qfalse; + } + } + } + //do normal checks + if ( pm->cmd.forwardmove > 0 //going forward && pm->ps->forceRageRecoveryTime < pm->cmd.serverTime //not in a force Rage recovery period && pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 //can force jump @@ -2494,6 +2792,36 @@ qboolean PM_CheckJumpForwardAttackMove( void ) saberMoveName_t PM_SaberFlipOverAttackMove( void ) { + //see if we have an overridden (or cancelled) kata move + if ( pm->ps->saber[0].jumpAtkFwdMove != LS_INVALID ) + { + if ( pm->ps->saber[0].jumpAtkFwdMove != LS_NONE ) + { + return (saberMoveName_t)pm->ps->saber[0].jumpAtkFwdMove; + } + } + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].jumpAtkFwdMove != LS_INVALID ) + { + if ( pm->ps->saber[1].jumpAtkFwdMove != LS_NONE ) + { + return (saberMoveName_t)pm->ps->saber[1].jumpAtkFwdMove; + } + } + } + //no overrides, cancelled? + if ( pm->ps->saber[0].jumpAtkFwdMove == LS_NONE ) + { + return LS_NONE; + } + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].jumpAtkFwdMove == LS_NONE ) + { + return LS_NONE; + } + } //FIXME: check above for room enough to jump! //FIXME: while in this jump, keep velocity[2] at a minimum until the end of the anim vec3_t fwdAngles, jumpFwd; @@ -2555,6 +2883,34 @@ qboolean PM_CheckFlipOverAttackMove( qboolean checkEnemy ) { return qfalse; } + //check to see if it's cancelled? + if ( pm->ps->saber[0].jumpAtkFwdMove == LS_NONE ) + { + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].jumpAtkFwdMove == LS_NONE + || pm->ps->saber[1].jumpAtkFwdMove == LS_INVALID ) + { + return qfalse; + } + } + else + { + return qfalse; + } + } + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].jumpAtkFwdMove == LS_NONE ) + { + if ( pm->ps->saber[0].jumpAtkFwdMove == LS_NONE + || pm->ps->saber[0].jumpAtkFwdMove == LS_INVALID ) + { + return qfalse; + } + } + } + //do normal checks if ( (pm->ps->saberAnimLevel == SS_MEDIUM //medium || pm->ps->saberAnimLevel == SS_TAVION )//tavion @@ -2625,6 +2981,36 @@ qboolean PM_CheckFlipOverAttackMove( qboolean checkEnemy ) saberMoveName_t PM_SaberBackflipAttackMove( void ) { + //see if we have an overridden (or cancelled) kata move + if ( pm->ps->saber[0].jumpAtkBackMove != LS_INVALID ) + { + if ( pm->ps->saber[0].jumpAtkBackMove != LS_NONE ) + { + return (saberMoveName_t)pm->ps->saber[0].jumpAtkBackMove; + } + } + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].jumpAtkBackMove != LS_INVALID ) + { + if ( pm->ps->saber[1].jumpAtkBackMove != LS_NONE ) + { + return (saberMoveName_t)pm->ps->saber[1].jumpAtkBackMove; + } + } + } + //no overrides, cancelled? + if ( pm->ps->saber[0].jumpAtkBackMove == LS_NONE ) + { + return LS_NONE; + } + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].jumpAtkBackMove == LS_NONE ) + { + return LS_NONE; + } + } pm->cmd.upmove = 0;//no jump just yet return LS_A_BACKFLIP_ATK; } @@ -2637,6 +3023,35 @@ qboolean PM_CheckBackflipAttackMove( void ) return qfalse; } + //check to see if it's cancelled? + if ( pm->ps->saber[0].jumpAtkBackMove == LS_NONE ) + { + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].jumpAtkBackMove == LS_NONE + || pm->ps->saber[1].jumpAtkBackMove == LS_INVALID ) + { + return qfalse; + } + } + else + { + return qfalse; + } + } + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].jumpAtkBackMove == LS_NONE ) + { + if ( pm->ps->saber[0].jumpAtkBackMove == LS_NONE + || pm->ps->saber[0].jumpAtkBackMove == LS_INVALID ) + { + return qfalse; + } + } + } + //do normal checks + if ( pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 //can force jump && pm->ps->forceRageRecoveryTime < pm->cmd.serverTime //not in a force Rage recovery period && pm->gent && !(pm->gent->flags&FL_LOCK_PLAYER_WEAPONS) // yes this locked weapons check also includes force powers, if we need a separate check later I'll make one @@ -2679,6 +3094,37 @@ saberMoveName_t PM_CheckDualSpinProtect( void ) return LS_NONE; } + //see if we have an overridden (or cancelled) kata move + if ( pm->ps->saber[0].kataMove != LS_INVALID ) + { + if ( pm->ps->saber[0].kataMove != LS_NONE ) + { + return (saberMoveName_t)pm->ps->saber[0].kataMove; + } + } + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].kataMove != LS_INVALID ) + { + if ( pm->ps->saber[1].kataMove != LS_NONE ) + { + return (saberMoveName_t)pm->ps->saber[1].kataMove; + } + } + } + //no overrides, cancelled? + if ( pm->ps->saber[0].kataMove == LS_NONE ) + { + return LS_NONE; + } + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].kataMove == LS_NONE ) + { + return LS_NONE; + } + } + //do normal checks if ( pm->ps->saberMove == LS_READY//ready //&& (pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer())//PLAYER ONLY...? //&& pm->ps->viewangles[0] > 30 //looking down @@ -2714,6 +3160,37 @@ saberMoveName_t PM_CheckStaffKata( void ) return LS_NONE; } + //see if we have an overridden (or cancelled) kata move + if ( pm->ps->saber[0].kataMove != LS_INVALID ) + { + if ( pm->ps->saber[0].kataMove != LS_NONE ) + { + return (saberMoveName_t)pm->ps->saber[0].kataMove; + } + } + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].kataMove != LS_INVALID ) + { + if ( pm->ps->saber[1].kataMove != LS_NONE ) + { + return (saberMoveName_t)pm->ps->saber[1].kataMove; + } + } + } + //no overrides, cancelled? + if ( pm->ps->saber[0].kataMove == LS_NONE ) + { + return LS_NONE; + } + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].kataMove == LS_NONE ) + { + return LS_NONE; + } + } + //do normal checks if ( pm->ps->saberMove == LS_READY//ready //&& (pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer())//PLAYER ONLY...? //&& pm->ps->viewangles[0] > 30 //looking down @@ -2750,6 +3227,16 @@ saberMoveName_t PM_CheckPullAttack( void ) return LS_NONE; } + if ( (pm->ps->saber[0].saberFlags&SFL_NO_PULL_ATTACK) ) + { + return LS_NONE; + } + if ( pm->ps->dualSabers + && (pm->ps->saber[1].saberFlags&SFL_NO_PULL_ATTACK) ) + { + return LS_NONE; + } + if ( (pm->ps->saberMove == LS_READY||PM_SaberInReturn(pm->ps->saberMove)||PM_SaberInReflect(pm->ps->saberMove))//ready //&& (pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer())//PLAYER ONLY && pm->ps->saberAnimLevel >= SS_FAST//single saber styles - FIXME: Tavion? @@ -2891,6 +3378,51 @@ saberMoveName_t PM_SaberAttackForMovement( int forwardmove, int rightmove, int c noSpecials = qtrue; } + saberMoveName_t overrideJumpRightAttackMove = LS_INVALID; + if ( pm->ps->saber[0].jumpAtkRightMove != LS_INVALID ) + { + if ( pm->ps->saber[0].jumpAtkRightMove != LS_NONE ) + {//actually overriding + overrideJumpRightAttackMove = (saberMoveName_t)pm->ps->saber[0].jumpAtkRightMove; + } + else if ( pm->ps->dualSabers + && pm->ps->saber[1].jumpAtkRightMove > LS_NONE ) + {//would be cancelling it, but check the second saber, too + overrideJumpRightAttackMove = (saberMoveName_t)pm->ps->saber[1].jumpAtkRightMove; + } + else + {//nope, just cancel it + overrideJumpRightAttackMove = LS_NONE; + } + } + else if ( pm->ps->dualSabers + && pm->ps->saber[1].jumpAtkRightMove != LS_INVALID ) + {//first saber not overridden, check second + overrideJumpRightAttackMove = (saberMoveName_t)pm->ps->saber[1].jumpAtkRightMove; + } + + saberMoveName_t overrideJumpLeftAttackMove = LS_INVALID; + if ( pm->ps->saber[0].jumpAtkLeftMove != LS_INVALID ) + { + if ( pm->ps->saber[0].jumpAtkLeftMove != LS_NONE ) + {//actually overriding + overrideJumpLeftAttackMove = (saberMoveName_t)pm->ps->saber[0].jumpAtkLeftMove; + } + else if ( pm->ps->dualSabers + && pm->ps->saber[1].jumpAtkLeftMove > LS_NONE ) + {//would be cancelling it, but check the second saber, too + overrideJumpLeftAttackMove = (saberMoveName_t)pm->ps->saber[1].jumpAtkLeftMove; + } + else + {//nope, just cancel it + overrideJumpLeftAttackMove = LS_NONE; + } + } + else if ( pm->ps->dualSabers + && pm->ps->saber[1].jumpAtkLeftMove != LS_INVALID ) + {//first saber not overridden, check second + overrideJumpLeftAttackMove = (saberMoveName_t)pm->ps->saber[1].jumpAtkLeftMove; + } #ifdef _XBOX if ( rightmove > 64 ) #else @@ -2898,6 +3430,7 @@ saberMoveName_t PM_SaberAttackForMovement( int forwardmove, int rightmove, int c #endif // _XBOX {//moving right if ( !noSpecials + && overrideJumpRightAttackMove != LS_NONE && (pm->ps->groundEntityNum != ENTITYNUM_NONE||level.time-pm->ps->lastOnGround<=250) //on ground or just jumped && (pm->cmd.buttons&BUTTON_ATTACK)//hitting attack && pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_0//have force jump 1 at least @@ -2911,7 +3444,11 @@ saberMoveName_t PM_SaberAttackForMovement( int forwardmove, int rightmove, int c G_DrainPowerForSpecialMove( pm->gent, FP_LEVITATION, SABER_ALT_ATTACK_POWER_LR ); } pm->cmd.upmove = 0; - if ( pm->ps->saberAnimLevel == SS_STAFF ) + if ( overrideJumpRightAttackMove != LS_INVALID ) + {//overridden with another move + return overrideJumpRightAttackMove; + } + else if ( pm->ps->saberAnimLevel == SS_STAFF ) { AngleVectors( fwdAngles, NULL, right, NULL ); pm->ps->velocity[0] = pm->ps->velocity[1] = 0; @@ -2920,20 +3457,24 @@ saberMoveName_t PM_SaberAttackForMovement( int forwardmove, int rightmove, int c } else { - /* - if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) - {//still on ground - VectorClear( pm->ps->velocity ); - return LS_JUMPATTACK_CART_RIGHT; - } - else - */ - {//in air - AngleVectors( fwdAngles, NULL, right, NULL ); - pm->ps->velocity[0] = pm->ps->velocity[1] = 0; - VectorMA( pm->ps->velocity, 190, right, pm->ps->velocity ); - PM_SetJumped( JUMP_VELOCITY, qtrue ); - return LS_JUMPATTACK_ARIAL_RIGHT; + if ( !(pm->ps->saber[0].saberFlags&SFL_NO_CARTWHEELS) + && (!pm->ps->dualSabers || !(pm->ps->saber[1].saberFlags&SFL_NO_CARTWHEELS)) ) + {//okay to do cartwheels with this saber + /* + if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) + {//still on ground + VectorClear( pm->ps->velocity ); + return LS_JUMPATTACK_CART_RIGHT; + } + else + */ + {//in air + AngleVectors( fwdAngles, NULL, right, NULL ); + pm->ps->velocity[0] = pm->ps->velocity[1] = 0; + VectorMA( pm->ps->velocity, 190, right, pm->ps->velocity ); + PM_SetJumped( JUMP_VELOCITY, qtrue ); + return LS_JUMPATTACK_ARIAL_RIGHT; + } } } } @@ -2975,6 +3516,7 @@ saberMoveName_t PM_SaberAttackForMovement( int forwardmove, int rightmove, int c #endif // _XBOX {//moving left if ( !noSpecials + && overrideJumpLeftAttackMove != LS_NONE && (pm->ps->groundEntityNum != ENTITYNUM_NONE||level.time-pm->ps->lastOnGround<=250) //on ground or just jumped && (pm->cmd.buttons&BUTTON_ATTACK)//hitting attack && pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_0//have force jump 1 at least @@ -2988,7 +3530,11 @@ saberMoveName_t PM_SaberAttackForMovement( int forwardmove, int rightmove, int c G_DrainPowerForSpecialMove( pm->gent, FP_LEVITATION, SABER_ALT_ATTACK_POWER_LR ); } pm->cmd.upmove = 0; - if ( pm->ps->saberAnimLevel == SS_STAFF ) + if ( overrideJumpRightAttackMove != LS_INVALID ) + {//overridden with another move + return overrideJumpRightAttackMove; + } + else if ( pm->ps->saberAnimLevel == SS_STAFF ) { AngleVectors( fwdAngles, NULL, right, NULL ); pm->ps->velocity[0] = pm->ps->velocity[1] = 0; @@ -2997,20 +3543,24 @@ saberMoveName_t PM_SaberAttackForMovement( int forwardmove, int rightmove, int c } else { - /* - if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) - {//still on ground - VectorClear( pm->ps->velocity ); - return LS_JUMPATTACK_ARIAL_LEFT; - } - else - */ - { - AngleVectors( fwdAngles, NULL, right, NULL ); - pm->ps->velocity[0] = pm->ps->velocity[1] = 0; - VectorMA( pm->ps->velocity, -190, right, pm->ps->velocity ); - PM_SetJumped( JUMP_VELOCITY, qtrue ); - return LS_JUMPATTACK_CART_LEFT; + if ( !(pm->ps->saber[0].saberFlags&SFL_NO_CARTWHEELS) + && (!pm->ps->dualSabers || !(pm->ps->saber[1].saberFlags&SFL_NO_CARTWHEELS)) ) + {//okay to do cartwheels with this saber + /* + if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) + {//still on ground + VectorClear( pm->ps->velocity ); + return LS_JUMPATTACK_ARIAL_LEFT; + } + else + */ + { + AngleVectors( fwdAngles, NULL, right, NULL ); + pm->ps->velocity[0] = pm->ps->velocity[1] = 0; + VectorMA( pm->ps->velocity, -190, right, pm->ps->velocity ); + PM_SetJumped( JUMP_VELOCITY, qtrue ); + return LS_JUMPATTACK_CART_LEFT; + } } } } @@ -3182,76 +3732,81 @@ saberMoveName_t PM_SaberAttackForMovement( int forwardmove, int rightmove, int c } } //if ( !PM_InKnockDown( pm->ps ) ) - if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) - {//only when on ground - if ( pm->gent && pm->gent->enemy ) - {//FIXME: or just trace for a valid enemy standing behind me? And no enemy in front? - vec3_t enemyDir, faceFwd, facingAngles = {0, pm->ps->viewangles[YAW], 0}; - AngleVectors( facingAngles, faceFwd, NULL, NULL ); - VectorSubtract( pm->gent->enemy->currentOrigin, pm->ps->origin, enemyDir ); - float dot = DotProduct( enemyDir, faceFwd ); - if ( dot < 0 ) - {//enemy is behind me - if ( dot < -0.75f - && DistanceSquared( pm->gent->currentOrigin, pm->gent->enemy->currentOrigin ) < 16384//128 squared - && (pm->ps->saberAnimLevel == SS_FAST || pm->ps->saberAnimLevel == SS_STAFF || (pm->gent->client &&(pm->gent->client->NPC_class == CLASS_TAVION||pm->gent->client->NPC_class == CLASS_ALORA)&&Q_irand(0,1))) ) - {//fast attacks and Tavion - if ( !(pm->ps->pm_flags&PMF_DUCKED) && pm->cmd.upmove >= 0 ) - {//can't do it while ducked? - if ( (pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer()) || (pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG) ) - {//only fencers and above can do this - return LS_A_BACKSTAB; + //check backstabs + if ( !(pm->ps->saber[0].saberFlags&SFL_NO_BACK_ATTACK) + && (!pm->ps->dualSabers || !(pm->ps->saber[1].saberFlags&SFL_NO_BACK_ATTACK)) ) + {//okay to do backstabs with this saber + if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) + {//only when on ground + if ( pm->gent && pm->gent->enemy ) + {//FIXME: or just trace for a valid enemy standing behind me? And no enemy in front? + vec3_t enemyDir, faceFwd, facingAngles = {0, pm->ps->viewangles[YAW], 0}; + AngleVectors( facingAngles, faceFwd, NULL, NULL ); + VectorSubtract( pm->gent->enemy->currentOrigin, pm->ps->origin, enemyDir ); + float dot = DotProduct( enemyDir, faceFwd ); + if ( dot < 0 ) + {//enemy is behind me + if ( dot < -0.75f + && DistanceSquared( pm->gent->currentOrigin, pm->gent->enemy->currentOrigin ) < 16384//128 squared + && (pm->ps->saberAnimLevel == SS_FAST || pm->ps->saberAnimLevel == SS_STAFF || (pm->gent->client &&(pm->gent->client->NPC_class == CLASS_TAVION||pm->gent->client->NPC_class == CLASS_ALORA)&&Q_irand(0,1))) ) + {//fast attacks and Tavion + if ( !(pm->ps->pm_flags&PMF_DUCKED) && pm->cmd.upmove >= 0 ) + {//can't do it while ducked? + if ( (pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer()) || (pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG) ) + {//only fencers and above can do this + return LS_A_BACKSTAB; + } + } + } + else if ( pm->ps->saberAnimLevel != SS_FAST + && pm->ps->saberAnimLevel != SS_STAFF ) + {//medium and higher attacks + if ( (pm->ps->pm_flags&PMF_DUCKED) || pm->cmd.upmove < 0 ) + { + return LS_A_BACK_CR; + } + else + { + return LS_A_BACK; } } } - else if ( pm->ps->saberAnimLevel != SS_FAST - && pm->ps->saberAnimLevel != SS_STAFF ) - {//medium and higher attacks - if ( (pm->ps->pm_flags&PMF_DUCKED) || pm->cmd.upmove < 0 ) - { - return LS_A_BACK_CR; + else + {//enemy in front + float enemyDistSq = DistanceSquared( pm->gent->currentOrigin, pm->gent->enemy->currentOrigin ); + if ( (pm->ps->saberAnimLevel == FORCE_LEVEL_1||pm->ps->saberAnimLevel == SS_STAFF||pm->gent->client->NPC_class==CLASS_TAVION||pm->gent->client->NPC_class == CLASS_ALORA||(pm->gent->client->NPC_class==CLASS_DESANN&&!Q_irand(0,3))) && enemyDistSq > 16384 || pm->gent->enemy->health <= 0 )//128 squared + {//my enemy is pretty far in front of me and I'm using fast attacks + if ( (pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer()) || + ( pm->gent && pm->gent->client && pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG && Q_irand( 0, pm->gent->NPC->rank ) > RANK_ENSIGN ) ) + {//only fencers and higher can do this, higher rank does it more + if ( PM_CheckEnemyInBack( 128 ) ) + { + return PM_PickBackStab(); + } + } } - else - { - return LS_A_BACK; + else if ( (pm->ps->saberAnimLevel >= FORCE_LEVEL_2 || pm->gent->client->NPC_class == CLASS_DESANN) && enemyDistSq > 40000 || pm->gent->enemy->health <= 0 )//200 squared + {//enemy is very faw away and I'm using medium/strong attacks + if ( (pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer()) || + ( pm->gent && pm->gent->client && pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG && Q_irand( 0, pm->gent->NPC->rank ) > RANK_ENSIGN ) ) + {//only fencers and higher can do this, higher rank does it more + if ( PM_CheckEnemyInBack( 164 ) ) + { + return PM_PickBackStab(); + } + } } } } else - {//enemy in front - float enemyDistSq = DistanceSquared( pm->gent->currentOrigin, pm->gent->enemy->currentOrigin ); - if ( (pm->ps->saberAnimLevel == FORCE_LEVEL_1||pm->ps->saberAnimLevel == SS_STAFF||pm->gent->client->NPC_class==CLASS_TAVION||pm->gent->client->NPC_class == CLASS_ALORA||(pm->gent->client->NPC_class==CLASS_DESANN&&!Q_irand(0,3))) && enemyDistSq > 16384 || pm->gent->enemy->health <= 0 )//128 squared - {//my enemy is pretty far in front of me and I'm using fast attacks - if ( (pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer()) || - ( pm->gent && pm->gent->client && pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG && Q_irand( 0, pm->gent->NPC->rank ) > RANK_ENSIGN ) ) - {//only fencers and higher can do this, higher rank does it more - if ( PM_CheckEnemyInBack( 128 ) ) - { - return PM_PickBackStab(); - } + {//no current enemy + if ( (pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer()) && pm->gent && pm->gent->client ) + {//only player + if ( PM_CheckEnemyInBack( 128 ) ) + { + return PM_PickBackStab(); } } - else if ( (pm->ps->saberAnimLevel >= FORCE_LEVEL_2 || pm->gent->client->NPC_class == CLASS_DESANN) && enemyDistSq > 40000 || pm->gent->enemy->health <= 0 )//200 squared - {//enemy is very faw away and I'm using medium/strong attacks - if ( (pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer()) || - ( pm->gent && pm->gent->client && pm->gent->NPC && pm->gent->NPC->rank >= RANK_LT_JG && Q_irand( 0, pm->gent->NPC->rank ) > RANK_ENSIGN ) ) - {//only fencers and higher can do this, higher rank does it more - if ( PM_CheckEnemyInBack( 164 ) ) - { - return PM_PickBackStab(); - } - } - } - } - } - else - {//no current enemy - if ( (pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer()) && pm->gent && pm->gent->client ) - {//only player - if ( PM_CheckEnemyInBack( 128 ) ) - { - return PM_PickBackStab(); - } } } } @@ -3844,12 +4399,24 @@ extern qboolean PM_SpinningSaberAnim( int anim ); extern float saberAnimSpeedMod[NUM_FORCE_POWER_LEVELS]; void PM_SaberStartTransAnim( int saberAnimLevel, int anim, float *animSpeed, gentity_t *gent ) { - if ( g_saberAnimSpeed->value != 1.0f ) + if ( anim >= BOTH_A1_T__B_ && anim <= BOTH_ROLL_STAB ) { - if ( anim >= BOTH_A1_T__B_ && anim <= BOTH_CROUCHATTACKBACK1 ) + if ( g_saberAnimSpeed->value != 1.0f ) { *animSpeed *= g_saberAnimSpeed->value; } + else if ( gent && gent->client && gent->client->ps.weapon == WP_SABER ) + { + if ( gent->client->ps.saber[0].animSpeedScale != 1.0f ) + { + *animSpeed *= gent->client->ps.saber[0].animSpeedScale; + } + if ( gent->client->ps.dualSabers + && gent->client->ps.saber[1].animSpeedScale != 1.0f ) + { + *animSpeed *= gent->client->ps.saber[1].animSpeedScale; + } + } } if ( gent && gent->client diff --git a/code/game/bg_pmove.cpp b/code/game/bg_pmove.cpp index 34d8335..97323ea 100644 --- a/code/game/bg_pmove.cpp +++ b/code/game/bg_pmove.cpp @@ -98,6 +98,8 @@ extern qboolean G_TryingSpecial( gentity_t *self, usercmd_t *cmd ); extern qboolean G_TryingJumpAttack( gentity_t *self, usercmd_t *cmd ); extern qboolean G_TryingJumpForwardAttack( gentity_t *self, usercmd_t *cmd ); extern void WP_SaberSwingSound( gentity_t *ent, int saberNum, swingType_t swingType ); +extern qboolean WP_UseFirstValidSaberStyle( gentity_t *ent, int *saberAnimLevel ); +extern qboolean WP_SaberStyleValidForSaber( gentity_t *ent, int saberAnimLevel ); qboolean PM_InKnockDown( playerState_t *ps ); qboolean PM_InKnockDownOnGround( playerState_t *ps ); @@ -125,6 +127,7 @@ extern cvar_t *d_slowmodeath; extern cvar_t *g_debugMelee; extern cvar_t *g_saberNewControlScheme; extern cvar_t *g_stepSlideFix; +extern cvar_t *g_saberAutoBlocking; static void PM_SetWaterLevelAtPoint( vec3_t org, int *waterlevel, int *watertype ); @@ -262,6 +265,15 @@ qboolean PM_CheckGrabWall( trace_t *trace ) {//player must have force jump 3 return qfalse; } + if ( (pm->ps->saber[0].saberFlags&SFL_NO_WALL_GRAB) ) + { + return qfalse; + } + if ( pm->ps->dualSabers + && (pm->ps->saber[1].saberFlags&SFL_NO_WALL_GRAB) ) + { + return qfalse; + } if ( (pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer()) ) {//player //only if we were in a longjump @@ -1241,7 +1253,10 @@ static qboolean PM_CheckJump( void ) pm->ps->legsAnim != BOTH_ALORA_FLIP_2 && pm->ps->legsAnim != BOTH_ALORA_FLIP_3 && cg.renderingThirdPerson//third person only - && !cg.zoomMode )//not zoomed in + && !cg.zoomMode //not zoomed in + && !(pm->ps->saber[0].saberFlags&SFL_NO_FLIPS)//okay to do flips with this saber + && (!pm->ps->dualSabers || !(pm->ps->saber[1].saberFlags&SFL_NO_FLIPS) )//okay to do flips with this saber + ) {//FIXME: this could end up playing twice if the jump is very long... int anim = BOTH_FORCEINAIR1; int parts = SETANIM_BOTH; @@ -1487,25 +1502,29 @@ static qboolean PM_CheckJump( void ) else if ( (pm->ps->clientNum >= MAX_CLIENTS&&!PM_ControlledByPlayer()) || pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 ) { - if ( pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer() ) - {//player: since we're on the ground, always do a cartwheel - /* - anim = BOTH_CARTWHEEL_RIGHT; - forcePowerCostOverride = G_CostForSpecialMove( SABER_ALT_ATTACK_POWER_LR ); - */ - } - else - { - vertPush = JUMP_VELOCITY; - if ( Q_irand( 0, 1 ) ) - { - anim = BOTH_ARIAL_RIGHT; + if ( !(pm->ps->saber[0].saberFlags&SFL_NO_CARTWHEELS) + && (!pm->ps->dualSabers || !(pm->ps->saber[1].saberFlags&SFL_NO_CARTWHEELS)) ) + {//okay to do cartwheels with this saber + if ( pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer() ) + {//player: since we're on the ground, always do a cartwheel + /* + anim = BOTH_CARTWHEEL_RIGHT; forcePowerCostOverride = G_CostForSpecialMove( SABER_ALT_ATTACK_POWER_LR ); + */ } else { - anim = BOTH_CARTWHEEL_RIGHT; - forcePowerCostOverride = G_CostForSpecialMove( SABER_ALT_ATTACK_POWER_LR ); + vertPush = JUMP_VELOCITY; + if ( Q_irand( 0, 1 ) ) + { + anim = BOTH_ARIAL_RIGHT; + forcePowerCostOverride = G_CostForSpecialMove( SABER_ALT_ATTACK_POWER_LR ); + } + else + { + anim = BOTH_CARTWHEEL_RIGHT; + forcePowerCostOverride = G_CostForSpecialMove( SABER_ALT_ATTACK_POWER_LR ); + } } } } @@ -1526,25 +1545,29 @@ static qboolean PM_CheckJump( void ) else if ( (pm->ps->clientNum >= MAX_CLIENTS&&!PM_ControlledByPlayer()) || pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 ) { - if ( pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer() ) - {//player: since we're on the ground, always do a cartwheel - /* - anim = BOTH_CARTWHEEL_LEFT; - forcePowerCostOverride = G_CostForSpecialMove( SABER_ALT_ATTACK_POWER_LR ); - */ - } - else - { - vertPush = JUMP_VELOCITY; - if ( Q_irand( 0, 1 ) ) - { - anim = BOTH_ARIAL_LEFT; + if ( !(pm->ps->saber[0].saberFlags&SFL_NO_CARTWHEELS) + && (!pm->ps->dualSabers || !(pm->ps->saber[1].saberFlags&SFL_NO_CARTWHEELS)) ) + {//okay to do cartwheels with this saber + if ( pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer() ) + {//player: since we're on the ground, always do a cartwheel + /* + anim = BOTH_CARTWHEEL_LEFT; forcePowerCostOverride = G_CostForSpecialMove( SABER_ALT_ATTACK_POWER_LR ); + */ } else { - anim = BOTH_CARTWHEEL_LEFT; - forcePowerCostOverride = G_CostForSpecialMove( SABER_ALT_ATTACK_POWER_LR ); + vertPush = JUMP_VELOCITY; + if ( Q_irand( 0, 1 ) ) + { + anim = BOTH_ARIAL_LEFT; + forcePowerCostOverride = G_CostForSpecialMove( SABER_ALT_ATTACK_POWER_LR ); + } + else + { + anim = BOTH_CARTWHEEL_LEFT; + forcePowerCostOverride = G_CostForSpecialMove( SABER_ALT_ATTACK_POWER_LR ); + } } } } @@ -1554,26 +1577,42 @@ static qboolean PM_CheckJump( void ) {//strafing right if ( pm->cmd.forwardmove > 0 ) {//wall-run - vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.0f; - anim = BOTH_WALL_RUN_RIGHT; + if ( !(pm->ps->saber[0].saberFlags&SFL_NO_WALL_RUNS) + && (!pm->ps->dualSabers || !(pm->ps->saber[1].saberFlags&SFL_NO_WALL_RUNS)) ) + {//okay to do wall-runs with this saber + vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.0f; + anim = BOTH_WALL_RUN_RIGHT; + } } else if ( pm->cmd.forwardmove == 0 ) {//wall-flip - vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.25f; - anim = BOTH_WALL_FLIP_RIGHT; + if ( !(pm->ps->saber[0].saberFlags&SFL_NO_WALL_FLIPS) + && (!pm->ps->dualSabers || !(pm->ps->saber[1].saberFlags&SFL_NO_WALL_FLIPS)) ) + {//okay to do wall-flips with this saber + vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.25f; + anim = BOTH_WALL_FLIP_RIGHT; + } } } else if ( pm->cmd.rightmove < 0 && pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 ) {//strafing left if ( pm->cmd.forwardmove > 0 ) {//wall-run - vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.0f; - anim = BOTH_WALL_RUN_LEFT; + if ( !(pm->ps->saber[0].saberFlags&SFL_NO_WALL_RUNS) + && (!pm->ps->dualSabers || !(pm->ps->saber[1].saberFlags&SFL_NO_WALL_RUNS)) ) + {//okay to do wall-runs with this saber + vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.0f; + anim = BOTH_WALL_RUN_LEFT; + } } else if ( pm->cmd.forwardmove == 0 ) {//wall-flip - vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.25f; - anim = BOTH_WALL_FLIP_LEFT; + if ( !(pm->ps->saber[0].saberFlags&SFL_NO_WALL_FLIPS) + && (!pm->ps->dualSabers || !(pm->ps->saber[1].saberFlags&SFL_NO_WALL_FLIPS)) ) + {//okay to do wall-flips with this saber + vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.25f; + anim = BOTH_WALL_FLIP_LEFT; + } } } else if ( /*pm->ps->clientNum >= MAX_CLIENTS//not the player @@ -1585,13 +1624,21 @@ static qboolean PM_CheckJump( void ) {//have to be moving... FIXME: make sure it's opposite the wall... or at least forward? if ( pm->ps->forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_2 ) {//run all the way up wwall - vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.0f; - anim = BOTH_FORCEWALLRUNFLIP_START; + if ( !(pm->ps->saber[0].saberFlags&SFL_NO_WALL_RUNS) + && (!pm->ps->dualSabers || !(pm->ps->saber[1].saberFlags&SFL_NO_WALL_RUNS)) ) + {//okay to do wall-runs with this saber + vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.0f; + anim = BOTH_FORCEWALLRUNFLIP_START; + } } else {//run just a couple steps up - vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.25f; - anim = BOTH_WALL_FLIP_BACK1; + if ( !(pm->ps->saber[0].saberFlags&SFL_NO_WALL_FLIPS) + && (!pm->ps->dualSabers || !(pm->ps->saber[1].saberFlags&SFL_NO_WALL_FLIPS)) ) + {//okay to do wall-flips with this saber + vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.25f; + anim = BOTH_WALL_FLIP_BACK1; + } } } } @@ -1601,46 +1648,82 @@ static qboolean PM_CheckJump( void ) {//back-jump does backflip... FIXME: always?! What about just doing a normal jump backwards? if ( pm->ps->velocity[2] >= 0 ) {//must be going up already - vertPush = JUMP_VELOCITY; - if ( pm->gent->client && pm->gent->client->NPC_class == CLASS_ALORA && !Q_irand( 0, 2 ) ) - { - anim = BOTH_ALORA_FLIP_B; - } - else - { - anim = PM_PickAnim( pm->gent, BOTH_FLIP_BACK1, BOTH_FLIP_BACK3 ); + if ( !(pm->ps->saber[0].saberFlags&SFL_NO_FLIPS) + && (!pm->ps->dualSabers || !(pm->ps->saber[1].saberFlags&SFL_NO_FLIPS)) ) + {//okay to do backstabs with this saber + vertPush = JUMP_VELOCITY; + if ( pm->gent->client && pm->gent->client->NPC_class == CLASS_ALORA && !Q_irand( 0, 2 ) ) + { + anim = BOTH_ALORA_FLIP_B; + } + else + { + anim = PM_PickAnim( pm->gent, BOTH_FLIP_BACK1, BOTH_FLIP_BACK3 ); + } } } } else if ( VectorLengthSquared( pm->ps->velocity ) < 256 /*16 squared*/) {//not moving - if ( pm->ps->weapon == WP_SABER && (pm->cmd.buttons & BUTTON_ATTACK) && pm->ps->saberAnimLevel == SS_MEDIUM ) + if ( pm->ps->weapon == WP_SABER && (pm->cmd.buttons & BUTTON_ATTACK) ) { - /* - //Only tavion does these now - if ( pm->ps->clientNum && Q_irand( 0, 1 ) ) - {//butterfly... FIXME: does direction matter? - vertPush = JUMP_VELOCITY; - if ( Q_irand( 0, 1 ) ) - { - anim = BOTH_BUTTERFLY_LEFT; + saberMoveName_t overrideJumpAttackUpMove = LS_INVALID; + if ( pm->ps->saber[0].jumpAtkUpMove != LS_INVALID ) + { + if ( pm->ps->saber[0].jumpAtkUpMove != LS_NONE ) + {//actually overriding + overrideJumpAttackUpMove = (saberMoveName_t)pm->ps->saber[0].jumpAtkUpMove; + } + else if ( pm->ps->dualSabers + && pm->ps->saber[1].jumpAtkUpMove > LS_NONE ) + {//would be cancelling it, but check the second saber, too + overrideJumpAttackUpMove = (saberMoveName_t)pm->ps->saber[1].jumpAtkUpMove; } else - { - anim = BOTH_BUTTERFLY_RIGHT; + {//nope, just cancel it + overrideJumpAttackUpMove = LS_NONE; } } - else - */if ( pm->ps->clientNum >= MAX_CLIENTS && !PM_ControlledByPlayer() )//NOTE: pretty much useless, so player never does these - {//jump-spin FIXME: does direction matter? - vertPush = forceJumpStrength[FORCE_LEVEL_2]/1.5f; - if ( pm->gent->client && pm->gent->client->NPC_class == CLASS_ALORA ) + else if ( pm->ps->dualSabers + && pm->ps->saber[1].jumpAtkUpMove != LS_INVALID ) + {//first saber not overridden, check second + overrideJumpAttackUpMove = (saberMoveName_t)pm->ps->saber[0].jumpAtkUpMove; + } + if ( overrideJumpAttackUpMove != LS_INVALID ) + {//do this move instead + if ( overrideJumpAttackUpMove != LS_NONE ) { - anim = BOTH_ALORA_SPIN; + anim = saberMoveData[overrideJumpAttackUpMove].animToUse; } - else - { - anim = Q_irand( BOTH_FJSS_TR_BL, BOTH_FJSS_TL_BR ); + } + else if ( pm->ps->saberAnimLevel == SS_MEDIUM ) + { + /* + //Only tavion does these now + if ( pm->ps->clientNum && Q_irand( 0, 1 ) ) + {//butterfly... FIXME: does direction matter? + vertPush = JUMP_VELOCITY; + if ( Q_irand( 0, 1 ) ) + { + anim = BOTH_BUTTERFLY_LEFT; + } + else + { + anim = BOTH_BUTTERFLY_RIGHT; + } + } + else + */if ( pm->ps->clientNum >= MAX_CLIENTS && !PM_ControlledByPlayer() )//NOTE: pretty much useless, so player never does these + {//jump-spin FIXME: does direction matter? + vertPush = forceJumpStrength[FORCE_LEVEL_2]/1.5f; + if ( pm->gent->client && pm->gent->client->NPC_class == CLASS_ALORA ) + { + anim = BOTH_ALORA_SPIN; + } + else + { + anim = Q_irand( BOTH_FJSS_TR_BL, BOTH_FJSS_TL_BR ); + } } } } @@ -2189,57 +2272,61 @@ static qboolean PM_CheckJump( void ) //&& (pm->ps->legsAnim == BOTH_JUMP1 || pm->ps->legsAnim == BOTH_INAIR1 ) )//not in a flip or spin or anything ) {//see if we're pushing at a wall and jump off it if so - //FIXME: make sure we have enough force power - //FIXME: check to see if we can go any higher - //FIXME: limit to a certain number of these in a row? - //FIXME: maybe don't require a ucmd direction, just check all 4? - //FIXME: should stick to the wall for a second, then push off... - vec3_t checkDir, traceto, mins = {pm->mins[0],pm->mins[1],0}, maxs = {pm->maxs[0],pm->maxs[1],24}, fwdAngles = {0, pm->ps->viewangles[YAW], 0}; - trace_t trace; - vec3_t idealNormal; - int anim = -1; + if ( !(pm->ps->saber[0].saberFlags&SFL_NO_WALL_GRAB) + && ( !pm->ps->dualSabers || !(pm->ps->saber[1].saberFlags&SFL_NO_WALL_GRAB) ) ) + {//okay to do wall-grabs with this saber + //FIXME: make sure we have enough force power + //FIXME: check to see if we can go any higher + //FIXME: limit to a certain number of these in a row? + //FIXME: maybe don't require a ucmd direction, just check all 4? + //FIXME: should stick to the wall for a second, then push off... + vec3_t checkDir, traceto, mins = {pm->mins[0],pm->mins[1],0}, maxs = {pm->maxs[0],pm->maxs[1],24}, fwdAngles = {0, pm->ps->viewangles[YAW], 0}; + trace_t trace; + vec3_t idealNormal; + int anim = -1; - if ( pm->cmd.rightmove ) - { - if ( pm->cmd.rightmove > 0 ) + if ( pm->cmd.rightmove ) { - anim = BOTH_FORCEWALLREBOUND_RIGHT; - AngleVectors( fwdAngles, NULL, checkDir, NULL ); + if ( pm->cmd.rightmove > 0 ) + { + anim = BOTH_FORCEWALLREBOUND_RIGHT; + AngleVectors( fwdAngles, NULL, checkDir, NULL ); + } + else if ( pm->cmd.rightmove < 0 ) + { + anim = BOTH_FORCEWALLREBOUND_LEFT; + AngleVectors( fwdAngles, NULL, checkDir, NULL ); + VectorScale( checkDir, -1, checkDir ); + } } - else if ( pm->cmd.rightmove < 0 ) + else if ( pm->cmd.forwardmove > 0 ) { - anim = BOTH_FORCEWALLREBOUND_LEFT; - AngleVectors( fwdAngles, NULL, checkDir, NULL ); + anim = BOTH_FORCEWALLREBOUND_FORWARD; + AngleVectors( fwdAngles, checkDir, NULL, NULL ); + } + else if ( pm->cmd.forwardmove < 0 ) + { + anim = BOTH_FORCEWALLREBOUND_BACK; + AngleVectors( fwdAngles, checkDir, NULL, NULL ); VectorScale( checkDir, -1, checkDir ); } - } - else if ( pm->cmd.forwardmove > 0 ) - { - anim = BOTH_FORCEWALLREBOUND_FORWARD; - AngleVectors( fwdAngles, checkDir, NULL, NULL ); - } - else if ( pm->cmd.forwardmove < 0 ) - { - anim = BOTH_FORCEWALLREBOUND_BACK; - AngleVectors( fwdAngles, checkDir, NULL, NULL ); - VectorScale( checkDir, -1, checkDir ); - } - if ( anim != -1 ) - {//trace in the dir we're pushing in and see if there's a vertical wall there - VectorMA( pm->ps->origin, 16, checkDir, traceto );//was 8 - pm->trace( &trace, pm->ps->origin, mins, maxs, traceto, pm->ps->clientNum, CONTENTS_SOLID );//FIXME: clip brushes too? - VectorSubtract( pm->ps->origin, traceto, idealNormal ); - VectorNormalize( idealNormal ); - gentity_t *traceEnt = &g_entities[trace.entityNum]; - if ( trace.fraction < 1.0f - && fabs(trace.plane.normal[2]) <= MAX_WALL_GRAB_SLOPE - &&((trace.entityNums.solid!=SOLID_BMODEL)||DotProduct(trace.plane.normal,idealNormal)>0.7) ) - {//there is a wall there - float dot = DotProduct( pm->ps->velocity, trace.plane.normal ); - if ( dot < 1.0f ) - {//can't be heading *away* from the wall! - //grab it! - PM_GrabWallForJump( anim ); + if ( anim != -1 ) + {//trace in the dir we're pushing in and see if there's a vertical wall there + VectorMA( pm->ps->origin, 16, checkDir, traceto );//was 8 + pm->trace( &trace, pm->ps->origin, mins, maxs, traceto, pm->ps->clientNum, CONTENTS_SOLID );//FIXME: clip brushes too? + VectorSubtract( pm->ps->origin, traceto, idealNormal ); + VectorNormalize( idealNormal ); + gentity_t *traceEnt = &g_entities[trace.entityNum]; + if ( trace.fraction < 1.0f + && fabs(trace.plane.normal[2]) <= MAX_WALL_GRAB_SLOPE + &&((trace.entityNums.solid!=SOLID_BMODEL)||DotProduct(trace.plane.normal,idealNormal)>0.7) ) + {//there is a wall there + float dot = DotProduct( pm->ps->velocity, trace.plane.normal ); + if ( dot < 1.0f ) + {//can't be heading *away* from the wall! + //grab it! + PM_GrabWallForJump( anim ); + } } } } @@ -3676,6 +3763,15 @@ static qboolean PM_TryRoll( void ) { return qfalse; } + if ( (pm->ps->saber[0].saberFlags&SFL_NO_ROLLS) ) + { + return qfalse; + } + if ( pm->ps->dualSabers + && (pm->ps->saber[1].saberFlags&SFL_NO_ROLLS) ) + { + return qfalse; + } if ( pm->ps->clientNum && pm->gent->NPC ) {//NPC if ( pm->gent->NPC->scriptFlags&SCF_NO_ACROBATICS ) @@ -9131,6 +9227,15 @@ int PM_ReadyPoseForSaberAnimLevel( void ) qboolean PM_CanDoDualDoubleAttacks( void ) { + if ( (pm->ps->saber[0].saberFlags&SFL_NO_MIRROR_ATTACKS) ) + { + return qfalse; + } + if ( pm->ps->dualSabers + && (pm->ps->saber[1].saberFlags&SFL_NO_MIRROR_ATTACKS) ) + { + return qfalse; + } //NOTE: assumes you're using SS_DUAL style and have both sabers on... if ( (pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer()) ) {//player @@ -9215,19 +9320,32 @@ void PM_SetSaberMove(saberMoveName_t newMove) if ( pm->ps->saberBlockingTime > cg.time ) { manualBlocking = qtrue; + if ( !pm->ps->SaberActive() ) + {//turn on all blades and sabers if none are currently on + pm->ps->SaberActivate(); + } if ( pm->ps->saber[0].type == SABER_CLAW ) { anim = BOTH_INAIR1;//FIXME: is there a better anim for this? } else if ( pm->ps->dualSabers && pm->ps->saber[1].Active() ) - { - anim = BOTH_INAIR1; + { + anim = BOTH_INAIR1; } else { anim = BOTH_P1_S1_T_; } } + else if ( pm->ps->saber[0].readyAnim != -1 ) + { + anim = pm->ps->saber[0].readyAnim; + } + else if ( pm->ps->dualSabers + && pm->ps->saber[1].readyAnim != -1 ) + { + anim = pm->ps->saber[1].readyAnim; + } else if ( pm->ps->saber[0].type == SABER_ARC ) {//FIXME: need it's own style? anim = BOTH_SABERFAST_STANCE; @@ -9257,11 +9375,22 @@ void PM_SetSaberMove(saberMoveName_t newMove) pm->ps->saberMove = newMove; return; } - if ( pm->ps->saber[0].style == SS_STAFF ) + if ( pm->ps->saber[0].drawAnim != -1 ) + { + anim = pm->ps->saber[0].drawAnim; + } + else if ( pm->ps->dualSabers + && pm->ps->saber[1].drawAnim != -1 ) + { + anim = pm->ps->saber[1].drawAnim; + } + else if ( pm->ps->saber[0].stylesLearned==(1<ps->dualSabers && pm->ps->saber[0].style == SS_NONE && pm->ps->saber[1].style == SS_NONE ) + else if ( pm->ps->dualSabers + && !(pm->ps->saber[0].stylesForbidden&(1<ps->saber[1].stylesForbidden&(1<ps->saber[0].style == SS_STAFF + if ( pm->ps->saber[0].putawayAnim != -1 ) + { + anim = pm->ps->saber[0].putawayAnim; + } + else if ( pm->ps->dualSabers + && pm->ps->saber[1].putawayAnim != -1 ) + { + anim = pm->ps->saber[1].putawayAnim; + } + else if ( pm->ps->saber[0].stylesLearned==(1<ps->saber[0].blade[1].active ) { anim = BOTH_S7_S1; } else if ( pm->ps->dualSabers - && pm->ps->saber[0].style == SS_NONE - && pm->ps->saber[1].style == SS_NONE + && !(pm->ps->saber[0].stylesForbidden&(1<ps->saber[1].stylesForbidden&(1<ps->saber[1].Active() ) { anim = BOTH_S6_S1; @@ -9542,9 +9680,21 @@ void PM_SetSaberMove(saberMoveName_t newMove) } } } - else if ( PM_SaberInStart( newMove ) && pm->ps->saberAnimLevel == SS_STRONG ) + else if ( PM_SaberInStart( newMove ) ) { - WP_SaberSwingSound( pm->gent, 0, SWING_FAST ); + //if ( g_saberRealisticCombat->integer < 1 ) + {//don't damage on the first few frames of a start anim because it may pop from one position to some drastically different one, killing the enemy without hitting them. + int damageDelay = 150; + if ( pm->ps->torsoAnimTimer < damageDelay ) + { + damageDelay = pm->ps->torsoAnimTimer; + } + //ent->client->ps.saberDamageDebounceTime = level.time + damageDelay; + } + if ( pm->ps->saberAnimLevel == SS_STRONG ) + { + WP_SaberSwingSound( pm->gent, 0, SWING_FAST ); + } } } @@ -10310,11 +10460,12 @@ void PM_SaberLockBreak( gentity_t *gent, gentity_t *genemy, saberLockResult_t re } //else see if we can knock the saber out of their hand //FIXME: for now, always disarm the right-hand saber - if ( genemy->client->ps.saber[0].disarmable ) + if ( !(genemy->client->ps.saber[0].saberFlags&SFL_NOT_DISARMABLE) ) { //add disarmBonus into this check - victoryStrength += pm->ps->SaberDisarmBonus()*2; - if ( genemy->client->ps.saber[0].twoHanded || (genemy->client->ps.dualSabers && genemy->client->ps.saber[1].Active()) ) + victoryStrength += pm->ps->SaberDisarmBonus( 0 )*2; + if ( (genemy->client->ps.saber[0].saberFlags&SFL_TWO_HANDED) + || (genemy->client->ps.dualSabers && genemy->client->ps.saber[1].Active()) ) {//defender gets a bonus for using a 2-handed saber or 2 sabers victoryStrength -= 2; } @@ -10332,7 +10483,7 @@ void PM_SaberLockBreak( gentity_t *gent, gentity_t *genemy, saberLockResult_t re } if ( Q_irand( 0, 10 ) < victoryStrength ) { - if ( !genemy->client->ps.saber[0].twoHanded + if ( !(genemy->client->ps.saber[0].saberFlags&SFL_TWO_HANDED) || !Q_irand( 0, 1 ) ) {//if it's a two-handed saber, it has a 50% chance of resisting a disarming WP_SaberLose( genemy, throwDir ); @@ -10355,7 +10506,7 @@ void PM_SaberLockBreak( gentity_t *gent, gentity_t *genemy, saberLockResult_t re int G_SaberLockStrength( gentity_t *gent ) { int strength = gent->client->ps.saber[0].lockBonus; - if ( gent->client->ps.saber[0].twoHanded ) + if ( (gent->client->ps.saber[0].saberFlags&SFL_TWO_HANDED) ) { strength += 1; } @@ -11049,13 +11200,13 @@ qboolean PM_SaberThrowable( void ) return qfalse; } - if ( pm->ps->saber[0].throwable ) + if ( !(pm->ps->saber[0].saberFlags&SFL_NOT_THROWABLE) ) {//yes, this saber is always throwable return qtrue; } //saber is not normally throwable - if ( pm->ps->saber[0].singleBladeThrowable ) + if ( (pm->ps->saber[0].saberFlags&SFL_SINGLE_BLADE_THROWABLE) ) {//it is throwable if only one blade is on if ( pm->ps->saber[0].numBlades > 1 ) {//it has more than one blade @@ -11082,7 +11233,11 @@ qboolean PM_CheckAltKickAttack( void ) if ( (pm->cmd.buttons&BUTTON_ALT_ATTACK) && (!(pm->ps->pm_flags&PMF_ALT_ATTACK_HELD) ||PM_SaberInReturn(pm->ps->saberMove)) && (!PM_FlippingAnim(pm->ps->legsAnim)||pm->ps->legsAnimTimer<=250) - && (!PM_SaberThrowable()) && pm->ps->SaberActive() ) + && (!PM_SaberThrowable()) + && pm->ps->SaberActive() + && !(pm->ps->saber[0].saberFlags&SFL_NO_KICKS)//okay to do kicks with this saber + && (!pm->ps->dualSabers || !(pm->ps->saber[1].saberFlags&SFL_NO_KICKS) )//okay to do kicks with this saber + ) { return qtrue; } @@ -11917,19 +12072,54 @@ void PM_WeaponLightsaber(void) pm->ps->saberAnimLevel = pm->ps->saber[0].singleBladeStyle;//SS_STRONG; animLevelOverridden = qtrue; } - else if ( pm->ps->saber[0].Active() && pm->ps->saber[0].style != SS_NONE ) - {//one of the sabers I'm using forces me to use a single style - pm->ps->saberAnimLevel = pm->ps->saber[0].style; + else if ( pm->gent + && cg.saberAnimLevelPending != pm->ps->saberAnimLevel + && WP_SaberStyleValidForSaber( pm->gent, cg.saberAnimLevelPending ) ) + {//go ahead and use the cg.saberAnimLevelPending below + animLevelOverridden = qfalse; + } + else if ( pm->gent + && ( WP_SaberStyleValidForSaber( pm->gent, pm->ps->saberAnimLevel ) + || WP_UseFirstValidSaberStyle( pm->gent, &pm->ps->saberAnimLevel ) ) ) + {//style we are using is not valid, switched us to a valid one animLevelOverridden = qtrue; } + /* + else if ( pm->ps->saber[0].Active() + && pm->ps->saber[0].stylesAllowed ) + {//one of the sabers I'm using forces me to use one of a set of styles + if ( !(pm->ps->saber[0].stylesAllowed&(1<ps->saberAnimLevel)) ) + {//I'm not currently using a valid one + for ( int styleNum = SS_NONE+1; styleNum < SS_NUM_SABER_STYLES; styleNum++ ) + {//loop through and use the first valid one + if ( (pm->ps->saber[0].stylesAllowed&(1<ps->saberAnimLevel = styleNum; + animLevelOverridden = qtrue; + } + } + } + } + */ else if ( pm->ps->dualSabers ) { - if ( pm->ps->saber[1].Active() && pm->ps->saber[1].style != SS_NONE ) - {//one of the sabers I'm using forces me to use a single style - pm->ps->saberAnimLevel = pm->ps->saber[1].style; - animLevelOverridden = qtrue; + /* + if ( pm->ps->saber[1].Active() + && pm->ps->saber[1].stylesAllowed ) + {//one of the sabers I'm using forces me to use one of a set of styles + if ( !(pm->ps->saber[1].stylesAllowed&(1<ps->saberAnimLevel)) ) + {//I'm not currently using a valid one + for ( int styleNum = SS_NONE+1; styleNum < SS_NUM_SABER_STYLES; styleNum++ ) + {//loop through and use the first valid one + if ( (pm->ps->saber[1].stylesAllowed&(1<ps->saberAnimLevel = styleNum; + animLevelOverridden = qtrue; + } + } + } } - else if ( pm->ps->saber[1].Active() ) + else*/ if ( pm->ps->saber[1].Active() ) {//if second saber is on, must use dual style pm->ps->saberAnimLevel = SS_DUAL; animLevelOverridden = qtrue; @@ -11937,7 +12127,7 @@ void PM_WeaponLightsaber(void) else if ( pm->ps->saber[0].Active() ) {//with only one saber on, use fast style pm->ps->saberAnimLevel = SS_FAST; - animLevelOverridden = qtrue; + animLevelOverridden = qtrue; } } if ( !animLevelOverridden ) @@ -11993,10 +12183,14 @@ void PM_WeaponLightsaber(void) { if ( G_EnoughPowerForSpecialMove( pm->ps->forcePower, SABER_ALT_ATTACK_POWER_FB ) ) { - PM_SetSaberMove( LS_ROLL_STAB ); - if ( pm->gent ) - { - G_DrainPowerForSpecialMove( pm->gent, FP_SABER_OFFENSE, SABER_ALT_ATTACK_POWER_FB ); + if ( !(pm->ps->saber[0].saberFlags&SFL_NO_ROLL_STAB) + && (!pm->ps->dualSabers || !(pm->ps->saber[1].saberFlags&SFL_NO_ROLL_STAB)) ) + {//okay to do roll-stab + PM_SetSaberMove( LS_ROLL_STAB ); + if ( pm->gent ) + { + G_DrainPowerForSpecialMove( pm->gent, FP_SABER_OFFENSE, SABER_ALT_ATTACK_POWER_FB ); + } } } } @@ -12277,34 +12471,87 @@ void PM_WeaponLightsaber(void) if ( PM_CanDoKata() ) { - //FIXME: make sure to turn on saber(s)! - switch ( pm->ps->saberAnimLevel ) + saberMoveName_t overrideMove = LS_INVALID; + //see if we have an overridden (or cancelled) kata move + if ( pm->ps->saber[0].kataMove != LS_INVALID ) { - case SS_FAST: - case SS_TAVION: - PM_SetSaberMove( LS_A1_SPECIAL ); - break; - case SS_MEDIUM: - PM_SetSaberMove( LS_A2_SPECIAL ); - break; - case SS_STRONG: - case SS_DESANN: - PM_SetSaberMove( LS_A3_SPECIAL ); - break; - case SS_DUAL: - PM_SetSaberMove( LS_DUAL_SPIN_PROTECT );//PM_CheckDualSpinProtect(); - break; - case SS_STAFF: - PM_SetSaberMove( LS_STAFF_SOULCAL ); - break; + if ( pm->ps->saber[0].kataMove != LS_NONE ) + { + overrideMove = (saberMoveName_t)pm->ps->saber[0].kataMove; + } } - pm->ps->weaponstate = WEAPON_FIRING; - if ( pm->gent ) + if ( overrideMove == LS_INVALID ) + {//not overridden by first saber, check second + if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].kataMove != LS_INVALID ) + { + if ( pm->ps->saber[1].kataMove != LS_NONE ) + { + overrideMove = (saberMoveName_t)pm->ps->saber[1].kataMove; + } + } + } + } + //no overrides, cancelled? + if ( overrideMove == LS_INVALID ) { - G_DrainPowerForSpecialMove( pm->gent, FP_SABER_OFFENSE, SABER_ALT_ATTACK_POWER, qtrue );//FP_SPEED, SINGLE_SPECIAL_POWER ); - //G_StartMatrixEffect( pm->gent, MEF_REVERSE_SPIN, pm->ps->torsoAnimTimer ); + if ( pm->ps->saber[0].kataMove == LS_NONE ) + { + overrideMove = LS_NONE; + } + else if ( pm->ps->dualSabers ) + { + if ( pm->ps->saber[1].kataMove == LS_NONE ) + { + overrideMove = LS_NONE; + } + } + } + if ( overrideMove == LS_INVALID ) + {//not overridden + //FIXME: make sure to turn on saber(s)! + switch ( pm->ps->saberAnimLevel ) + { + case SS_FAST: + case SS_TAVION: + PM_SetSaberMove( LS_A1_SPECIAL ); + break; + case SS_MEDIUM: + PM_SetSaberMove( LS_A2_SPECIAL ); + break; + case SS_STRONG: + case SS_DESANN: + PM_SetSaberMove( LS_A3_SPECIAL ); + break; + case SS_DUAL: + PM_SetSaberMove( LS_DUAL_SPIN_PROTECT );//PM_CheckDualSpinProtect(); + break; + case SS_STAFF: + PM_SetSaberMove( LS_STAFF_SOULCAL ); + break; + } + pm->ps->weaponstate = WEAPON_FIRING; + if ( pm->gent ) + { + G_DrainPowerForSpecialMove( pm->gent, FP_SABER_OFFENSE, SABER_ALT_ATTACK_POWER, qtrue );//FP_SPEED, SINGLE_SPECIAL_POWER ); + //G_StartMatrixEffect( pm->gent, MEF_REVERSE_SPIN, pm->ps->torsoAnimTimer ); + } + } + else if ( overrideMove != LS_NONE ) + { + PM_SetSaberMove( overrideMove ); + pm->ps->weaponstate = WEAPON_FIRING; + if ( pm->gent ) + { + G_DrainPowerForSpecialMove( pm->gent, FP_SABER_OFFENSE, SABER_ALT_ATTACK_POWER, qtrue );//FP_SPEED, SINGLE_SPECIAL_POWER ); + //G_StartMatrixEffect( pm->gent, MEF_REVERSE_SPIN, pm->ps->torsoAnimTimer ); + } + } + if ( overrideMove != LS_NONE ) + {//not cancelled + return; } - return; } if ( PM_CheckAltKickAttack() ) @@ -14317,6 +14564,14 @@ void PM_AdjustAttackStates( pmove_t *pm ) { int amount; + if ( !g_saberAutoBlocking->integer + && !g_saberNewControlScheme->integer + && (pm->cmd.buttons&BUTTON_FORCE_FOCUS) ) + { + pm->ps->saberBlockingTime = pm->cmd.serverTime + 100; + pm->cmd.buttons &= ~BUTTON_ATTACK; + pm->cmd.buttons &= ~BUTTON_ALT_ATTACK; + } // get ammo usage if ( pm->cmd.buttons & BUTTON_ALT_ATTACK ) { @@ -14340,7 +14595,7 @@ void PM_AdjustAttackStates( pmove_t *pm ) } //saber staff alt-attack does a special attack anim, non-throwable sabers do kicks if ( pm->ps->saberAnimLevel != SS_STAFF - && pm->ps->saber[0].throwable ) + && !(pm->ps->saber[0].saberFlags&SFL_NOT_THROWABLE) ) {//using a throwable saber, so remove the saber throw button if ( !g_saberNewControlScheme->integer && PM_CanDoKata() ) diff --git a/code/game/bg_public.h b/code/game/bg_public.h index 3d04738..7ac9092 100644 --- a/code/game/bg_public.h +++ b/code/game/bg_public.h @@ -508,6 +508,14 @@ typedef struct animation_s { #define AED_MOVE_FWD 0 #define AED_MOVE_RT 1 #define AED_MOVE_UP 2 +//indices for AEV_SABER_SWING data +#define AED_SABER_SWING_SABERNUM 0 +#define AED_SABER_SWING_TYPE 1 +#define AED_SABER_SWING_PROBABILITY 2 +//indices for AEV_SABER_SPIN data +#define AED_SABER_SPIN_SABERNUM 0 +#define AED_SABER_SPIN_TYPE 1 //0 = saberspinoff, 1 = saberspin, 2-4 = saberspin1-saberspin3 +#define AED_SABER_SPIN_PROBABILITY 2 typedef enum {//NOTENOTE: Be sure to update animEventTypeTable and ParseAnimationEvtBlock(...) if you change this enum list! @@ -518,6 +526,8 @@ typedef enum AEV_FIRE, //# animID AEV_FIRE framenum altfire chancetofire AEV_MOVE, //# animID AEV_MOVE framenum forwardpush rightpush uppush AEV_SOUNDCHAN, //# animID AEV_SOUNDCHAN framenum CHANNEL soundpath randomlow randomhi chancetoplay + AEV_SABER_SWING, //# animID AEV_SABER_SWING framenum CHANNEL randomlow randomhi chancetoplay + AEV_SABER_SPIN, //# animID AEV_SABER_SPIN framenum CHANNEL chancetoplay AEV_NUM_AEV } animEventType_t; diff --git a/code/game/bg_vehicleLoad.c b/code/game/bg_vehicleLoad.c index 865da19..6a83286 100644 --- a/code/game/bg_vehicleLoad.c +++ b/code/game/bg_vehicleLoad.c @@ -69,8 +69,8 @@ extern stringID_table_t animTable [MAX_ANIMATIONS+1]; // These buffers are filled in with the same contents and then just read from in // a few places. We only need one copy on Xbox. -#define MAX_VEH_WEAPON_DATA_SIZE 0x4000 -#define MAX_VEHICLE_DATA_SIZE 0x10000 +#define MAX_VEH_WEAPON_DATA_SIZE 0x20000 +#define MAX_VEHICLE_DATA_SIZE 0x80000 #if !defined(_XBOX) || defined(QAGAME) char VehWeaponParms[MAX_VEH_WEAPON_DATA_SIZE]; @@ -151,6 +151,7 @@ vehField_t vehWeaponFields[NUM_VWEAP_PARMS] = {"loopSound", VWFOFS(iLoopSound), VF_SOUND_CLIENT}, //index of loopSound {"speed", VWFOFS(fSpeed), VF_FLOAT}, //speed of projectile/range of traceline {"homing", VWFOFS(fHoming), VF_FLOAT}, //0.0 = not homing, 0.5 = half vel to targ, half cur vel, 1.0 = all vel to targ + {"homingFOV", VWFOFS(fHomingFOV), VF_FLOAT},//missile will lose lock on if DotProduct of missile direction and direction to target ever drops below this (-1 to 1, -1 = never lose target, 0 = lose if ship gets behind missile, 1 = pretty much will lose it's target right away) {"lockOnTime", VWFOFS(iLockOnTime), VF_INT}, //0 = no lock time needed, else # of ms needed to lock on {"damage", VWFOFS(iDamage), VF_INT}, //damage done when traceline or projectile directly hits target {"splashDamage", VWFOFS(iSplashDamage), VF_INT},//damage done to ents in splashRadius of end of traceline or projectile origin on impact @@ -1338,6 +1339,7 @@ int VEH_LoadVehicle( const char *vehicleName ) G_SoundIndex( "sound/vehicles/common/release.wav" ); #elif CGAME trap_R_RegisterShader( "gfx/menus/radar/bracket" ); + trap_R_RegisterShader( "gfx/menus/radar/lead" ); trap_R_RegisterShaderNoMip( "gfx/menus/radar/asteroid" ); trap_S_RegisterSound( "sound/vehicles/common/impactalarm.wav" ); trap_S_RegisterSound( "sound/vehicles/common/linkweaps.wav" ); diff --git a/code/game/g_active.cpp b/code/game/g_active.cpp index 18901e0..434d9b8 100644 --- a/code/game/g_active.cpp +++ b/code/game/g_active.cpp @@ -166,6 +166,15 @@ int G_FindLookItem( gentity_t *self ) {//can't see him continue; } + if ( ent->item->giType == IT_WEAPON + && ent->item->giType == WP_SABER ) + {//a weapon_saber pickup + if ( self->client->ps.dualSabers//using 2 sabers already + || (self->client->ps.saber[0].saberFlags&SFL_TWO_HANDED) )//using a 2-handed saber + {//hands are full already, don't look at saber pickups + continue; + } + } //rate him based on how close & how in front he is VectorSubtract( ent->currentOrigin, center, dir ); rating = (1.0f-(VectorNormalize( dir )/radius)); @@ -4691,6 +4700,20 @@ void ClientAlterSpeed(gentity_t *ent, usercmd_t *ucmd, qboolean controlledByPlay { client->ps.speed *= 0.75; } + + if ( client->ps.weapon == WP_SABER ) + { + if ( client->ps.saber[0].moveSpeedScale != 1.0f ) + { + client->ps.speed *= client->ps.saber[0].moveSpeedScale; + } + if ( client->ps.dualSabers + && client->ps.saber[1].moveSpeedScale != 1.0f ) + { + client->ps.speed *= client->ps.saber[1].moveSpeedScale; + } + } + } } diff --git a/code/game/g_client.cpp b/code/game/g_client.cpp index ae848ac..f12797a 100644 --- a/code/game/g_client.cpp +++ b/code/game/g_client.cpp @@ -667,7 +667,7 @@ Player_RestoreFromPrevLevel Argument : gentity_t *ent ============ */ -void Player_RestoreFromPrevLevel(gentity_t *ent) +static void Player_RestoreFromPrevLevel(gentity_t *ent, SavedGameJustLoaded_e eSavedGameJustLoaded) { gclient_t *client = ent->client; int i; @@ -810,15 +810,57 @@ void Player_RestoreFromPrevLevel(gentity_t *ent) var = strtok( s, " " ); while( var != NULL ) { - /* While there are tokens in "s" */ - client->ps.forcePowerLevel[i++] = atoi(var); - /* Get next token: */ - var = strtok( NULL, " " ); + /* While there are tokens in "s" */ + client->ps.forcePowerLevel[i++] = atoi(var); + /* Get next token: */ + var = strtok( NULL, " " ); } assert (i==NUM_FORCE_POWERS); client->ps.forceGripEntityNum = client->ps.forceDrainEntityNum = ENTITYNUM_NONE; } + + + // if we're in DEMO mode read in the forcepowers from the + // demo cvar, even though we already might have read in something from above + if(eSavedGameJustLoaded == eNO && gi.Cvar_VariableIntegerValue("com_demo") ) + { + // the new JK2 stuff - force powers, etc... + // + gi.Cvar_VariableStringBuffer( "demo_playerfplvl", s, sizeof(s) ); + int j=0; + var = strtok( s, " " ); + while( var != NULL ) + { + /* While there are tokens in "s" */ + client->ps.forcePowerLevel[j] = atoi(var); + if( client->ps.forcePowerLevel[j] ) + { + client->ps.forcePowersKnown |= (1 << j ); + } + j++; + /* Get next token: */ + var = strtok( NULL, " " ); + } + assert (j==NUM_FORCE_POWERS); + + client->ps.forceGripEntityNum = client->ps.forceDrainEntityNum = ENTITYNUM_NONE; + + // now do weapons + gi.Cvar_VariableStringBuffer( "demo_playerwpns", s, sizeof(s) ); + + client->ps.stats[STAT_WEAPONS] = atoi(s); + + for(j=0 ; jps.stats[STAT_WEAPONS] & (1<ps.ammo[weaponData[j].ammoIndex] = ammoData[weaponData[j].ammoIndex].max; + } + } + + } } } @@ -1817,9 +1859,13 @@ void G_SetSabersFromCVars( gentity_t *ent ) && Q_stricmp( "NULL", g_saber->string ) ) {//FIXME: how to specify second saber? WP_SaberParseParms( g_saber->string, &ent->client->ps.saber[0] ); - if ( ent->client->ps.saber[0].style ) + if ( ent->client->ps.saber[0].stylesLearned ) { - ent->client->ps.saberStylesKnown |= (1<client->ps.saber[0].style); + ent->client->ps.saberStylesKnown |= ent->client->ps.saber[0].stylesLearned; + } + if ( ent->client->ps.saber[0].singleBladeStyle ) + { + ent->client->ps.saberStylesKnown |= ent->client->ps.saber[0].singleBladeStyle; } } @@ -1847,14 +1893,18 @@ void G_SetSabersFromCVars( gentity_t *ent ) && Q_stricmp( "none", g_saber2->string ) && Q_stricmp( "NULL", g_saber2->string ) ) { - if ( !ent->client->ps.saber[0].twoHanded ) + if ( !(ent->client->ps.saber[0].saberFlags&SFL_TWO_HANDED) ) {//can't use a second saber if first one is a two-handed saber...? WP_SaberParseParms( g_saber2->string, &ent->client->ps.saber[1] ); - if ( ent->client->ps.saber[1].style ) + if ( ent->client->ps.saber[1].stylesLearned ) { - ent->client->ps.saberStylesKnown |= (1<client->ps.saber[1].style); + ent->client->ps.saberStylesKnown |= ent->client->ps.saber[1].stylesLearned; } - if ( ent->client->ps.saber[1].twoHanded ) + if ( ent->client->ps.saber[1].singleBladeStyle ) + { + ent->client->ps.saberStylesKnown |= ent->client->ps.saber[1].singleBladeStyle; + } + if ( (ent->client->ps.saber[1].saberFlags&SFL_TWO_HANDED) ) {//tsk tsk, can't use a twoHanded saber as second saber WP_RemoveSaber( ent, 1 ); } @@ -1992,17 +2042,25 @@ void G_ReloadSaberData( gentity_t *ent ) if ( ent->client->ps.saber[0].name != NULL ) { WP_SaberParseParms( ent->client->ps.saber[0].name, &ent->client->ps.saber[0], qfalse ); - if ( ent->client->ps.saber[0].style ) + if ( ent->client->ps.saber[0].stylesLearned ) { - ent->client->ps.saberStylesKnown |= (1<client->ps.saber[0].style); + ent->client->ps.saberStylesKnown |= ent->client->ps.saber[0].stylesLearned; + } + if ( ent->client->ps.saber[0].singleBladeStyle ) + { + ent->client->ps.saberStylesKnown |= ent->client->ps.saber[0].singleBladeStyle; } } if ( ent->client->ps.saber[1].name != NULL ) { WP_SaberParseParms( ent->client->ps.saber[1].name, &ent->client->ps.saber[1], qfalse ); - if ( ent->client->ps.saber[1].style ) + if ( ent->client->ps.saber[1].stylesLearned ) { - ent->client->ps.saberStylesKnown |= (1<client->ps.saber[1].style); + ent->client->ps.saberStylesKnown |= ent->client->ps.saber[1].stylesLearned; + } + if ( ent->client->ps.saber[1].singleBladeStyle ) + { + ent->client->ps.saberStylesKnown |= ent->client->ps.saber[1].singleBladeStyle; } } } @@ -2216,9 +2274,13 @@ qboolean ClientSpawn(gentity_t *ent, SavedGameJustLoaded_e eSavedGameJustLoaded client->ps.saberStylesKnown |= (1<ps.saber[0].style ) +// if ( client->ps.saber[0].stylesLearned ) // { -// client->ps.saberStylesKnown |= (1<ps.saber[0].style); +// client->ps.saberStylesKnown |= client->ps.saber[0].stylesLearned; +// } +// if ( ent->client->ps.saber[1].singleSaberStyle ) +// { +// ent->client->ps.saberStylesKnown |= ent->client->ps.saber[1].singleSaberStyle; // } WP_InitForcePowers( ent );//Initialize force powers } @@ -2264,7 +2326,7 @@ qboolean ClientSpawn(gentity_t *ent, SavedGameJustLoaded_e eSavedGameJustLoaded // restore some player data // - Player_RestoreFromPrevLevel(ent); + Player_RestoreFromPrevLevel(ent, eSavedGameJustLoaded); //FIXME: put this BEFORE the Player_RestoreFromPrevLevel check above? if (eSavedGameJustLoaded == eNO) @@ -2316,6 +2378,7 @@ qboolean ClientSpawn(gentity_t *ent, SavedGameJustLoaded_e eSavedGameJustLoaded ent->client->ps.ammo[weaponData[WP_NONE].ammoIndex] = 32000; ent->client->ps.weapon = WP_NONE; ent->client->ps.weaponstate = WEAPON_READY; + ent->client->ps.dualSabers = qfalse; } if ( ent->client->ps.stats[STAT_WEAPONS] & ( 1 << WP_SABER ) ) diff --git a/code/game/g_cmds.cpp b/code/game/g_cmds.cpp index f65ad99..5fc704f 100644 --- a/code/game/g_cmds.cpp +++ b/code/game/g_cmds.cpp @@ -1090,6 +1090,15 @@ void G_SetTauntAnim( gentity_t *ent, int taunt ) { anim = BOTH_ENGAGETAUNT; } + else if ( ent->client->ps.saber[0].tauntAnim != -1 ) + { + anim = ent->client->ps.saber[0].tauntAnim; + } + else if ( ent->client->ps.dualSabers + && ent->client->ps.saber[1].tauntAnim != -1 ) + { + anim = ent->client->ps.saber[1].tauntAnim; + } else { switch ( ent->client->ps.saberAnimLevel ) @@ -1124,7 +1133,19 @@ void G_SetTauntAnim( gentity_t *ent, int taunt ) } break; case TAUNT_BOW: - anim = BOTH_BOW; + if ( ent->client->ps.saber[0].bowAnim != -1 ) + { + anim = ent->client->ps.saber[0].bowAnim; + } + else if ( ent->client->ps.dualSabers + && ent->client->ps.saber[1].bowAnim != -1 ) + { + anim = ent->client->ps.saber[1].bowAnim; + } + else + { + anim = BOTH_BOW; + } if ( ent->client->ps.saber[1].Active() ) {//turn off second saber G_Sound( ent, ent->client->ps.saber[1].soundOff ); @@ -1136,7 +1157,19 @@ void G_SetTauntAnim( gentity_t *ent, int taunt ) ent->client->ps.SaberDeactivate(); break; case TAUNT_MEDITATE: - anim = BOTH_MEDITATE; + if ( ent->client->ps.saber[0].meditateAnim != -1 ) + { + anim = ent->client->ps.saber[0].meditateAnim; + } + else if ( ent->client->ps.dualSabers + && ent->client->ps.saber[1].meditateAnim != -1 ) + { + anim = ent->client->ps.saber[1].meditateAnim; + } + else + { + anim = BOTH_MEDITATE; + } if ( ent->client->ps.saber[1].Active() ) {//turn off second saber G_Sound( ent, ent->client->ps.saber[1].soundOff ); @@ -1151,51 +1184,75 @@ void G_SetTauntAnim( gentity_t *ent, int taunt ) if ( ent->client->ps.weapon == WP_SABER ) { ent->client->ps.SaberActivate(); - switch ( ent->client->ps.saberAnimLevel ) + if ( ent->client->ps.saber[0].flourishAnim != -1 ) { - case SS_FAST: - case SS_TAVION: - anim = BOTH_SHOWOFF_FAST; - break; - case SS_MEDIUM: - anim = BOTH_SHOWOFF_MEDIUM; - break; - case SS_STRONG: - case SS_DESANN: - anim = BOTH_SHOWOFF_STRONG; - break; - case SS_DUAL: - anim = BOTH_SHOWOFF_DUAL; - break; - case SS_STAFF: - anim = BOTH_SHOWOFF_STAFF; - break; + anim = ent->client->ps.saber[0].flourishAnim; + } + else if ( ent->client->ps.dualSabers + && ent->client->ps.saber[1].flourishAnim != -1 ) + { + anim = ent->client->ps.saber[1].flourishAnim; + } + else + { + switch ( ent->client->ps.saberAnimLevel ) + { + case SS_FAST: + case SS_TAVION: + anim = BOTH_SHOWOFF_FAST; + break; + case SS_MEDIUM: + anim = BOTH_SHOWOFF_MEDIUM; + break; + case SS_STRONG: + case SS_DESANN: + anim = BOTH_SHOWOFF_STRONG; + break; + case SS_DUAL: + anim = BOTH_SHOWOFF_DUAL; + break; + case SS_STAFF: + anim = BOTH_SHOWOFF_STAFF; + break; + } } } break; case TAUNT_GLOAT: - switch ( ent->client->ps.saberAnimLevel ) + if ( ent->client->ps.saber[0].gloatAnim != -1 ) { - case SS_FAST: - case SS_TAVION: - anim = BOTH_VICTORY_FAST; - break; - case SS_MEDIUM: - anim = BOTH_VICTORY_MEDIUM; - break; - case SS_STRONG: - case SS_DESANN: - ent->client->ps.SaberActivate(); - anim = BOTH_VICTORY_STRONG; - break; - case SS_DUAL: - ent->client->ps.SaberActivate(); - anim = BOTH_VICTORY_DUAL; - break; - case SS_STAFF: - ent->client->ps.SaberActivate(); - anim = BOTH_VICTORY_STAFF; - break; + anim = ent->client->ps.saber[0].gloatAnim; + } + else if ( ent->client->ps.dualSabers + && ent->client->ps.saber[1].gloatAnim != -1 ) + { + anim = ent->client->ps.saber[1].gloatAnim; + } + else + { + switch ( ent->client->ps.saberAnimLevel ) + { + case SS_FAST: + case SS_TAVION: + anim = BOTH_VICTORY_FAST; + break; + case SS_MEDIUM: + anim = BOTH_VICTORY_MEDIUM; + break; + case SS_STRONG: + case SS_DESANN: + ent->client->ps.SaberActivate(); + anim = BOTH_VICTORY_STRONG; + break; + case SS_DUAL: + ent->client->ps.SaberActivate(); + anim = BOTH_VICTORY_DUAL; + break; + case SS_STAFF: + ent->client->ps.SaberActivate(); + anim = BOTH_VICTORY_STAFF; + break; + } } break; } @@ -1219,6 +1276,90 @@ void G_SetTauntAnim( gentity_t *ent, int taunt ) } } } + +extern cvar_t *g_saberPickuppableDroppedSabers; +extern void WP_RemoveSaber( gentity_t *ent, int saberNum ); +extern void CG_ChangeWeapon( int num ); +extern void ChangeWeapon( gentity_t *ent, int newWeapon ); +void Cmd_SaberDrop_f( gentity_t *ent, int saberNum ) +{ + if ( saberNum < 0 ) + { + return; + } + if ( saberNum > 1 ) + { + return; + } + if ( !ent || !ent->client ) + { + return; + } + if ( ent->weaponModel[saberNum] <= 0 ) + { + return; + } + + if ( ent->client->ps.weapon != WP_SABER ) + { + return; + } + + if ( ent->client->ps.weaponTime > 0 ) + { + return; + } + + if ( ent->client->ps.saberMove != LS_READY + && ent->client->ps.saberMove != LS_PUTAWAY + && ent->client->ps.saberMove != LS_DRAW + && ent->client->ps.saberMove != LS_NONE ) + { + return; + } + + if ( !g_saberPickuppableDroppedSabers->integer ) + { + return; + } + + if ( !ent->client->ps.saber[saberNum].name + || !ent->client->ps.saber[saberNum].name[0] ) + { + return; + } + + //have a valid string to use for saberType + + //turn it into a pick-uppable item! + if ( G_DropSaberItem( ent->client->ps.saber[saberNum].name, + ent->client->ps.saber[saberNum].blade[0].color, + (saberNum==0?ent->client->renderInfo.handRPoint:ent->client->renderInfo.handLPoint), + ent->client->ps.velocity, + ent->currentAngles ) + != NULL ) + {//dropped it + WP_RemoveSaber( ent, saberNum ); + } + + if ( ent->weaponModel[0] <= 0 + && ent->weaponModel[1] <= 0 ) + {//no sabers left! + //remove saber from inventory + ent->client->ps.stats[STAT_WEAPONS] &= ~(1<s.number < MAX_CLIENTS ) + {//player + CG_ChangeWeapon( WP_NONE ); + } + else + { + ChangeWeapon( ent, WP_NONE ); + } + ent->client->ps.weapon = WP_NONE; + } +} + /* ================= ClientCommand @@ -1453,4 +1594,22 @@ void ClientCommand( int clientNum ) { { Cmd_FlushCamFile_f( ent ); } + else if ( Q_stricmp( cmd, "dropsaber" ) == 0 ) + { + char *cmd2 = gi.argv(1); + int saberNum = 2;//by default, drop both + if ( cmd2 && cmd2[0] ) + { + saberNum = atoi(cmd2); + } + if ( saberNum > 1 ) + {//drop both + Cmd_SaberDrop_f( ent, 1 ); + Cmd_SaberDrop_f( ent, 0 ); + } + else + {//drop either left or right + Cmd_SaberDrop_f( ent, saberNum ); + } + } } diff --git a/code/game/g_combat.cpp b/code/game/g_combat.cpp index 6e17709..8e40219 100644 --- a/code/game/g_combat.cpp +++ b/code/game/g_combat.cpp @@ -26,9 +26,12 @@ extern cvar_t *g_debugDamage; extern qboolean stop_icarus; extern cvar_t *g_dismemberment; extern cvar_t *g_saberRealisticCombat; +extern cvar_t *g_saberPickuppableDroppedSabers; extern cvar_t *g_timescale; extern cvar_t *d_slowmodeath; extern gentity_t *player; +extern cvar_t *debug_subdivision; +extern cvar_t *g_dismemberProbabilities; gentity_t *g_lastClientDamaged; @@ -76,6 +79,7 @@ static int G_PickDeathAnim( gentity_t *self, vec3_t point, int damage, int mod, static void G_TrackWeaponUsage( gentity_t *self, gentity_t *inflictor, int add, int mod ); static qboolean G_Dismemberable( gentity_t *self, int hitLoc ); extern gitem_t *FindItemForAmmo( ammo_t ammo ); +extern void WP_RemoveSaber( gentity_t *ent, int saberNum ); qboolean G_GetRootSurfNameWithVariant( gentity_t *ent, const char *rootSurfName, char *returnSurfName, int returnSize ); @@ -124,10 +128,38 @@ gentity_t *TossClientItems( gentity_t *self ) weapon = self->s.weapon; if ( weapon == WP_SABER ) { - if ( self->weaponModel[0] < 0 || (self->client->ps.saber[0].disarmable && WP_SaberLose( self, NULL )) ) - { + if ( self->weaponModel[0] < 0 ) + {//don't have one in right hand self->s.weapon = WP_NONE; } + else if ( !(self->client->ps.saber[0].saberFlags&SFL_NOT_DISARMABLE) + || g_saberPickuppableDroppedSabers->integer ) + {//okay to drop it + if ( WP_SaberLose( self, NULL ) ) + { + self->s.weapon = WP_NONE; + } + } + if ( g_saberPickuppableDroppedSabers->integer ) + {//drop your left one, too + if ( self->weaponModel[1] >= 0 ) + {//have one in left + if ( !(self->client->ps.saber[0].saberFlags&SFL_NOT_DISARMABLE) + || g_saberPickuppableDroppedSabers->integer ) + {//okay to drop it + //just drop an item + if ( self->client->ps.saber[1].name + && self->client->ps.saber[1].name[0] ) + {//have a valid string to use for saberType + //turn it into a pick-uppable item! + if ( G_DropSaberItem( self->client->ps.saber[1].name, self->client->ps.saber[1].blade[0].color, self->client->renderInfo.handLPoint, self->client->ps.velocity, self->currentAngles ) != NULL ) + {//dropped it + WP_RemoveSaber( self, 1 ); + } + } + } + } + } } else if ( weapon == WP_BLASTER_PISTOL ) {//FIXME: either drop the pistol and make the pickup only give ammo or drop ammo @@ -1215,7 +1247,8 @@ qboolean G_GetHitLocFromSurfName( gentity_t *ent, const char *surfName, int *hit } #endif //_DEBUG - if ( g_saberRealisticCombat->integer > 1 ) + if ( g_saberRealisticCombat->integer > 1 + || debug_subdivision->integer ) { dismember = qtrue; } @@ -1231,12 +1264,12 @@ qboolean G_GetHitLocFromSurfName( gentity_t *ent, const char *surfName, int *hit { dismember = qtrue; } - else if ( g_dismemberment->integer == 113811381138 || !ent->client->dismembered ) + else if ( debug_subdivision->integer || !ent->client->dismembered ) { if ( dir && (dir[0] || dir[1] || dir[2]) && bladeDir && (bladeDir[0] || bladeDir[1] || bladeDir[2]) ) {//we care about direction (presumably for dismemberment) - if ( G_Dismemberable( ent, *hitLoc ) ) + if ( g_dismemberProbabilities->value<=0.0f||G_Dismemberable( ent, *hitLoc ) ) {//the probability let us continue char *tagName = NULL; float aoa = 0.5f; @@ -2019,7 +2052,7 @@ static qboolean G_Dismember( gentity_t *ent, vec3_t point, newBolt = gi.G2API_AddBolt( &limb->ghoul2[limb->playerModel], limbTagName ); if ( newBolt != -1 ) { - G_PlayEffect( G_EffectIndex("blaster/smoke_bolton"), limb->playerModel, newBolt, limb->s.number, newPoint); + G_PlayEffect( G_EffectIndex("saber/limb_bolton"), limb->playerModel, newBolt, limb->s.number, newPoint); } } /* @@ -2241,9 +2274,9 @@ static qboolean G_Dismemberable( gentity_t *self, int hitLoc ) {//cannot dismember me right now return qfalse; } - if ( g_dismemberment->integer != 113811381138 && g_saberRealisticCombat->integer < 2 ) + if ( !debug_subdivision->integer && g_saberRealisticCombat->integer < 2 ) { - if ( 1 ) //g_dismemberProbabilities->value > 0.0f == it always is now, no cheating and changing the game from what was approved. + if ( g_dismemberProbabilities->value > 0.0f ) {//use the ent-specific dismemberProbabilities float dismemberProb = 0; // check which part of the body it is. Then check the npc's probability @@ -2278,7 +2311,7 @@ static qboolean G_Dismemberable( gentity_t *self, int hitLoc ) } //check probability of this happening on this npc - if ( Q_flrand( 1, 100 ) > dismemberProb*2.0f )//probabilities seemed really really low, had to crank them up + if ( floor((Q_flrand( 1, 100 )*g_dismemberProbabilities->value)) > dismemberProb*2.0f )//probabilities seemed really really low, had to crank them up { return qfalse; } @@ -2287,6 +2320,25 @@ static qboolean G_Dismemberable( gentity_t *self, int hitLoc ) return qtrue; } +static qboolean G_Dismemberable2( gentity_t *self, int hitLoc ) +{ + if ( self->client->dismembered ) + {//cannot dismember me right now + return qfalse; + } + if ( !debug_subdivision->integer && g_saberRealisticCombat->integer < 2 ) + { + if ( g_dismemberProbabilities->value <= 0.0f ) + {//add the passed-in damage to the locationDamage array, check to see if it's taken enough damage to actually dismember + if ( self->locationDamage[hitLoc] < (self->client->ps.stats[STAT_MAX_HEALTH]*hitLocHealthPercentage[hitLoc]) ) + {//this location has not taken enough damage to dismember + return qfalse; + } + } + } + return qtrue; +} + #define MAX_VARIANTS 8 qboolean G_GetRootSurfNameWithVariant( gentity_t *ent, const char *rootSurfName, char *returnSurfName, int returnSize ) { @@ -2317,15 +2369,16 @@ qboolean G_DoDismemberment( gentity_t *self, vec3_t point, int mod, int damage, //extern cvar_t *g_iscensored; // dismemberment -- FIXME: should have a check for how long npc has been dead so people can't // continue to dismember a dead body long after it's been dead - //NOTE that you can only cut one thing off unless the dismemberment is == 113811381138 + //NOTE that you can only cut one thing off unless the debug_subdivisions is on #ifdef GERMAN_CENSORED if ( 0 ) //germany == censorship #else if ( /*!g_iscensored->integer &&*/ ( g_dismemberment->integer || g_saberRealisticCombat->integer > 1 ) && mod == MOD_SABER )//only lightsaber #endif {//FIXME: don't do strcmps here - if ( G_StandardHumanoid( self ) ) - {//we're using probabilities + if ( G_StandardHumanoid( self ) + && (force||g_dismemberProbabilities->value>0.0f||G_Dismemberable2( self, hitLoc )) ) + {//either it's a forced dismemberment or we're using probabilities (which are checked before this) or we've done enough damage to this location //FIXME: check the hitLoc and hitDir against the cap tag for the place //where the split will be- if the hit dir is roughly perpendicular to //the direction of the cap, then the split is allowed, otherwise we @@ -3868,7 +3921,12 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); } else { - if ( ( + if ( g_saberPickuppableDroppedSabers->integer ) + {//always drop your sabers + TossClientItems( self ); + self->client->ps.weapon = self->s.weapon = WP_NONE; + } + else if ( ( (hitLoc != HL_HAND_RT&&hitLoc !=HL_CHEST_RT&&hitLoc!=HL_ARM_RT&&hitLoc!=HL_BACK_LT) || self->client->dismembered || meansOfDeath != MOD_SABER @@ -6018,6 +6076,35 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, const { knockback = 0; } + + if ( (dflags&DAMAGE_SABER_KNOCKBACK1) ) + { + if ( attacker && attacker->client ) + { + knockback *= attacker->client->ps.saber[0].knockbackScale; + } + } + if ( (dflags&DAMAGE_SABER_KNOCKBACK1_B2) ) + { + if ( attacker && attacker->client ) + { + knockback *= attacker->client->ps.saber[0].knockbackScale2; + } + } + if ( (dflags&DAMAGE_SABER_KNOCKBACK2) ) + { + if ( attacker && attacker->client ) + { + knockback *= attacker->client->ps.saber[1].knockbackScale; + } + } + if ( (dflags&DAMAGE_SABER_KNOCKBACK2_B2) ) + { + if ( attacker && attacker->client ) + { + knockback *= attacker->client->ps.saber[1].knockbackScale2; + } + } // figure momentum add, even if the damage won't be taken if ( knockback && !(dflags&DAMAGE_DEATH_KNOCKBACK) ) //&& targ->client { diff --git a/code/game/g_items.cpp b/code/game/g_items.cpp index d0ffafe..090799b 100644 --- a/code/game/g_items.cpp +++ b/code/game/g_items.cpp @@ -16,10 +16,12 @@ extern qboolean PM_InKnockDown( playerState_t *ps ); extern qboolean PM_InGetUp( playerState_t *ps ); extern void WP_SetSaber( gentity_t *ent, int saberNum, char *saberName ); extern void WP_RemoveSaber( gentity_t *ent, int saberNum ); +extern void WP_SaberFallSound( gentity_t *owner, gentity_t *saber ); extern saber_colors_t TranslateSaberColor( const char *name ); extern cvar_t *g_spskill; extern cvar_t *g_sex; +extern cvar_t *g_saberPickuppableDroppedSabers; #define MAX_BACTA_HEAL_AMOUNT 25 @@ -44,6 +46,8 @@ extern cvar_t *g_sex; #define ITMSF_VERTICAL 16 #define ITMSF_INVISIBLE 32 #define ITMSF_NOGLOW 64 +#define ITMSF_USEPICKUP 128 +#define ITMSF_STATIONARY 2048 //====================================================================== @@ -228,48 +232,197 @@ int Pickup_Battery( gentity_t *ent, gentity_t *other ) //====================================================================== -extern void G_SetSabersFromCVars( gentity_t *ent ); -void Pickup_Saber( gentity_t *self, qboolean hadSaber, qboolean saberSolo, char *saberType, char *saberColor ) +void G_CopySaberItemValues( gentity_t *pickUpSaber, gentity_t *oldSaber ) { + if ( oldSaber && pickUpSaber ) + { + oldSaber->spawnflags = pickUpSaber->spawnflags; + oldSaber->random = pickUpSaber->random; + oldSaber->flags = pickUpSaber->flags; + } +} + +gentity_t *G_DropSaberItem( const char *saberType, saber_colors_t saberColor, vec3_t saberPos, vec3_t saberVel, vec3_t saberAngles, gentity_t *copySaber ) +{//turn it into a pick-uppable item! + gentity_t *newItem = NULL; + if ( saberType + && saberType[0] ) + {//have a valid string to use for saberType + newItem = G_Spawn(); + if ( newItem ) + { + newItem->classname = G_NewString( "weapon_saber" ); + VectorCopy( saberPos, newItem->s.origin ); + G_SetOrigin( newItem, newItem->s.origin ); + VectorCopy( saberAngles, newItem->s.angles ); + G_SetAngles( newItem, newItem->s.angles ); + newItem->spawnflags = 128;/*ITMSF_USEPICKUP*/ + newItem->spawnflags |= 64;/*ITMSF_NOGLOW*/ + newItem->NPC_type = G_NewString( saberType );//saberType + //FIXME: transfer per-blade color somehow? + newItem->NPC_targetname = saberColorStringForColor[saberColor]; + newItem->count = 1; + newItem->flags = FL_DROPPED_ITEM; + G_SpawnItem( newItem, FindItemForWeapon( WP_SABER ) ); + newItem->s.pos.trType = TR_GRAVITY; + newItem->s.pos.trTime = level.time; + VectorCopy( saberVel, newItem->s.pos.trDelta ); + //newItem->s.eFlags |= EF_BOUNCE_HALF; + //copy some values from another saber, if provided: + G_CopySaberItemValues( copySaber, newItem ); + //don't *think* about calling FinishSpawningItem, just do it! + newItem->e_ThinkFunc = thinkF_NULL; + newItem->nextthink = -1; + FinishSpawningItem( newItem ); + newItem->delay = level.time + 500;//so you can't pick it back up right away + } + } + return newItem; +} + +extern void G_SetSabersFromCVars( gentity_t *ent ); +qboolean Pickup_Saber( gentity_t *self, qboolean hadSaber, gentity_t *pickUpSaber ) +{ + //NOTE: loopAnim = saberSolo, alt_fire = saberLeftHand, NPC_type = saberType, NPC_targetname = saberColor + qboolean foundIt = qfalse; + + if ( !pickUpSaber || !self || !self->client ) + { + return qfalse; + } + //G_RemoveWeaponModels( ent );//??? - if ( Q_stricmp( "player", saberType ) == 0 ) + if ( Q_stricmp( "player", pickUpSaber->NPC_type ) == 0 ) {//"player" means use cvar info G_SetSabersFromCVars( self ); + foundIt = qtrue; } else { saberInfo_t newSaber={0}; - if ( WP_SaberParseParms( saberType, &newSaber ) ) + qboolean swapSabers = qfalse; + + if ( self->client->ps.weapon == WP_SABER + && self->client->ps.weaponTime > 0 ) + {//can't pick up a new saber while the old one is busy (also helps to work as a debouncer so you don't swap out sabers rapidly when touching more than one at a time) + return qfalse; + } + + if ( pickUpSaber->count == 1 + && g_saberPickuppableDroppedSabers->integer ) + { + swapSabers = qtrue; + } + + if ( WP_SaberParseParms( pickUpSaber->NPC_type, &newSaber ) ) {//successfully found a saber .sab entry to use - //FIXME: what about dual sabers? int saberNum = 0; - if ( saberSolo//only supposed to use this one saber when grab this pickup - || newSaber.twoHanded //new saber is two-handed - || (hadSaber && self->client->ps.saber[0].twoHanded) )//old saber is two-handed + qboolean removeLeftSaber = qfalse; + if ( pickUpSaber->alt_fire ) + {//always go in the left hand + if ( !hadSaber ) + {//can't have a saber only in your left hand! + return qfalse; + } + saberNum = 1; + //just in case... + removeLeftSaber = qtrue; + } + else if ( !hadSaber ) + {//don't have a saber at all yet, put it in our right hand + saberNum = 0; + //just in case... + removeLeftSaber = qtrue; + } + else if ( pickUpSaber->loopAnim//only supposed to use this one saber when grab this pickup + || (newSaber.saberFlags&SFL_TWO_HANDED) //new saber is two-handed + || (hadSaber && (self->client->ps.saber[0].saberFlags&SFL_TWO_HANDED)) )//old saber is two-handed {//replace the old right-hand saber and remove the left hand one - WP_RemoveSaber( self, 1 ); + saberNum = 0; + removeLeftSaber = qtrue; } else - {//add it as a second saber - saberNum = 1; + {//have, at least, a saber in our right hand and the new one could go in either left or right hand + if ( self->client->ps.dualSabers ) + {//I already have 2 sabers + vec3_t dir2Saber, rightDir; + //to determine which one to replace, see which side of me it's on + VectorSubtract( pickUpSaber->currentOrigin, self->currentOrigin, dir2Saber ); + dir2Saber[2] = 0; + AngleVectors( self->currentAngles, NULL, rightDir, NULL ); + rightDir[2] = 0; + if ( DotProduct( rightDir, dir2Saber ) > 0 ) + { + saberNum = 0; + } + else + { + saberNum = 1; + //just in case... + removeLeftSaber = qtrue; + } + } + else + {//just add it as a second saber + saberNum = 1; + //just in case... + removeLeftSaber = qtrue; + } } - WP_SetSaber( self, saberNum, saberType ); - WP_SaberInitBladeData( self ); - if ( self->client->ps.saber[saberNum].style ) + if ( saberNum == 0 ) + {//want to reach out with right hand + if ( self->client->ps.torsoAnim == BOTH_BUTTON_HOLD ) + {//but only if already playing the pickup with left hand anim... + NPC_SetAnim( self, SETANIM_TORSO, BOTH_SABERPULL, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + } + if ( swapSabers ) + {//drop first one where the one we're picking up is + G_DropSaberItem( self->client->ps.saber[saberNum].name, self->client->ps.saber[saberNum].blade[0].color, pickUpSaber->currentOrigin, (float *)vec3_origin, pickUpSaber->currentAngles, pickUpSaber ); + if ( removeLeftSaber ) + {//drop other one at my origin + G_DropSaberItem( self->client->ps.saber[1].name, self->client->ps.saber[1].blade[0].color, self->currentOrigin, (float *)vec3_origin, self->currentAngles, pickUpSaber ); + } + } + } + else { - self->client->ps.saberStylesKnown |= (1<client->ps.saber[saberNum].style); + if ( swapSabers ) + { + G_DropSaberItem( self->client->ps.saber[saberNum].name, self->client->ps.saber[saberNum].blade[0].color, pickUpSaber->currentOrigin, (float *)vec3_origin, pickUpSaber->currentAngles, pickUpSaber ); + } } - if ( saberColor != NULL ) + if ( removeLeftSaber ) + { + WP_RemoveSaber( self, 1 ); + } + WP_SetSaber( self, saberNum, pickUpSaber->NPC_type ); + WP_SaberInitBladeData( self ); + if ( self->client->ps.saber[saberNum].stylesLearned ) + { + self->client->ps.saberStylesKnown |= self->client->ps.saber[saberNum].stylesLearned; + } + if ( self->client->ps.saber[saberNum].singleBladeStyle ) + { + self->client->ps.saberStylesKnown |= self->client->ps.saber[saberNum].singleBladeStyle; + } + if ( pickUpSaber->NPC_targetname != NULL ) {//NPC_targetname = saberColor - saber_colors_t saber_color = TranslateSaberColor( saberColor ); + saber_colors_t saber_color = TranslateSaberColor( pickUpSaber->NPC_targetname ); for ( int bladeNum = 0; bladeNum < MAX_BLADES; bladeNum++ ) { self->client->ps.saber[saberNum].blade[bladeNum].color = saber_color; } } + if ( self->client->ps.torsoAnim == BOTH_BUTTON_HOLD + || self->client->ps.torsoAnim == BOTH_SABERPULL ) + {//don't let them attack right away, force them to finish the anim + self->client->ps.weaponTime = self->client->ps.torsoAnimTimer; + } + foundIt = qtrue; } WP_SaberFreeStrings(newSaber); } + return foundIt; } extern void CG_ChangeWeapon( int num ); @@ -308,13 +461,16 @@ int Pickup_Weapon (gentity_t *ent, gentity_t *other) if ( ent->item->giTag == WP_SABER && (!hadWeapon || ent->NPC_type != NULL) ) {//didn't have a saber or it is specifying a certain kind of saber to use - //NOTE: alt_fire = saberSolo, NPC_type = saberType, NPC_targetname = saberColor - Pickup_Saber( other, hadWeapon, ent->alt_fire, ent->NPC_type, ent->NPC_targetname ); + if ( !Pickup_Saber( other, hadWeapon, ent ) ) + { + return 0; + } } if ( other->s.number ) {//NPC - if ( other->s.weapon == WP_NONE ) + if ( other->s.weapon == WP_NONE + || ent->item->giTag == WP_SABER ) {//NPC with no weapon picked up a weapon, change to this weapon //FIXME: clear/set the alt-fire flag based on the picked up weapon and my class? other->client->ps.weapon = ent->item->giTag; @@ -331,6 +487,26 @@ int Pickup_Weapon (gentity_t *ent, gentity_t *other) } } } + if ( ent->item->giTag == WP_SABER ) + {//picked up a saber + if ( other->s.weapon != WP_SABER ) + {//player picking up saber + other->client->ps.weapon = WP_SABER; + other->client->ps.weaponstate = WEAPON_RAISING; + if ( other->s.number < MAX_CLIENTS ) + {//make sure the cgame-side knows this + CG_ChangeWeapon( WP_SABER ); + } + else + {//make sure the cgame-side knows this + ChangeWeapon( other, WP_SABER ); + } + } + if ( !other->client->ps.SaberActive() ) + {//turn it/them on! + other->client->ps.SaberActivate(); + } + } if ( quantity ) { @@ -601,6 +777,25 @@ void Touch_Item (gentity_t *ent, gentity_t *other, trace_t *trace) { gi.Printf( "Touch_Item: %s is not an item!\n", ent->classname); return; } + + if ( ent->item->giType == IT_WEAPON + && ent->item->giTag == WP_SABER ) + {//a saber + if ( ent->delay > level.time ) + {//just picked it up, don't pick up again right away + return; + } + } + + if ( other->s.number < MAX_CLIENTS + && (ent->spawnflags&ITMSF_USEPICKUP) ) + {//only if player is holing use button + if ( !(other->client->usercmd.buttons&BUTTON_USE) ) + {//not holding use? + return; + } + } + qboolean bHadWeapon = qfalse; // call the item-specific pickup function switch( ent->item->giType ) @@ -673,6 +868,21 @@ extern void CG_ItemPickup( int itemNum, qboolean bHadItem ); // fire item targets G_UseTargets (ent, other); + if ( ent->item->giType == IT_WEAPON + && ent->item->giTag == WP_SABER ) + {//a saber that was picked up + if ( ent->count < 0 ) + {//infinite supply + ent->delay = level.time + 500; + return; + } + ent->count--; + if ( ent->count > 0 ) + {//still have more to pick up + ent->delay = level.time + 500; + return; + } + } // wait of -1 will not respawn // if ( ent->wait == -1 ) { @@ -820,6 +1030,13 @@ void Use_Item( gentity_t *ent, gentity_t *other, gentity_t *activator ) { if ( (ent->svFlags&SVF_PLAYER_USABLE) && other && !other->s.number ) {//used directly by the player, pick me up + if ( (ent->spawnflags&ITMSF_USEPICKUP) ) + {//player has to be touching me and hit use to pick it up, so don't allow this + if ( !G_BoundsOverlap( ent->absmin, ent->absmax, other->absmin, other->absmax ) ) + {//not touching + return; + } + } GEntity_TouchFunc( ent, other, NULL ); } else @@ -893,15 +1110,21 @@ void FinishSpawningItem( gentity_t *ent ) { if ( ent->item->giType == IT_WEAPON && ent->item->giTag == WP_SABER && ent->NPC_type - && ent->NPC_type[0] - && Q_stricmp( "player", ent->NPC_type ) == 0 - && g_saber->string - && g_saber->string[0] - && Q_stricmp( "none", g_saber->string ) - && Q_stricmp( "NULL", g_saber->string ) ) - {//player's saber + && ent->NPC_type[0] ) + { saberInfo_t itemSaber; - WP_SaberParseParms( g_saber->string, &itemSaber ); + if ( Q_stricmp( "player", ent->NPC_type ) == 0 + && g_saber->string + && g_saber->string[0] + && Q_stricmp( "none", g_saber->string ) + && Q_stricmp( "NULL", g_saber->string ) ) + {//player's saber + WP_SaberParseParms( g_saber->string, &itemSaber ); + } + else + {//specific saber + WP_SaberParseParms( ent->NPC_type, &itemSaber ); + } //NOTE: should I keep this string around for any reason? Will I ever need it later? //ent->??? = G_NewString( itemSaber.model ); gi.G2API_InitGhoul2Model( ent->ghoul2, itemSaber.model, G_ModelIndex( itemSaber.model )); @@ -934,7 +1157,8 @@ void FinishSpawningItem( gentity_t *ent ) { // Hang in air? ent->s.origin[2] += 1;//just to get it off the damn ground because coplanar = insolid - if ( ent->spawnflags & ITMSF_SUSPEND) + if ( (ent->spawnflags&ITMSF_SUSPEND) + || (ent->flags&FL_DROPPED_ITEM) ) { // suspended G_SetOrigin( ent, ent->s.origin ); @@ -987,6 +1211,17 @@ void FinishSpawningItem( gentity_t *ent ) { ent->contents = 0; } + if ( (ent->spawnflags&ITMSF_STATIONARY) ) + {//can't be pushed around + ent->flags |= FL_NO_KNOCKBACK; + } + + if ( (ent->flags&FL_DROPPED_ITEM) ) + {//go away after 30 seconds + ent->e_ThinkFunc = thinkF_G_FreeEntity; + ent->nextthink = level.time + 30000; + } + gi.linkentity (ent); } @@ -1118,6 +1353,16 @@ void G_SpawnItem (gentity_t *ent, gitem_t *item) { G_Error("team name %s not recognized\n", ent->team); } } + + if ( ent->item + && ent->item->giType == IT_WEAPON + && ent->item->giTag == WP_SABER ) + {//weapon_saber item + if ( !ent->count ) + {//can only pick up once + ent->count = 1; + } + } ent->team = NULL; } @@ -1132,6 +1377,15 @@ void G_BounceItem( gentity_t *ent, trace_t *trace ) { vec3_t velocity; float dot; int hitTime; + qboolean droppedSaber = qtrue; + + if ( ent->item + && ent->item->giType == IT_WEAPON + && ent->item->giTag == WP_SABER + && (ent->flags&FL_DROPPED_ITEM) ) + { + droppedSaber = qtrue; + } // reflect the velocity on the trace plane hitTime = level.previousTime + ( level.time - level.previousTime ) * trace->fraction; @@ -1142,12 +1396,49 @@ void G_BounceItem( gentity_t *ent, trace_t *trace ) { // cut the velocity to keep from bouncing forever VectorScale( ent->s.pos.trDelta, ent->physicsBounce, ent->s.pos.trDelta ); + if ( droppedSaber ) + {//a dropped saber item + //FIXME: use NPC_type (as saberType) to get proper bounce sound? + WP_SaberFallSound( NULL, ent ); + } + // check for stop - if ( trace->plane.normal[2] > 0 && ent->s.pos.trDelta[2] < 40 ) { + if ( trace->plane.normal[2] > 0 && ent->s.pos.trDelta[2] < 40 ) + {//stop G_SetOrigin( ent, trace->endpos ); ent->s.groundEntityNum = trace->entityNum; + if ( droppedSaber ) + {//a dropped saber item + //stop rotation + VectorClear( ent->s.apos.trDelta ); + ent->currentAngles[PITCH] = SABER_PITCH_HACK; + ent->currentAngles[ROLL] = 0; + if ( ent->NPC_type + && ent->NPC_type[0] ) + {//we have a valid saber for this + saberInfo_t saber; + if ( WP_SaberParseParms( ent->NPC_type, &saber ) ) + { + if ( (saber.saberFlags&SFL_BOLT_TO_WRIST) ) + { + ent->currentAngles[PITCH] = 0; + } + } + } + pitch_roll_for_slope( ent, trace->plane.normal, ent->currentAngles, qtrue ); + G_SetAngles( ent, ent->currentAngles ); + } return; } + //bounce + if ( droppedSaber ) + {//a dropped saber item + //change rotation + VectorCopy( ent->currentAngles, ent->s.apos.trBase ); + ent->s.apos.trType = TR_LINEAR; + ent->s.apos.trTime = level.time; + VectorSet( ent->s.apos.trDelta, Q_irand( -300, 300 ), Q_irand( -300, 300 ), Q_irand( -300, 300 ) ); + } VectorAdd( ent->currentOrigin, trace->plane.normal, ent->currentOrigin); VectorCopy( ent->currentOrigin, ent->s.pos.trBase ); @@ -1189,11 +1480,48 @@ void G_RunItem( gentity_t *ent ) { ent->s.pos.trDelta[1] += crandom() * 40.0f; ent->s.pos.trDelta[2] += random() * 20.0f; } + else if ( (ent->flags&FL_DROPPED_ITEM) + && ent->item + && ent->item->giType == IT_WEAPON + && ent->item->giTag == WP_SABER ) + {//a dropped saber item, check below, just in case + int ignore = ENTITYNUM_NONE; + if ( ent->clipmask ) + { + mask = ent->clipmask; + } + else + { + mask = MASK_SOLID|CONTENTS_PLAYERCLIP;//shouldn't be able to get anywhere player can't + } + if ( ent->owner ) + { + ignore = ent->owner->s.number; + } + else if ( ent->activator ) + { + ignore = ent->activator->s.number; + } + VectorSet( origin, ent->currentOrigin[0], ent->currentOrigin[1], ent->currentOrigin[2]-1 ); + gi.trace( &tr, ent->currentOrigin, ent->mins, ent->maxs, origin, ignore, mask ); + if ( !tr.allsolid + && !tr.startsolid + && tr.fraction > 0.001f ) + {//wha? fall.... + ent->s.pos.trType = TR_GRAVITY; + ent->s.pos.trTime = level.time; + } + } return; } // get current position EvaluateTrajectory( &ent->s.pos, level.time, origin ); + if ( ent->s.apos.trType != TR_STATIONARY ) + { + EvaluateTrajectory( &ent->s.apos, level.time, ent->currentAngles ); + G_SetAngles( ent, ent->currentAngles ); + } // trace a line from the previous position to the current position if ( ent->clipmask ) @@ -1302,3 +1630,4 @@ void ItemUse_Bacta(gentity_t *ent) G_SoundOnEnt( ent, CHAN_VOICE, va( "sound/weapons/force/heal%d_%c.mp3", Q_irand( 1, 4 ), g_sex->string[0] ) ); } + diff --git a/code/game/g_local.h b/code/game/g_local.h index 3efaf18..ec03210 100644 --- a/code/game/g_local.h +++ b/code/game/g_local.h @@ -295,6 +295,7 @@ void G_PlayEffect( const char *name, const vec3_t origin ); void G_PlayEffect( const char *name, int clientNum ); void G_PlayEffect( const char *name, const vec3_t origin, const vec3_t fwd ); void G_PlayEffect( const char *name, const vec3_t origin, const vec3_t axis[3] ); +void G_PlayEffect( int fxID, const vec3_t origin ); void G_PlayEffect( int fxID, const vec3_t origin, const vec3_t fwd ); void G_PlayEffect( int fxID, const vec3_t origin, const vec3_t axis[3] ); void G_PlayEffect( int fxID, const int modelIndex, const int boltIndex, const int entNum, const vec3_t origin, int iLoopTime = qfalse, qboolean isRelative = qfalse );//iLoopTime 0 = not looping, 1 for infinite, else duration @@ -372,7 +373,10 @@ void G_Throw( gentity_t *targ, const vec3_t newDir, float push ); #define DAMAGE_CUSTOM_HUD 0x00002000 // really dumb, but.... #define DAMAGE_IMPACT_DIE 0x00004000 // if a vehicle hits a wall it should instantly die #define DAMAGE_DIE_ON_IMPACT 0x00008000 // ignores force-power based protection - +#define DAMAGE_SABER_KNOCKBACK1 0x00010000 // scale knockback based on saber1's knockbackScale value +#define DAMAGE_SABER_KNOCKBACK2 0x00020000 // scale knockback based on saber2's knockbackScale value +#define DAMAGE_SABER_KNOCKBACK1_B2 0x00040000 // scale knockback based on saber1's knockbackScale2 value +#define DAMAGE_SABER_KNOCKBACK2_B2 0x00080000 // scale knockback based on saber2's knockbackScale2 value // // g_missile.c // diff --git a/code/game/g_main.cpp b/code/game/g_main.cpp index 4d6c9dd..628a1cd 100644 --- a/code/game/g_main.cpp +++ b/code/game/g_main.cpp @@ -161,6 +161,7 @@ cvar_t *g_numEntities; cvar_t *g_saberAutoBlocking; cvar_t *g_saberRealisticCombat; +cvar_t *debug_subdivision; cvar_t *g_saberDamageCapping; cvar_t *g_saberMoveSpeed; cvar_t *g_saberAnimSpeed; @@ -170,6 +171,8 @@ cvar_t *g_debugSaberLock; cvar_t *g_saberLockRandomNess; cvar_t *g_debugMelee; cvar_t *g_saberRestrictForce; +cvar_t *g_saberPickuppableDroppedSabers; +cvar_t *g_dismemberProbabilities; cvar_t *g_speederControlScheme; @@ -596,7 +599,7 @@ void G_InitCvars( void ) { g_sex = gi.cvar ("sex", "f", CVAR_USERINFO | CVAR_ARCHIVE|CVAR_SAVEGAME|CVAR_NORESTART ); g_spskill = gi.cvar ("g_spskill", "0", CVAR_ARCHIVE | CVAR_SAVEGAME|CVAR_NORESTART); g_knockback = gi.cvar( "g_knockback", "1000", CVAR_CHEAT ); - g_dismemberment = gi.cvar ( "g_dismemberment", "3", CVAR_ARCHIVE );//0 = none, 1 = arms and hands, 2 = legs, 3 = waist and head, 4 = mega dismemberment + g_dismemberment = gi.cvar ( "g_dismemberment", "3", CVAR_ARCHIVE );//0 = none, 1 = arms and hands, 2 = legs, 3 = waist and head // for now I'm making default 10 seconds g_corpseRemovalTime = gi.cvar ( "g_corpseRemovalTime", "10", CVAR_ARCHIVE );//number of seconds bodies stick around for, at least... 0 = never go away g_synchSplitAnims = gi.cvar ( "g_synchSplitAnims", "1", 0 ); @@ -631,6 +634,8 @@ void G_InitCvars( void ) { g_saberAutoBlocking = gi.cvar( "g_saberAutoBlocking", "1", CVAR_CHEAT );//must press +block button to do any blocking g_saberRealisticCombat = gi.cvar( "g_saberMoreRealistic", "0", CVAR_CHEAT|CVAR_INIT );//makes collision more precise, increases damage + debug_subdivision = gi.cvar( "debug_subdivision", "0", CVAR_CHEAT|CVAR_INIT );//debug for dismemberment + g_dismemberProbabilities = gi.cvar ( "g_dismemberProbabilities", "1", CVAR_CHEAT|CVAR_INIT );//0 = ignore probabilities, 1 = use probabilities g_saberDamageCapping = gi.cvar( "g_saberDamageCapping", "1", CVAR_CHEAT );//caps damage of sabers vs players and NPC who use sabers g_saberMoveSpeed = gi.cvar( "g_saberMoveSpeed", "1", CVAR_CHEAT );//how fast you run while attacking with a saber g_saberAnimSpeed = gi.cvar( "g_saberAnimSpeed", "1", CVAR_CHEAT );//how fast saber animations run @@ -640,6 +645,7 @@ void G_InitCvars( void ) { g_saberLockRandomNess = gi.cvar( "g_saberLockRandomNess", "2", CVAR_ARCHIVE );//just for debugging/development, controls frequency of saberlocks g_debugMelee = gi.cvar( "g_debugMelee", "0", CVAR_CHEAT );//just for debugging/development, test kicks and grabs g_saberRestrictForce = gi.cvar( "g_saberRestrictForce", "0", CVAR_ARCHIVE );//restricts certain force powers when using a 2-handed saber or 2 sabers + g_saberPickuppableDroppedSabers = gi.cvar( "g_saberPickuppableDroppedSabers", "0", CVAR_CHEAT );//lets you pick up sabers that are dropped g_AIsurrender = gi.cvar( "g_AIsurrender", "0", CVAR_CHEAT ); g_numEntities = gi.cvar( "g_numEntities", "0", 0 ); @@ -1473,7 +1479,7 @@ qboolean G_RagDoll(gentity_t *ent, vec3_t forcedAngles) } VectorCopy(forcedAngles, G2Angles); - forcedAngles[0] = forcedAngles[2] = 0; + //forcedAngles[0] = forcedAngles[2] = 0; if (ent->client->ps.heldByClient <= ENTITYNUM_WORLD) { diff --git a/code/game/g_savegame.cpp b/code/game/g_savegame.cpp index 0a6e53e..5d721aa 100644 --- a/code/game/g_savegame.cpp +++ b/code/game/g_savegame.cpp @@ -632,6 +632,79 @@ static LPCSTR SG_GetChidText(unsigned long chid) return chidtext; } +extern void WP_SaberSetDefaults( saberInfo_t *saber, qboolean setColors); +static void SG_ConvertRetailSaberinfoToNewSaberinfo( void *sabData, saberInfo_t *saberNew ) +{ + saberInfoRetail_t *saberRetail = ((saberInfoRetail_t *)(sabData)); + + for ( int saberNum = 0; saberNum < 2; saberNum++ ) + { + WP_SaberSetDefaults( &saberNew[saberNum], qfalse ); + if ( !saberRetail[saberNum].activeBlocking ) + { + saberNew[saberNum].saberFlags |= SFL_NOT_ACTIVE_BLOCKING; + } + memcpy( saberNew[saberNum].blade, saberRetail[saberNum].blade, sizeof( saberRetail[saberNum].blade ) ); + saberNew[saberNum].breakParryBonus = saberRetail[saberNum].breakParryBonus; + saberNew[saberNum].brokenSaber1 = saberRetail[saberNum].brokenSaber1; + saberNew[saberNum].brokenSaber2 = saberRetail[saberNum].brokenSaber2; + if ( !saberRetail[saberNum].disarmable ) + { + saberNew[saberNum].saberFlags |= SFL_NOT_DISARMABLE; + } + saberNew[saberNum].disarmBonus = saberRetail[saberNum].disarmBonus; + saberNew[saberNum].forceRestrictions = saberRetail[saberNum].forceRestrictions; + saberNew[saberNum].fullName = saberRetail[saberNum].fullName; + if ( !saberRetail[saberNum].lockable ) + { + saberNew[saberNum].saberFlags |= SFL_NOT_LOCKABLE; + } + saberNew[saberNum].lockBonus = saberRetail[saberNum].lockBonus; + saberNew[saberNum].maxChain = saberRetail[saberNum].maxChain; + saberNew[saberNum].model = saberRetail[saberNum].model; + saberNew[saberNum].name = saberRetail[saberNum].name; + saberNew[saberNum].numBlades = saberRetail[saberNum].numBlades; + saberNew[saberNum].parryBonus = saberRetail[saberNum].parryBonus; + if ( saberRetail[saberNum].returnDamage ) + { + saberNew[saberNum].saberFlags |= SFL_RETURN_DAMAGE; + } + saberNew[saberNum].singleBladeStyle = saberRetail[saberNum].singleBladeStyle; + if ( saberRetail[saberNum].singleBladeThrowable ) + { + saberNew[saberNum].saberFlags |= SFL_SINGLE_BLADE_THROWABLE; + } + saberNew[saberNum].skin = saberRetail[saberNum].skin; + saberNew[saberNum].soundLoop = saberRetail[saberNum].soundLoop; + saberNew[saberNum].soundOff = saberRetail[saberNum].soundOff; + saberNew[saberNum].soundOn = saberRetail[saberNum].soundOn; + if ( saberRetail[saberNum].style != SS_NONE + && saberRetail[saberNum].style < SS_NUM_SABER_STYLES ) + {//OLD WAY: only allowed ONE style + //learn only this style + saberNew[saberNum].stylesLearned = (1<iReadSize); - memset(&pbData[iReadSize], 0, iSize-iReadSize); // zero out new objectives that weren't in old-format save file + if ( iSize == (int)(iReadSize+((sizeof(saberInfo_t)-sizeof(saberInfoRetail_t))*2)) ) + { + gclient_t newClient; + const int preSaberDataSize = ((int)&newClient.ps.saber[0]-(int)&newClient); + memcpy( &newClient, pbData, preSaberDataSize ); + SG_ConvertRetailSaberinfoToNewSaberinfo( ((void *)(&((gclient_t *)(pbData))->ps.saber[0])), &newClient.ps.saber[0] ); + memcpy( &newClient.ps.dualSabers, pbData+preSaberDataSize+(sizeof(saberInfoRetail_t)*2), sizeof(newClient)-(preSaberDataSize+(sizeof(saberInfo_t)*2)) ); + memcpy( pbData, &newClient, sizeof(gclient_t) ); + } + else + {//opps, not a saberInfo size mismatch, some other FUBAR-ness... + G_Error(va("EvaluateFields(): variable-sized chunk '%s' without handler!",SG_GetChidText(ulChid))); + } break; -*/ + default: // won't return... // @@ -885,7 +969,7 @@ static void ReadGEntities(qboolean qbAutosave) { gclient_t tempGClient; - EvaluateFields(savefields_gClient, (byte *)&tempGClient, (byte *)pEntOriginal->client, 'GCLI', sizeof(*pEnt->client),qfalse); + EvaluateFields(savefields_gClient, (byte *)&tempGClient, (byte *)pEntOriginal->client, 'GCLI', sizeof(*pEnt->client),qtrue);//qfalse); // can we pinch the original's client handle or do we have to alloc a new one?... // @@ -1098,13 +1182,13 @@ void ReadLevel(qboolean qbAutosave, qboolean qbLoadTransition) //Read & throw away gclient info gclient_t junkClient; - EvaluateFields(savefields_gClient, (byte *)&junkClient, (byte *)&level.clients[0], 'GCLI', sizeof(*level.clients), qfalse); + EvaluateFields(savefields_gClient, (byte *)&junkClient, (byte *)&level.clients[0], 'GCLI', sizeof(*level.clients), qtrue);//qfalse); + + ReadLevelLocals(); // level_locals_t level //Read & throw away objective info objectives_t junkObj[MAX_MISSION_OBJ]; gi.ReadFromSaveGame('OBJT', (void *) &junkObj, 0); - - ReadLevelLocals(); // level_locals_t level } else { @@ -1113,7 +1197,7 @@ void ReadLevel(qboolean qbAutosave, qboolean qbLoadTransition) assert(level.maxclients == 1); // I'll need to know if this changes, otherwise I'll need to change the way things work gclient_t GClient; - EvaluateFields(savefields_gClient, (byte *)&GClient, (byte *)&level.clients[0], 'GCLI', sizeof(*level.clients), qfalse); + EvaluateFields(savefields_gClient, (byte *)&GClient, (byte *)&level.clients[0], 'GCLI', sizeof(*level.clients), qtrue);//qfalse); level.clients[0] = GClient; // struct copy ReadLevelLocals(); // level_locals_t level } diff --git a/code/game/g_spawn.cpp b/code/game/g_spawn.cpp index 910f833..473bc9a 100644 --- a/code/game/g_spawn.cpp +++ b/code/game/g_spawn.cpp @@ -315,10 +315,12 @@ field_t fields[] = { {"NPC_target4", FOFS(target4), F_LSTRING},//NPC_spawner only {"NPC_type", FOFS(NPC_type), F_LSTRING}, {"ownername", FOFS(ownername), F_LSTRING}, - //for saber + //for weapon_saber {"saberType", FOFS(NPC_type), F_LSTRING}, {"saberColor", FOFS(NPC_targetname), F_LSTRING}, - {"saberSolo", FOFS(alt_fire), F_INT}, + {"saberLeftHand", FOFS(alt_fire), F_INT}, + {"saberSolo", FOFS(loopAnim), F_INT}, + {"saberPitch", FOFS(random), F_FLOAT}, //freaky camera shit {"startRGBA", FOFS(startRGBA), F_VECTOR4}, {"finalRGBA", FOFS(finalRGBA), F_VECTOR4}, diff --git a/code/game/g_svcmds.cpp b/code/game/g_svcmds.cpp index 238fb7c..2e30591 100644 --- a/code/game/g_svcmds.cpp +++ b/code/game/g_svcmds.cpp @@ -18,6 +18,8 @@ extern void G_Knockdown( gentity_t *self, gentity_t *attacker, const vec3_t push extern void WP_SetSaber( gentity_t *ent, int saberNum, char *saberName ); extern void WP_RemoveSaber( gentity_t *ent, int saberNum ); extern saber_colors_t TranslateSaberColor( const char *name ); +extern qboolean WP_SaberBladeUseSecondBladeStyle( saberInfo_t *saber, int bladeNum ); +extern qboolean WP_UseFirstValidSaberStyle( gentity_t *ent, int *saberAnimLevel ); extern void G_SetWeapon( gentity_t *self, int wp ); extern stringID_table_t WPTable[]; @@ -182,7 +184,7 @@ static void Svcmd_Saber_f() gi.cvar_set( "g_saber", saber ); WP_SetSaber( &g_entities[0], 0, saber ); - if ( saber2 && saber2[0] && !g_entities[0].client->ps.saber[0].twoHanded ) + if ( saber2 && saber2[0] && !(g_entities[0].client->ps.saber[0].saberFlags&SFL_TWO_HANDED) ) {//want to use a second saber and first one is not twoHanded gi.cvar_set( "g_saber2", saber2 ); WP_SetSaber( &g_entities[0], 1, saber2 ); @@ -737,6 +739,7 @@ static void Svcmd_ForceSetLevel_f( int forcePower ) extern qboolean PM_SaberInStart( int move ); extern qboolean PM_SaberInTransition( int move ); extern qboolean PM_SaberInAttack( int move ); +extern qboolean WP_SaberCanTurnOffSomeBlades( saberInfo_t *saber ); void Svcmd_SaberAttackCycle_f( void ) { if ( !&g_entities[0] || !g_entities[0].client ) @@ -751,32 +754,64 @@ void Svcmd_SaberAttackCycle_f( void ) return; } - if ( self->client->ps.dualSabers ) + if ( self->client->ps.dualSabers ) {//can't cycle styles with dualSabers, so just toggle second saber on/off - if ( self->client->ps.saber[1].Active() ) - {//turn it off - self->client->ps.saber[1].Deactivate(); - G_SoundIndexOnEnt( self, CHAN_WEAPON, self->client->ps.saber[0].soundOff ); - } - else if ( !self->client->ps.saber[0].Active() ) - {//first one is off, too, so just turn that one on - if ( !self->client->ps.saberInFlight ) - {//but only if it's in your hand! - self->client->ps.saber[0].Activate(); + if ( WP_SaberCanTurnOffSomeBlades( &self->client->ps.saber[1] ) ) + {//can turn second saber off + if ( self->client->ps.saber[1].ActiveManualOnly() ) + {//turn it off + qboolean skipThisBlade; + for ( int bladeNum = 0; bladeNum < self->client->ps.saber[1].numBlades; bladeNum++ ) + { + skipThisBlade = qfalse; + if ( WP_SaberBladeUseSecondBladeStyle( &self->client->ps.saber[1], bladeNum ) ) + {//check to see if we should check the secondary style's flags + if ( (self->client->ps.saber[1].saberFlags2&SFL2_NO_MANUAL_DEACTIVATE2) ) + { + skipThisBlade = qtrue; + } + } + else + {//use the primary style's flags + if ( (self->client->ps.saber[1].saberFlags2&SFL2_NO_MANUAL_DEACTIVATE) ) + { + skipThisBlade = qtrue; + } + } + if ( !skipThisBlade ) + { + self->client->ps.saber[1].BladeActivate( bladeNum, qfalse ); + G_SoundIndexOnEnt( self, CHAN_WEAPON, self->client->ps.saber[1].soundOff ); + } + } } + else if ( !self->client->ps.saber[0].ActiveManualOnly() ) + {//first one is off, too, so just turn that one on + if ( !self->client->ps.saberInFlight ) + {//but only if it's in your hand! + self->client->ps.saber[0].Activate(); + } + } + else + {//turn on the second one + self->client->ps.saber[1].Activate(); + } + return; } - else - {//turn on the second one - self->client->ps.saber[1].Activate(); - } - return; } - else if ( self->client->ps.saber[0].numBlades > 1 )//self->client->ps.saber[0].type == SABER_STAFF ) + else if ( self->client->ps.saber[0].numBlades > 1 + && WP_SaberCanTurnOffSomeBlades( &self->client->ps.saber[0] ) )//self->client->ps.saber[0].type == SABER_STAFF ) {//can't cycle styles with saberstaff, so just toggles saber blades on/off if ( self->client->ps.saberInFlight ) {//can't turn second blade back on if it's in the air, you naughty boy! return; } + /* + if ( self->client->ps.saber[0].singleBladeStyle == SS_NONE ) + {//can't use just one blade? + return; + } + */ qboolean playedSound = qfalse; if ( !self->client->ps.saber[0].blade[0].active ) {//first one is not even on @@ -785,28 +820,71 @@ void Svcmd_SaberAttackCycle_f( void ) return; } - for ( int i = 1; i < self->client->ps.saber[0].numBlades; i++ ) + qboolean skipThisBlade; + for ( int bladeNum = 1; bladeNum < self->client->ps.saber[0].numBlades; bladeNum++ ) { - if ( !self->client->ps.saber[0].blade[i].active ) + if ( !self->client->ps.saber[0].blade[bladeNum].active ) {//extra is off, turn it on - self->client->ps.SaberBladeActivate( 0, i, qtrue ); + self->client->ps.saber[0].BladeActivate( bladeNum, qtrue ); } else {//turn extra off - self->client->ps.SaberBladeActivate( 0, i, qfalse ); - if ( !playedSound ) + skipThisBlade = qfalse; + if ( WP_SaberBladeUseSecondBladeStyle( &self->client->ps.saber[1], bladeNum ) ) + {//check to see if we should check the secondary style's flags + if ( (self->client->ps.saber[1].saberFlags2&SFL2_NO_MANUAL_DEACTIVATE2) ) + { + skipThisBlade = qtrue; + } + } + else + {//use the primary style's flags + if ( (self->client->ps.saber[1].saberFlags2&SFL2_NO_MANUAL_DEACTIVATE) ) + { + skipThisBlade = qtrue; + } + } + if ( !skipThisBlade ) { - G_SoundIndexOnEnt( self, CHAN_WEAPON, self->client->ps.saber[0].soundOff ); - playedSound = qtrue; + self->client->ps.saber[0].BladeActivate( bladeNum, qfalse ); + if ( !playedSound ) + { + G_SoundIndexOnEnt( self, CHAN_WEAPON, self->client->ps.saber[0].soundOff ); + playedSound = qtrue; + } } } } return; } - //FIXME: if dualSabers and both on, do something here, too... maybe toggle the second one on/off? + int allowedStyles = self->client->ps.saberStylesKnown; + if ( self->client->ps.dualSabers + && self->client->ps.saber[0].Active() + && self->client->ps.saber[1].Active() ) + { + allowedStyles |= (1<client->ps.saber[0].stylesLearned&(1<client->ps.saber[1].stylesLearned&(1<client->ps.saber[0].stylesForbidden&(1<client->ps.saber[1].stylesForbidden&(1<client->ps.saber[0].stylesForbidden&(1<client->ps.saber[1].stylesForbidden&(1<client->ps.saberStylesKnown ) + if ( !allowedStyles ) { return; } @@ -823,7 +901,7 @@ void Svcmd_SaberAttackCycle_f( void ) saberAnimLevel++; int sanityCheck = 0; while ( self->client->ps.saberAnimLevel != saberAnimLevel - && !(self->client->ps.saberStylesKnown&(1<client->ps.saberStylesKnown&(1<s.number ) { cg.saberAnimLevelPending = saberAnimLevel; @@ -1121,7 +1201,7 @@ qboolean ConsoleCommand( void ) { Svcmd_ForceSetLevel_f( FP_PROTECT ); Svcmd_ForceSetLevel_f( FP_ABSORB ); Svcmd_ForceSetLevel_f( FP_SEE ); - for ( int i = SS_FAST; i < SS_NUM_SABER_STYLES; i++ ) + for ( int i = SS_NONE+1; i < SS_NUM_SABER_STYLES; i++ ) { g_entities[0].client->ps.saberStylesKnown |= (1<s.eType == ET_ITEM ) {//item, see if we could actually pick it up + if ( (target->spawnflags&128/*ITMSF_USEPICKUP*/) ) + {//player has to be touching me and hit use to pick it up, so don't allow this + if ( !G_BoundsOverlap( target->absmin, target->absmax, ent->absmin, ent->absmax ) ) + {//not touching + return qfalse; + } + } if ( !BG_CanItemBeGrabbed( &target->s, &ent->client->ps ) ) {//nope, so don't indicate that we can use it return qfalse; diff --git a/code/game/g_vehicles.h b/code/game/g_vehicles.h index 0b12152..91fa499 100644 --- a/code/game/g_vehicles.h +++ b/code/game/g_vehicles.h @@ -48,6 +48,7 @@ typedef struct int iLoopSound; //index of loopSound float fSpeed; //speed of projectile/range of traceline float fHoming; //0.0 = not homing, 0.5 = half vel to targ, half cur vel, 1.0 = all vel to targ + float fHomingFOV; int iLockOnTime; //0 = no lock time needed, else # of ms needed to lock on int iDamage; //damage done when traceline or projectile directly hits target int iSplashDamage;//damage done to ents in splashRadius of end of traceline or projectile origin on impact @@ -60,7 +61,7 @@ typedef struct qboolean bExplodeOnExpire; //when iLifeTime is up, explodes rather than simply removing itself } vehWeaponInfo_t; //NOTE: this MUST stay up to date with the number of variables in the vehFields table!!! -#define NUM_VWEAP_PARMS 24 +#define NUM_VWEAP_PARMS 25 #define VWFOFS(x) ((int)&(((vehWeaponInfo_t *)0)->x)) diff --git a/code/game/game.zip b/code/game/game.zip new file mode 100644 index 0000000..d115f92 Binary files /dev/null and b/code/game/game.zip differ diff --git a/code/game/mssccprj.scc b/code/game/mssccprj.scc index b1297bc..bdb1859 100644 --- a/code/game/mssccprj.scc +++ b/code/game/mssccprj.scc @@ -1,5 +1,5 @@ SCC = This is a Source Code Control file [game.vcproj] -SCC_Aux_Path = "\\ravendata1\vss\central_code" +SCC_Aux_Path = "\\ravendata1\VSS\central_code" SCC_Project_Name = "$/jedi/code/game", IVBAAAAA diff --git a/code/game/q_shared.h b/code/game/q_shared.h index 2b9c011..a440d86 100644 --- a/code/game/q_shared.h +++ b/code/game/q_shared.h @@ -1670,8 +1670,281 @@ typedef enum SS_NUM_SABER_STYLES } saber_styles_t; +//SABER FLAGS +//Old bools converted to a flag now +#define SFL_NOT_LOCKABLE (1<<0)//can't get into a saberlock +#define SFL_NOT_THROWABLE (1<<1)//can't be thrown - FIXME: maybe make this a max level of force saber throw that can be used with this saber? +#define SFL_NOT_DISARMABLE (1<<2)//can't be dropped +#define SFL_NOT_ACTIVE_BLOCKING (1<<3)//don't to try to block incoming shots with this saber +#define SFL_TWO_HANDED (1<<4)//uses both hands +#define SFL_SINGLE_BLADE_THROWABLE (1<<5)//can throw this saber if only the first blade is on +#define SFL_RETURN_DAMAGE (1<<6)//when returning from a saber throw, it keeps spinning and doing damage +//NEW FLAGS +#define SFL_ON_IN_WATER (1<<7)//if set, weapon stays active even in water +#define SFL_BOUNCE_ON_WALLS (1<<8)//if set, the saber will bounce back when it hits solid architecture (good for real-sword type mods) +#define SFL_BOLT_TO_WRIST (1<<9)//if set, saber model is bolted to wrist, not in hand... useful for things like claws & shields, etc. +//#define SFL_STICK_ON_IMPACT (1<= numBlades ) + return; + + blade[iBlade].active = bActive; + } + + qboolean Active() + { + for ( int i = 0; i < numBlades; i++ ) + { + if ( blade[i].active ) + { + return qtrue; + } + } + return qfalse; + } + qboolean ActiveManualOnly() + { + for ( int i = 0; i < numBlades; i++ ) + { + if ( bladeStyle2Start > 0 ) + { + if ( i >= bladeStyle2Start ) + { + if ( (saberFlags2&SFL2_NO_MANUAL_DEACTIVATE2) ) + {//don't count this blade + continue; + } + } + else if ( (saberFlags2&SFL2_NO_MANUAL_DEACTIVATE) ) + {//don't count this blade + continue; + } + } + else if ( (saberFlags2&SFL2_NO_MANUAL_DEACTIVATE) ) + {//don't count any of these blades! + continue; + } + else if ( blade[i].active ) + { + return qtrue; + } + } + return qfalse; + } + void SetLength( float length ) + { + for ( int i = 0; i < numBlades; i++ ) + { + blade[i].length = length; + } + } + float Length() + {//return largest length + float len1 = 0; + for ( int i = 0; i < numBlades; i++ ) + { + if ( blade[i].length > len1 ) + { + len1 = blade[i].length; + } + } + return len1; + }; + float LengthMax() + { + float len1 = 0; + for ( int i = 0; i < numBlades; i++ ) + { + if ( blade[i].lengthMax > len1 ) + { + len1 = blade[i].lengthMax; + } + } + return len1; + }; + void ActivateTrail ( float duration ) + { + for ( int i = 0; i < numBlades; i++ ) + { + blade[i].ActivateTrail( duration ); + } + }; + void DeactivateTrail ( float duration ) + { + for ( int i = 0; i < numBlades; i++ ) + { + blade[i].DeactivateTrail( duration ); + } + }; +} saberInfo_t; + +//NOTE: Below is the *retail* version of the saberInfo_t structure - it is ONLY used for loading retail-version savegames (we load the savegame into this smaller structure, then copy each field into the appropriate field in the new structure - see SG_ConvertRetailSaberinfoToNewSaberinfo() +typedef struct { char *name; //entry in sabers.cfg, if any char *fullName; //the "Proper Name" of the saber, shown in the UI @@ -1786,8 +2059,7 @@ typedef struct blade[i].DeactivateTrail( duration ); } }; -} saberInfo_t; - +} saberInfoRetail_t; #define MAX_SABERS 2 // if this ever changes then update the table "static const save_field_t savefields_gClient[]"!!!!!!!!!!!! @@ -1972,16 +2244,32 @@ typedef struct playerState_s { saber[1].DeactivateTrail( duration ); } }; - int SaberDisarmBonus( void ) + int SaberDisarmBonus( int bladeNum ) { int disarmBonus = 0; if ( saber[0].Active() ) { - disarmBonus += saber[0].disarmBonus; + if ( saber[0].bladeStyle2Start > 0 + && bladeNum >= saber[0].bladeStyle2Start ) + { + disarmBonus += saber[0].disarmBonus2; + } + else + { + disarmBonus += saber[0].disarmBonus; + } } if ( dualSabers && saber[1].Active() ) {//bonus for having 2 sabers - disarmBonus += 1 + saber[1].disarmBonus; + if ( saber[1].bladeStyle2Start > 0 + && bladeNum >= saber[1].bladeStyle2Start ) + { + disarmBonus += 1 + saber[1].disarmBonus2; + } + else + { + disarmBonus += 1 + saber[1].disarmBonus; + } } return disarmBonus; }; @@ -2266,6 +2554,7 @@ typedef struct SSkinGoreData_s //qboolean baseModelOnly; int lifeTime; // effect expires after this amount of time + int firstModel; // which model to start the gore on (can skip the first) int fadeOutTime; //specify the duration of fading, from the lifeTime (e.g. 3000 will start fading 3 seconds before removal and be faded entirely by removal) //int shrinkOutTime; // unimplemented //float alphaModulate; // unimplemented diff --git a/code/game/vssver.scc b/code/game/vssver.scc index 3cc7cbe..cf869e7 100644 Binary files a/code/game/vssver.scc and b/code/game/vssver.scc differ diff --git a/code/game/wp_saber.cpp b/code/game/wp_saber.cpp index 4433fa2..7177400 100644 --- a/code/game/wp_saber.cpp +++ b/code/game/wp_saber.cpp @@ -17,6 +17,8 @@ static int victimEntityNum[MAX_SABER_VICTIMS]; static float totalDmg[MAX_SABER_VICTIMS]; static vec3_t dmgDir[MAX_SABER_VICTIMS]; +static vec3_t dmgNormal[MAX_SABER_VICTIMS]; +static vec3_t dmgBladeVec[MAX_SABER_VICTIMS]; static vec3_t dmgSpot[MAX_SABER_VICTIMS]; static float dmgFraction[MAX_SABER_VICTIMS]; static int hitLoc[MAX_SABER_VICTIMS]; @@ -28,9 +30,6 @@ static float sabersCrossed; static int saberHitEntity; static int numVictims = 0; -#define SABER_PITCH_HACK 90 - - extern cvar_t *g_sex; extern cvar_t *g_timescale; extern cvar_t *g_dismemberment; @@ -40,13 +39,19 @@ extern cvar_t *d_slowmodeath; extern cvar_t *g_cheats; extern cvar_t *g_debugMelee; extern cvar_t *g_saberRestrictForce; +extern cvar_t *g_saberPickuppableDroppedSabers; +extern cvar_t *debug_subdivision; + +extern qboolean WP_SaberBladeUseSecondBladeStyle( saberInfo_t *saber, int bladeNum ); +extern qboolean WP_SaberBladeDoTransitionDamage( saberInfo_t *saber, int bladeNum ); extern qboolean Q3_TaskIDPending( gentity_t *ent, taskID_t taskType ); extern qboolean G_ClearViewEntity( gentity_t *ent ); extern void G_SetViewEntity( gentity_t *self, gentity_t *viewEntity ); extern qboolean G_ControlledByPlayer( gentity_t *self ); extern void G_AddVoiceEvent( gentity_t *self, int event, int speakDebounceTime ); extern void CG_ChangeWeapon( int num ); +extern void CG_SaberDoWeaponHitMarks( gclient_t *client, gentity_t *saberEnt, gentity_t *hitEnt, int saberNum, int bladeNum, vec3_t hitPos, vec3_t hitDir, vec3_t uaxis, vec3_t splashBackDir, float sizeTimeScale ); extern void G_AngerAlert( gentity_t *self ); extern void G_ReflectMissile( gentity_t *ent, gentity_t *missile, vec3_t forward ); extern int G_CheckLedgeDive( gentity_t *self, float checkDist, const vec3_t checkVel, qboolean tryOpposite, qboolean tryPerp ); @@ -64,6 +69,7 @@ extern qboolean PM_InAnimForSaberMove( int anim, int saberMove ); extern qboolean PM_SpinningSaberAnim( int anim ); extern qboolean PM_SaberInSpecialAttack( int anim ); extern qboolean PM_SaberInAttack( int move ); +extern qboolean PM_SaberInAttackPure( int move ); extern qboolean PM_SaberInTransition( int move ); extern qboolean PM_SaberInStart( int move ); extern qboolean PM_SaberInTransitionAny( int move ); @@ -94,6 +100,7 @@ extern qboolean PM_StabDownAnim( int anim ); extern int PM_PowerLevelForSaberAnim( playerState_t *ps, int saberNum = 0 ); extern void PM_VelocityForSaberMove( playerState_t *ps, vec3_t throwDir ); extern qboolean PM_VelocityForBlockedMove( playerState_t *ps, vec3_t throwDir ); +extern qboolean PM_SaberCanInterruptMove( int move, int anim ); extern int Jedi_ReCalcParryTime( gentity_t *self, evasionType_t evasionType ); extern qboolean Jedi_DodgeEvasion( gentity_t *self, gentity_t *shooter, trace_t *tr, int hitLoc ); extern void Jedi_PlayDeflectSound( gentity_t *self ); @@ -105,6 +112,8 @@ extern qboolean Jedi_CultistDestroyer( gentity_t *self ); extern qboolean Boba_Flying( gentity_t *self ); extern void JET_FlyStart( gentity_t *self ); extern void Boba_DoFlameThrower( gentity_t *self ); +extern void Boba_StopFlameThrower( gentity_t *self ); + extern Vehicle_t *G_IsRidingVehicle( gentity_t *ent ); extern int SaberDroid_PowerLevelForSaberAnim( gentity_t *self ); extern qboolean G_ValidEnemy( gentity_t *self, gentity_t *enemy ); @@ -139,6 +148,7 @@ extern cvar_t *g_saberNewControlScheme; extern int g_crosshairEntNum; qboolean g_saberNoEffects = qfalse; +qboolean g_noClashFlare = qfalse; int g_saberFlashTime = 0; vec3_t g_saberFlashPos = {0,0,0}; @@ -418,6 +428,17 @@ void WP_SaberAddG2SaberModels( gentity_t *ent, int specificSaberNum ) } } int handBolt = ((saberNum == 0) ? ent->handRBolt : ent->handLBolt); + if ( (ent->client->ps.saber[saberNum].saberFlags&SFL_BOLT_TO_WRIST) ) + {//special case, bolt to forearm + if ( saberNum == 0 ) + { + handBolt = gi.G2API_AddBolt( &ent->ghoul2[ent->playerModel], "*r_hand_cap_r_arm" ); + } + else + { + handBolt = gi.G2API_AddBolt( &ent->ghoul2[ent->playerModel], "*l_hand_cap_l_arm" ); + } + } G_CreateG2AttachedWeaponModel( ent, ent->client->ps.saber[saberNum].model, handBolt, saberNum ); if ( ent->client->ps.saber[saberNum].skin != NULL ) @@ -591,6 +612,56 @@ void WP_SetSaberEntModelSkin( gentity_t *ent, gentity_t *saberent ) } } +void WP_SaberFallSound( gentity_t *owner, gentity_t *saber ) +{ + if ( !saber ) + { + return; + } + if ( owner && owner->client ) + {//have an owner, use their data (assume saberNum is 0 because only the 0 saber can be thrown) + if ( owner->client->ps.saber[0].fallSound[0] ) + {//have an override + G_Sound( saber, owner->client->ps.saber[0].fallSound[Q_irand( 0, 2 )] ); + } + else if ( owner->client->ps.saber[0].type == SABER_SITH_SWORD ) + {//is a sith sword + G_Sound( saber, G_SoundIndex( va( "sound/weapons/sword/fall%d.wav", Q_irand( 1, 7 ) ) ) ); + } + else + {//normal saber + G_Sound( saber, G_SoundIndex( va( "sound/weapons/saber/bounce%d.wav", Q_irand( 1, 3 ) ) ) ); + } + } + else if ( saber->NPC_type && saber->NPC_type[0] ) + {//have a saber name to look up + saberInfo_t saberInfo; + if ( WP_SaberParseParms( saber->NPC_type, &saberInfo ) ) + {//found it + if ( saberInfo.fallSound[0] ) + {//have an override sound + G_Sound( saber, saberInfo.fallSound[Q_irand( 0, 2 )] ); + } + else if ( saberInfo.type == SABER_SITH_SWORD ) + {//is a sith sword + G_Sound( saber, G_SoundIndex( va( "sound/weapons/sword/fall%d.wav", Q_irand( 1, 7 ) ) ) ); + } + else + {//normal saber + G_Sound( saber, G_SoundIndex( va( "sound/weapons/saber/bounce%d.wav", Q_irand( 1, 3 ) ) ) ); + } + } + else + {//can't find it + G_Sound( saber, G_SoundIndex( va( "sound/weapons/saber/bounce%d.wav", Q_irand( 1, 3 ) ) ) ); + } + } + else + {//no saber name specified + G_Sound( saber, G_SoundIndex( va( "sound/weapons/saber/bounce%d.wav", Q_irand( 1, 3 ) ) ) ); + } +} + void WP_SaberSwingSound( gentity_t *ent, int saberNum, swingType_t swingType ) { int index = 1; @@ -611,17 +682,13 @@ void WP_SaberSwingSound( gentity_t *ent, int saberNum, swingType_t swingType ) index = Q_irand( 7, 9 ); } #ifdef _IMMERSION - if ( ent->client->ps.saber[saberNum].type == SABER_SITH_SWORD ) - { - G_SoundOnEnt( ent, CHAN_WEAPON, va( "sound/weapons/sword/swing%d.wav", Q_irand( 1, 4 ) ) ); - } - else - { - G_SoundOnEnt( ent, CHAN_WEAPON, va( "sound/weapons/saber/saberhup%d.wav", index ) ); - } G_Force( ent, G_ForceIndex( va( "fffx/weapons/saber/saberhup%d", index ), FF_CHANNEL_WEAPON ) ); -#else - if ( ent->client->ps.saber[saberNum].type == SABER_SITH_SWORD ) +#endif // _IMMERSION + if ( ent->client->ps.saber[saberNum].swingSound[0] ) + { + G_SoundIndexOnEnt( ent, CHAN_WEAPON, ent->client->ps.saber[saberNum].swingSound[Q_irand( 0, 2 )] ); + } + else if ( ent->client->ps.saber[saberNum].type == SABER_SITH_SWORD ) { G_SoundOnEnt( ent, CHAN_WEAPON, va( "sound/weapons/sword/swing%d.wav", Q_irand( 1, 4 ) ) ); } @@ -629,19 +696,30 @@ void WP_SaberSwingSound( gentity_t *ent, int saberNum, swingType_t swingType ) { G_SoundOnEnt( ent, CHAN_WEAPON, va( "sound/weapons/saber/saberhup%d.wav", index ) ); } -#endif // _IMMERSION } -void WP_SaberHitSound( gentity_t *ent, int saberNum ) +void WP_SaberHitSound( gentity_t *ent, int saberNum, int bladeNum ) { int index = 1; if ( !ent || !ent->client ) { return; } -#ifdef _IMMERSION index = Q_irand( 1, 3 ); - if ( ent->client->ps.saber[saberNum].type == SABER_SITH_SWORD ) +#ifdef _IMMERSION + G_Force( ent, G_ForceIndex( va( "fffx/weapons/saber/saberhit%d", index), FF_CHANNEL_WEAPON ) ); +#endif // _IMMERSION + if ( !WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && ent->client->ps.saber[saberNum].hitSound[0] ) + { + G_Sound( ent, ent->client->ps.saber[saberNum].hitSound[Q_irand( 0, 2 )] ); + } + else if ( WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && ent->client->ps.saber[saberNum].hit2Sound[0] ) + { + G_Sound( ent, ent->client->ps.saber[saberNum].hit2Sound[Q_irand( 0, 2 )] ); + } + else if ( ent->client->ps.saber[saberNum].type == SABER_SITH_SWORD ) { G_Sound( ent, G_SoundIndex( va( "sound/weapons/sword/stab%d.wav", Q_irand( 1, 4 ) ) ) ); } @@ -649,17 +727,139 @@ void WP_SaberHitSound( gentity_t *ent, int saberNum ) { G_Sound( ent, G_SoundIndex( va( "sound/weapons/saber/saberhit%d.wav", index ) ) ); } - G_Force( ent, G_ForceIndex( va( "fffx/weapons/saber/saberhit%d", index), FF_CHANNEL_WEAPON ) ); -#else - if ( ent->client->ps.saber[saberNum].type == SABER_SITH_SWORD ) +} + +void WP_SaberBlockSound( gentity_t *ent, gentity_t *hitEnt, int saberNum, int bladeNum ) +{ + int index = 1; + if ( !ent || !ent->client ) { - G_Sound( ent, G_SoundIndex( va( "sound/weapons/sword/stab%d.wav", Q_irand( 1, 4 ) ) ) ); + return; } - else + index = Q_irand( 1, 9 ); +#ifdef _IMMERSION + if ( ent->s.number < MAX_CLIENTS ) { - G_Sound( ent, G_SoundIndex( va( "sound/weapons/saber/saberhit%d.wav", Q_irand( 1, 3 ) ) ) ); + if ( !ent->client->ps.saberInFlight ) + { + G_Force( ent, G_ForceIndex( va( "fffx/weapons/saber/saberblock%d", index), FF_CHANNEL_WEAPON ) ); + } + } + if ( hitEnt && hitEnt->s.number < MAX_CLIENTS ) + { + if ( hitEnt->client && !hitEnt->client->ps.saberInFlight ) + { + G_Force( hitEnt, G_ForceIndex( va( "fffx/weapons/saber/saberblock%d", index), FF_CHANNEL_WEAPON ) ); + } } #endif // _IMMERSION + if ( !WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && ent->client->ps.saber[saberNum].blockSound[0] ) + { + G_Sound( ent, ent->client->ps.saber[saberNum].blockSound[Q_irand( 0, 2 )] ); + } + else if ( WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && ent->client->ps.saber[saberNum].block2Sound[0] ) + { + G_Sound( ent, ent->client->ps.saber[saberNum].block2Sound[Q_irand( 0, 2 )] ); + } + else + { + G_Sound( ent, G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", index ) ) ); + } +} + + +void WP_SaberBounceOnWallSound( gentity_t *ent, int saberNum, int bladeNum ) +{ + int index = 1; + if ( !ent || !ent->client ) + { + return; + } + index = Q_irand( 1, 9 ); +#ifdef _IMMERSION + if ( ent->s.number < MAX_CLIENTS ) + { + if ( !ent->client->ps.saberInFlight ) + { + G_Force( ent, G_ForceIndex( va( "fffx/weapons/saber/saberblock%d", index), FF_CHANNEL_WEAPON ) ); + } + } +#endif // _IMMERSION + if ( !WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && ent->client->ps.saber[saberNum].bounceSound[0] ) + { + G_Sound( ent, ent->client->ps.saber[saberNum].bounceSound[Q_irand( 0, 2 )] ); + } + else if ( WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && ent->client->ps.saber[saberNum].bounce2Sound[0] ) + { + G_Sound( ent, ent->client->ps.saber[saberNum].bounce2Sound[Q_irand( 0, 2 )] ); + } + else if ( !WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && ent->client->ps.saber[saberNum].blockSound[0] ) + { + G_Sound( ent, ent->client->ps.saber[saberNum].blockSound[Q_irand( 0, 2 )] ); + } + else if ( WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && ent->client->ps.saber[saberNum].block2Sound[0] ) + { + G_Sound( ent, ent->client->ps.saber[saberNum].block2Sound[Q_irand( 0, 2 )] ); + } + else + { + G_Sound( ent, G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", index ) ) ); + } +} + +void WP_SaberBounceSound( gentity_t *ent, gentity_t *hitEnt, gentity_t *playOnEnt, int saberNum, int bladeNum, qboolean doForce ) +{ + int index = 1; + if ( !ent || !ent->client ) + { + return; + } + index = Q_irand( 1, 3 ); +#ifdef _IMMERSION + if ( doForce ) + { + if ( ent->s.number < MAX_CLIENTS + && (!playOnEnt || playOnEnt == ent) ) + { + if ( !ent->client->ps.saberInFlight ) + { + G_Force( ent, G_ForceIndex( va( "fffx/weapons/saber/saberbounce%d", index), FF_CHANNEL_WEAPON ) ); + } + } + if ( hitEnt && hitEnt->s.number < MAX_CLIENTS ) + { + if ( hitEnt->client && !hitEnt->client->ps.saberInFlight ) + { + G_Force( hitEnt, G_ForceIndex( va( "fffx/weapons/saber/saberbounce%d", index), FF_CHANNEL_WEAPON ) ); + } + } + } +#endif // _IMMERSION + if ( !playOnEnt ) + { + playOnEnt = ent; + } + //NOTE: we don't allow overriding of the saberbounce sound, but since it's just a variant on the saberblock sound, we use that as the override + if ( !WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && ent->client->ps.saber[saberNum].blockSound[0] ) + { + G_Sound( playOnEnt, ent->client->ps.saber[saberNum].blockSound[Q_irand( 0, 2 )] ); + } + else if ( WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && ent->client->ps.saber[saberNum].block2Sound[0] ) + { + G_Sound( playOnEnt, ent->client->ps.saber[saberNum].block2Sound[Q_irand( 0, 2 )] ); + } + else + { + G_Sound( playOnEnt, G_SoundIndex( va( "sound/weapons/saber/saberbounce%d.wav", index ) ) ); + } } int WP_SaberInitBladeData( gentity_t *ent ) @@ -1072,7 +1272,7 @@ qboolean WP_GetSaberDeflectionAngle( gentity_t *attacker, gentity_t *defender ) } -void WP_SaberClearDamageForEntNum( int entityNum ) +void WP_SaberClearDamageForEntNum( gentity_t *attacker, int entityNum, int saberNum, int bladeNum ) { #ifndef FINAL_BUILD if ( d_saberCombat->integer ) @@ -1087,10 +1287,58 @@ void WP_SaberClearDamageForEntNum( int entityNum ) { return; } + + //FIXME: if hit their saber in WP_SaberDamageForTrace, need to still do knockback on them... + float knockBackScale = 0.0f; + if ( attacker && attacker->client ) + { + if ( !WP_SaberBladeUseSecondBladeStyle( &attacker->client->ps.saber[saberNum], bladeNum ) + && attacker->client->ps.saber[saberNum].knockbackScale > 0.0f ) + { + knockBackScale = attacker->client->ps.saber[saberNum].knockbackScale; + } + else if ( WP_SaberBladeUseSecondBladeStyle( &attacker->client->ps.saber[saberNum], bladeNum ) + && attacker->client->ps.saber[saberNum].knockbackScale2 > 0.0f ) + { + knockBackScale = attacker->client->ps.saber[saberNum].knockbackScale2; + } + } + for ( int i = 0; i < numVictims; i++ ) { if ( victimEntityNum[i] == entityNum ) { + //hold on a sec, let's still do any accumulated knockback + if ( knockBackScale ) + { + gentity_t *victim = &g_entities[victimEntityNum[i]]; + if ( victim && victim->client ) + { + vec3_t center, dirToCenter; + float knockDownThreshHold, knockback = knockBackScale * totalDmg[i] * 0.5f; + + VectorAdd( victim->absmin, victim->absmax, center ); + VectorScale( center, 0.5, center ); + VectorSubtract( victim->currentOrigin, saberHitLocation, dirToCenter ); + VectorNormalize( dirToCenter ); + G_Throw( victim, dirToCenter, knockback ); + if ( victim->client->ps.groundEntityNum != ENTITYNUM_NONE + && dirToCenter[2] <= 0 ) + {//hit downward on someone who is standing on firm ground, so more likely to knock them down + knockDownThreshHold = Q_irand( 25, 50 ); + } + else + { + knockDownThreshHold = Q_irand( 75, 125 ); + } + + if ( knockback > knockDownThreshHold ) + { + G_Knockdown( victim, attacker, dirToCenter, 350, qtrue ); + } + } + } + //now clear everything totalDmg[i] = 0;//no damage hitLoc[i] = HL_NONE; hitDismemberLoc[i] = HL_NONE; @@ -1102,13 +1350,14 @@ void WP_SaberClearDamageForEntNum( int entityNum ) extern float damageModifier[]; extern float hitLocHealthPercentage[]; -qboolean WP_SaberApplyDamage( gentity_t *ent, float baseDamage, int baseDFlags, qboolean brokenParry, saberType_t saberType, qboolean thrownSaber ) +qboolean WP_SaberApplyDamage( gentity_t *ent, float baseDamage, int baseDFlags, + qboolean brokenParry, int saberNum, int bladeNum, qboolean thrownSaber ) { qboolean didDamage = qfalse; gentity_t *victim; int dFlags = baseDFlags; float maxDmg; - + saberType_t saberType = ent->client->ps.saber[saberNum].type; if ( !numVictims ) { @@ -1220,6 +1469,8 @@ qboolean WP_SaberApplyDamage( gentity_t *ent, float baseDamage, int baseDFlags, { gentity_t *inflictor = ent; didDamage = qtrue; + qboolean vicWasDismembered = qtrue; + qboolean vicWasAlive = (qboolean)(victim->health>0); if ( baseDamage <= 0.1f ) {//just get their attention? @@ -1232,17 +1483,32 @@ qboolean WP_SaberApplyDamage( gentity_t *ent, float baseDamage, int baseDFlags, {//already being knocked around dFlags |= DAMAGE_NO_KNOCKBACK; } - if ( g_dismemberment->integer == 113811381138 || g_saberRealisticCombat->integer ) - { - dFlags |= DAMAGE_DISMEMBER; - if ( hitDismember[i] ) - { - victim->client->dismembered = false; - } + if ( !WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && (ent->client->ps.saber[saberNum].saberFlags2&SFL2_NO_DISMEMBERMENT) ) + {//no dismemberment! (blunt/stabbing weapon?) } - else if ( hitDismember[i] ) + else if ( WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && (ent->client->ps.saber[saberNum].saberFlags2&SFL2_NO_DISMEMBERMENT2) ) + {//no dismemberment! (blunt/stabbing weapon?) + } + else { - dFlags |= DAMAGE_DISMEMBER; + if ( debug_subdivision->integer || g_saberRealisticCombat->integer ) + { + dFlags |= DAMAGE_DISMEMBER; + if ( hitDismember[i] ) + { + victim->client->dismembered = false; + } + } + else if ( hitDismember[i] ) + { + dFlags |= DAMAGE_DISMEMBER; + } + if ( !victim->client->dismembered ) + { + vicWasDismembered = qfalse; + } } if ( baseDamage <= 1.0f ) {//very mild damage @@ -1257,8 +1523,11 @@ qboolean WP_SaberApplyDamage( gentity_t *ent, float baseDamage, int baseDFlags, if ( victim->takedamage ) {//some other breakable thing //create a flash here - g_saberFlashTime = level.time-50; - VectorCopy( dmgSpot[i], g_saberFlashPos ); + if ( !g_noClashFlare ) + { + g_saberFlashTime = level.time-50; + VectorCopy( dmgSpot[i], g_saberFlashPos ); + } } } if ( !PM_SuperBreakWinAnim( ent->client->ps.torsoAnim ) @@ -1357,11 +1626,76 @@ qboolean WP_SaberApplyDamage( gentity_t *ent, float baseDamage, int baseDFlags, {//do knockback dFlags &= ~(DAMAGE_NO_KNOCKBACK|DAMAGE_DEATH_KNOCKBACK); } + if ( !WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && ent->client->ps.saber[saberNum].knockbackScale > 0.0f ) + { + dFlags &= ~(DAMAGE_NO_KNOCKBACK|DAMAGE_DEATH_KNOCKBACK); + if ( saberNum < 1 ) + { + dFlags |= DAMAGE_SABER_KNOCKBACK1; + } + else + { + dFlags |= DAMAGE_SABER_KNOCKBACK2; + } + } + else if ( WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && ent->client->ps.saber[saberNum].knockbackScale2 > 0.0f ) + { + dFlags &= ~(DAMAGE_NO_KNOCKBACK|DAMAGE_DEATH_KNOCKBACK); + if ( saberNum < 1 ) + { + dFlags |= DAMAGE_SABER_KNOCKBACK1_B2; + } + else + { + dFlags |= DAMAGE_SABER_KNOCKBACK2_B2; + } + } if ( thrownSaber ) { inflictor = &g_entities[ent->client->ps.saberEntityNum]; } - G_Damage( victim, inflictor, ent, dmgDir[i], dmgSpot[i], ceil(totalDmg[i]), dFlags, MOD_SABER, hitDismemberLoc[i] ); + int damage = 0; + if ( !WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && ent->client->ps.saber[saberNum].damageScale != 1.0f ) + { + damage = ceil(totalDmg[i]*ent->client->ps.saber[saberNum].damageScale); + } + else if ( WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && ent->client->ps.saber[saberNum].damageScale2 != 1.0f ) + { + damage = ceil(totalDmg[i]*ent->client->ps.saber[saberNum].damageScale2); + } + else + { + damage = ceil(totalDmg[i]); + } + G_Damage( victim, inflictor, ent, dmgDir[i], dmgSpot[i], damage, dFlags, MOD_SABER, hitDismemberLoc[i] ); + if ( damage > 0 && cg.time ) + { + float sizeTimeScale = 1.0f; + if ( (vicWasAlive + && victim->health <= 0 ) + || (!vicWasDismembered + && victim->client->dismembered + && hitDismemberLoc[i] != HL_NONE + && hitDismember[i]) ) + { + sizeTimeScale = 3.0f; + } + //FIXME: if not hitting the first model on the enemy, don't do this! + CG_SaberDoWeaponHitMarks( ent->client, + (ent->client->ps.saberInFlight?&g_entities[ent->client->ps.saberEntityNum]:NULL), + victim, + saberNum, + bladeNum, + dmgSpot[i], + dmgDir[i], + dmgBladeVec[i], + dmgNormal[i], + sizeTimeScale ); + } #ifndef FINAL_BUILD if ( d_saberCombat->integer ) { @@ -1376,7 +1710,9 @@ qboolean WP_SaberApplyDamage( gentity_t *ent, float baseDamage, int baseDFlags, } #endif //do the effect - //G_PlayEffect( G_EffectIndex( "blood_sparks" ), dmgSpot[i], dmgDir[i] ); + //vec3_t splashBackDir; + //VectorScale( dmgNormal[i], -1, splashBackDir ); + //G_PlayEffect( G_EffectIndex( "blood_sparks" ), dmgSpot[i], splashBackDir ); if ( ent->s.number == 0 ) { AddSoundEvent( victim->owner, dmgSpot[i], 256, AEL_DISCOVERED ); @@ -1401,7 +1737,7 @@ qboolean WP_SaberApplyDamage( gentity_t *ent, float baseDamage, int baseDFlags, return didDamage; } -void WP_SaberDamageAdd( float trDmg, int trVictimEntityNum, vec3_t trDmgDir, vec3_t trDmgSpot, float dmg, float fraction, int trHitLoc, qboolean trDismember, int trDismemberLoc ) +void WP_SaberDamageAdd( float trDmg, int trVictimEntityNum, vec3_t trDmgDir, vec3_t trDmgBladeVec, vec3_t trDmgNormal, vec3_t trDmgSpot, float dmg, float fraction, int trHitLoc, qboolean trDismember, int trDismemberLoc ) { int curVictim = 0; @@ -1446,6 +1782,14 @@ void WP_SaberDamageAdd( float trDmg, int trVictimEntityNum, vec3_t trDmgDir, vec { VectorCopy( trDmgDir, dmgDir[curVictim] ); } + if ( !VectorLengthSquared( dmgBladeVec[curVictim] ) ) + { + VectorCopy( trDmgBladeVec, dmgBladeVec[curVictim] ); + } + if ( !VectorLengthSquared( dmgNormal[curVictim] ) ) + { + VectorCopy( trDmgNormal, dmgNormal[curVictim] ); + } if ( !VectorLengthSquared( dmgSpot[curVictim] ) ) { VectorCopy( trDmgSpot, dmgSpot[curVictim] ); @@ -1752,7 +2096,7 @@ const char *hit_blood_sparks = "sparks/blood_sparks2"; // could have changed thi const char *hit_sparks = "saber/saber_cut"; //extern char *hitLocName[]; -qboolean WP_SaberDamageEffects( trace_t *tr, const vec3_t start, float length, float dmg, vec3_t dmgDir, vec3_t bladeDir, int enemyTeam, saberType_t saberType ) +qboolean WP_SaberDamageEffects( trace_t *tr, const vec3_t start, float length, float dmg, vec3_t dmgDir, vec3_t bladeVec, int enemyTeam, saberType_t saberType, saberInfo_t *saber, int bladeNum ) { int hitEntNum[MAX_G2_COLLISIONS]; @@ -1764,7 +2108,8 @@ qboolean WP_SaberDamageEffects( trace_t *tr, const vec3_t start, float length, f float hitEntDmgAdd[MAX_G2_COLLISIONS] = {0}; float hitEntDmgSub[MAX_G2_COLLISIONS] = {0}; vec3_t hitEntPoint[MAX_G2_COLLISIONS]; - vec3_t hitEntDir[MAX_G2_COLLISIONS]; + vec3_t hitEntNormal[MAX_G2_COLLISIONS]; + vec3_t bladeDir; float hitEntStartFrac[MAX_G2_COLLISIONS] = {0}; int trHitLoc[MAX_G2_COLLISIONS] = {HL_NONE};//same as 0 int trDismemberLoc[MAX_G2_COLLISIONS] = {HL_NONE};//same as 0 @@ -1772,9 +2117,12 @@ qboolean WP_SaberDamageEffects( trace_t *tr, const vec3_t start, float length, f int i,z; int numHitEnts = 0; float distFromStart,doDmg; - const char *hitEffect, *trSurfName; + int hitEffect = 0; + const char *trSurfName; gentity_t *hitEnt; + VectorNormalize2( bladeVec, bladeDir ); + for (z=0; z < MAX_G2_COLLISIONS; z++) { if ( tr->G2CollisionMap[z].mEntityNum == -1 ) @@ -1830,15 +2178,50 @@ qboolean WP_SaberDamageEffects( trace_t *tr, const vec3_t start, float length, f hitEntStartFrac[numHitEnts] = hitEntDmgSub[numHitEnts]/length; //remember the entrance point VectorCopy( coll.mCollisionPosition, hitEntPoint[numHitEnts] ); - //remember the entrance dir - VectorCopy( coll.mCollisionNormal, hitEntDir[numHitEnts] ); - VectorNormalize( hitEntDir[numHitEnts] ); + //remember the normal of the face we hit + VectorCopy( coll.mCollisionNormal, hitEntNormal[numHitEnts] ); + VectorNormalize( hitEntNormal[numHitEnts] ); //do the effect //FIXME: check material rather than team? hitEnt = &g_entities[hitEntNum[numHitEnts]]; - hitEffect = hit_blood_sparks; + if ( hitEnt + && hitEnt->client + && coll.mModelIndex > 0 ) + {//hit a submodel on the enemy, not their actual body! + if ( !WP_SaberBladeUseSecondBladeStyle( saber, bladeNum ) + && saber->hitOtherEffect ) + { + hitEffect = saber->hitOtherEffect; + } + else if ( WP_SaberBladeUseSecondBladeStyle( saber, bladeNum ) + && saber->hitOtherEffect2 ) + { + hitEffect = saber->hitOtherEffect2; + } + else + { + hitEffect = G_EffectIndex( hit_sparks ); + } + } + else + { + if ( !WP_SaberBladeUseSecondBladeStyle( saber, bladeNum ) + && saber->hitPersonEffect ) + { + hitEffect = saber->hitPersonEffect; + } + else if ( WP_SaberBladeUseSecondBladeStyle( saber, bladeNum ) + && saber->hitPersonEffect2 ) + { + hitEffect = saber->hitPersonEffect2; + } + else + { + hitEffect = G_EffectIndex( hit_blood_sparks ); + } + } if ( hitEnt != NULL ) { if ( hitEnt->client ) @@ -1849,7 +2232,20 @@ qboolean WP_SaberDamageEffects( trace_t *tr, const vec3_t start, float length, f npc_class == CLASS_PROTOCOL || npc_class == CLASS_MARK1 || npc_class == CLASS_MARK2 || npc_class == CLASS_INTERROGATOR || npc_class == CLASS_ATST || npc_class == CLASS_SENTRY ) { - hitEffect = hit_sparks; + if ( !WP_SaberBladeUseSecondBladeStyle( saber, bladeNum ) + && saber->hitOtherEffect ) + { + hitEffect = saber->hitOtherEffect; + } + else if ( WP_SaberBladeUseSecondBladeStyle( saber, bladeNum ) + && saber->hitOtherEffect2 ) + { + hitEffect = saber->hitOtherEffect2; + } + else + { + hitEffect = G_EffectIndex( hit_sparks ); + } } } else @@ -1871,11 +2267,24 @@ qboolean WP_SaberDamageEffects( trace_t *tr, const vec3_t start, float length, f ||(hitEnt->flags&FL_DMG_BY_HEAVY_WEAP_ONLY) )//HEAVY weapon damage only ) {//no hit effect (besides regular client-side one) - hitEffect = NULL; + hitEffect = 0; } else { - hitEffect = hit_sparks; + if ( !WP_SaberBladeUseSecondBladeStyle( saber, bladeNum ) + && saber->hitOtherEffect ) + { + hitEffect = saber->hitOtherEffect; + } + else if ( WP_SaberBladeUseSecondBladeStyle( saber, bladeNum ) + && saber->hitOtherEffect2 ) + { + hitEffect = saber->hitOtherEffect2; + } + else + { + hitEffect = G_EffectIndex( hit_sparks ); + } } } } @@ -1885,19 +2294,11 @@ qboolean WP_SaberDamageEffects( trace_t *tr, const vec3_t start, float length, f //FIXME: play less if damage is less? if ( !g_saberNoEffects ) { - if ( hitEffect != NULL ) + if ( hitEffect != 0 ) { + //FIXME: when you have multiple blades hitting someone for many sequential server frames, this can get a bit chuggy! G_PlayEffect( hitEffect, coll.mCollisionPosition, coll.mCollisionNormal ); } - /* - if ( hitEnt && hitEnt->client ) - { - CG_AddGhoul2Mark( PGORE_DECAL02, Q_flrand(3.5, 4.0), coll.mCollisionPosition, hitEntDir[numHitEnts], hitEnt->s.number, - hitEnt->client->ps.origin, hitEnt->client->renderInfo.legsYaw, hitEnt->ghoul2 ); - CG_AddGhoul2Mark( PGORE_DECAL03, Q_flrand(3.5, 4.0), coll.mCollisionPosition, hitEntDir[numHitEnts], hitEnt->s.number, - hitEnt->client->ps.origin, hitEnt->client->renderInfo.legsYaw, hitEnt->ghoul2 ); - } - */ } //Get the hit location based on surface name @@ -1965,18 +2366,79 @@ qboolean WP_SaberDamageEffects( trace_t *tr, const vec3_t start, float length, f } if ( doDmg > 0 ) { - WP_SaberDamageAdd( 1.0, hitEntNum[i], hitEntDir[i], hitEntPoint[i], ceil(doDmg), hitEntStartFrac[i], trHitLoc[i], trDismember[i], trDismemberLoc[i] ); + WP_SaberDamageAdd( 1.0, hitEntNum[i], dmgDir, bladeVec, hitEntNormal[i], hitEntPoint[i], ceil(doDmg), hitEntStartFrac[i], trHitLoc[i], trDismember[i], trDismemberLoc[i] ); } } } return (numHitEnts>0); } +void WP_SaberBlockEffect( gentity_t *attacker, int saberNum, int bladeNum, vec3_t position, vec3_t normal, qboolean cutNotBlock ) +{ + saberInfo_t *saber = NULL; + + if ( attacker && attacker->client ) + { + saber = &attacker->client->ps.saber[saberNum]; + } + + if ( saber + && !WP_SaberBladeUseSecondBladeStyle( saber, bladeNum ) + && saber->blockEffect ) + { + if ( normal ) + { + G_PlayEffect( saber->blockEffect, position, normal ); + } + else + { + G_PlayEffect( saber->blockEffect, position ); + } + } + else if ( saber + && WP_SaberBladeUseSecondBladeStyle( saber, bladeNum ) + && saber->blockEffect2 ) + { + if ( normal ) + { + G_PlayEffect( saber->blockEffect2, position, normal ); + } + else + { + G_PlayEffect( saber->blockEffect2, position ); + } + } + else if ( cutNotBlock ) + { + if ( normal ) + { + G_PlayEffect( "saber/saber_cut", position, normal ); + } + else + { + G_PlayEffect( "saber/saber_cut", position ); + } + } + else + { + + if ( normal ) + { + G_PlayEffect( "saber/saber_block", position, normal ); + } + else + { + G_PlayEffect( "saber/saber_block", position ); + } + } +} + void WP_SaberKnockaway( gentity_t *attacker, trace_t *tr ) { WP_SaberDrop( attacker, &g_entities[attacker->client->ps.saberEntityNum] ); - G_Sound( &g_entities[attacker->client->ps.saberEntityNum], G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", Q_irand(1, 9) ) ) ); - G_PlayEffect( "saber/saber_block", tr->endpos ); + WP_SaberBlockSound( attacker, NULL, 0, 0 ); + //G_Sound( &g_entities[attacker->client->ps.saberEntityNum], G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", Q_irand(1, 9) ) ) ); + WP_SaberBlockEffect( attacker, 0, 0, tr->endpos, NULL, qfalse ); saberHitFraction = tr->fraction; #ifndef FINAL_BUILD if ( d_saberCombat->integer ) @@ -1986,8 +2448,11 @@ void WP_SaberKnockaway( gentity_t *attacker, trace_t *tr ) #endif VectorCopy( tr->endpos, saberHitLocation ); saberHitEntity = tr->entityNum; - g_saberFlashTime = level.time-50; - VectorCopy( saberHitLocation, g_saberFlashPos ); + if ( !g_noClashFlare ) + { + g_saberFlashTime = level.time-50; + VectorCopy( saberHitLocation, g_saberFlashPos ); + } //FIXME: make hitEnt play an attack anim or some other special anim when this happens //gentity_t *hitEnt = &g_entities[tr->entityNum]; @@ -2031,17 +2496,41 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg if ( !noGhoul ) { - if ( !attacker->s.number - || (attacker->client - && (attacker->client->playerTeam==TEAM_PLAYER - || attacker->client->NPC_class==CLASS_SHADOWTROOPER - || attacker->client->NPC_class==CLASS_ALORA - || (attacker->NPC && (attacker->NPC->aiFlags&NPCAI_BOSS_CHARACTER)) - ) - ) - )//&&attackStrength==FORCE_LEVEL_3) + float useRadiusForDamage = 0; + + if ( attacker + && attacker->client ) + {//see if we're not drawing the blade, if so, do a trace based on radius of blade (because the radius is being used to simulate a larger/smaller piece of a solid weapon)... + if ( !WP_SaberBladeUseSecondBladeStyle( &attacker->client->ps.saber[saberNum], bladeNum ) + && (attacker->client->ps.saber[saberNum].saberFlags2&SFL2_NO_BLADE) ) + {//not drawing blade + useRadiusForDamage = attacker->client->ps.saber[saberNum].blade[bladeNum].radius; + } + else if ( WP_SaberBladeUseSecondBladeStyle( &attacker->client->ps.saber[saberNum], bladeNum ) + && (attacker->client->ps.saber[saberNum].saberFlags2&SFL2_NO_BLADE2) ) + {//not drawing blade + useRadiusForDamage = attacker->client->ps.saber[saberNum].blade[bladeNum].radius; + } + } + if ( !useRadiusForDamage ) + {//do normal check for larger-size saber traces + if ( !attacker->s.number + || (attacker->client + && (attacker->client->playerTeam==TEAM_PLAYER + || attacker->client->NPC_class==CLASS_SHADOWTROOPER + || attacker->client->NPC_class==CLASS_ALORA + || (attacker->NPC && (attacker->NPC->aiFlags&NPCAI_BOSS_CHARACTER)) + ) + ) + )//&&attackStrength==FORCE_LEVEL_3) + { + useRadiusForDamage = 2; + } + } + + if ( useRadiusForDamage > 0 )//&&attackStrength==FORCE_LEVEL_3) {//player,. player allies, shadowtroopers, tavion and desann use larger traces - vec3_t traceMins = {-2,-2,-2}, traceMaxs = {2,2,2}; + vec3_t traceMins = {-useRadiusForDamage,-useRadiusForDamage,-useRadiusForDamage}, traceMaxs = {useRadiusForDamage,useRadiusForDamage,useRadiusForDamage}; gi.trace( &tr, start, traceMins, traceMaxs, end2, ignore, mask, G2_COLLIDE, 10 );//G2_SUPERSIZEDBBOX } /* @@ -2079,6 +2568,11 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg if ( tr.entityNum == ENTITYNUM_WORLD ) { + if ( attacker && attacker->client && (attacker->client->ps.saber[saberNum].saberFlags&SFL_BOUNCE_ON_WALLS) ) + { + VectorCopy( tr.endpos, saberHitLocation ); + VectorCopy( tr.plane.normal, saberHitNormal ); + } return qtrue; } @@ -2318,7 +2812,7 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg if ( attacker && attacker->client && attacker->client->ps.saberInFlight ) {//thrown saber hit something if ( ( hitEnt && hitEnt->client && hitEnt->health > 0 && ( hitEnt->client->NPC_class == CLASS_DESANN || !Q_stricmp("Yoda",hitEnt->NPC_type) || hitEnt->client->NPC_class == CLASS_LUKE || hitEnt->client->NPC_class == CLASS_BOBAFETT || (hitEnt->client->ps.powerups[PW_GALAK_SHIELD] > 0) ) ) || - ( owner && owner->client && owner->health > 0 && ( owner->client->NPC_class == CLASS_DESANN || !Q_stricmp("Yoda",owner->NPC_type) || owner->client->NPC_class == CLASS_LUKE || hitEnt->client->NPC_class == CLASS_BOBAFETT || (owner->client->ps.powerups[PW_GALAK_SHIELD] > 0) ) ) ) + ( owner && owner->client && owner->health > 0 && ( owner->client->NPC_class == CLASS_DESANN || !Q_stricmp("Yoda",owner->NPC_type) || owner->client->NPC_class == CLASS_LUKE || (owner->client->ps.powerups[PW_GALAK_SHIELD] > 0) ) ) ) {//Luke and Desann slap thrown sabers aside //FIXME: control the direction of the thrown saber... if hit Galak's shield, bounce directly away from his origin? WP_SaberKnockaway( attacker, &tr ); @@ -2338,12 +2832,17 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg { //no team damage: if ( !hitEnt->client || attacker == NULL || !attacker->client || (hitEnt->client->playerTeam != attacker->client->playerTeam) ) { + vec3_t bladeVec={0}; + if ( attacker && attacker->client ) + { + VectorScale( bladeDir, attacker->client->ps.saber[saberNum].blade[bladeNum].length, bladeVec ); + } //multiply the damage by the total distance of the swipe VectorSubtract( end2, start, dir ); float len = VectorNormalize( dir );//VectorLength( dir ); if ( noGhoul || !hitEnt->ghoul2.size() ) {//we weren't doing a ghoul trace - const char *hitEffect = NULL; + int hitEffect = 0; if ( dmg >= 1.0 && hitEnt->bmodel ) { dmg = 1.0; @@ -2379,7 +2878,9 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg trFrac = (1.0f - tr.fraction); dmgFrac = tr.fraction; } - WP_SaberDamageAdd( trFrac, tr.entityNum, dir, tr.endpos, dmg, dmgFrac, HL_NONE, qfalse, HL_NONE ); + vec3_t backdir; + VectorScale( dir, -1, backdir ); + WP_SaberDamageAdd( trFrac, tr.entityNum, dir, bladeVec, backdir, tr.endpos, dmg, dmgFrac, HL_NONE, qfalse, HL_NONE ); if ( !tr.allsolid && !tr.startsolid ) { VectorScale( dir, -1, dir ); @@ -2395,7 +2896,20 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg npc_class == CLASS_PROTOCOL || npc_class == CLASS_MARK1 || npc_class == CLASS_MARK2 || npc_class == CLASS_INTERROGATOR || npc_class == CLASS_ATST || npc_class == CLASS_SENTRY ) { - hitEffect = hit_sparks; + if ( !WP_SaberBladeUseSecondBladeStyle( &attacker->client->ps.saber[saberNum], bladeNum ) + && attacker->client->ps.saber[saberNum].hitOtherEffect ) + { + hitEffect = attacker->client->ps.saber[saberNum].hitOtherEffect; + } + else if ( WP_SaberBladeUseSecondBladeStyle( &attacker->client->ps.saber[saberNum], bladeNum ) + && attacker->client->ps.saber[saberNum].hitOtherEffect2 ) + { + hitEffect = attacker->client->ps.saber[saberNum].hitOtherEffect2; + } + else + { + hitEffect = G_EffectIndex( hit_sparks ); + } } } else @@ -2410,27 +2924,45 @@ qboolean WP_SaberDamageForTrace( int ignore, vec3_t start, vec3_t end, float dmg } else { - hitEffect = hit_sparks; + if ( !WP_SaberBladeUseSecondBladeStyle( &attacker->client->ps.saber[saberNum], bladeNum ) + && attacker->client->ps.saber[saberNum].hitOtherEffect ) + { + hitEffect = attacker->client->ps.saber[saberNum].hitOtherEffect; + } + else if ( WP_SaberBladeUseSecondBladeStyle( &attacker->client->ps.saber[saberNum], bladeNum ) + && attacker->client->ps.saber[saberNum].hitOtherEffect2 ) + { + hitEffect = attacker->client->ps.saber[saberNum].hitOtherEffect2; + } + else + { + hitEffect = G_EffectIndex( hit_sparks ); + } } } } } - if ( !g_saberNoEffects && hitEffect != NULL ) + if ( !g_saberNoEffects && hitEffect != 0 ) { G_PlayEffect( hitEffect, tr.endpos, dir );//"saber_cut" } } else {//we were doing a ghoul trace - if ( !WP_SaberDamageEffects( &tr, start, len, dmg, dir, bladeDir, attacker->client->enemyTeam, saberType ) ) - {//didn't hit a ghoul ent - /* - if ( && hitEnt->ghoul2.size() ) - {//it was a ghoul2 model so we should have hit it - return qfalse; + if ( !attacker + || !attacker->client + || attacker->client->ps.saberLockTime < level.time ) + { + if ( !WP_SaberDamageEffects( &tr, start, len, dmg, dir, bladeVec, attacker->client->enemyTeam, saberType, &attacker->client->ps.saber[saberNum], bladeNum ) ) + {//didn't hit a ghoul ent + /* + if ( && hitEnt->ghoul2.size() ) + {//it was a ghoul2 model so we should have hit it + return qfalse; + } + */ } - */ } } } @@ -3080,9 +3612,21 @@ qboolean WP_SabersCheckLock( gentity_t *ent1, gentity_t *ent2 ) { return qfalse; } - if ( !ent1->client->ps.saber[0].lockable || !ent2->client->ps.saber[0].lockable ) + if ( (ent1->client->ps.saber[0].saberFlags&SFL_NOT_LOCKABLE) + || (ent2->client->ps.saber[0].saberFlags&SFL_NOT_LOCKABLE) ) + {//one of these sabers cannot lock (like a lance) + return qfalse; + } + if ( ent1->client->ps.dualSabers + && ent1->client->ps.saber[1].Active() + && (ent1->client->ps.saber[1].saberFlags&SFL_NOT_LOCKABLE) ) + {//one of these sabers cannot lock (like a lance) + return qfalse; + } + if ( ent2->client->ps.dualSabers + && ent2->client->ps.saber[1].Active() + && (ent2->client->ps.saber[1].saberFlags&SFL_NOT_LOCKABLE) ) {//one of these sabers cannot lock (like a lance) - //FIXME: check the second sabers too? return qfalse; } if ( ent1->painDebounceTime > level.time-1000 || ent2->painDebounceTime > level.time-1000 ) @@ -3510,7 +4054,7 @@ qboolean WP_SabersCheckLock( gentity_t *ent1, gentity_t *ent2 ) return qfalse; } -qboolean WP_SaberParry( gentity_t *victim, gentity_t *attacker ) +qboolean WP_SaberParry( gentity_t *victim, gentity_t *attacker, int saberNum, int bladeNum ) { if ( !victim || !victim->client || !attacker ) { @@ -3541,7 +4085,7 @@ qboolean WP_SaberParry( gentity_t *victim, gentity_t *attacker ) //since it was parried, take away any damage done //FIXME: what if the damage was done before the parry? - WP_SaberClearDamageForEntNum( victim->s.number ); + WP_SaberClearDamageForEntNum( attacker, victim->s.number, saberNum, bladeNum ); //tell the victim to get mad at me if ( victim->enemy != attacker && victim->client->playerTeam != attacker->client->playerTeam ) @@ -3878,6 +4422,98 @@ int G_CostForSpecialMove( int cost, qboolean kataMove ) } } +extern qboolean G_EntIsBreakable( int entityNum, gentity_t *breaker ); +void WP_SaberRadiusDamage( gentity_t *ent, vec3_t point, float radius, int damage, float knockBack ) +{ + if ( !ent || !ent->client ) + { + return; + } + else if ( radius <= 0.0f || (damage <= 0 && knockBack <= 0) ) + { + return; + } + else + { + vec3_t mins, maxs, entDir; + gentity_t *radiusEnts[128]; + int numEnts, i; + float dist; + + //Setup the bbox to search in + for ( i = 0; i < 3; i++ ) + { + mins[i] = point[i] - radius; + maxs[i] = point[i] + radius; + } + + //Get the number of entities in a given space + numEnts = gi.EntitiesInBox( mins, maxs, radiusEnts, 128 ); + + for ( i = 0; i < numEnts; i++ ) + { + if ( !radiusEnts[i]->inuse ) + { + continue; + } + + if ( radiusEnts[i] == ent ) + {//Skip myself + continue; + } + + if ( radiusEnts[i]->client == NULL ) + {//must be a client + if ( G_EntIsBreakable( radiusEnts[i]->s.number, ent ) ) + {//damage breakables within range, but not as much + G_Damage( radiusEnts[i], ent, ent, vec3_origin, radiusEnts[i]->currentOrigin, 10, 0, MOD_EXPLOSIVE_SPLASH ); + } + continue; + } + + if ( (radiusEnts[i]->client->ps.eFlags&EF_HELD_BY_RANCOR) + || (radiusEnts[i]->client->ps.eFlags&EF_HELD_BY_WAMPA) ) + {//can't be one being held + continue; + } + + VectorSubtract( radiusEnts[i]->currentOrigin, point, entDir ); + dist = VectorNormalize( entDir ); + if ( dist <= radius ) + {//in range + if ( damage > 0 ) + {//do damage + int points = ceil((float)damage*dist/radius); + G_Damage( radiusEnts[i], ent, ent, vec3_origin, radiusEnts[i]->currentOrigin, points, DAMAGE_NO_KNOCKBACK, MOD_EXPLOSIVE_SPLASH ); + } + if ( knockBack > 0 ) + {//do knockback + if ( radiusEnts[i]->client + && radiusEnts[i]->client->NPC_class != CLASS_RANCOR + && radiusEnts[i]->client->NPC_class != CLASS_ATST + && !(radiusEnts[i]->flags&FL_NO_KNOCKBACK) )//don't throw them back + { + float knockbackStr = knockBack*dist/radius; + entDir[2] += 0.1f; + VectorNormalize( entDir ); + G_Throw( radiusEnts[i], entDir, knockbackStr ); + if ( radiusEnts[i]->health > 0 ) + {//still alive + if ( knockbackStr > 50 ) + {//close enough and knockback high enough to possibly knock down + if ( dist < (radius*0.5f) + || radiusEnts[i]->client->ps.groundEntityNum != ENTITYNUM_NONE ) + {//within range of my fist or within ground-shaking range and not in the air + G_Knockdown( radiusEnts[i], ent, entDir, 500, qtrue ); + } + } + } + } + } + } + } + } +} /* --------------------------------------------------------- void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) @@ -3903,6 +4539,7 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) } memset( totalDmg, 0, sizeof( totalDmg) ); memset( dmgDir, 0, sizeof( dmgDir ) ); + memset( dmgNormal, 0, sizeof( dmgNormal ) ); memset( dmgSpot, 0, sizeof( dmgSpot ) ); memset( dmgFraction, 0, sizeof( dmgFraction ) ); memset( hitLoc, HL_NONE, sizeof( hitLoc ) ); @@ -3936,7 +4573,11 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) return; } - int saberContents = gi.pointcontents( ent->client->renderInfo.muzzlePoint, ent->client->ps.saberEntityNum ); + int saberContents = 0; + if ( !(ent->client->ps.saber[saberNum].saberFlags&SFL_ON_IN_WATER) ) + {//saber can't stay on underwater + saberContents = gi.pointcontents( ent->client->renderInfo.muzzlePoint, ent->client->ps.saberEntityNum ); + } if ( (saberContents&CONTENTS_WATER)|| (saberContents&CONTENTS_SLIME)|| (saberContents&CONTENTS_LAVA) ) @@ -3996,7 +4637,7 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) } //or unless returning else if ( ent->client->ps.saberEntityState == SES_RETURNING - && ent->client->ps.saber[0].returnDamage == qfalse )//type != SABER_STAR ) + && !(ent->client->ps.saber[0].saberFlags&SFL_RETURN_DAMAGE) )//type != SABER_STAR ) {//special case, since we're returning, chances are if we hit something //it's going to be butt-first. So do less damage. baseDamage = 0.1f; @@ -4036,10 +4677,38 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) {//don't kill with this hit baseDFlags = DAMAGE_NO_KILL; } + if ( (!WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && (ent->client->ps.saber[saberNum].saberFlags2&SFL2_NO_IDLE_EFFECT) ) + || ( WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && (ent->client->ps.saber[saberNum].saberFlags2&SFL2_NO_IDLE_EFFECT2) ) + ) + {//do nothing at all when idle + return; + } baseDamage = 0; } else if ( ent->client->ps.saberLockTime > level.time ) {//just do effects + if ( (!WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && (ent->client->ps.saber[saberNum].saberFlags2&SFL2_NO_IDLE_EFFECT) ) + || ( WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && (ent->client->ps.saber[saberNum].saberFlags2&SFL2_NO_IDLE_EFFECT2) ) + ) + {//do nothing at all when idle + return; + } + baseDamage = 0; + } + else if ( !WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && ent->client->ps.saber[saberNum].damageScale <= 0.0f + && ent->client->ps.saber[saberNum].knockbackScale <= 0.0f ) + {//this blade does no damage and no knockback (only for blocking?) + baseDamage = 0; + } + else if ( WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && ent->client->ps.saber[saberNum].damageScale2 <= 0.0f + && ent->client->ps.saber[saberNum].knockbackScale2 <= 0.0f ) + {//this blade does no damage and no knockback (only for blocking?) baseDamage = 0; } else if ( ent->client->ps.saberBlocked > BLOCKED_NONE @@ -4049,6 +4718,14 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) ) ) {//don't do damage if parrying/reflecting/bouncing/deflecting or not actually attacking or in a transition to/from/between attacks + if ( (!WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && (ent->client->ps.saber[saberNum].saberFlags2&SFL2_NO_IDLE_EFFECT) ) + || ( WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && (ent->client->ps.saber[saberNum].saberFlags2&SFL2_NO_IDLE_EFFECT2) ) + ) + {//do nothing at all when idle + return; + } baseDamage = 0; } else @@ -4057,10 +4734,18 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) if ( !PM_SaberInSpecialAttack( ent->client->ps.torsoAnim ) && !PM_InAnimForSaberMove( ent->client->ps.torsoAnim, ent->client->ps.saberMove ) ) {//forced into some other animation somehow, like a pain or death? + if ( (!WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && (ent->client->ps.saber[saberNum].saberFlags2&SFL2_NO_IDLE_EFFECT) ) + || ( WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && (ent->client->ps.saber[saberNum].saberFlags2&SFL2_NO_IDLE_EFFECT2) ) + ) + {//do nothing at all when idle + return; + } baseDamage = 0; } else if ( ent->client->ps.weaponstate == WEAPON_FIRING && ent->client->ps.saberBlocked == BLOCKED_NONE && - ( PM_SaberInAttack(ent->client->ps.saberMove) || PM_SaberInSpecialAttack( ent->client->ps.torsoAnim ) || PM_SpinningSaberAnim(ent->client->ps.torsoAnim) || entPowerLevel > FORCE_LEVEL_2 ) )// || ent->client->ps.saberAnimLevel == SS_STAFF ) ) + ( PM_SaberInAttack(ent->client->ps.saberMove) || PM_SaberInSpecialAttack( ent->client->ps.torsoAnim ) || PM_SpinningSaberAnim(ent->client->ps.torsoAnim) || entPowerLevel > FORCE_LEVEL_2 || (WP_SaberBladeDoTransitionDamage( &ent->client->ps.saber[saberNum], bladeNum )&&PM_SaberInTransitionAny(ent->client->ps.saberMove)) ) )// || ent->client->ps.saberAnimLevel == SS_STAFF ) ) {//normal attack swing swinging/spinning (or if using strong set), do normal damage //FIXME: or if using staff? //FIXME: more damage for higher attack power levels? // More damage based on length/color of saber? @@ -4148,8 +4833,16 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) //VectorCopy( ent->client->renderInfo.muzzlePointNext, mp2 ); //VectorCopy( ent->client->renderInfo.muzzleDirNext, md2 ); //prediction was causing gaps in swing (G2 problem) so *don't* predict + if ( ent->client->ps.saberDamageDebounceTime > level.time ) + {//really only used when a saber attack start anim starts, not actually for stopping damage + //we just want to not use the old position to trace the attack from... + VectorCopy( ent->client->ps.saber[saberNum].blade[bladeNum].muzzlePoint, ent->client->ps.saber[saberNum].blade[bladeNum].muzzlePointOld ); + VectorCopy( ent->client->ps.saber[saberNum].blade[bladeNum].muzzleDir, ent->client->ps.saber[saberNum].blade[bladeNum].muzzleDirOld ); + } + //do the damage trace from the last position... VectorCopy( ent->client->ps.saber[saberNum].blade[bladeNum].muzzlePointOld, mp1 ); VectorCopy( ent->client->ps.saber[saberNum].blade[bladeNum].muzzleDirOld, md1 ); + //...to the current one. VectorCopy( ent->client->ps.saber[saberNum].blade[bladeNum].muzzlePoint, mp2 ); VectorCopy( ent->client->ps.saber[saberNum].blade[bladeNum].muzzleDir, md2 ); @@ -4506,16 +5199,23 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) if ( entAttacking ) {//add twoHanded bonus and breakParryBonus to entPowerLevel here //This makes staff too powerful - if ( ent->client->ps.saber[saberNum].twoHanded ) + if ( (ent->client->ps.saber[saberNum].saberFlags&SFL_TWO_HANDED) ) { entPowerLevel++; } //FIXME: what if dualSabers && both sabers are hitting at same time? - entPowerLevel += ent->client->ps.saber[saberNum].breakParryBonus; + if ( !WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) ) + { + entPowerLevel += ent->client->ps.saber[saberNum].breakParryBonus; + } + else if ( WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) ) + { + entPowerLevel += ent->client->ps.saber[saberNum].breakParryBonus2; + } } else if ( entDefending ) {//add twoHanded bonus and dualSaber bonus and parryBonus to entPowerLevel here - if ( ent->client->ps.saber[saberNum].twoHanded + if ( (ent->client->ps.saber[saberNum].saberFlags&SFL_TWO_HANDED) || (ent->client->ps.dualSabers && ent->client->ps.saber[1].Active()) ) { entPowerLevel++; @@ -4549,7 +5249,7 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) } if ( hitOwnerAttacking ) {//add twoHanded bonus and breakParryBonus to entPowerLevel here - if ( hitOwner->client->ps.saber[0].twoHanded ) + if ( (hitOwner->client->ps.saber[0].saberFlags&SFL_TWO_HANDED) ) { hitOwnerPowerLevel++; } @@ -4561,7 +5261,8 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) } else if ( hitOwnerDefending ) {//add twoHanded bonus and dualSaber bonus and parryBonus to entPowerLevel here - if ( hitOwner->client->ps.saber[0].twoHanded || (hitOwner->client->ps.dualSabers && hitOwner->client->ps.saber[1].Active()) ) + if ( (hitOwner->client->ps.saber[0].saberFlags&SFL_TWO_HANDED) + || (hitOwner->client->ps.dualSabers && hitOwner->client->ps.saber[1].Active()) ) { hitOwnerPowerLevel++; } @@ -4636,7 +5337,7 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) && (hitOwnerPowerLevel > FORCE_LEVEL_2||(hitOwner->client->ps.forcePowerLevel[FP_SABER_DEFENSE]>FORCE_LEVEL_2&&Q_irand(0,hitOwner->client->ps.forcePowerLevel[FP_SABER_OFFENSE]))) ) {//knockaways can make fast-attacker go into a broken parry anim if the ent is using fast or med (but not Tavion) //make me parry - WP_SaberParry( hitOwner, ent ); + WP_SaberParry( hitOwner, ent, saberNum, bladeNum ); //turn the parry into a knockaway hitOwner->client->ps.saberBounceMove = PM_KnockawayForParry( hitOwner->client->ps.saberBlocked ); //make them go into a broken parry @@ -4644,10 +5345,10 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) ent->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN; if ( saberNum == 0 ) {//FIXME: can only lose right-hand saber for now - if ( ent->client->ps.saber[saberNum].disarmable + if ( !(ent->client->ps.saber[saberNum].saberFlags&SFL_NOT_DISARMABLE) && ent->client->ps.forcePowerLevel[FP_SABER_DEFENSE] < FORCE_LEVEL_2 //&& (ent->s.number||g_saberRealisticCombat->integer) - && Q_irand( 0, hitOwner->client->ps.SaberDisarmBonus() ) > 0 + && Q_irand( 0, hitOwner->client->ps.SaberDisarmBonus( 0 ) ) > 0 && (hitOwner->s.number || g_saberAutoBlocking->integer || !Q_irand( 0, 2 )) )//if player defending and autoblocking is on, this is less likely to happen, so don't do the random check {//knocked the saber right out of his hand! (never happens to player) //Get a good velocity to send the saber in based on my parry move @@ -4683,10 +5384,10 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) hitOwner->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN; hitOwner->client->ps.saberBounceMove = LS_NONE; //FIXME: for now, you always disarm the right-hand saber - if ( hitOwner->client->ps.saber[0].disarmable + if ( !(hitOwner->client->ps.saber[0].saberFlags&SFL_NOT_DISARMABLE) && hitOwner->client->ps.forcePowerLevel[FP_SABER_DEFENSE] < FORCE_LEVEL_2 //&& (ent->s.number||g_saberRealisticCombat->integer) - && Q_irand( 0, 2-ent->client->ps.SaberDisarmBonus() ) <= 0 ) + && Q_irand( 0, 2-ent->client->ps.SaberDisarmBonus( bladeNum ) ) <= 0 ) {//knocked the saber right out of his hand! //get the right velocity for my attack direction vec3_t throwDir; @@ -4730,7 +5431,7 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) } else {//just a parry, possibly the hitOwner can knockaway the ent - WP_SaberParry( hitOwner, ent ); + WP_SaberParry( hitOwner, ent, saberNum, bladeNum ); if ( PM_SaberInBounce( ent->client->ps.saberMove ) //FIXME: saberMove not set until pmove! && activeDefense && hitOwner->client->ps.saberAnimLevel != SS_FAST //&& hitOwner->client->ps.saberAnimLevel != FORCE_LEVEL_5 @@ -4789,7 +5490,7 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) } else { - WP_SaberParry( ent, hitOwner ); + WP_SaberParry( ent, hitOwner, saberNum, bladeNum ); } collisionResolved = qtrue; } @@ -4822,14 +5523,14 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) ent->client->ps.saberEventFlags |= SEF_BLOCKED; //since it was blocked/deflected, take away any damage done //FIXME: what if the damage was done before the parry? - WP_SaberClearDamageForEntNum( hitOwner->s.number ); + WP_SaberClearDamageForEntNum( ent, hitOwner->s.number, saberNum, bladeNum ); } } else {//saber collided when not attacking, parry it //since it was blocked/deflected, take away any damage done //FIXME: what if the damage was done before the parry? - WP_SaberClearDamageForEntNum( hitOwner->s.number ); + WP_SaberClearDamageForEntNum( ent, hitOwner->s.number, saberNum, bladeNum ); /* if ( ent->s.number || g_saberAutoBlocking->integer || ent->client->ps.saberBlockingTime > level.time ) {//either an NPC or a player who has blocking @@ -4847,7 +5548,7 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) { //since it was blocked/deflected, take away any damage done //FIXME: what if the damage was done before the parry? - WP_SaberClearDamageForEntNum( hitOwner->s.number ); + WP_SaberClearDamageForEntNum( ent, hitOwner->s.number, saberNum, bladeNum ); } } else @@ -4875,7 +5576,7 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) {//saber collided when not attacking, parry it if ( !PM_SaberInBrokenParry( hitOwner->client->ps.saberMove ) ) {//not currently in a broken parry - if ( !WP_SaberParry( hitOwner, ent ) ) + if ( !WP_SaberParry( hitOwner, ent, saberNum, bladeNum ) ) {//FIXME: hitOwner can't parry, do some time-consuming saber-knocked-aside broken parry anim? //hitOwner->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN; } @@ -4910,55 +5611,30 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) { if ( inFlightSaberBlocked ) {//FIXME: never hear this sound - G_Sound( &g_entities[ent->client->ps.saberEntityNum], G_SoundIndex( va( "sound/weapons/saber/saberbounce%d.wav", Q_irand(1,3) ) ) ); + WP_SaberBounceSound( ent, hitOwner, &g_entities[ent->client->ps.saberEntityNum], 0, 0, qfalse ); } else { if ( deflected ) { -#ifdef _IMMERSION - int index = Q_irand(1,3); - G_Sound( ent, G_SoundIndex( va("sound/weapons/saber/saberbounce%d.wav", index) ) ); - int ff = G_ForceIndex( va("fffx/weapons/saber/saberbounce%d", index), FF_CHANNEL_WEAPON ); - if ( !ent->s.saberInFlight ) - { - G_Force( ent, ff ); - } - if ( hitOwner && !hitOwner->s.saberInFlight ) - { - G_Force( hitOwner, ff ); - } -#else - G_Sound( ent, G_SoundIndex( va( "sound/weapons/saber/saberbounce%d.wav", Q_irand(1,3) ) ) ); -#endif // _IMMERSION + WP_SaberBounceSound( ent, hitOwner, NULL, saberNum, bladeNum, qtrue ); } else { -#ifdef _IMMERSION - int index = Q_irand(1, 9); - G_Sound( ent, G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", index) ) ); - int ff = G_ForceIndex( va("fffx/weapons/saber/saberblock%d", index), FF_CHANNEL_WEAPON ); - if ( !ent->s.saberInFlight ) - { - G_Force( ent, ff ); - } - if ( hitOwner && !hitOwner->s.saberInFlight ) - { - G_Force( hitOwner, ff ); - } -#else - G_Sound( ent, G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", Q_irand(1, 9) ) ) ); -#endif // _IMMERSION + WP_SaberBlockSound( ent, hitOwner, saberNum, bladeNum ); } } if ( !g_saberNoEffects ) { - G_PlayEffect( "saber/saber_block", saberHitLocation, saberHitNormal ); + WP_SaberBlockEffect( ent, saberNum, bladeNum, saberHitLocation, saberHitNormal, qfalse ); } } // Set the little screen flash - only when an attack is blocked - g_saberFlashTime = level.time-50; - VectorCopy( saberHitLocation, g_saberFlashPos ); + if ( !g_noClashFlare ) + { + g_saberFlashTime = level.time-50; + VectorCopy( saberHitLocation, g_saberFlashPos ); + } } if ( saberHitFraction < 1.0f ) @@ -4979,7 +5655,7 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) {//33% chance knockAway = 2; } - knockAway -= hitOwner->client->ps.SaberDisarmBonus(); + knockAway -= hitOwner->client->ps.SaberDisarmBonus( 0 ); } if ( Q_irand( 0, knockAway ) <= 0 || //random ( hitOwner @@ -4991,7 +5667,20 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) {//knock it aside and turn it off if ( !g_saberNoEffects ) { - G_PlayEffect( "saber/saber_cut", saberHitLocation, saberHitNormal ); + if ( !WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && ent->client->ps.saber[saberNum].hitOtherEffect ) + { + G_PlayEffect( ent->client->ps.saber[saberNum].hitOtherEffect, saberHitLocation, saberHitNormal ); + } + else if ( WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && ent->client->ps.saber[saberNum].hitOtherEffect2 ) + { + G_PlayEffect( ent->client->ps.saber[saberNum].hitOtherEffect2, saberHitLocation, saberHitNormal ); + } + else + { + G_PlayEffect( "saber/saber_cut", saberHitLocation, saberHitNormal ); + } } if ( hitEnt ) { @@ -5019,47 +5708,80 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) } } - if ( ent->client->ps.saberLockTime > level.time - && ent->s.number < ent->client->ps.saberLockEnemy - && !Q_irand( 0, 3 ) ) - {//need to make some kind of effect - vec3_t hitNorm = {0,0,1}; - if ( WP_SabersIntersection( ent, &g_entities[ent->client->ps.saberLockEnemy], g_saberFlashPos ) ) - { - if ( Q_irand( 0, 10 ) ) + if ( ent->client->ps.saberLockTime > level.time ) + { + if ( ent->s.number < ent->client->ps.saberLockEnemy + && !Q_irand( 0, 3 ) ) + {//need to make some kind of effect + vec3_t hitNorm = {0,0,1}; + if ( WP_SabersIntersection( ent, &g_entities[ent->client->ps.saberLockEnemy], g_saberFlashPos ) ) { - if ( !g_saberNoEffects ) + if ( Q_irand( 0, 10 ) ) { - G_PlayEffect( "saber/saber_block", g_saberFlashPos, hitNorm ); + if ( !g_saberNoEffects ) + { + WP_SaberBlockEffect( ent, saberNum, bladeNum, g_saberFlashPos, hitNorm, qfalse ); + } } + else + { + if ( !g_noClashFlare ) + { + g_saberFlashTime = level.time-50; + } + if ( !g_saberNoEffects ) + { + WP_SaberBlockEffect( ent, saberNum, bladeNum, g_saberFlashPos, hitNorm, qtrue ); + } + } + WP_SaberBlockSound( ent, &g_entities[ent->client->ps.saberLockEnemy], 0, 0 ); + } + } + } + else + { + if ( hit_wall + && (ent->client->ps.saber[saberNum].saberFlags&SFL_BOUNCE_ON_WALLS) + && (PM_SaberInAttackPure( ent->client->ps.saberMove ) //only in a normal attack anim + || ent->client->ps.saberMove == LS_A_JUMP_T__B_ ) //or in the strong jump-fwd-attack "death from above" move + ) + {//bounce off walls + //do anim + ent->client->ps.saberBlocked = BLOCKED_ATK_BOUNCE; + ent->client->ps.saberBounceMove = LS_D1_BR+(saberMoveData[ent->client->ps.saberMove].startQuad-Q_BR); + //do bounce sound & force feedback + WP_SaberBounceOnWallSound( ent, saberNum, bladeNum ); + //do hit effect + if ( !g_saberNoEffects ) + { + if ( !WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && ent->client->ps.saber[saberNum].hitOtherEffect ) + { + G_PlayEffect( ent->client->ps.saber[saberNum].hitOtherEffect, saberHitLocation, saberHitNormal ); + } + else if ( WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) + && ent->client->ps.saber[saberNum].hitOtherEffect2 ) + { + G_PlayEffect( ent->client->ps.saber[saberNum].hitOtherEffect2, saberHitLocation, saberHitNormal ); + } + else + { + G_PlayEffect( "saber/saber_cut", saberHitLocation, saberHitNormal ); + } + } + //do radius damage/knockback, if any + if ( !WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[saberNum], bladeNum ) ) + { + WP_SaberRadiusDamage( ent, saberHitLocation, ent->client->ps.saber[saberNum].splashRadius, ent->client->ps.saber[saberNum].splashDamage, ent->client->ps.saber[saberNum].splashKnockback ); } else { - g_saberFlashTime = level.time-50; - if ( !g_saberNoEffects ) - { - G_PlayEffect( "saber/saber_cut", g_saberFlashPos, hitNorm ); - } + WP_SaberRadiusDamage( ent, saberHitLocation, ent->client->ps.saber[saberNum].splashRadius2, ent->client->ps.saber[saberNum].splashDamage2, ent->client->ps.saber[saberNum].splashKnockback2 ); } -#ifdef _IMMERSION - int index = Q_irand(1, 9); - G_Sound( ent, G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", index ) ) ); - int ff = G_ForceIndex( va("fffx/weapons/saber/saberblock%d", index), FF_CHANNEL_WEAPON ); - if ( !ent->s.saberInFlight ) - { - G_Force( ent, ff ); - } - if ( !g_entities[ent->client->ps.saberLockEnemy].s.saberInFlight ) - { - G_Force( &g_entities[ent->client->ps.saberLockEnemy], ff ); - } -#else - G_Sound( ent, G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", Q_irand(1, 9) ) ) ); -#endif // _IMMERSION } } - if ( WP_SaberApplyDamage( ent, baseDamage, baseDFlags, brokenParry, ent->client->ps.saber[saberNum].type, (qboolean)(saberNum==0&&ent->client->ps.saberInFlight) ) ) + if ( WP_SaberApplyDamage( ent, baseDamage, baseDFlags, brokenParry, saberNum, bladeNum, (qboolean)(saberNum==0&&ent->client->ps.saberInFlight) ) ) {//actually did damage to something #ifndef FINAL_BUILD if ( d_saberCombat->integer ) @@ -5067,7 +5789,7 @@ void WP_SaberDamageTrace( gentity_t *ent, int saberNum, int bladeNum ) gi.Printf( "base damage was %4.2f\n", baseDamage ); } #endif - WP_SaberHitSound( ent, saberNum ); + WP_SaberHitSound( ent, saberNum, bladeNum ); } if ( hit_wall ) @@ -5109,6 +5831,12 @@ void WP_SabersDamageTrace( gentity_t *ent, qboolean noEffects ) g_saberNoEffects = qtrue; } } + g_noClashFlare = qfalse; + if ( (!WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[0], i ) && (ent->client->ps.saber[0].saberFlags2&SFL2_NO_CLASH_FLARE) ) + || ( WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[0], i ) && (ent->client->ps.saber[0].saberFlags2&SFL2_NO_CLASH_FLARE2) ) ) + { + g_noClashFlare = qtrue; + } WP_SaberDamageTrace( ent, 0, i ); } // Saber 2. @@ -5130,10 +5858,17 @@ void WP_SabersDamageTrace( gentity_t *ent, qboolean noEffects ) g_saberNoEffects = qtrue; } } + g_noClashFlare = qfalse; + if ( (!WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[1], i ) && (ent->client->ps.saber[1].saberFlags2&SFL2_NO_CLASH_FLARE) ) + || ( WP_SaberBladeUseSecondBladeStyle( &ent->client->ps.saber[1], i ) && (ent->client->ps.saber[1].saberFlags2&SFL2_NO_CLASH_FLARE2) ) ) + { + g_noClashFlare = qtrue; + } WP_SaberDamageTrace( ent, 1, i ); } } g_saberNoEffects = qfalse; + g_noClashFlare = qfalse; } //SABER THROWING============================================================================ @@ -5179,7 +5914,16 @@ void WP_SaberImpact( gentity_t *owner, gentity_t *saber, trace_t *trace ) dmg = 20; } G_Damage( other, saber, owner, dir, trace->endpos, dmg, 0, MOD_SABER ); - G_PlayEffect( "saber/saber_cut", trace->endpos, dir ); + if ( owner + && owner->client + && owner->client->ps.saber[0].hitOtherEffect ) + { + G_PlayEffect( owner->client->ps.saber[0].hitOtherEffect, trace->endpos, dir ); + } + else + { + G_PlayEffect( "saber/saber_cut", trace->endpos, dir ); + } if ( owner->s.number == 0 ) { AddSoundEvent( owner, trace->endpos, 256, AEL_DISCOVERED ); @@ -5200,10 +5944,21 @@ void WP_SaberImpact( gentity_t *owner, gentity_t *saber, trace_t *trace ) //Big flash //FIXME: bigger effect/sound? //FIXME: STILL DOESNT WORK!!! - G_Sound( saber, G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", Q_irand(1, 9) ) ) ); - G_PlayEffect( "saber/saber_block", trace->endpos ); - g_saberFlashTime = level.time-50; - VectorCopy( trace->endpos, g_saberFlashPos ); + WP_SaberBlockSound( saber->owner, NULL, 0, 0 ); + //G_Sound( saber, G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", Q_irand(1, 9) ) ) ); + WP_SaberBlockEffect( saber->owner, 0, 0, trace->endpos, NULL, qfalse); + qboolean noFlare = qfalse; + if ( saber->owner + && saber->owner->client + && (saber->owner->client->ps.saber[0].saberFlags2&SFL2_NO_CLASH_FLARE) ) + { + noFlare = qtrue; + } + if ( !noFlare ) + { + g_saberFlashTime = level.time-50; + VectorCopy( trace->endpos, g_saberFlashPos ); + } } if ( owner && owner->s.number == 0 && owner->client ) @@ -5285,16 +6040,7 @@ void WP_SaberImpact( gentity_t *owner, gentity_t *saber, trace_t *trace ) if ( saber->s.pos.trType == TR_GRAVITY ) {//bounced //play a bounce sound - if ( owner - && owner->client - && owner->client->ps.saber[0].type == SABER_SITH_SWORD ) - { - G_Sound( saber, G_SoundIndex( va( "sound/weapons/sword/fall%d.wav", Q_irand( 1, 7 ) ) ) ); - } - else - { - G_Sound( saber, G_SoundIndex( va( "sound/weapons/saber/bounce%d.wav", Q_irand( 1, 3 ) ) ) ); - } + WP_SaberFallSound( owner, saber ); //change rotation VectorCopy( saber->currentAngles, saber->s.apos.trBase ); saber->s.apos.trType = TR_LINEAR; @@ -5305,19 +6051,11 @@ void WP_SaberImpact( gentity_t *owner, gentity_t *saber, trace_t *trace ) else if ( saber->s.pos.trType == TR_STATIONARY ) {//stopped //play a bounce sound - if ( owner - && owner->client - && owner->client->ps.saber[0].type == SABER_SITH_SWORD ) - { - G_Sound( saber, G_SoundIndex( va( "sound/weapons/sword/fall%d.wav", Q_irand( 1, 7 ) ) ) ); - } - else - { - G_Sound( saber, G_SoundIndex( va( "sound/weapons/saber/bounce%d.wav", Q_irand( 1, 3 ) ) ) ); - } + WP_SaberFallSound( owner, saber ); //stop rotation VectorClear( saber->s.apos.trDelta ); - saber->currentAngles[0] = SABER_PITCH_HACK; + pitch_roll_for_slope( saber, trace->plane.normal, saber->currentAngles ); + saber->currentAngles[0] += SABER_PITCH_HACK; VectorCopy( saber->currentAngles, saber->s.apos.trBase ); //remember when it fell so it can return automagically saber->aimDebounceTime = level.time; @@ -5330,10 +6068,21 @@ void WP_SaberImpact( gentity_t *owner, gentity_t *saber, trace_t *trace ) || ( other->client->ps.powerups[PW_GALAK_SHIELD] > 0 ) ) ) {//Luke, Desann and Tavion slap thrown sabers aside WP_SaberDrop( owner, saber ); - G_Sound( saber, G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", Q_irand(1, 9) ) ) ); - G_PlayEffect( "saber/saber_block", trace->endpos ); - g_saberFlashTime = level.time-50; - VectorCopy( trace->endpos, g_saberFlashPos ); + WP_SaberBlockSound( owner, other, 0, 0 ); + //G_Sound( saber, G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", Q_irand(1, 9) ) ) ); + WP_SaberBlockEffect( owner, 0, 0, trace->endpos, NULL, qfalse ); + qboolean noFlare = qfalse; + if ( owner + && owner->client + && (owner->client->ps.saber[0].saberFlags2&SFL2_NO_CLASH_FLARE) ) + { + noFlare = qtrue; + } + if ( !noFlare ) + { + g_saberFlashTime = level.time-50; + VectorCopy( trace->endpos, g_saberFlashPos ); + } //FIXME: make Luke/Desann/Tavion play an attack anim or some other special anim when this happens Jedi_PlayDeflectSound( other ); } @@ -5485,16 +6234,26 @@ void WP_SaberInFlightReflectCheck( gentity_t *self, usercmd_t *ucmd ) //FIXME: prevent it from damaging me? WP_SaberReturn( missile_list[x]->owner, missile_list[x] ); VectorNormalize2( missile_list[x]->s.pos.trDelta, fx_dir ); - G_PlayEffect( "saber/saber_block", missile_list[x]->currentOrigin, fx_dir ); + WP_SaberBlockEffect( self, 0, 0, missile_list[x]->currentOrigin, fx_dir, qfalse ); if ( missile_list[x]->owner->client->ps.saberInFlight && self->client->ps.saberInFlight ) { - G_Sound( missile_list[x], G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", Q_irand(1, 9) ) ) ); - g_saberFlashTime = level.time-50; - gentity_t *saber = &g_entities[self->client->ps.saberEntityNum]; - vec3_t org; - VectorSubtract( missile_list[x]->currentOrigin, saber->currentOrigin, org ); - VectorMA( saber->currentOrigin, 0.5, org, org ); - VectorCopy( org, g_saberFlashPos ); + WP_SaberBlockSound( self, missile_list[x]->owner, 0, 0 ); + //G_Sound( missile_list[x], G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", Q_irand(1, 9) ) ) ); + qboolean noFlare = qfalse; + if ( (missile_list[x]->owner->client->ps.saber[0].saberFlags2&SFL2_NO_CLASH_FLARE) + && (self->client->ps.saber[0].saberFlags2&SFL2_NO_CLASH_FLARE) ) + { + noFlare = qtrue; + } + if ( !noFlare ) + { + g_saberFlashTime = level.time-50; + gentity_t *saber = &g_entities[self->client->ps.saberEntityNum]; + vec3_t org; + VectorSubtract( missile_list[x]->currentOrigin, saber->currentOrigin, org ); + VectorMA( saber->currentOrigin, 0.5, org, org ); + VectorCopy( org, g_saberFlashPos ); + } } } } @@ -5543,9 +6302,12 @@ qboolean WP_SaberValidateEnemy( gentity_t *self, gentity_t *enemy ) return qfalse; } */ - if ( enemy->client->ps.forcePowersKnown ) - {//not other jedi? - return qfalse; + if ( enemy->s.number >= MAX_CLIENTS ) + {//NPCs can cheat and use the homing saber throw 3 on the player + if ( enemy->client->ps.forcePowersKnown ) + {//not other jedi? + return qfalse; + } } if ( DistanceSquared( self->client->renderInfo.handRPoint, enemy->currentOrigin ) > saberThrowDistSquared[self->client->ps.forcePowerLevel[FP_SABERTHROW]] ) @@ -5826,7 +6588,7 @@ void WP_RunSaber( gentity_t *self, gentity_t *saber ) //if it's heading back, point it's base at us if ( self->client->ps.saberEntityState == SES_RETURNING - && self->client->ps.saber[0].returnDamage == qfalse )//type != SABER_STAR ) + && !(self->client->ps.saber[0].saberFlags&SFL_RETURN_DAMAGE) )//type != SABER_STAR ) { fwdangles[0] += SABER_PITCH_HACK; VectorCopy( fwdangles, saber->s.apos.trBase ); @@ -5898,6 +6660,12 @@ qboolean WP_SaberLaunch( gentity_t *self, gentity_t *saber, qboolean thrown, qbo } //clear the enemy saber->enemy = NULL; + +//===FIXME!!!============================================================================================== + //We should copy the right-hand saber's g2 instance to the thrown saber + //Then back again when you catch it!!! +//===FIXME!!!============================================================================================== + //draw it saber->s.eFlags &= ~EF_NODRAW; saber->svFlags |= SVF_BROADCAST; @@ -5953,7 +6721,7 @@ qboolean WP_SaberLaunch( gentity_t *self, gentity_t *saber, qboolean thrown, qbo if ( thrown ) {//this is a regular throw, so turn the saber on //turn saber on - if ( self->client->ps.saber[0].singleBladeThrowable )//SaberStaff() ) + if ( (self->client->ps.saber[0].saberFlags&SFL_SINGLE_BLADE_THROWABLE) )//SaberStaff() ) {//only first blade can be on if ( !self->client->ps.saber[0].blade[0].active ) {//turn on first one @@ -6098,6 +6866,10 @@ void WP_SaberCatch( gentity_t *self, gentity_t *saber, qboolean switchToSaber ) { //clear the enemy saber->enemy = NULL; +//===FIXME!!!============================================================================================== + //We should copy the thrown saber's g2 instance to the right-hand saber + //When you catch it, and vice-versa when you throw it!!! +//===FIXME!!!============================================================================================== //don't draw it saber->s.eFlags |= EF_NODRAW; saber->svFlags &= SVF_BROADCAST; @@ -6134,7 +6906,7 @@ void WP_SaberCatch( gentity_t *self, gentity_t *saber, qboolean switchToSaber ) } else {//if it's not active, turn it on - if ( self->client->ps.saber[0].singleBladeThrowable )//SaberStaff() ) + if ( (self->client->ps.saber[0].saberFlags&SFL_SINGLE_BLADE_THROWABLE) )//SaberStaff() ) {//only first blade can be on if ( !self->client->ps.saber[0].blade[0].active ) {//only turn it on if first blade is off, otherwise, leave as-is @@ -6162,7 +6934,7 @@ void WP_SaberReturn( gentity_t *self, gentity_t *saber ) //FIXME: when it's returning, flies butt first, but seems to do a lot of damage when going through people... hmm... self->client->ps.saberEntityState = SES_RETURNING; //turn down the saber trail - if ( self->client->ps.saber[0].returnDamage == qfalse )//type != SABER_STAR ) + if ( !(self->client->ps.saber[0].saberFlags&SFL_RETURN_DAMAGE) )//type != SABER_STAR ) { self->client->ps.saber[0].DeactivateTrail( 75 ); } @@ -6241,6 +7013,15 @@ void WP_SaberPull( gentity_t *self, gentity_t *saber ) } } +char *saberColorStringForColor[SABER_PURPLE+1] = +{ + "red",//SABER_RED + "orange",//SABER_ORANGE + "yellow",//SABER_YELLOW + "green",//SABER_GREEN + "blue",//SABER_BLUE + "purple"//SABER_PURPLE +}; // Check if we are throwing it, launch it if needed, update position if needed. void WP_SaberThrow( gentity_t *self, usercmd_t *ucmd ) @@ -6336,13 +7117,31 @@ void WP_SaberThrow( gentity_t *self, usercmd_t *ucmd ) if ( saberent->s.pos.trType != TR_STATIONARY ) {//saber is in flight, lerp it + if ( self->health <= 0 )//&& level.time > saberent->s.time + 5000 ) + {//make us free ourselves after a time + if ( g_saberPickuppableDroppedSabers->integer + && G_DropSaberItem( self->client->ps.saber[0].name, self->client->ps.saber[0].blade[0].color, saberent->currentOrigin, saberent->s.pos.trDelta, saberent->currentAngles ) != NULL ) + {//dropped it + //free it + G_FreeEntity( saberent ); + //forget it + self->client->ps.saberEntityNum = ENTITYNUM_NONE; + return; + } + } WP_RunSaber( self, saberent ); } else {//it fell on the ground - if ( self->health <= 0 && level.time > saberent->s.time + 5000 ) + if ( self->health <= 0 )//&& level.time > saberent->s.time + 5000 ) {//make us free ourselves after a time + if ( g_saberPickuppableDroppedSabers->integer ) + {//spawn an item + G_DropSaberItem( self->client->ps.saber[0].name, self->client->ps.saber[0].blade[0].color, saberent->currentOrigin, saberent->s.pos.trDelta, saberent->currentAngles ); + } + //free it G_FreeEntity( saberent ); + //forget it self->client->ps.saberEntityNum = ENTITYNUM_NONE; return; } @@ -6846,7 +7645,7 @@ void WP_SaberStartMissileBlockCheck( gentity_t *self, usercmd_t *ucmd ) } } - if ( !self->client->ps.saber[0].activeBlocking ) + if ( (self->client->ps.saber[0].saberFlags&SFL_NOT_ACTIVE_BLOCKING) ) {//can't actively block with this saber type return; } @@ -7262,20 +8061,80 @@ void WP_SaberUpdate( gentity_t *self, usercmd_t *ucmd ) //is our saber in flight? if ( !self->client->ps.saberInFlight ) { // It isn't, which means we can update its position as we will. + qboolean alwaysBlock[MAX_SABERS][MAX_BLADES]; + qboolean forceBlock = qfalse; + qboolean noBlocking = qfalse; + + //clear out last frame's numbers + VectorClear(saberent->mins); + VectorClear(saberent->maxs); + Vehicle_t *pVeh = G_IsRidingVehicle( self ); if ( !self->client->ps.SaberActive() + || !self->client->ps.saberBlocking || PM_InKnockDown( &self->client->ps ) || PM_SuperBreakLoseAnim( self->client->ps.torsoAnim ) || (pVeh && pVeh->m_pVehicleInfo && pVeh->m_pVehicleInfo->type != VH_ANIMAL && pVeh->m_pVehicleInfo->type != VH_FLIER) )//riding a vehicle that you cannot block shots on {//can't block if saber isn't on - VectorClear(saberent->mins); - VectorClear(saberent->maxs); + int i, j; + for ( i = 0; i < MAX_SABERS; i++ ) + { + //initialize to not blocking + for ( j = 0; j < MAX_BLADES; j++ ) + { + alwaysBlock[i][j] = qfalse; + } + if ( i > 0 && !self->client->ps.dualSabers ) + {//not using a second saber, leave it not blocking + } + else + { + if ( (self->client->ps.saber[i].saberFlags2&SFL2_ALWAYS_BLOCK) ) + { + for ( j = 0; j < self->client->ps.saber[i].numBlades; j++ ) + { + alwaysBlock[i][j] = qtrue; + forceBlock = qtrue; + } + } + if ( self->client->ps.saber[i].bladeStyle2Start > 0 ) + { + for ( j = self->client->ps.saber[i].bladeStyle2Start; j < self->client->ps.saber[i].numBlades; j++ ) + { + if ( (self->client->ps.saber[i].saberFlags2&SFL2_ALWAYS_BLOCK2) ) + { + alwaysBlock[i][j] = qtrue; + forceBlock = qtrue; + } + else + { + alwaysBlock[i][j] = qfalse; + } + } + } + } + } + if ( !forceBlock ) + { + noBlocking = qtrue; + } + else if ( !self->client->ps.saberBlocking ) + {//turn blocking on! + self->client->ps.saberBlocking = BLK_TIGHT; + } + } + if ( noBlocking ) + { + //VectorClear(saberent->mins); + //VectorClear(saberent->maxs); G_SetOrigin(saberent, self->currentOrigin); } - else if ( self->client->ps.saberBlocking == BLK_TIGHT || self->client->ps.saberBlocking == BLK_WIDE ) + else if ( self->client->ps.saberBlocking == BLK_TIGHT + || self->client->ps.saberBlocking == BLK_WIDE ) {//FIXME: keep bbox in front of player, even when wide? vec3_t saberOrg; - if ( ( (self->s.number&&!Jedi_SaberBusy(self)&&!g_saberRealisticCombat->integer) || (self->s.number == 0 && self->client->ps.saberBlocking == BLK_WIDE && (g_saberAutoBlocking->integer||self->client->ps.saberBlockingTime>level.time)) ) + if ( !forceBlock + && ( (self->s.number&&!Jedi_SaberBusy(self)&&!g_saberRealisticCombat->integer) || (self->s.number == 0 && self->client->ps.saberBlocking == BLK_WIDE && (g_saberAutoBlocking->integer||self->client->ps.saberBlockingTime>level.time)) ) && self->client->ps.weaponTime <= 0 && !G_InCinematicSaberAnim( self ) ) {//full-size blocking for non-attacking player with g_saberAutoBlocking on @@ -7305,6 +8164,17 @@ void WP_SaberUpdate( gentity_t *self, usercmd_t *ucmd ) { for ( int bladeNum = 0; bladeNum < self->client->ps.saber[saberNum].numBlades; bladeNum++ ) { + if ( self->client->ps.saber[saberNum].blade[bladeNum].length <= 0.0f ) + {//don't include blades that are not on... + continue; + } + if ( forceBlock ) + {//doing blade-specific bbox-sizing only, see if this blade should be counted + if ( !alwaysBlock[saberNum][bladeNum] ) + {//this blade doesn't count right now + continue; + } + } VectorCopy( self->client->ps.saber[saberNum].blade[bladeNum].muzzlePoint, saberBase ); VectorMA( saberBase, self->client->ps.saber[saberNum].blade[bladeNum].length, self->client->ps.saber[saberNum].blade[bladeNum].muzzleDir, saberTip ); VectorMA( saberBase, self->client->ps.saber[saberNum].blade[bladeNum].length*0.5, self->client->ps.saber[saberNum].blade[bladeNum].muzzleDir, saberOrg ); @@ -7345,20 +8215,23 @@ void WP_SaberUpdate( gentity_t *self, usercmd_t *ucmd ) } } } - if ( self->client->ps.weaponTime > 0 - || self->s.number - || g_saberAutoBlocking->integer - || self->client->ps.saberBlockingTime > level.time ) - {//if attacking or blocking (or an NPC), inflate to a minimum size - for ( int i = 0; i < 3; i++ ) - { - if ( saberent->maxs[i] < minsize ) + if ( !forceBlock ) + {//not doing special "alwaysBlock" bbox + if ( self->client->ps.weaponTime > 0 + || self->s.number + || g_saberAutoBlocking->integer + || self->client->ps.saberBlockingTime > level.time ) + {//if attacking or blocking (or an NPC), inflate to a minimum size + for ( int i = 0; i < 3; i++ ) { - saberent->maxs[i] = minsize; - } - if ( saberent->mins[i] > -minsize ) - { - saberent->mins[i] = -minsize; + if ( saberent->maxs[i] < minsize ) + { + saberent->maxs[i] = minsize; + } + if ( saberent->mins[i] > -minsize ) + { + saberent->mins[i] = -minsize; + } } } } @@ -7424,8 +8297,8 @@ void WP_SaberUpdate( gentity_t *self, usercmd_t *ucmd ) */ else { // Otherwise there is no blocking possible. - VectorClear(saberent->mins); - VectorClear(saberent->maxs); + //VectorClear(saberent->mins); + //VectorClear(saberent->maxs); G_SetOrigin(saberent, self->currentOrigin); } saberent->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER; @@ -7689,6 +8562,13 @@ void WP_ResistForcePush( gentity_t *self, gentity_t *pusher, qboolean noPenalty { return; } + + //NOTE: don't interrupt big anims with this! + if ( !PM_SaberCanInterruptMove( self->client->ps.saberMove, self->client->ps.torsoAnim ) ) + {//can't interrupt my current torso anim/sabermove with this, so ignore it entirely! + return; + } + if ( (!self->s.number ||( self->NPC && (self->NPC->aiFlags&NPCAI_BOSS_CHARACTER) ) ||( self->client && self->client->NPC_class == CLASS_SHADOWTROOPER ) @@ -7701,6 +8581,7 @@ void WP_ResistForcePush( gentity_t *self, gentity_t *pusher, qboolean noPenalty { runningResist = qtrue; } + if ( !runningResist && self->client->ps.groundEntityNum != ENTITYNUM_NONE && !PM_SpinningSaberAnim( self->client->ps.legsAnim ) @@ -7715,8 +8596,8 @@ void WP_ResistForcePush( gentity_t *self, gentity_t *pusher, qboolean noPenalty {//play resist just in torso parts = SETANIM_TORSO; } - //FIXME: don't interrupt big anims with this! NPC_SetAnim( self, parts, BOTH_RESISTPUSH, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + if ( !noPenalty ) { if ( !runningResist ) @@ -8044,36 +8925,42 @@ qboolean WP_ForceThrowable( gentity_t *ent, gentity_t *forwardEnt, gentity_t *se return qfalse; } } - else if ( ent->s.eType == ET_ITEM - && ent->item - && ent->item->giType == IT_HOLDABLE - && ent->item->giTag == INV_SECURITY_KEY ) - //&& (ent->flags&FL_DROPPED_ITEM) ??? - {//dropped security keys can't be pushed? But placed ones can...? does this make any sense? - if ( !pull || self->s.number ) - {//can't push, NPC's can't do anything to it + else if ( ent->s.eType == ET_ITEM ) + { + if ( (ent->flags&FL_NO_KNOCKBACK) ) + { return qfalse; } - else - { - if ( g_crosshairEntNum != ent->s.number ) - {//player can pull it if looking *right* at it - if ( cone >= 1.0f ) - {//we did a forwardEnt trace - if ( forwardEnt != ent ) - {//must be pointing right at them - return qfalse; + if ( ent->item + && ent->item->giType == IT_HOLDABLE + && ent->item->giTag == INV_SECURITY_KEY ) + //&& (ent->flags&FL_DROPPED_ITEM) ??? + {//dropped security keys can't be pushed? But placed ones can...? does this make any sense? + if ( !pull || self->s.number ) + {//can't push, NPC's can't do anything to it + return qfalse; + } + else + { + if ( g_crosshairEntNum != ent->s.number ) + {//player can pull it if looking *right* at it + if ( cone >= 1.0f ) + {//we did a forwardEnt trace + if ( forwardEnt != ent ) + {//must be pointing right at them + return qfalse; + } } - } - else if ( forward ) - {//do a forwardEnt trace - trace_t tr; - vec3_t end; - VectorMA( self->client->renderInfo.eyePoint, radius, forward, end ); - gi.trace( &tr, self->client->renderInfo.eyePoint, vec3_origin, vec3_origin, end, self->s.number, MASK_OPAQUE|CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_ITEM|CONTENTS_CORPSE );//was MASK_SHOT, changed to match crosshair trace - if ( tr.entityNum != ent->s.number ) - {//last chance - return qfalse; + else if ( forward ) + {//do a forwardEnt trace + trace_t tr; + vec3_t end; + VectorMA( self->client->renderInfo.eyePoint, radius, forward, end ); + gi.trace( &tr, self->client->renderInfo.eyePoint, vec3_origin, vec3_origin, end, self->s.number, MASK_OPAQUE|CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_ITEM|CONTENTS_CORPSE );//was MASK_SHOT, changed to match crosshair trace + if ( tr.entityNum != ent->s.number ) + {//last chance + return qfalse; + } } } } @@ -11711,6 +12598,8 @@ void ForceJump( gentity_t *self, usercmd_t *ucmd ) { case FJ_FORWARD: if ( ((self->client->NPC_class == CLASS_BOBAFETT||self->client->NPC_class == CLASS_ROCKETTROOPER) && self->client->ps.forceJumpCharge > 300 ) + || (self->client->ps.saber[0].saberFlags&SFL_NO_FLIPS) + || (self->client->ps.dualSabers && (self->client->ps.saber[1].saberFlags&SFL_NO_FLIPS) ) || ( self->NPC && self->NPC->rank != RANK_CREWMAN && self->NPC->rank <= RANK_LT_JG ) ) @@ -11731,6 +12620,8 @@ void ForceJump( gentity_t *self, usercmd_t *ucmd ) break; case FJ_BACKWARD: if ( ((self->client->NPC_class == CLASS_BOBAFETT||self->client->NPC_class == CLASS_ROCKETTROOPER) && self->client->ps.forceJumpCharge > 300 ) + || (self->client->ps.saber[0].saberFlags&SFL_NO_FLIPS) + || (self->client->ps.dualSabers && (self->client->ps.saber[1].saberFlags&SFL_NO_FLIPS) ) || ( self->NPC && self->NPC->rank != RANK_CREWMAN && self->NPC->rank <= RANK_LT_JG ) ) @@ -11744,6 +12635,8 @@ void ForceJump( gentity_t *self, usercmd_t *ucmd ) break; case FJ_RIGHT: if ( ((self->client->NPC_class == CLASS_BOBAFETT||self->client->NPC_class == CLASS_ROCKETTROOPER) && self->client->ps.forceJumpCharge > 300 ) + || (self->client->ps.saber[0].saberFlags&SFL_NO_FLIPS) + || (self->client->ps.dualSabers && (self->client->ps.saber[1].saberFlags&SFL_NO_FLIPS) ) || ( self->NPC && self->NPC->rank != RANK_CREWMAN && self->NPC->rank <= RANK_LT_JG ) ) @@ -11757,6 +12650,8 @@ void ForceJump( gentity_t *self, usercmd_t *ucmd ) break; case FJ_LEFT: if ( ((self->client->NPC_class == CLASS_BOBAFETT||self->client->NPC_class == CLASS_ROCKETTROOPER) && self->client->ps.forceJumpCharge > 300 ) + || (self->client->ps.saber[0].saberFlags&SFL_NO_FLIPS) + || (self->client->ps.dualSabers && (self->client->ps.saber[1].saberFlags&SFL_NO_FLIPS) ) || ( self->NPC && self->NPC->rank != RANK_CREWMAN && self->NPC->rank <= RANK_LT_JG ) ) @@ -12126,7 +13021,7 @@ qboolean WP_ForcePowerUsable( gentity_t *self, forcePowers_t forcePower, int ove return qfalse; } - if ( self->client->ps.saber[0].singleBladeThrowable//SaberStaff() //using staff + if ( (self->client->ps.saber[0].saberFlags&SFL_SINGLE_BLADE_THROWABLE)//SaberStaff() //using staff && !self->client->ps.dualSabers //only 1, in right hand && !self->client->ps.saber[0].blade[1].active )//only first blade is on {//allow power @@ -12134,14 +13029,14 @@ qboolean WP_ForcePowerUsable( gentity_t *self, forcePowers_t forcePower, int ove } else { - if ( forcePower == FP_SABERTHROW && !self->client->ps.saber[0].throwable ) + if ( forcePower == FP_SABERTHROW && (self->client->ps.saber[0].saberFlags&SFL_NOT_THROWABLE) ) {//cannot throw this kind of saber return qfalse; } if ( self->client->ps.saber[0].Active() ) { - if ( self->client->ps.saber[0].twoHanded ) + if ( (self->client->ps.saber[0].saberFlags&SFL_TWO_HANDED) ) { if ( g_saberRestrictForce->integer ) { @@ -12158,7 +13053,8 @@ qboolean WP_ForcePowerUsable( gentity_t *self, forcePowers_t forcePower, int ove } } } - if ( self->client->ps.saber[0].twoHanded || (self->client->ps.dualSabers && self->client->ps.saber[1].Active()) ) + if ( (self->client->ps.saber[0].saberFlags&SFL_TWO_HANDED) + || (self->client->ps.dualSabers && self->client->ps.saber[1].Active()) ) {//this saber requires the use of two hands OR our other hand is using an active saber too if ( (self->client->ps.saber[0].forceRestrictions&(1<buttons & BUTTON_FORCE_LIGHTNING ) + if ( !self->s.number + && self->client->NPC_class == CLASS_BOBAFETT ) + {//Boba Fett + if ( ucmd->buttons & BUTTON_FORCE_LIGHTNING ) + {//start flamethrower + Boba_DoFlameThrower( self ); + return; + } + else if ( self->client->ps.forcePowerDuration[FP_LIGHTNING] ) + { + self->client->ps.forcePowerDuration[FP_LIGHTNING] = 0; + Boba_StopFlameThrower( self ); + return; + } + } + else if ( ucmd->buttons & BUTTON_FORCE_LIGHTNING ) { ForceLightning( self ); } diff --git a/code/game/wp_saber.h b/code/game/wp_saber.h index a1a7b34..6a68c76 100644 --- a/code/game/wp_saber.h +++ b/code/game/wp_saber.h @@ -130,6 +130,8 @@ typedef enum #define MEF_MULTI_SPIN 0x000040 //spin once every second, until the effect stops #define MEF_LOOK_AT_ENEMY 0x000200 +#define SABER_PITCH_HACK 90 + extern float forceJumpStrength[]; extern float forceJumpHeight[]; extern float forceJumpHeightMax[]; @@ -140,6 +142,7 @@ extern void ForceSpeed( gentity_t *self, int duration = 0 ); extern float forceSpeedValue[]; extern float forceSpeedRangeMod[]; extern float forceSpeedFOVMod[]; +extern char *saberColorStringForColor[]; #define FORCE_SPEED_DURATION 10000.0f #define FORCE_RAGE_DURATION 10000.0f @@ -183,6 +186,7 @@ extern void WP_SaberFreeStrings( saberInfo_t &saber ); extern qboolean G_EnoughPowerForSpecialMove( int forcePower, int cost, qboolean kataMove = qfalse ); extern void G_DrainPowerForSpecialMove( gentity_t *self, forcePowers_t fp, int cost, qboolean kataMove = qfalse ); extern int G_CostForSpecialMove( int cost, qboolean kataMove = qfalse ); +extern gentity_t *G_DropSaberItem( const char *saberType, saber_colors_t saberColor, vec3_t saberPos, vec3_t saberVel, vec3_t saberAngles, gentity_t *copySaber = NULL ); typedef enum { diff --git a/code/game/wp_saberLoad.cpp b/code/game/wp_saberLoad.cpp index 7ef6446..28d29a3 100644 --- a/code/game/wp_saberLoad.cpp +++ b/code/game/wp_saberLoad.cpp @@ -13,7 +13,7 @@ extern qboolean PM_SaberInAttack( int move ); extern stringID_table_t FPTable[]; -#define MAX_SABER_DATA_SIZE 0x8000 +#define MAX_SABER_DATA_SIZE 0x80000 char SaberParms[MAX_SABER_DATA_SIZE]; void Saber_SithSwordPrecache( void ) @@ -56,6 +56,72 @@ stringID_table_t SaberTable[] = "", -1 }; +stringID_table_t SaberMoveTable[] = +{ + ENUM2STRING(LS_NONE), + // Attacks + ENUM2STRING(LS_A_TL2BR), + ENUM2STRING(LS_A_L2R), + ENUM2STRING(LS_A_BL2TR), + ENUM2STRING(LS_A_BR2TL), + ENUM2STRING(LS_A_R2L), + ENUM2STRING(LS_A_TR2BL), + ENUM2STRING(LS_A_T2B), + ENUM2STRING(LS_A_BACKSTAB), + ENUM2STRING(LS_A_BACK), + ENUM2STRING(LS_A_BACK_CR), + ENUM2STRING(LS_ROLL_STAB), + ENUM2STRING(LS_A_LUNGE), + ENUM2STRING(LS_A_JUMP_T__B_), + ENUM2STRING(LS_A_FLIP_STAB), + ENUM2STRING(LS_A_FLIP_SLASH), + ENUM2STRING(LS_JUMPATTACK_DUAL), + ENUM2STRING(LS_JUMPATTACK_ARIAL_LEFT), + ENUM2STRING(LS_JUMPATTACK_ARIAL_RIGHT), + ENUM2STRING(LS_JUMPATTACK_CART_LEFT), + ENUM2STRING(LS_JUMPATTACK_CART_RIGHT), + ENUM2STRING(LS_JUMPATTACK_STAFF_LEFT), + ENUM2STRING(LS_JUMPATTACK_STAFF_RIGHT), + ENUM2STRING(LS_BUTTERFLY_LEFT), + ENUM2STRING(LS_BUTTERFLY_RIGHT), + ENUM2STRING(LS_A_BACKFLIP_ATK), + ENUM2STRING(LS_SPINATTACK_DUAL), + ENUM2STRING(LS_SPINATTACK), + ENUM2STRING(LS_LEAP_ATTACK), + ENUM2STRING(LS_SWOOP_ATTACK_RIGHT), + ENUM2STRING(LS_SWOOP_ATTACK_LEFT), + ENUM2STRING(LS_TAUNTAUN_ATTACK_RIGHT), + ENUM2STRING(LS_TAUNTAUN_ATTACK_LEFT), + ENUM2STRING(LS_KICK_F), + ENUM2STRING(LS_KICK_B), + ENUM2STRING(LS_KICK_R), + ENUM2STRING(LS_KICK_L), + ENUM2STRING(LS_KICK_S), + ENUM2STRING(LS_KICK_BF), + ENUM2STRING(LS_KICK_RL), + ENUM2STRING(LS_KICK_F_AIR), + ENUM2STRING(LS_KICK_B_AIR), + ENUM2STRING(LS_KICK_R_AIR), + ENUM2STRING(LS_KICK_L_AIR), + ENUM2STRING(LS_STABDOWN), + ENUM2STRING(LS_STABDOWN_STAFF), + ENUM2STRING(LS_STABDOWN_DUAL), + ENUM2STRING(LS_DUAL_SPIN_PROTECT), + ENUM2STRING(LS_STAFF_SOULCAL), + ENUM2STRING(LS_A1_SPECIAL), + ENUM2STRING(LS_A2_SPECIAL), + ENUM2STRING(LS_A3_SPECIAL), + ENUM2STRING(LS_UPSIDE_DOWN_ATTACK), + ENUM2STRING(LS_PULL_ATTACK_STAB), + ENUM2STRING(LS_PULL_ATTACK_SWING), + ENUM2STRING(LS_SPINATTACK_ALORA), + ENUM2STRING(LS_DUAL_FB), + ENUM2STRING(LS_DUAL_LR), + ENUM2STRING(LS_HILT_BASH), + "", -1 +}; + + saber_styles_t TranslateSaberStyle( const char *name ) { if ( !Q_stricmp( name, "fast" ) ) @@ -117,6 +183,176 @@ void WP_SaberFreeStrings( saberInfo_t &saber ) } } +qboolean WP_SaberBladeUseSecondBladeStyle( saberInfo_t *saber, int bladeNum ) +{ + if ( saber ) + { + if ( saber->bladeStyle2Start > 0 ) + { + if ( bladeNum >= saber->bladeStyle2Start ) + { + return qtrue; + } + } + } + return qfalse; +} + +qboolean WP_SaberBladeDoTransitionDamage( saberInfo_t *saber, int bladeNum ) +{ + if ( !WP_SaberBladeUseSecondBladeStyle( saber, bladeNum ) + && (saber->saberFlags2&SFL2_TRANSITION_DAMAGE) ) + {//use first blade style for this blade + return qtrue; + } + else if ( WP_SaberBladeUseSecondBladeStyle( saber, bladeNum ) + && (saber->saberFlags2&SFL2_TRANSITION_DAMAGE2) ) + {//use second blade style for this blade + return qtrue; + } + return qfalse; +} + +qboolean WP_UseFirstValidSaberStyle( gentity_t *ent, int *saberAnimLevel ) +{ + if ( ent && ent->client ) + { + qboolean styleInvalid = qfalse; + int validStyles = 0, styleNum; + + //initially, all styles are valid + for ( styleNum = SS_NONE+1; styleNum < SS_NUM_SABER_STYLES; styleNum++ ) + { + validStyles |= (1<client->ps.saber[0].Active() + && ent->client->ps.saber[0].stylesForbidden ) + { + if ( (ent->client->ps.saber[0].stylesForbidden&(1<<*saberAnimLevel)) ) + {//not a valid style for first saber! + styleInvalid = qtrue; + validStyles &= ~ent->client->ps.saber[0].stylesForbidden; + } + } + if ( ent->client->ps.dualSabers ) + {//check second saber, too + if ( ent->client->ps.saber[1].Active() + && ent->client->ps.saber[1].stylesForbidden ) + { + if ( (ent->client->ps.saber[1].stylesForbidden&(1<<*saberAnimLevel)) ) + {//not a valid style for second saber! + styleInvalid = qtrue; + //only the ones both sabers allow is valid + validStyles &= ~ent->client->ps.saber[1].stylesForbidden; + } + } + else + {//can't use dual style if not using 2 sabers + validStyles &= ~(1<client ) + { + if ( ent->client->ps.saber[0].Active() + && ent->client->ps.saber[0].stylesForbidden ) + { + if ( (ent->client->ps.saber[0].stylesForbidden&(1<client->ps.dualSabers ) + {//check second saber, too + if ( ent->client->ps.saber[1].Active() ) + { + if ( ent->client->ps.saber[1].stylesForbidden ) + { + if ( (ent->client->ps.saber[1].stylesForbidden&(1<client->ps.saber[0].Active() + && (ent->client->ps.saber[0].stylesLearned&(1<client->ps.saber[1].stylesLearned&(1<bladeStyle2Start > 0 + && saber->numBlades > saber->bladeStyle2Start ) + { + if ( (saber->saberFlags2&SFL2_NO_MANUAL_DEACTIVATE) + && (saber->saberFlags2&SFL2_NO_MANUAL_DEACTIVATE2) ) + {//all blades are always on + return qfalse; + } + } + else + { + if ( (saber->saberFlags2&SFL2_NO_MANUAL_DEACTIVATE) ) + {//all blades are always on + return qfalse; + } + } + //you can turn some off + return qtrue; +} + void WP_SaberSetDefaults( saberInfo_t *saber, qboolean setColors = qtrue ) { //Set defaults so that, if it fails, there's at least something there @@ -138,23 +374,112 @@ void WP_SaberSetDefaults( saberInfo_t *saber, qboolean setColors = qtrue ) saber->soundOff = G_SoundIndex( "sound/weapons/saber/enemy_saber_off.wav" ); saber->numBlades = 1; saber->type = SABER_SINGLE; - saber->style = SS_NONE; + saber->stylesLearned = 0; + saber->stylesForbidden = 0; saber->maxChain = 0;//0 = use default behavior - saber->lockable = qtrue; - saber->throwable = qtrue; - saber->disarmable = qtrue; - saber->activeBlocking = qtrue; - saber->twoHanded = qfalse; saber->forceRestrictions = 0; saber->lockBonus = 0; saber->parryBonus = 0; saber->breakParryBonus = 0; + saber->breakParryBonus2 = 0; saber->disarmBonus = 0; + saber->disarmBonus2 = 0; saber->singleBladeStyle = SS_NONE;//makes it so that you use a different style if you only have the first blade active - saber->singleBladeThrowable = qfalse;//makes it so that you can throw this saber if only the first blade is on saber->brokenSaber1 = NULL;//if saber is actually hit by another saber, it can be cut in half/broken and will be replaced with this saber in your right hand saber->brokenSaber2 = NULL;//if saber is actually hit by another saber, it can be cut in half/broken and will be replaced with this saber in your left hand - saber->returnDamage = qfalse;//when returning from a saber throw, it keeps spinning and doing damage +//===NEW======================================================================================== + //these values are global to the saber, like all of the ones above + saber->saberFlags = 0; //see all the SFL_ flags + saber->saberFlags2 = 0; //see all the SFL2_ flags + saber->spinSound = 0; //none - if set, plays this sound as it spins when thrown + saber->swingSound[0] = 0; //none - if set, plays one of these 3 sounds when swung during an attack - NOTE: must provide all 3!!! + saber->swingSound[1] = 0; //none - if set, plays one of these 3 sounds when swung during an attack - NOTE: must provide all 3!!! + saber->swingSound[2] = 0; //none - if set, plays one of these 3 sounds when swung during an attack - NOTE: must provide all 3!!! + saber->fallSound[0] = 0; //none - if set, plays one of these 3 sounds when weapon falls to the ground - NOTE: must provide all 3!!! + saber->fallSound[1] = 0; //none - if set, plays one of these 3 sounds when weapon falls to the ground - NOTE: must provide all 3!!! + saber->fallSound[2] = 0; //none - if set, plays one of these 3 sounds when weapon falls to the ground - NOTE: must provide all 3!!! + + //done in game (server-side code) + saber->moveSpeedScale = 1.0f; //1.0 - you move faster/slower when using this saber + saber->animSpeedScale = 1.0f; //1.0 - plays normal attack animations faster/slower + + saber->kataMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they press both attack buttons at the same time + saber->lungeAtkMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they crouch+fwd+attack + saber->jumpAtkUpMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they jump+attack + saber->jumpAtkFwdMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they jump+fwd+attack + saber->jumpAtkBackMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they jump+back+attack + saber->jumpAtkRightMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they jump+rightattack + saber->jumpAtkLeftMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they jump+left+attack + saber->readyAnim = -1; //-1 - anim to use when standing idle + saber->drawAnim = -1; //-1 - anim to use when drawing weapon + saber->putawayAnim = -1; //-1 - anim to use when putting weapon away + saber->tauntAnim = -1; //-1 - anim to use when hit "taunt" + saber->bowAnim = -1; //-1 - anim to use when hit "bow" + saber->meditateAnim = -1; //-1 - anim to use when hit "meditate" + saber->flourishAnim = -1; //-1 - anim to use when hit "flourish" + saber->gloatAnim = -1; //-1 - anim to use when hit "gloat" + + //***NOTE: you can only have a maximum of 2 "styles" of blades, so this next value, "bladeStyle2Start" is the number of the first blade to use these value on... all blades before this use the normal values above, all blades at and after this number use the secondary values below*** + saber->bladeStyle2Start = 0; //0 - if set, blades from this number and higher use the following values (otherwise, they use the normal values already set) + + //***The following can be different for the extra blades - not setting them individually defaults them to the value for the whole saber (and first blade)*** + + //===PRIMARY BLADES===================== + //done in cgame (client-side code) + saber->trailStyle = 0; //0 - default (0) is normal, 1 is a motion blur and 2 is no trail at all (good for real-sword type mods) + saber->g2MarksShader[0]=0; //none - if set, the game will use this shader for marks on enemies instead of the default "gfx/damage/saberglowmark" + saber->g2WeaponMarkShader[0]=0; //none - if set, the game will ry to project this shader onto the weapon when it damages a person (good for a blood splatter on the weapon) + //saber->bladeShader = 0; //none - if set, overrides the shader used for the saber blade? + //saber->trailShader = 0; //none - if set, overrides the shader used for the saber trail? + saber->hitSound[0] = 0; //none - if set, plays one of these 3 sounds when saber hits a person - NOTE: must provide all 3!!! + saber->hitSound[1] = 0; //none - if set, plays one of these 3 sounds when saber hits a person - NOTE: must provide all 3!!! + saber->hitSound[2] = 0; //none - if set, plays one of these 3 sounds when saber hits a person - NOTE: must provide all 3!!! + saber->blockSound[0] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits another saber/sword - NOTE: must provide all 3!!! + saber->blockSound[1] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits another saber/sword - NOTE: must provide all 3!!! + saber->blockSound[2] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits another saber/sword - NOTE: must provide all 3!!! + saber->bounceSound[0] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits a wall and bounces off (must set bounceOnWall to 1 to use these sounds) - NOTE: must provide all 3!!! + saber->bounceSound[1] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits a wall and bounces off (must set bounceOnWall to 1 to use these sounds) - NOTE: must provide all 3!!! + saber->bounceSound[2] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits a wall and bounces off (must set bounceOnWall to 1 to use these sounds) - NOTE: must provide all 3!!! + saber->blockEffect = 0; //none - if set, plays this effect when the saber/sword hits another saber/sword (instead of "saber/saber_block.efx") + saber->hitPersonEffect = 0; //none - if set, plays this effect when the saber/sword hits a person (instead of "saber/blood_sparks_mp.efx") + saber->hitOtherEffect = 0; //none - if set, plays this effect when the saber/sword hits something else damagable (instead of "saber/saber_cut.efx") + saber->bladeEffect = 0; //none - if set, plays this effect at the blade tag + + //done in game (server-side code) + saber->knockbackScale = 0; //0 - if non-zero, uses damage done to calculate an appropriate amount of knockback + saber->damageScale = 1.0f; //1 - scale up or down the damage done by the saber + saber->splashRadius = 0.0f; //0 - radius of splashDamage + saber->splashDamage = 0; //0 - amount of splashDamage, 100% at a distance of 0, 0% at a distance = splashRadius + saber->splashKnockback = 0.0f; //0 - amount of splashKnockback, 100% at a distance of 0, 0% at a distance = splashRadius + + //===SECONDARY BLADES=================== + //done in cgame (client-side code) + saber->trailStyle2 = 0; //0 - default (0) is normal, 1 is a motion blur and 2 is no trail at all (good for real-sword type mods) + saber->g2MarksShader2[0]=0; //none - if set, the game will use this shader for marks on enemies instead of the default "gfx/damage/saberglowmark" + saber->g2WeaponMarkShader2[0]=0; //none - if set, the game will ry to project this shader onto the weapon when it damages a person (good for a blood splatter on the weapon) + //saber->bladeShader = 0; //none - if set, overrides the shader used for the saber blade? + //saber->trailShader = 0; //none - if set, overrides the shader used for the saber trail? + saber->hit2Sound[0] = 0; //none - if set, plays one of these 3 sounds when saber hits a person - NOTE: must provide all 3!!! + saber->hit2Sound[1] = 0; //none - if set, plays one of these 3 sounds when saber hits a person - NOTE: must provide all 3!!! + saber->hit2Sound[2] = 0; //none - if set, plays one of these 3 sounds when saber hits a person - NOTE: must provide all 3!!! + saber->block2Sound[0] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits another saber/sword - NOTE: must provide all 3!!! + saber->block2Sound[1] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits another saber/sword - NOTE: must provide all 3!!! + saber->block2Sound[2] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits another saber/sword - NOTE: must provide all 3!!! + saber->bounce2Sound[0] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits a wall and bounces off (must set bounceOnWall to 1 to use these sounds) - NOTE: must provide all 3!!! + saber->bounce2Sound[1] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits a wall and bounces off (must set bounceOnWall to 1 to use these sounds) - NOTE: must provide all 3!!! + saber->bounce2Sound[2] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits a wall and bounces off (must set bounceOnWall to 1 to use these sounds) - NOTE: must provide all 3!!! + saber->blockEffect2 = 0; //none - if set, plays this effect when the saber/sword hits another saber/sword (instead of "saber/saber_block.efx") + saber->hitPersonEffect2 = 0; //none - if set, plays this effect when the saber/sword hits a person (instead of "saber/blood_sparks_mp.efx") + saber->hitOtherEffect2 = 0; //none - if set, plays this effect when the saber/sword hits something else damagable (instead of "saber/saber_cut.efx") + saber->bladeEffect2 = 0; //none - if set, plays this effect at the blade tag + + //done in game (server-side code) + saber->knockbackScale2 = 0; //0 - if non-zero, uses damage done to calculate an appropriate amount of knockback + saber->damageScale2 = 1.0f; //1 - scale up or down the damage done by the saber + saber->splashRadius2 = 0.0f; //0 - radius of splashDamage + saber->splashDamage2 = 0; //0 - amount of splashDamage, 100% at a distance of 0, 0% at a distance = splashRadius + saber->splashKnockback2 = 0.0f; //0 - amount of splashKnockback, 100% at a distance of 0, 0% at a distance = splashRadius +//========================================================================================================================================= } qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber, qboolean setColors ) @@ -311,7 +636,7 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber, qboolean SkipRestOfLine( &p ); continue; } - if ( n < 1 || n >= MAX_BLADES ) + if ( n < 1 || n > MAX_BLADES ) { G_Error( "WP_SaberParseParms: saber %s has illegal number of blades (%d) max: %d", SaberName, n, MAX_BLADES ); continue; @@ -470,11 +795,46 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber, qboolean //locked saber style if ( !Q_stricmp( token, "saberStyle" ) ) { + int style, styleNum; if ( COM_ParseString( &p, &value ) ) { continue; } - saber->style = TranslateSaberStyle( value ); + //OLD WAY: only allowed ONE style + style = TranslateSaberStyle( value ); + //learn only this style + saber->stylesLearned = (1<stylesForbidden = 0; + for ( styleNum = SS_NONE+1; styleNum < SS_NUM_SABER_STYLES; styleNum++ ) + { + if ( styleNum != style ) + { + saber->stylesForbidden |= (1<stylesLearned |= (1<stylesForbidden |= (1<lockable = ((qboolean)(n!=0)); + if ( n == 0 ) + { + saber->saberFlags |= SFL_NOT_LOCKABLE; + } continue; } @@ -510,7 +873,10 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber, qboolean SkipRestOfLine( &p ); continue; } - saber->throwable = ((qboolean)(n!=0)); + if ( n == 0 ) + { + saber->saberFlags |= SFL_NOT_THROWABLE; + } continue; } @@ -522,7 +888,10 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber, qboolean SkipRestOfLine( &p ); continue; } - saber->disarmable = ((qboolean)(n!=0)); + if ( n == 0 ) + { + saber->saberFlags |= SFL_NOT_DISARMABLE; + } continue; } @@ -534,7 +903,10 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber, qboolean SkipRestOfLine( &p ); continue; } - saber->activeBlocking = ((qboolean)(n!=0)); + if ( n == 0 ) + { + saber->saberFlags |= SFL_NOT_ACTIVE_BLOCKING; + } continue; } @@ -546,7 +918,10 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber, qboolean SkipRestOfLine( &p ); continue; } - saber->twoHanded = ((qboolean)(n!=0)); + if ( n ) + { + saber->saberFlags |= SFL_TWO_HANDED; + } continue; } @@ -601,6 +976,18 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber, qboolean continue; } + //breakParryBonus2 + if ( !Q_stricmp( token, "breakParryBonus2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->breakParryBonus2 = n; + continue; + } + //disarmBonus if ( !Q_stricmp( token, "disarmBonus" ) ) { @@ -613,6 +1000,18 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber, qboolean continue; } + //disarmBonus2 + if ( !Q_stricmp( token, "disarmBonus2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->disarmBonus2 = n; + continue; + } + //single blade saber style if ( !Q_stricmp( token, "singleBladeStyle" ) ) { @@ -632,7 +1031,10 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber, qboolean SkipRestOfLine( &p ); continue; } - saber->singleBladeThrowable = ((qboolean)(n!=0)); + if ( n ) + { + saber->saberFlags |= SFL_SINGLE_BLADE_THROWABLE; + } continue; } @@ -666,7 +1068,547 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber, qboolean SkipRestOfLine( &p ); continue; } - saber->returnDamage = ((qboolean)(n!=0)); + if ( n ) + { + saber->saberFlags |= SFL_RETURN_DAMAGE; + } + continue; + } + + //spin sound (when thrown) + if ( !Q_stricmp( token, "spinSound" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->spinSound = G_SoundIndex( (char *)value ); + continue; + } + + //swing sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "swingSound1" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->swingSound[0] = G_SoundIndex( (char *)value ); + continue; + } + + //swing sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "swingSound2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->swingSound[1] = G_SoundIndex( (char *)value ); + continue; + } + + //swing sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "swingSound3" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->swingSound[2] = G_SoundIndex( (char *)value ); + continue; + } + + //fall sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "fallSound1" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->fallSound[0] = G_SoundIndex( (char *)value ); + continue; + } + + //fall sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "fallSound2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->fallSound[1] = G_SoundIndex( (char *)value ); + continue; + } + + //fall sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "fallSound3" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->fallSound[2] = G_SoundIndex( (char *)value ); + continue; + } + + //you move faster/slower when using this saber + if ( !Q_stricmp( token, "moveSpeedScale" ) ) + { + if ( COM_ParseFloat( &p, &f ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->moveSpeedScale = f; + continue; + } + + //plays normal attack animations faster/slower + if ( !Q_stricmp( token, "animSpeedScale" ) ) + { + if ( COM_ParseFloat( &p, &f ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->animSpeedScale = f; + continue; + } + + //if set, weapon stays active even in water + if ( !Q_stricmp( token, "onInWater" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_ON_IN_WATER; + } + continue; + } + + //if non-zero, the saber will bounce back when it hits solid architecture (good for real-sword type mods) + if ( !Q_stricmp( token, "bounceOnWalls" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_BOUNCE_ON_WALLS; + } + continue; + } + + //if set, saber model is bolted to wrist, not in hand... useful for things like claws & shields, etc. + if ( !Q_stricmp( token, "boltToWrist" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_BOLT_TO_WRIST; + } + continue; + } + + //kata move + if ( !Q_stricmp( token, "kataMove" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + int saberMove = GetIDForString( SaberMoveTable, value ); + if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX ) + { + saber->kataMove = saberMove; //LS_INVALID - if set, player will execute this move when they press both attack buttons at the same time + } + continue; + } + //lungeAtkMove move + if ( !Q_stricmp( token, "lungeAtkMove" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + int saberMove = GetIDForString( SaberMoveTable, value ); + if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX ) + { + saber->lungeAtkMove = saberMove; + } + continue; + } + //jumpAtkUpMove move + if ( !Q_stricmp( token, "jumpAtkUpMove" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + int saberMove = GetIDForString( SaberMoveTable, value ); + if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX ) + { + saber->jumpAtkUpMove = saberMove; + } + continue; + } + //jumpAtkFwdMove move + if ( !Q_stricmp( token, "jumpAtkFwdMove" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + int saberMove = GetIDForString( SaberMoveTable, value ); + if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX ) + { + saber->jumpAtkFwdMove = saberMove; + } + continue; + } + //jumpAtkBackMove move + if ( !Q_stricmp( token, "jumpAtkBackMove" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + int saberMove = GetIDForString( SaberMoveTable, value ); + if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX ) + { + saber->jumpAtkBackMove = saberMove; + } + continue; + } + //jumpAtkRightMove move + if ( !Q_stricmp( token, "jumpAtkRightMove" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + int saberMove = GetIDForString( SaberMoveTable, value ); + if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX ) + { + saber->jumpAtkRightMove = saberMove; + } + continue; + } + //jumpAtkLeftMove move + if ( !Q_stricmp( token, "jumpAtkLeftMove" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + int saberMove = GetIDForString( SaberMoveTable, value ); + if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX ) + { + saber->jumpAtkLeftMove = saberMove; + } + continue; + } + //readyAnim + if ( !Q_stricmp( token, "readyAnim" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + int anim = GetIDForString( animTable, value ); + if ( anim >= 0 && anim < MAX_ANIMATIONS ) + { + saber->readyAnim = anim; + } + continue; + } + //drawAnim + if ( !Q_stricmp( token, "drawAnim" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + int anim = GetIDForString( animTable, value ); + if ( anim >= 0 && anim < MAX_ANIMATIONS ) + { + saber->drawAnim = anim; + } + continue; + } + //putawayAnim + if ( !Q_stricmp( token, "putawayAnim" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + int anim = GetIDForString( animTable, value ); + if ( anim >= 0 && anim < MAX_ANIMATIONS ) + { + saber->putawayAnim = anim; + } + continue; + } + //tauntAnim + if ( !Q_stricmp( token, "tauntAnim" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + int anim = GetIDForString( animTable, value ); + if ( anim >= 0 && anim < MAX_ANIMATIONS ) + { + saber->tauntAnim = anim; + } + continue; + } + //bowAnim + if ( !Q_stricmp( token, "bowAnim" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + int anim = GetIDForString( animTable, value ); + if ( anim >= 0 && anim < MAX_ANIMATIONS ) + { + saber->bowAnim = anim; + } + continue; + } + //meditateAnim + if ( !Q_stricmp( token, "meditateAnim" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + int anim = GetIDForString( animTable, value ); + if ( anim >= 0 && anim < MAX_ANIMATIONS ) + { + saber->meditateAnim = anim; + } + continue; + } + //flourishAnim + if ( !Q_stricmp( token, "flourishAnim" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + int anim = GetIDForString( animTable, value ); + if ( anim >= 0 && anim < MAX_ANIMATIONS ) + { + saber->flourishAnim = anim; + } + continue; + } + //gloatAnim + if ( !Q_stricmp( token, "gloatAnim" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + int anim = GetIDForString( animTable, value ); + if ( anim >= 0 && anim < MAX_ANIMATIONS ) + { + saber->gloatAnim = anim; + } + continue; + } + + //if set, cannot do roll-stab move at end of roll + if ( !Q_stricmp( token, "noRollStab" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_ROLL_STAB; + } + continue; + } + + //if set, cannot do pull+attack move (move not available in MP anyway) + if ( !Q_stricmp( token, "noPullAttack" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_PULL_ATTACK; + } + continue; + } + + //if set, cannot do back-stab moves + if ( !Q_stricmp( token, "noBackAttack" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_BACK_ATTACK; + } + continue; + } + + //if set, cannot do stabdown move (when enemy is on ground) + if ( !Q_stricmp( token, "noStabDown" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_STABDOWN; + } + continue; + } + + //if set, cannot side-run or forward-run on walls + if ( !Q_stricmp( token, "noWallRuns" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_WALL_RUNS; + } + continue; + } + + //if set, cannot do backflip off wall or side-flips off walls + if ( !Q_stricmp( token, "noWallFlips" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_WALL_FLIPS; + } + continue; + } + + //if set, cannot grab wall & jump off + if ( !Q_stricmp( token, "noWallGrab" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_WALL_GRAB; + } + continue; + } + + //if set, cannot roll + if ( !Q_stricmp( token, "noRolls" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_ROLLS; + } + continue; + } + + //if set, cannot do flips + if ( !Q_stricmp( token, "noFlips" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_FLIPS; + } + continue; + } + + //if set, cannot do cartwheels + if ( !Q_stricmp( token, "noCartwheels" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_CARTWHEELS; + } + continue; + } + + //if set, cannot do kicks (can't do kicks anyway if using a throwable saber/sword) + if ( !Q_stricmp( token, "noKicks" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_KICKS; + } + continue; + } + + //if set, cannot do the simultaneous attack left/right moves (only available in Dual Lightsaber Combat Style) + if ( !Q_stricmp( token, "noMirrorAttacks" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_MIRROR_ATTACKS; + } continue; } @@ -676,6 +1618,776 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber, qboolean continue; } +//===ABOVE THIS, ALL VALUES ARE GLOBAL TO THE SABER======================================================== + //bladeStyle2Start - where to start using the second set of blade data + if ( !Q_stricmp( token, "bladeStyle2Start" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->bladeStyle2Start = n; + continue; + } +//===BLADE-SPECIFIC FIELDS================================================================================= + + //===PRIMARY BLADE==================================== + //stops the saber from drawing marks on the world (good for real-sword type mods) + if ( !Q_stricmp( token, "noWallMarks" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_WALL_MARKS; + } + continue; + } + + //stops the saber from drawing a dynamic light (good for real-sword type mods) + if ( !Q_stricmp( token, "noDlight" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_DLIGHT; + } + continue; + } + + //stops the saber from drawing a blade (good for real-sword type mods) + if ( !Q_stricmp( token, "noBlade" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_BLADE; + } + continue; + } + + //default (0) is normal, 1 is a motion blur and 2 is no trail at all (good for real-sword type mods) + if ( !Q_stricmp( token, "trailStyle" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->trailStyle = n; + continue; + } + + //if set, the game will use this shader for marks on enemies instead of the default "gfx/damage/saberglowmark" + if ( !Q_stricmp( token, "g2MarksShader" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + SkipRestOfLine( &p ); + continue; + } + Q_strncpyz( saber->g2MarksShader, value, sizeof(saber->g2MarksShader), qtrue ); + //NOTE: registers this on cgame side where it registers all client assets + continue; + } + + //if set, the game will ry to project this shader onto the weapon when it damages a person (good for a blood splatter on the weapon) + if ( !Q_stricmp( token, "g2WeaponMarkShader" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + SkipRestOfLine( &p ); + continue; + } + Q_strncpyz( saber->g2WeaponMarkShader, value, sizeof(saber->g2WeaponMarkShader), qtrue ); + //NOTE: registers this on cgame side where it registers all client assets + continue; + } + + //if non-zero, uses damage done to calculate an appropriate amount of knockback + if ( !Q_stricmp( token, "knockbackScale" ) ) + { + if ( COM_ParseFloat( &p, &f ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->knockbackScale = f; + continue; + } + + //scale up or down the damage done by the saber + if ( !Q_stricmp( token, "damageScale" ) ) + { + if ( COM_ParseFloat( &p, &f ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->damageScale = f; + continue; + } + + //if non-zero, the saber never does dismemberment (good for pointed/blunt melee weapons) + if ( !Q_stricmp( token, "noDismemberment" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_DISMEMBERMENT; + } + continue; + } + + //if non-zero, the saber will not do damage or any effects when it is idle (not in an attack anim). (good for real-sword type mods) + if ( !Q_stricmp( token, "noIdleEffect" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_IDLE_EFFECT; + } + continue; + } + + //if set, the blades will always be blocking (good for things like shields that should always block) + if ( !Q_stricmp( token, "alwaysBlock" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_ALWAYS_BLOCK; + } + continue; + } + + //if set, the blades cannot manually be toggled on and off + if ( !Q_stricmp( token, "noManualDeactivate" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_MANUAL_DEACTIVATE; + } + continue; + } + + //if set, the blade does damage in start, transition and return anims (like strong style does) + if ( !Q_stricmp( token, "transitionDamage" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_TRANSITION_DAMAGE; + } + continue; + } + + //splashRadius - radius of splashDamage + if ( !Q_stricmp( token, "splashRadius" ) ) + { + if ( COM_ParseFloat( &p, &f ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->splashRadius = f; + continue; + } + + //splashDamage - amount of splashDamage, 100% at a distance of 0, 0% at a distance = splashRadius + if ( !Q_stricmp( token, "splashDamage" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->splashDamage = n; + continue; + } + + //splashKnockback - amount of splashKnockback, 100% at a distance of 0, 0% at a distance = splashRadius + if ( !Q_stricmp( token, "splashKnockback" ) ) + { + if ( COM_ParseFloat( &p, &f ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->splashKnockback = f; + continue; + } + + //hit sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "hitSound1" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->hitSound[0] = G_SoundIndex( (char *)value ); + continue; + } + + //hit sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "hitSound2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->hitSound[1] = G_SoundIndex( (char *)value ); + continue; + } + + //hit sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "hitSound3" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->hitSound[2] = G_SoundIndex( (char *)value ); + continue; + } + + //block sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "blockSound1" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->blockSound[0] = G_SoundIndex( (char *)value ); + continue; + } + + //block sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "blockSound2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->blockSound[1] = G_SoundIndex( (char *)value ); + continue; + } + + //block sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "blockSound3" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->blockSound[2] = G_SoundIndex( (char *)value ); + continue; + } + + //bounce sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "bounceSound1" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->bounceSound[0] = G_SoundIndex( (char *)value ); + continue; + } + + //bounce sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "bounceSound2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->bounceSound[1] = G_SoundIndex( (char *)value ); + continue; + } + + //bounce sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "bounceSound3" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->bounceSound[2] = G_SoundIndex( (char *)value ); + continue; + } + + //block effect - when saber/sword hits another saber/sword + if ( !Q_stricmp( token, "blockEffect" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->blockEffect = G_EffectIndex( (char *)value ); + continue; + } + + //hit person effect - when saber/sword hits a person + if ( !Q_stricmp( token, "hitPersonEffect" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->hitPersonEffect = G_EffectIndex( (char *)value ); + continue; + } + + //hit other effect - when saber/sword hits sopmething else damagable + if ( !Q_stricmp( token, "hitOtherEffect" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->hitOtherEffect = G_EffectIndex( (char *)value ); + continue; + } + + //blade effect + if ( !Q_stricmp( token, "bladeEffect" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->bladeEffect = G_EffectIndex( (char *)value ); + continue; + } + + //if non-zero, the saber will not do the big, white clash flare with other sabers + if ( !Q_stricmp( token, "noClashFlare" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_CLASH_FLARE; + } + continue; + } + + //===SECONDARY BLADE==================================== + //stops the saber from drawing marks on the world (good for real-sword type mods) + if ( !Q_stricmp( token, "noWallMarks2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_WALL_MARKS2; + } + continue; + } + + //stops the saber from drawing a dynamic light (good for real-sword type mods) + if ( !Q_stricmp( token, "noDlight2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_DLIGHT2; + } + continue; + } + + //stops the saber from drawing a blade (good for real-sword type mods) + if ( !Q_stricmp( token, "noBlade2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_BLADE2; + } + continue; + } + + //default (0) is normal, 1 is a motion blur and 2 is no trail at all (good for real-sword type mods) + if ( !Q_stricmp( token, "trailStyle2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->trailStyle2 = n; + continue; + } + + //if set, the game will use this shader for marks on enemies instead of the default "gfx/damage/saberglowmark" + if ( !Q_stricmp( token, "g2MarksShader2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + SkipRestOfLine( &p ); + continue; + } + Q_strncpyz( saber->g2MarksShader2, value, sizeof(saber->g2MarksShader2), qtrue ); + //NOTE: registers this on cgame side where it registers all client assets + continue; + } + + //if set, the game will ry to project this shader onto the weapon when it damages a person (good for a blood splatter on the weapon) + if ( !Q_stricmp( token, "g2WeaponMarkShader2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + SkipRestOfLine( &p ); + continue; + } + Q_strncpyz( saber->g2WeaponMarkShader2, value, sizeof(saber->g2WeaponMarkShader2), qtrue ); + //NOTE: registers this on cgame side where it registers all client assets + continue; + } + + //if non-zero, uses damage done to calculate an appropriate amount of knockback + if ( !Q_stricmp( token, "knockbackScale2" ) ) + { + if ( COM_ParseFloat( &p, &f ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->knockbackScale2 = f; + continue; + } + + //scale up or down the damage done by the saber + if ( !Q_stricmp( token, "damageScale2" ) ) + { + if ( COM_ParseFloat( &p, &f ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->damageScale2 = f; + continue; + } + + //if non-zero, the saber never does dismemberment (good for pointed/blunt melee weapons) + if ( !Q_stricmp( token, "noDismemberment2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_DISMEMBERMENT2; + } + continue; + } + + //if non-zero, the saber will not do damage or any effects when it is idle (not in an attack anim). (good for real-sword type mods) + if ( !Q_stricmp( token, "noIdleEffect2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_IDLE_EFFECT2; + } + continue; + } + + //if set, the blades will always be blocking (good for things like shields that should always block) + if ( !Q_stricmp( token, "alwaysBlock2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_ALWAYS_BLOCK2; + } + continue; + } + + //if set, the blades cannot manually be toggled on and off + if ( !Q_stricmp( token, "noManualDeactivate2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_MANUAL_DEACTIVATE2; + } + continue; + } + + //if set, the blade does damage in start, transition and return anims (like strong style does) + if ( !Q_stricmp( token, "transitionDamage2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_TRANSITION_DAMAGE2; + } + continue; + } + + //splashRadius - radius of splashDamage + if ( !Q_stricmp( token, "splashRadius2" ) ) + { + if ( COM_ParseFloat( &p, &f ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->splashRadius2 = f; + continue; + } + + //splashDamage - amount of splashDamage, 100% at a distance of 0, 0% at a distance = splashRadius + if ( !Q_stricmp( token, "splashDamage2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->splashDamage2 = n; + continue; + } + + //splashKnockback - amount of splashKnockback, 100% at a distance of 0, 0% at a distance = splashRadius + if ( !Q_stricmp( token, "splashKnockback2" ) ) + { + if ( COM_ParseFloat( &p, &f ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->splashKnockback2 = f; + continue; + } + + //hit sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "hit2Sound1" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->hit2Sound[0] = G_SoundIndex( (char *)value ); + continue; + } + + //hit sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "hit2Sound2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->hit2Sound[1] = G_SoundIndex( (char *)value ); + continue; + } + + //hit sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "hit2Sound3" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->hit2Sound[2] = G_SoundIndex( (char *)value ); + continue; + } + + //block sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "block2Sound1" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->block2Sound[0] = G_SoundIndex( (char *)value ); + continue; + } + + //block sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "block2Sound2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->block2Sound[1] = G_SoundIndex( (char *)value ); + continue; + } + + //block sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "block2Sound3" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->block2Sound[2] = G_SoundIndex( (char *)value ); + continue; + } + + //bounce sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "bounce2Sound1" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->bounce2Sound[0] = G_SoundIndex( (char *)value ); + continue; + } + + //bounce sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "bounce2Sound2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->bounce2Sound[1] = G_SoundIndex( (char *)value ); + continue; + } + + //bounce sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "bounce2Sound3" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->bounce2Sound[2] = G_SoundIndex( (char *)value ); + continue; + } + + //block effect - when saber/sword hits another saber/sword + if ( !Q_stricmp( token, "blockEffect2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->blockEffect2 = G_EffectIndex( (char *)value ); + continue; + } + + //hit person effect - when saber/sword hits a person + if ( !Q_stricmp( token, "hitPersonEffect2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->hitPersonEffect2 = G_EffectIndex( (char *)value ); + continue; + } + + //hit other effect - when saber/sword hits sopmething else damagable + if ( !Q_stricmp( token, "hitOtherEffect2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->hitOtherEffect2 = G_EffectIndex( (char *)value ); + continue; + } + + //blade effect 2 + if ( !Q_stricmp( token, "bladeEffect2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->bladeEffect = G_EffectIndex( (char *)value ); + continue; + } + + //if non-zero, the saber will not do the big, white clash flare with other sabers + if ( !Q_stricmp( token, "noClashFlare2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_CLASH_FLARE2; + } + continue; + } + +//===END BLADE-SPECIFIC FIELDS============================================================================= + gi.Printf( "WARNING: unknown keyword '%s' while parsing '%s'\n", token, SaberName ); SkipRestOfLine( &p ); } @@ -711,7 +2423,7 @@ void WP_RemoveSaber( gentity_t *ent, int saberNum ) if ( ent->client->ps.saberAnimLevel == SS_DUAL || ent->client->ps.saberAnimLevel == SS_STAFF ) {//change to the style to the default - for ( int i = SS_FAST; i < SS_NUM_SABER_STYLES; i++ ) + for ( int i = SS_NONE+1; i < SS_NUM_SABER_STYLES; i++ ) { if ( (ent->client->ps.saberStylesKnown&(1<weaponModel[saberNum] = -1; } WP_SaberParseParms( saberName, &ent->client->ps.saber[saberNum] );//get saber info - if ( ent->client->ps.saber[saberNum].style ) + if ( ent->client->ps.saber[saberNum].stylesLearned ) { - ent->client->ps.saberStylesKnown |= (1<client->ps.saber[saberNum].style); + ent->client->ps.saberStylesKnown |= ent->client->ps.saber[saberNum].stylesLearned; } - if ( saberNum == 1 && ent->client->ps.saber[1].twoHanded ) + if ( ent->client->ps.saber[saberNum].singleBladeStyle ) + { + ent->client->ps.saberStylesKnown |= ent->client->ps.saber[saberNum].singleBladeStyle; + } + if ( saberNum == 1 && (ent->client->ps.saber[1].saberFlags&SFL_TWO_HANDED) ) {//not allowed to use a 2-handed saber as second saber WP_RemoveSaber( ent, saberNum ); return; } G_ModelIndex( ent->client->ps.saber[saberNum].model ); WP_SaberInitBladeData( ent ); - //int boltNum = ent->handRBolt; if ( saberNum == 1 ) - { + {//now have 2 sabers ent->client->ps.dualSabers = qtrue; - //boltNum = ent->handLBolt; } + /* + else if ( saberNum == 0 ) + { + if ( ent->weaponModel[1] == -1 ) + {//don't have 2 sabers + ent->client->ps.dualSabers = qfalse; + } + } + */ WP_SaberAddG2SaberModels( ent, saberNum ); ent->client->ps.saber[saberNum].SetLength( 0.0f ); ent->client->ps.saber[saberNum].Activate(); - if ( ent->client->ps.saber[saberNum].style != SS_NONE ) + if ( ent->client->ps.saber[saberNum].stylesLearned ) {//change to the style we're supposed to be using - ent->client->ps.saberAnimLevel = ent->client->ps.saber[saberNum].style; - ent->client->ps.saberStylesKnown |= (1<client->ps.saberAnimLevel); - if ( ent->s.number < MAX_CLIENTS ) - { - cg.saberAnimLevelPending = ent->client->ps.saberAnimLevel; - } + ent->client->ps.saberStylesKnown |= ent->client->ps.saber[saberNum].stylesLearned; + } + if ( ent->client->ps.saber[saberNum].singleBladeStyle ) + { + ent->client->ps.saberStylesKnown |= ent->client->ps.saber[saberNum].singleBladeStyle; + } + WP_UseFirstValidSaberStyle( ent, &ent->client->ps.saberAnimLevel ); + if ( ent->s.number < MAX_CLIENTS ) + { + cg.saberAnimLevelPending = ent->client->ps.saberAnimLevel; } } @@ -829,7 +2556,7 @@ qboolean WP_BreakSaber( gentity_t *ent, const char *surfName, saberType_t saberT } if ( Q_stricmpn( "w_", surfName, 2 ) - && Q_stricmpn( "saber_", surfName, 6 ) //hack because using mod-community made saber + && Q_stricmpn( "saber", surfName, 5 ) //hack because using mod-community made saber && Q_stricmp( "cylinder01", surfName ) )//hack because using mod-community made saber {//didn't hit my weapon return qfalse; @@ -933,7 +2660,7 @@ void WP_SaberLoadParms( void ) len = COM_Compress( buffer ); if ( totallen + len >= MAX_SABER_DATA_SIZE ) { - G_Error( "WP_SaberLoadParms: ran out of space before reading %s\n(you must make the .npc files smaller)", holdChar ); + G_Error( "WP_SaberLoadParms: ran out of space before reading %s\n(you must make the .sab files smaller)", holdChar ); } strcat( marker, buffer ); gi.FS_FreeFile( buffer ); diff --git a/code/ghoul2/G2.h b/code/ghoul2/G2.h index b029095..e9a4d3b 100644 --- a/code/ghoul2/G2.h +++ b/code/ghoul2/G2.h @@ -78,13 +78,13 @@ void G2_List_Model_Surfaces(const char *fileName); void G2_List_Model_Bones(const char *fileName, int frame); qboolean G2_GetAnimFileName(const char *fileName, char **filename); #ifdef _G2_GORE -void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CCollisionRecord *collRecMap, int entNum, EG2_Collision eG2TraceType, int useLod, float fRadius, float ssize,float tsize,float theta,int shader, SSkinGoreData *gore); +void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CCollisionRecord *collRecMap, int entNum, EG2_Collision eG2TraceType, int useLod, float fRadius, float ssize,float tsize,float theta,int shader, SSkinGoreData *gore, qboolean skipIfLODNotMatch); #else void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CCollisionRecord *collRecMap, int entNum, EG2_Collision eG2TraceType, int useLod, float fRadius); #endif void TransformAndTranslatePoint (const vec3_t in, vec3_t out, mdxaBone_t *mat); #ifdef _G2_GORE -void G2_TransformModel(CGhoul2Info_v &ghoul2, const int frameNum, vec3_t scale, CMiniHeap *G2VertSpace, int useLod, bool ApplyGore); +void G2_TransformModel(CGhoul2Info_v &ghoul2, const int frameNum, vec3_t scale, CMiniHeap *G2VertSpace, int useLod, bool ApplyGore, SSkinGoreData *gore=NULL); #else void G2_TransformModel(CGhoul2Info_v &ghoul2, const int frameNum, vec3_t scale, CMiniHeap *G2VertSpace, int useLod); #endif diff --git a/code/ghoul2/G2_API.cpp b/code/ghoul2/G2_API.cpp index 17d62c7..23e21ae 100644 --- a/code/ghoul2/G2_API.cpp +++ b/code/ghoul2/G2_API.cpp @@ -1731,7 +1731,7 @@ void G2API_CollisionDetect(CCollisionRecord *collRecMap, CGhoul2Info_v &ghoul2, // now walk each model and check the ray against each poly - sigh, this is SO expensive. I wish there was a better way to do this. #ifdef _G2_GORE - G2_TraceModels(ghoul2, transRayStart, transRayEnd, collRecMap, entNum, eG2TraceType, useLod, fRadius,0,0,0,0,0); + G2_TraceModels(ghoul2, transRayStart, transRayEnd, collRecMap, entNum, eG2TraceType, useLod, fRadius,0,0,0,0,0,qfalse); #else G2_TraceModels(ghoul2, transRayStart, transRayEnd, collRecMap, entNum, eG2TraceType, useLod, fRadius); #endif @@ -1992,10 +1992,10 @@ void G2API_AddSkinGore(CGhoul2Info_v &ghoul2,SSkinGoreData &gore) // now having done that, time to build the model G2VertSpaceServer->ResetHeap(); - G2_TransformModel(ghoul2, gore.currentTime, gore.scale,G2VertSpaceServer,lod,true); + G2_TransformModel(ghoul2, gore.currentTime, gore.scale,G2VertSpaceServer,lod,true,&gore); // now walk each model and compute new texture coordinates - G2_TraceModels(ghoul2, transHitLocation, transRayDirection, 0, gore.entNum, G2_NOCOLLIDE,lod,1.0f,gore.SSize,gore.TSize,gore.theta,gore.shader,&gore); + G2_TraceModels(ghoul2, transHitLocation, transRayDirection, 0, gore.entNum, G2_NOCOLLIDE,lod,1.0f,gore.SSize,gore.TSize,gore.theta,gore.shader,&gore,qtrue); } } #else diff --git a/code/ghoul2/G2_misc.cpp b/code/ghoul2/G2_misc.cpp index 58f2a94..2405192 100644 --- a/code/ghoul2/G2_misc.cpp +++ b/code/ghoul2/G2_misc.cpp @@ -42,7 +42,7 @@ static map,int> GoreTagsTemp; // this is a surface index to gore t // temporarily during the generation phase so we reuse gore tags per LOD int goreModelIndex; -bool AddGoreToAllModels=false; +static cvar_t *cg_g2MarksAllModels=NULL; GoreTextureCoordinates *FindGoreRecord(int tag); static inline void DestroyGoreTexCoordinates(int tag) @@ -551,14 +551,33 @@ void G2_TransformSurfaces(int surfaceNum, surfaceInfo_v &rootSList, // main calling point for the model transform for collision detection. At this point all of the skeleton has been transformed. #ifdef _G2_GORE -void G2_TransformModel(CGhoul2Info_v &ghoul2, const int frameNum, vec3_t scale, CMiniHeap *G2VertSpace, int useLod, bool ApplyGore) +void G2_TransformModel(CGhoul2Info_v &ghoul2, const int frameNum, vec3_t scale, CMiniHeap *G2VertSpace, int useLod, bool ApplyGore, SSkinGoreData *gore) #else void G2_TransformModel(CGhoul2Info_v &ghoul2, const int frameNum, vec3_t scale, CMiniHeap *G2VertSpace, int useLod) #endif { int i, lod; vec3_t correctScale; + qboolean firstModelOnly = qfalse; + if ( cg_g2MarksAllModels == NULL ) + { + cg_g2MarksAllModels = Cvar_Get( "cg_g2MarksAllModels", "0", 0 ); + } + + if (cg_g2MarksAllModels == NULL + || !cg_g2MarksAllModels->integer ) + { + firstModelOnly = qtrue; + } + +#ifdef _G2_GORE + if ( gore + && gore->firstModel > 0 ) + { + firstModelOnly = qfalse; + } +#endif VectorCopy(scale, correctScale); // check for scales of 0 - that's the default I believe @@ -598,7 +617,13 @@ void G2_TransformModel(CGhoul2Info_v &ghoul2, const int frameNum, vec3_t scale, if (lod>=g.currentModel->numLods) { g.mTransformedVertsArray = 0; - return; + if ( firstModelOnly ) + { + // we don't really need to do multiple models for gore. + return; + } + //do the rest + continue; } } else @@ -621,7 +646,8 @@ void G2_TransformModel(CGhoul2Info_v &ghoul2, const int frameNum, vec3_t scale, G2_TransformSurfaces(g.mSurfaceRoot, g.mSlist, g.mBoneCache, g.currentModel, lod, correctScale, G2VertSpace, g.mTransformedVertsArray, false); #ifdef _G2_GORE - if (ApplyGore&&!AddGoreToAllModels) + + if (ApplyGore && firstModelOnly ) { // we don't really need to do multiple models for gore. break; @@ -1507,7 +1533,7 @@ static void G2_TraceSurfaces(CTraceSurface &TS) } #ifdef _G2_GORE -void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CCollisionRecord *collRecMap, int entNum, EG2_Collision eG2TraceType, int useLod, float fRadius, float ssize,float tsize,float theta,int shader, SSkinGoreData *gore) +void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CCollisionRecord *collRecMap, int entNum, EG2_Collision eG2TraceType, int useLod, float fRadius, float ssize,float tsize,float theta,int shader, SSkinGoreData *gore, qboolean skipIfLODNotMatch) #else void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CCollisionRecord *collRecMap, int entNum, EG2_Collision eG2TraceType, int useLod, float fRadius) #endif @@ -1515,9 +1541,31 @@ void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CColl int i, lod; skin_t *skin; shader_t *cust_shader; + qboolean firstModelOnly = qfalse; + int firstModel = 0; + + if ( cg_g2MarksAllModels == NULL ) + { + cg_g2MarksAllModels = Cvar_Get( "cg_g2MarksAllModels", "0", 0 ); + } + + if (cg_g2MarksAllModels == NULL + || !cg_g2MarksAllModels->integer ) + { + firstModelOnly = qtrue; + } + +#ifdef _G2_GORE + if ( gore + && gore->firstModel > 0 ) + { + firstModel = gore->firstModel; + firstModelOnly = qfalse; + } +#endif // walk each possible model for this entity and try tracing against it - for (i=0; inext ) { if ( path->pack ) { // a tiny attempt to keep the checksum from being scannable from the exe - if ( (path->pack->checksum ^ 0x84268436u) != (DEMO_PAK_CHECKSUM ^ 0x84268436u) ) { + if ( (path->pack->checksum ^ 0x10228436u) != (DEMO_PAK_CHECKSUM ^ 0x10228436u) ) { Com_Error( ERR_FATAL, "Corrupted pk3: %u", path->pack->checksum ); } } diff --git a/code/qcommon/vssver.scc b/code/qcommon/vssver.scc index 8567cec..a7917c7 100644 Binary files a/code/qcommon/vssver.scc and b/code/qcommon/vssver.scc differ diff --git a/code/renderer/tr_init.cpp b/code/renderer/tr_init.cpp index 36edf4a..8eddd09 100644 --- a/code/renderer/tr_init.cpp +++ b/code/renderer/tr_init.cpp @@ -860,6 +860,8 @@ void GL_SetDefaultState( void ) GfxInfo_f ================ */ +extern bool g_bTextureRectangleHack; + void GfxInfo_f( void ) { cvar_t *sys_cpustring = Cvar_Get( "sys_cpustring", "", CVAR_ROM ); @@ -945,6 +947,7 @@ void GfxInfo_f( void ) Com_Printf ("anisotropic filtering: %s ", enablestrings[(r_ext_texture_filter_anisotropic->integer != 0) && glConfig.maxTextureFilterAnisotropy] ); Com_Printf ("(%f of %f)\n", r_ext_texture_filter_anisotropic->value, glConfig.maxTextureFilterAnisotropy ); Com_Printf ("Dynamic Glow: %s\n", enablestrings[r_DynamicGlow->integer] ); + if (g_bTextureRectangleHack) Com_Printf ("Dynamic Glow ATI BAD DRIVER HACK %s\n", enablestrings[g_bTextureRectangleHack] ); if ( r_finish->integer ) { VID_Printf( PRINT_ALL, "Forcing glFinish\n" ); @@ -958,6 +961,10 @@ void GfxInfo_f( void ) } } +void R_AtiHackToggle_f(void) +{ + g_bTextureRectangleHack = !g_bTextureRectangleHack; +} /************************************************************************************************ * R_FogDistance_f * @@ -1092,7 +1099,7 @@ void R_Register( void ) r_ext_texture_env_add = Cvar_Get( "r_ext_texture_env_add", "1", CVAR_ARCHIVE | CVAR_LATCH); r_ext_texture_filter_anisotropic = Cvar_Get( "r_ext_texture_filter_anisotropic", "16", CVAR_ARCHIVE ); - r_DynamicGlow = Cvar_Get( "r_DynamicGlow", "1", CVAR_ARCHIVE ); + r_DynamicGlow = Cvar_Get( "r_DynamicGlow", "0", CVAR_ARCHIVE ); r_DynamicGlowPasses = Cvar_Get( "r_DynamicGlowPasses", "5", CVAR_CHEAT ); r_DynamicGlowDelta = Cvar_Get( "r_DynamicGlowDelta", "0.8f", CVAR_CHEAT ); r_DynamicGlowIntensity = Cvar_Get( "r_DynamicGlowIntensity", "1.13f", CVAR_CHEAT ); @@ -1275,6 +1282,7 @@ extern qboolean Sys_LowPhysicalMemory(); Cmd_AddCommand( "modellist", R_Modellist_f ); #ifndef _XBOX Cmd_AddCommand( "modelist", R_ModeList_f ); + Cmd_AddCommand( "r_atihack", R_AtiHackToggle_f ); #endif Cmd_AddCommand( "screenshot", R_ScreenShot_f ); Cmd_AddCommand( "screenshot_tga", R_ScreenShotTGA_f ); @@ -1422,7 +1430,10 @@ void RE_Shutdown( qboolean destroyWindow ) { Cmd_RemoveCommand ("shaderlist"); Cmd_RemoveCommand ("skinlist"); Cmd_RemoveCommand ("modellist"); +#ifndef _XBOX Cmd_RemoveCommand ("modelist" ); + Cmd_RemoveCommand ("r_atihack"); +#endif Cmd_RemoveCommand ("screenshot"); Cmd_RemoveCommand ("screenshot_tga"); Cmd_RemoveCommand ("gfxinfo"); diff --git a/code/renderer/tr_stl.cpp b/code/renderer/tr_stl.cpp index 99566a5..d3d09d7 100644 --- a/code/renderer/tr_stl.cpp +++ b/code/renderer/tr_stl.cpp @@ -28,10 +28,6 @@ typedef map ShaderEntryPtrs_t; ShaderEntryPtrs_t ShaderEntryPtrs; - - - - void ShaderEntryPtrs_Clear(void) { ShaderEntryPtrs.clear(); @@ -52,6 +48,10 @@ void ShaderEntryPtrs_Insert(const char *token, const char *p) { ShaderEntryPtrs[token] = p; } + else + { + VID_Printf( PRINT_DEVELOPER, "Duplicate shader entry %s!\n",token ); + } } diff --git a/code/renderer/vssver.scc b/code/renderer/vssver.scc index 2e2475e..386f233 100644 Binary files a/code/renderer/vssver.scc and b/code/renderer/vssver.scc differ diff --git a/code/server/sv_ccmds.cpp b/code/server/sv_ccmds.cpp index fc80491..23f97f1 100644 --- a/code/server/sv_ccmds.cpp +++ b/code/server/sv_ccmds.cpp @@ -43,21 +43,22 @@ static client_t *SV_SetPlayer( void ) { //========================================================= // don't call this directly, it should only be called from SV_Map_f() or SV_MapTransition_f() // -static void SV_Map_( ForceReload_e eForceReload ) +static bool SV_Map_( ForceReload_e eForceReload ) { char *map; char expanded[MAX_QPATH]; map = Cmd_Argv(1); if ( !*map ) { - return; + Com_Printf ("no map specified\n"); + return false; } // make sure the level exists before trying to change, so that // a typo at the server console won't end the game if (strchr (map, '\\') ) { Com_Printf ("Can't have mapnames with a \\\n"); - return; + return false; } #ifndef _XBOX // Could check for maps/%s/brushes.mle or something... @@ -69,7 +70,7 @@ static void SV_Map_( ForceReload_e eForceReload ) {//yes, it's happened, someone deleted a map during my build... Com_Error( ERR_FATAL, "Can't find map %s\n", expanded ); } - return; + return false; } #endif @@ -79,6 +80,7 @@ static void SV_Map_( ForceReload_e eForceReload ) } SV_SpawnServer( map, eForceReload, qtrue ); // start up the map + return true; } @@ -250,20 +252,21 @@ static void SV_Map_f( void ) eForceReload = eForceReload_ALL; } - SV_Map_( eForceReload ); - - // set the cheat value - // if the level was started with "map ", then - // cheats will not be allowed. If started with "devmap " - // then cheats will be allowed - if ( !Q_stricmpn( Cmd_Argv(0), "devmap", 6 ) ) { - Cvar_Set( "helpUsObi", "1" ); - } else { + if (SV_Map_( eForceReload )) + { + // set the cheat value + // if the level was started with "map ", then + // cheats will not be allowed. If started with "devmap " + // then cheats will be allowed + if ( !Q_stricmpn( Cmd_Argv(0), "devmap", 6 ) ) { + Cvar_Set( "helpUsObi", "1" ); + } else { #ifdef _XBOX - Cvar_Set( "helpUsObi", "1" ); + Cvar_Set( "helpUsObi", "1" ); #else - Cvar_Set( "helpUsObi", "0" ); + Cvar_Set( "helpUsObi", "0" ); #endif + } } } diff --git a/code/server/vssver.scc b/code/server/vssver.scc index f09e1ce..8b8eae3 100644 Binary files a/code/server/vssver.scc and b/code/server/vssver.scc differ diff --git a/code/smartheap/vssver.scc b/code/smartheap/vssver.scc index f8d6308..3bcf5e6 100644 Binary files a/code/smartheap/vssver.scc and b/code/smartheap/vssver.scc differ diff --git a/code/ui/ui_atoms.cpp b/code/ui/ui_atoms.cpp index 5a5d508..445014b 100644 --- a/code/ui/ui_atoms.cpp +++ b/code/ui/ui_atoms.cpp @@ -279,7 +279,7 @@ void UI_Init( int apiVersion, uiimport_t *uiimport, qboolean inGameLoad ) ui.Cvar_Create( "ui_prisonerobj_currtotal", "0", CVAR_ROM|CVAR_SAVEGAME|CVAR_NORESTART); ui.Cvar_Create( "ui_prisonerobj_mintotal", "0", CVAR_ROM|CVAR_SAVEGAME|CVAR_NORESTART); - ui.Cvar_Create( "g_dismemberment", "3", CVAR_ARCHIVE );//0 = none, 1 = arms and hands, 2 = legs, 3 = waist and head, 4 = mega dismemberment + ui.Cvar_Create( "g_dismemberment", "3", CVAR_ARCHIVE );//0 = none, 1 = arms and hands, 2 = legs, 3 = waist and head ui.Cvar_Create( "cg_gunAutoFirst", "1", CVAR_ARCHIVE ); ui.Cvar_Create( "cg_crosshairIdentifyTarget", "1", CVAR_ARCHIVE ); ui.Cvar_Create( "g_subtitles", "0", CVAR_ARCHIVE ); diff --git a/code/ui/ui_local.h b/code/ui/ui_local.h index ea681d7..67fc8dc 100644 --- a/code/ui/ui_local.h +++ b/code/ui/ui_local.h @@ -165,6 +165,8 @@ typedef struct { int moveAnimTime; int languageCount; int languageCountIndex; + + int forcePowerLevel[NUM_FORCE_POWERS]; } uiInfo_t; extern uiInfo_t uiInfo; diff --git a/code/ui/ui_main.cpp b/code/ui/ui_main.cpp index 9080a7b..2d6263b 100644 --- a/code/ui/ui_main.cpp +++ b/code/ui/ui_main.cpp @@ -128,6 +128,9 @@ static void UI_DecrementForcePowerLevel( void ); static void UI_DecrementCurrentForcePower ( void ); static void UI_ShutdownForceHelp( void ); static void UI_ForceHelpActive( void ); +static void UI_DemoSetForceLevels( void ); +static void UI_RecordForceLevels( void ); +static void UI_RecordWeapons( void ); static void UI_ResetCharacterListBoxes( void ); @@ -1226,6 +1229,18 @@ static qboolean UI_RunMenuScript ( const char **args ) { UI_ForceHelpActive(); } + else if (Q_stricmp(name, "demosetforcelevels") == 0) + { + UI_DemoSetForceLevels(); + } + else if (Q_stricmp(name, "recordforcelevels") == 0) + { + UI_RecordForceLevels(); + } + else if (Q_stricmp(name, "recordweapons") == 0) + { + UI_RecordWeapons(); + } else if (Q_stricmp(name, "showforceleveldesc") == 0) { const char *forceName; @@ -1807,8 +1822,6 @@ UI_FeederSelection */ static void UI_FeederSelection(float feederID, int index, itemDef_t *item) { - static char info[MAX_STRING_CHARS]; - if (feederID == FEEDER_SAVEGAMES) { s_savegame.currentLine = index; @@ -2574,9 +2587,21 @@ void _UI_Init( qboolean inGameLoad ) { menuSet = "ui/menus.txt"; } + if ( Cvar_VariableIntegerValue("com_demo") ) + { + menuSet = "ui/demo_menus.txt"; + } + if (inGameLoad) { - UI_LoadMenus("ui/ingame.txt", qtrue); + if ( Cvar_VariableIntegerValue("com_demo") ) + { + UI_LoadMenus("ui/demo_ingame.txt", qtrue); + } + else + { + UI_LoadMenus("ui/ingame.txt", qtrue); + } } else { @@ -2887,6 +2912,12 @@ void UI_Load(void) menuSet = "ui/menus.txt"; } + if ( Cvar_VariableIntegerValue("com_demo") ) + { + menuSet = "ui/demo_menus.txt"; + } + + String_Init(); @@ -4273,12 +4304,12 @@ static void UI_UpdateFightingStyleChoices ( void ) if (!strcmpi("staff",Cvar_VariableString ( "ui_saber_type" ))) { Cvar_Set ( "ui_fightingstylesallowed", "0" ); - Cvar_Set ( "ui_newfightingstyle", "1" ); // Default, MEDIUM + Cvar_Set ( "ui_newfightingstyle", "4" ); // SS_STAFF } else if (!strcmpi("dual",Cvar_VariableString ( "ui_saber_type" ))) { Cvar_Set ( "ui_fightingstylesallowed", "0" ); - Cvar_Set ( "ui_newfightingstyle", "1" ); // Default, MEDIUM + Cvar_Set ( "ui_newfightingstyle", "3" ); // SS_DUAL } else { @@ -4424,6 +4455,7 @@ static void UI_InitAllocForcePowers ( const char *forceName ) menuDef_t *menu; itemDef_t *item; short forcePowerI=0; + int forcelevel; menu = Menu_GetFocused(); // Get current menu @@ -4437,14 +4469,22 @@ static void UI_InitAllocForcePowers ( const char *forceName ) return; } + int com_demo = Cvar_VariableIntegerValue( "com_demo" ); + client_t* cl = &svs.clients[0]; // 0 because only ever us as a player - if (!cl) + // NOTE: this UIScript can be called outside the running game now, so handle that case + // by getting info frim UIInfo instead of PlayerState + if( cl && !com_demo ) { - return; + playerState_t* pState = cl->gentity->client; + forcelevel = pState->forcePowerLevel[powerEnums[forcePowerI].powerEnum]; } - playerState_t* pState = cl->gentity->client; - + else + { // always want this to happen in demo mode + forcelevel = uiInfo.forcePowerLevel[powerEnums[forcePowerI].powerEnum]; + } + char itemName[128]; Com_sprintf (itemName, sizeof(itemName), "%s_hexpic", powerEnums[forcePowerI].title); item = (itemDef_s *) Menu_FindItemByName(menu, itemName); @@ -4452,19 +4492,20 @@ static void UI_InitAllocForcePowers ( const char *forceName ) if (item) { char itemGraphic[128]; - Com_sprintf (itemGraphic, sizeof(itemGraphic), "gfx/menus/hex_pattern_%d",pState->forcePowerLevel[powerEnums[forcePowerI].powerEnum]); + Com_sprintf (itemGraphic, sizeof(itemGraphic), "gfx/menus/hex_pattern_%d",forcelevel); item->window.background = ui.R_RegisterShaderNoMip(itemGraphic); // If maxed out on power - don't allow update -/* if (pState->forcePowerLevel[powerEnums[forcePowerI].powerEnum]>=3) + if (forcelevel>=3) { Com_sprintf (itemName, sizeof(itemName), "%s_fbutton", powerEnums[forcePowerI].title); item = (itemDef_s *) Menu_FindItemByName(menu, itemName); - if (item) // This is okay, because core powers don't have a hex button + if (item) { - item->window.flags &= ~WINDOW_VISIBLE; + item->action = 0; //you are bad, no action for you! + item->descText = 0; //no desc either! } - } */ + } } // Set weapons button to inactive @@ -4605,6 +4646,141 @@ static void UI_ForceHelpActive( void ) } } +// Set the force levels depending on the level chosen +static void UI_DemoSetForceLevels( void ) +{ + menuDef_t *menu; + + menu = Menu_GetFocused(); // Get current menu + + if (!menu) + { + return; + } + + char buffer[MAX_STRING_CHARS]; + + client_t* cl = &svs.clients[0]; // 0 because only ever us as a player + playerState_t* pState = NULL; + if( cl ) + { + pState = cl->gentity->client; + } + + ui.Cvar_VariableStringBuffer( "ui_demo_level", buffer, sizeof(buffer)); + if( Q_stricmp( buffer, "t1_sour")==0 ) + {// NOTE : always set the uiInfo powers + // level 1 in all core powers + uiInfo.forcePowerLevel[FP_LEVITATION]=1; + uiInfo.forcePowerLevel[FP_SPEED]=1; + uiInfo.forcePowerLevel[FP_PUSH]=1; + uiInfo.forcePowerLevel[FP_PULL]=1; + uiInfo.forcePowerLevel[FP_SEE]=1; + uiInfo.forcePowerLevel[FP_SABER_OFFENSE]=1; + uiInfo.forcePowerLevel[FP_SABER_DEFENSE]=1; + uiInfo.forcePowerLevel[FP_SABERTHROW]=1; + // plus these extras + uiInfo.forcePowerLevel[FP_HEAL]=1; + uiInfo.forcePowerLevel[FP_TELEPATHY]=1; + uiInfo.forcePowerLevel[FP_GRIP]=1; + + // and set the rest to zero + uiInfo.forcePowerLevel[FP_ABSORB]=0; + uiInfo.forcePowerLevel[FP_PROTECT]=0; + uiInfo.forcePowerLevel[FP_DRAIN]=0; + uiInfo.forcePowerLevel[FP_LIGHTNING]=0; + uiInfo.forcePowerLevel[FP_RAGE]=0; + } + else + { + // level 3 in all core powers + uiInfo.forcePowerLevel[FP_LEVITATION]=3; + uiInfo.forcePowerLevel[FP_SPEED]=3; + uiInfo.forcePowerLevel[FP_PUSH]=3; + uiInfo.forcePowerLevel[FP_PULL]=3; + uiInfo.forcePowerLevel[FP_SEE]=3; + uiInfo.forcePowerLevel[FP_SABER_OFFENSE]=3; + uiInfo.forcePowerLevel[FP_SABER_DEFENSE]=3; + uiInfo.forcePowerLevel[FP_SABERTHROW]=3; + + // plus these extras + uiInfo.forcePowerLevel[FP_HEAL]=1; + uiInfo.forcePowerLevel[FP_TELEPATHY]=1; + uiInfo.forcePowerLevel[FP_GRIP]=2; + uiInfo.forcePowerLevel[FP_LIGHTNING]=1; + uiInfo.forcePowerLevel[FP_PROTECT]=1; + + // and set the rest to zero + + uiInfo.forcePowerLevel[FP_ABSORB]=0; + uiInfo.forcePowerLevel[FP_DRAIN]=0; + uiInfo.forcePowerLevel[FP_RAGE]=0; + } + + if (pState) + {//i am carrying over from a previous level, so get the increased power! (non-core only) + uiInfo.forcePowerLevel[FP_HEAL] = max(pState->forcePowerLevel[FP_HEAL], uiInfo.forcePowerLevel[FP_HEAL]); + uiInfo.forcePowerLevel[FP_TELEPATHY]=max(pState->forcePowerLevel[FP_TELEPATHY], uiInfo.forcePowerLevel[FP_TELEPATHY]); + uiInfo.forcePowerLevel[FP_GRIP]=max(pState->forcePowerLevel[FP_GRIP], uiInfo.forcePowerLevel[FP_GRIP]); + uiInfo.forcePowerLevel[FP_LIGHTNING]=max(pState->forcePowerLevel[FP_LIGHTNING], uiInfo.forcePowerLevel[FP_LIGHTNING]); + uiInfo.forcePowerLevel[FP_PROTECT]=max(pState->forcePowerLevel[FP_PROTECT], uiInfo.forcePowerLevel[FP_PROTECT]); + + uiInfo.forcePowerLevel[FP_ABSORB]=max(pState->forcePowerLevel[FP_ABSORB], uiInfo.forcePowerLevel[FP_ABSORB]); + uiInfo.forcePowerLevel[FP_DRAIN]=max(pState->forcePowerLevel[FP_DRAIN], uiInfo.forcePowerLevel[FP_DRAIN]); + uiInfo.forcePowerLevel[FP_RAGE]=max(pState->forcePowerLevel[FP_RAGE], uiInfo.forcePowerLevel[FP_RAGE]); + } +} + +// record the force levels into a cvar so when restoring player from map transition +// the force levels are set up correctly +static void UI_RecordForceLevels( void ) +{ + menuDef_t *menu; + + menu = Menu_GetFocused(); // Get current menu + + if (!menu) + { + return; + } + + const char *s2 = ""; + int i; + for (i=0;i< NUM_FORCE_POWERS; i++) + { + s2 = va("%s %i",s2, uiInfo.forcePowerLevel[i]); + } + Cvar_Set( "demo_playerfplvl", s2 ); + +} + +// record the weapons into a cvar so when restoring player from map transition +// the force levels are set up correctly +static void UI_RecordWeapons( void ) +{ + menuDef_t *menu; + + menu = Menu_GetFocused(); // Get current menu + + if (!menu) + { + return; + } + + const char *s2 = ""; + + int wpns = 0; + // always add blaster and saber + wpns |= (1<gentity->client; + forcelevel = pState->forcePowerLevel[powerEnums[uiInfo.forcePowerUpdated].powerEnum]; + } + else + { // always want this to happen in demo mode + forcelevel = uiInfo.forcePowerLevel[powerEnums[uiInfo.forcePowerUpdated].powerEnum]; } - - playerState_t* pState = cl->gentity->client; - if (uiInfo.forcePowerUpdated == FP_UPDATED_NONE) { @@ -4752,17 +4934,26 @@ static void UI_DecrementCurrentForcePower ( void ) DC->startLocalSound(uiInfo.uiDC.Assets.forceUnchosenSound, CHAN_AUTO ); - if (pState->forcePowerLevel[powerEnums[uiInfo.forcePowerUpdated].powerEnum]>0) + if (forcelevel>0) { - pState->forcePowerLevel[powerEnums[uiInfo.forcePowerUpdated].powerEnum]--; // Decrement it - // Turn off power if level is 0 - if (pState->forcePowerLevel[powerEnums[uiInfo.forcePowerUpdated].powerEnum]<1) + if( pState && !com_demo ) { - pState->forcePowersKnown &= ~( 1 << powerEnums[uiInfo.forcePowerUpdated].powerEnum ); + pState->forcePowerLevel[powerEnums[uiInfo.forcePowerUpdated].powerEnum]--; // Decrement it + forcelevel = pState->forcePowerLevel[powerEnums[uiInfo.forcePowerUpdated].powerEnum]; + // Turn off power if level is 0 + if (pState->forcePowerLevel[powerEnums[uiInfo.forcePowerUpdated].powerEnum]<1) + { + pState->forcePowersKnown &= ~( 1 << powerEnums[uiInfo.forcePowerUpdated].powerEnum ); + } + } + else + { // always want this to happen in demo mode + uiInfo.forcePowerLevel[powerEnums[uiInfo.forcePowerUpdated].powerEnum]--; // Decrement it + forcelevel = uiInfo.forcePowerLevel[powerEnums[uiInfo.forcePowerUpdated].powerEnum]; } } - UI_SetHexPicLevel( menu,uiInfo.forcePowerUpdated,pState->forcePowerLevel[powerEnums[uiInfo.forcePowerUpdated].powerEnum],qfalse ); + UI_SetHexPicLevel( menu,uiInfo.forcePowerUpdated,forcelevel,qfalse ); UI_ShowForceLevelDesc ( powerEnums[uiInfo.forcePowerUpdated].title ); @@ -4781,7 +4972,7 @@ static void UI_DecrementCurrentForcePower ( void ) // Show point has not been allocated UI_SetPowerTitleText( qfalse); - // Make weapons button active + // Make weapons button inactive UI_ForcePowerWeaponsButton(qfalse); // Hide the deallocate button @@ -4808,6 +4999,7 @@ static void UI_DecrementCurrentForcePower ( void ) uiInfo.forcePowerUpdated = FP_UPDATED_NONE; // It's as if nothing happened. } + void Item_MouseEnter(itemDef_t *item, float x, float y); // Try to increment force power level (Used by Force Power Allocation screen) @@ -4829,16 +5021,23 @@ static void UI_AffectForcePowerLevel ( const char *forceName ) return; } + int com_demo = Cvar_VariableIntegerValue( "com_demo" ); // Get player state client_t* cl = &svs.clients[0]; // 0 because only ever us as a player - - if (!cl) // No client, get out + playerState_t* pState = NULL; + int forcelevel; + if( cl && !com_demo) { - return; + pState = cl->gentity->client; + forcelevel = pState->forcePowerLevel[powerEnums[forcePowerI].powerEnum]; } - playerState_t* pState = cl->gentity->client; + else + { // always want this to happen in demo mode + forcelevel = uiInfo.forcePowerLevel[powerEnums[forcePowerI].powerEnum]; + } + - if (pState->forcePowerLevel[powerEnums[forcePowerI].powerEnum]>2) + if (forcelevel>2) { // Too big, can't be incremented return; } @@ -4848,10 +5047,19 @@ static void UI_AffectForcePowerLevel ( const char *forceName ) uiInfo.forcePowerUpdated = forcePowerI; // Remember which power was updated - pState->forcePowerLevel[powerEnums[forcePowerI].powerEnum]++; // Increment it - pState->forcePowersKnown |= ( 1 << powerEnums[forcePowerI].powerEnum ); + if( pState && !com_demo ) + { + pState->forcePowerLevel[powerEnums[forcePowerI].powerEnum]++; // Increment it + pState->forcePowersKnown |= ( 1 << powerEnums[forcePowerI].powerEnum ); + forcelevel = pState->forcePowerLevel[powerEnums[forcePowerI].powerEnum]; + } + else + { // always want this to happen in demo mode + uiInfo.forcePowerLevel[powerEnums[forcePowerI].powerEnum]++; // Increment it + forcelevel = uiInfo.forcePowerLevel[powerEnums[forcePowerI].powerEnum]; + } - UI_SetHexPicLevel( menu,uiInfo.forcePowerUpdated,pState->forcePowerLevel[powerEnums[forcePowerI].powerEnum],qtrue ); + UI_SetHexPicLevel( menu,uiInfo.forcePowerUpdated,forcelevel,qtrue ); UI_ShowForceLevelDesc ( forceName ); @@ -4888,7 +5096,6 @@ static void UI_AffectForcePowerLevel ( const char *forceName ) // Just grab an item to hand it to the function. item = (itemDef_s *) Menu_FindItemByName(menu, "deallocate_fbutton"); - if (item) { // Show all icons as greyed-out @@ -5046,6 +5253,14 @@ static void UI_UpdateFightingStyle ( void ) { saberStyle = SS_STRONG; } + else if (fightingStyle == 3) + { + saberStyle = SS_DUAL; + } + else if (fightingStyle == 4) + { + saberStyle = SS_STAFF; + } else // 0 is Fast { saberStyle = SS_FAST; @@ -5445,25 +5660,25 @@ static void UI_AddWeaponSelection ( const int weaponIndex, const int ammoIndex, // Get player state client_t* cl = &svs.clients[0]; // 0 because only ever us as a player - if (!cl) // No client, get out + // NOTE : this UIScript can now be run from outside the game, so don't + // return out here, just skip this part + if (cl) { - return; - } - - // Add weapon - if (cl->gentity && cl->gentity->client) - { - playerState_t* pState = cl->gentity->client; - - if ((weaponIndex>0) && (weaponIndexgentity && cl->gentity->client) { - pState->stats[ STAT_WEAPONS ] |= ( 1 << weaponIndex ); - } + playerState_t* pState = cl->gentity->client; - // Give them ammo too - if ((ammoIndex>0) && (ammoIndexammo[ ammoIndex ] = ammoAmount; + if ((weaponIndex>0) && (weaponIndexstats[ STAT_WEAPONS ] |= ( 1 << weaponIndex ); + } + + // Give them ammo too + if ((ammoIndex>0) && (ammoIndexammo[ ammoIndex ] = ammoAmount; + } } } @@ -5549,29 +5764,31 @@ static void UI_RemoveWeaponSelection ( const int weaponSelectionIndex ) // Get player state client_t* cl = &svs.clients[0]; // 0 because only ever us as a player - if (!cl) // No client, get out + // NOTE : this UIScript can now be run from outside the game, so don't + // return out here, just skip this part + if (cl) // No client, get out { - return; - } - // Remove weapon - if (cl->gentity && cl->gentity->client) - { - playerState_t* pState = cl->gentity->client; - - if ((weaponIndex>0) && (weaponIndexgentity && cl->gentity->client) { - pState->stats[ STAT_WEAPONS ] &= ~( 1 << weaponIndex ); - } + playerState_t* pState = cl->gentity->client; - // Remove ammo too - if ((ammoIndex>0) && (ammoIndex0) && (weaponIndexammo[ ammoIndex ] = 0; + pState->stats[ STAT_WEAPONS ] &= ~( 1 << weaponIndex ); + } + + // Remove ammo too + if ((ammoIndex>0) && (ammoIndexammo[ ammoIndex ] = 0; + } } } + } // Now do a little clean up @@ -5731,25 +5948,25 @@ static void UI_AddThrowWeaponSelection ( const int weaponIndex, const int ammoIn client_t* cl = &svs.clients[0]; // 0 because only ever us as a player - if (!cl) // No client, get out + // NOTE : this UIScript can now be run from outside the game, so don't + // return out here, just skip this part + if (cl) // No client, get out { - return; - } - - // Add weapon - if (cl->gentity && cl->gentity->client) - { - playerState_t* pState = cl->gentity->client; - - if ((weaponIndex>0) && (weaponIndexgentity && cl->gentity->client) { - pState->stats[ STAT_WEAPONS ] |= ( 1 << weaponIndex ); - } + playerState_t* pState = cl->gentity->client; - // Give them ammo too - if ((ammoIndex>0) && (ammoIndexammo[ ammoIndex ] = ammoAmount; + if ((weaponIndex>0) && (weaponIndexstats[ STAT_WEAPONS ] |= ( 1 << weaponIndex ); + } + + // Give them ammo too + if ((ammoIndex>0) && (ammoIndexammo[ ammoIndex ] = ammoAmount; + } } } @@ -5810,27 +6027,27 @@ static void UI_RemoveThrowWeaponSelection ( void ) client_t* cl = &svs.clients[0]; // 0 because only ever us as a player - if (!cl) // No client, get out + // NOTE : this UIScript can now be run from outside the game, so don't + // return out here, just skip this part + if (cl) // No client, get out { - return; - } - - // Remove weapon - if (cl->gentity && cl->gentity->client) - { - playerState_t* pState = cl->gentity->client; - - if ((uiInfo.selectedThrowWeapon>0) && (uiInfo.selectedThrowWeapongentity && cl->gentity->client) { - pState->stats[ STAT_WEAPONS ] &= ~( 1 << uiInfo.selectedThrowWeapon ); - } + playerState_t* pState = cl->gentity->client; - // Remove ammo too - if ((uiInfo.selectedThrowWeaponAmmoIndex>0) && (uiInfo.selectedThrowWeaponAmmoIndexammo[ uiInfo.selectedThrowWeaponAmmoIndex ] = 0; - } + if ((uiInfo.selectedThrowWeapon>0) && (uiInfo.selectedThrowWeaponstats[ STAT_WEAPONS ] &= ~( 1 << uiInfo.selectedThrowWeapon ); + } + // Remove ammo too + if ((uiInfo.selectedThrowWeaponAmmoIndex>0) && (uiInfo.selectedThrowWeaponAmmoIndexammo[ uiInfo.selectedThrowWeaponAmmoIndex ] = 0; + } + + } } // Now do a little clean up diff --git a/code/ui/ui_saber.cpp b/code/ui/ui_saber.cpp index a2f5768..fbd319c 100644 --- a/code/ui/ui_saber.cpp +++ b/code/ui/ui_saber.cpp @@ -14,7 +14,7 @@ USER INTERFACE SABER LOADING & DISPLAY CODE #include "ui_shared.h" #include "../ghoul2/G2.h" -#define MAX_SABER_DATA_SIZE 0x8000 +#define MAX_SABER_DATA_SIZE 0x80000 // On Xbox, static linking lets us steal the buffer from wp_saberLoad // Just make sure that the saber data size is the same #ifdef _XBOX @@ -181,6 +181,39 @@ int UI_SaberNumBladesForSaber( const char *saberName ) return numBlades; } +qboolean UI_SaberShouldDrawBlade( const char *saberName, int bladeNum ) +{ + int bladeStyle2Start = 0, noBlade = 0; + char bladeStyle2StartString[8]={0}; + char noBladeString[8]={0}; + UI_SaberParseParm( saberName, "bladeStyle2Start", bladeStyle2StartString ); + if ( bladeStyle2StartString + && bladeStyle2StartString[0] ) + { + bladeStyle2Start = atoi( bladeStyle2StartString ); + } + if ( bladeStyle2Start + && bladeNum >= bladeStyle2Start ) + {//use second blade style + UI_SaberParseParm( saberName, "noBlade2", noBladeString ); + if ( noBladeString + && noBladeString[0] ) + { + noBlade = atoi( noBladeString ); + } + } + else + {//use first blade style + UI_SaberParseParm( saberName, "noBlade", noBladeString ); + if ( noBladeString + && noBladeString[0] ) + { + noBlade = atoi( noBladeString ); + } + } + return ((qboolean)(noBlade==0)); +} + float UI_SaberBladeLengthForSaber( const char *saberName, int bladeNum ) { char lengthString[8]={0}; @@ -795,7 +828,10 @@ void UI_SaberDrawBlades( itemDef_t *item, vec3_t origin, float curYaw ) saberType_t saberType = TranslateSaberType( saberTypeString ); for ( int curBlade = 0; curBlade < numBlades; curBlade++ ) { - UI_SaberDrawBlade( item, saber, saberModel, saberType, origin, curYaw, curBlade ); + if ( UI_SaberShouldDrawBlade( saber, curBlade ) ) + { + UI_SaberDrawBlade( item, saber, saberModel, saberType, origin, curYaw, curBlade ); + } } } } diff --git a/code/ui/ui_shared.cpp b/code/ui/ui_shared.cpp index 8f70cd1..e47ca9f 100644 --- a/code/ui/ui_shared.cpp +++ b/code/ui/ui_shared.cpp @@ -2739,7 +2739,13 @@ qboolean Script_SetCvar(itemDef_t *item, const char **args) const char *cvar, *val; if (String_Parse(args, &cvar) && String_Parse(args, &val)) { - DC->setCVar(cvar, val); + if(!stricmp(val,"(NULL)")) + { + DC->setCVar(cvar, ""); + } + else { + DC->setCVar(cvar, val); + } } return qtrue; @@ -5331,13 +5337,21 @@ menuDef_t *Menus_ActivateByName(const char *p) } + const int com_demo = Cvar_VariableIntegerValue( "com_demo" ); if (!m) { // A hack so we don't have to load all three mission menus before we know what tier we're on if (!Q_stricmp( p, "ingameMissionSelect1" ) ) { - UI_LoadMenus("ui/tier1.txt",qfalse); - Menus_CloseAll(); - Menus_OpenByName("ingameMissionSelect1"); + if ( com_demo ) + { + Menus_OpenByName("demo_MissionSelect"); + } + else + { + UI_LoadMenus("ui/tier1.txt",qfalse); + Menus_CloseAll(); + Menus_OpenByName("ingameMissionSelect1"); + } } else if (!Q_stricmp( p, "ingameMissionSelect2" ) ) { @@ -5356,26 +5370,53 @@ menuDef_t *Menus_ActivateByName(const char *p) Com_Printf(S_COLOR_YELLOW"WARNING: Menus_ActivateByName: Unable to find menu '%s'\n",p); } } - - // First time, show force select instructions - if (!Q_stricmp( p, "ingameForceSelect" ) ) + + if( !com_demo ) { - int tier_storyinfo = Cvar_VariableIntegerValue( "tier_storyinfo" ); - - if (tier_storyinfo==1) + // First time, show force select instructions + if (!Q_stricmp( p, "ingameForceSelect" ) ) { - Menus_OpenByName("ingameForceHelp"); + int tier_storyinfo = Cvar_VariableIntegerValue( "tier_storyinfo" ); + + if (tier_storyinfo==1) + { + Menus_OpenByName("ingameForceHelp"); + } + } + + // First time, show weapons select instructions + if (!Q_stricmp( p, "ingameWpnSelect" ) ) + { + int tier_storyinfo = Cvar_VariableIntegerValue( "tier_storyinfo" ); + + if (tier_storyinfo==1) + { + Menus_OpenByName("ingameWpnSelectHelp"); + } } } - - // First time, show weapons select instructions - if (!Q_stricmp( p, "ingameWpnSelect" ) ) + else // demo { - int tier_storyinfo = Cvar_VariableIntegerValue( "tier_storyinfo" ); - - if (tier_storyinfo==1) + // First time, show force select instructions + if (!Q_stricmp( p, "demo_ForceSelect" ) ) { - Menus_OpenByName("ingameWpnSelectHelp"); + int tier_storyinfo = Cvar_VariableIntegerValue( "tier_storyinfo" ); + + if (!tier_storyinfo) + { + Menus_OpenByName("ingameForceHelp"); + } + } + + // First time, show weapons select instructions + if (!Q_stricmp( p, "demo_WpnSelect" ) ) + { + int tier_storyinfo = Cvar_VariableIntegerValue( "tier_storyinfo" ); + + if (!tier_storyinfo) + { + Menus_OpenByName("ingameWpnSelectHelp"); + } } } diff --git a/code/ui/vssver.scc b/code/ui/vssver.scc index 4cc024e..9149b20 100644 Binary files a/code/ui/vssver.scc and b/code/ui/vssver.scc differ diff --git a/code/unix/vssver.scc b/code/unix/vssver.scc index 19a4372..d09a34b 100644 Binary files a/code/unix/vssver.scc and b/code/unix/vssver.scc differ diff --git a/code/vssver.scc b/code/vssver.scc index 8279590..66e14d8 100644 Binary files a/code/vssver.scc and b/code/vssver.scc differ diff --git a/code/win32/AutoVersion.h b/code/win32/AutoVersion.h index 5d7f440..146c82f 100644 --- a/code/win32/AutoVersion.h +++ b/code/win32/AutoVersion.h @@ -3,15 +3,21 @@ #define VERSION_MAJOR_RELEASE 1 #define VERSION_MINOR_RELEASE 0 -#define VERSION_EXTERNAL_BUILD 0 +#define VERSION_EXTERNAL_BUILD 1 #define VERSION_INTERNAL_BUILD 0 -#define VERSION_STRING "1, 0, 0, 0" -#define VERSION_STRING_DOTTED "1.0.0.0" +#define VERSION_STRING "1, 0, 1, 0" +#define VERSION_STRING_DOTTED "1.0.1.0" -#define VERSION_BUILD_NUMBER 73 +#define VERSION_BUILD_NUMBER 80 // BEGIN COMMENTS +// 1.0.1.0 10/24/2003 16:29:53 jmonroe patch rc1 +// 1.0.0.4 10/17/2003 17:45:31 jmonroe fix ati texture rect hack +// 1.0.0.3 08/29/2003 18:17:37 jmonroe hide saberrealisticcombat and g_dismemberment debug value +// 1.0.0.2 08/12/2003 17:48:44 jmonroe demo, take 3 +// 1.0.0.1 08/07/2003 19:53:23 jmonroe demo round 2 +// 1.0.0.0 08/01/2003 16:59:44 jmonroe push demo code changes // 1.0.0.0 07/21/2003 16:09:23 jmonroe going gold // 0.0.12.0 07/20/2003 19:04:44 jmonroe build 0.12 for qa // 0.0.11.0 07/19/2003 15:30:08 jmonroe stuff diff --git a/code/win32/FeelIt/vssver.scc b/code/win32/FeelIt/vssver.scc index 0e2ef87..7b6e31b 100644 Binary files a/code/win32/FeelIt/vssver.scc and b/code/win32/FeelIt/vssver.scc differ diff --git a/code/win32/vssver.scc b/code/win32/vssver.scc index 04d9926..585c109 100644 Binary files a/code/win32/vssver.scc and b/code/win32/vssver.scc differ diff --git a/code/win32/win_glimp.cpp b/code/win32/win_glimp.cpp index ee7445e..ad9034c 100644 --- a/code/win32/win_glimp.cpp +++ b/code/win32/win_glimp.cpp @@ -1353,17 +1353,17 @@ static void GLW_InitExtensions( void ) } // Figure out which texture rectangle extension to use. - // TOTAL HACK!!! This will need to be fixed. - // FIXMEFIXMEFIXME! bool bTexRectSupported = false; - if ( strstr( glConfig.extensions_string, "GL_EXT_texture_rectangle" ) ) + if ( strnicmp( glConfig.vendor_string, "ATI Technologies",16 )==0 + && strnicmp( glConfig.version_string, "1.3.3",5 )==0 + && glConfig.version_string[5] < '9' ) //1.3.34 and 1.3.37 and 1.3.38 are broken for sure, 1.3.39 is not { g_bTextureRectangleHack = true; - bTexRectSupported = true; } - else if ( strstr( glConfig.extensions_string, "GL_NV_texture_rectangle" ) ) + + if ( strstr( glConfig.extensions_string, "GL_NV_texture_rectangle" ) + || strstr( glConfig.extensions_string, "GL_EXT_texture_rectangle" ) ) { - g_bTextureRectangleHack = false; bTexRectSupported = true; } diff --git a/code/win32/win_main.cpp b/code/win32/win_main.cpp index 386dc46..ee85260 100644 --- a/code/win32/win_main.cpp +++ b/code/win32/win_main.cpp @@ -937,13 +937,13 @@ void Sys_In_Restart_f( void ) { IN_Init(); } -static inline bool Sys_IsExpired() +static bool Sys_IsExpired() { #if 0 // sec min Hr Day Mon Yr - struct tm t_valid_start = { 0, 0, 8, 5, 8, 103 }; //zero based months! + struct tm t_valid_start = { 0, 0, 8, 23, 6, 103 }; //zero based months! // sec min Hr Day Mon Yr - struct tm t_valid_end = { 0, 0, 20, 13, 8, 103 }; + struct tm t_valid_end = { 0, 0, 20, 30, 6, 103 }; // struct tm t_valid_end = t_valid_start; // t_valid_end.tm_mday += 8; time_t startTime = mktime( &t_valid_start); diff --git a/code/x_exe/mssccprj.scc b/code/x_exe/mssccprj.scc index 3bfb92d..431d5b4 100644 --- a/code/x_exe/mssccprj.scc +++ b/code/x_exe/mssccprj.scc @@ -1,5 +1,5 @@ SCC = This is a Source Code Control file [x_exe.vcproj] -SCC_Aux_Path = "\\ravendata1\vss\central_code" +SCC_Aux_Path = "\\ravendata1\VSS\central_code" SCC_Project_Name = "$/jedi/code/x_exe", YUHAAAAA diff --git a/code/x_exe/vssver.scc b/code/x_exe/vssver.scc index 4e78126..10c5ecc 100644 Binary files a/code/x_exe/vssver.scc and b/code/x_exe/vssver.scc differ diff --git a/code/x_game/mssccprj.scc b/code/x_game/mssccprj.scc index c5430d3..58a6022 100644 --- a/code/x_game/mssccprj.scc +++ b/code/x_game/mssccprj.scc @@ -1,5 +1,5 @@ SCC = This is a Source Code Control file [x_game.vcproj] -SCC_Aux_Path = "\\ravendata1\vss\central_code" +SCC_Aux_Path = "\\ravendata1\VSS\central_code" SCC_Project_Name = "$/jedi/code/x_game", XUHAAAAA diff --git a/code/x_game/vssver.scc b/code/x_game/vssver.scc index fd18bfa..05e60b0 100644 Binary files a/code/x_game/vssver.scc and b/code/x_game/vssver.scc differ diff --git a/code/zlib32/vssver.scc b/code/zlib32/vssver.scc index 4cf098d..e53c57a 100644 Binary files a/code/zlib32/vssver.scc and b/code/zlib32/vssver.scc differ diff --git a/codemp/Debug/vssver.scc b/codemp/Debug/vssver.scc index 796ec67..cc8d206 100644 Binary files a/codemp/Debug/vssver.scc and b/codemp/Debug/vssver.scc differ diff --git a/codemp/RMG/vssver.scc b/codemp/RMG/vssver.scc index 993f7cb..b6b5629 100644 Binary files a/codemp/RMG/vssver.scc and b/codemp/RMG/vssver.scc differ diff --git a/codemp/Ratl/vssver.scc b/codemp/Ratl/vssver.scc index 1139239..892935e 100644 Binary files a/codemp/Ratl/vssver.scc and b/codemp/Ratl/vssver.scc differ diff --git a/codemp/Ravl/vssver.scc b/codemp/Ravl/vssver.scc index e1f2b8f..2337e5a 100644 Binary files a/codemp/Ravl/vssver.scc and b/codemp/Ravl/vssver.scc differ diff --git a/codemp/Splines/mssccprj.scc b/codemp/Splines/mssccprj.scc index ed50979..0e0a7a5 100644 --- a/codemp/Splines/mssccprj.scc +++ b/codemp/Splines/mssccprj.scc @@ -1,5 +1,5 @@ SCC = This is a Source Code Control file [Splines.dsp] -SCC_Aux_Path = "\\ravendata1\vss\central_code" +SCC_Aux_Path = "\\ravendata1\VSS\central_code" SCC_Project_Name = "$/jedi/codemp/Splines", CSAAAAAA diff --git a/codemp/Splines/vssver.scc b/codemp/Splines/vssver.scc index 8c927b7..83b495f 100644 Binary files a/codemp/Splines/vssver.scc and b/codemp/Splines/vssver.scc differ diff --git a/codemp/WinDed.vcproj b/codemp/WinDed.vcproj index 0bde5a3..e75b6e9 100644 --- a/codemp/WinDed.vcproj +++ b/codemp/WinDed.vcproj @@ -6,7 +6,7 @@ SccProjectName=""$/jedi/codemp", CAAAAAAA" SccAuxPath="" SccLocalPath="." - SccProvider="MSSCCI:SourceOffSite"> + SccProvider="MSSCCI:Microsoft Visual SourceSafe"> @@ -52,6 +52,9 @@ LinkIncremental="1" SuppressStartupBanner="TRUE" ProgramDatabaseFile=".\Release/jk2Ded.pdb" + GenerateMapFile="TRUE" + MapFileName="release\jampDed.map" + MapLines="TRUE" SubSystem="1" OptimizeReferences="2" EnableCOMDATFolding="2" diff --git a/codemp/botlib/mssccprj.scc b/codemp/botlib/mssccprj.scc index ddd41c1..e308a90 100644 --- a/codemp/botlib/mssccprj.scc +++ b/codemp/botlib/mssccprj.scc @@ -1,5 +1,5 @@ SCC = This is a Source Code Control file [botlib.vcproj] -SCC_Aux_Path = "\\ravendata1\vss\central_code" +SCC_Aux_Path = "\\ravendata1\VSS\central_code" SCC_Project_Name = "$/jedi/codemp/botlib", EAAAAAAA diff --git a/codemp/botlib/vssver.scc b/codemp/botlib/vssver.scc index 6b5dbb0..0f4dcde 100644 Binary files a/codemp/botlib/vssver.scc and b/codemp/botlib/vssver.scc differ diff --git a/codemp/cgame/cg_draw.c b/codemp/cgame/cg_draw.c index 8986c27..97a06e2 100644 --- a/codemp/cgame/cg_draw.c +++ b/codemp/cgame/cg_draw.c @@ -1802,10 +1802,16 @@ qboolean CG_CheckTargetVehicle( centity_t **pTargetVeh, float *alpha ) *alpha = 1.0f; + //FIXME: need to clear all of these when you die? if ( cg.predictedPlayerState.rocketLockIndex < ENTITYNUM_WORLD ) { targetNum = cg.predictedPlayerState.rocketLockIndex; } + else if ( cg.crosshairVehNum < ENTITYNUM_WORLD + && cg.time - cg.crosshairVehTime < 3000 ) + {//crosshair was on a vehicle in the last 3 seconds + targetNum = cg.crosshairVehNum; + } else if ( cg.crosshairClientNum < ENTITYNUM_WORLD ) { targetNum = cg.crosshairClientNum; @@ -2984,13 +2990,13 @@ static float CG_DrawEnemyInfo ( float y ) clientNum = cgs.duelWinner; } - ci = &cgs.clientinfo[ clientNum ]; - - if ( !ci ) + if ( clientNum >= MAX_CLIENTS || !(&cgs.clientinfo[ clientNum ]) ) { return y; } + ci = &cgs.clientinfo[ clientNum ]; + size = ICON_SIZE * 1.25; y += 5; @@ -4369,7 +4375,7 @@ void CG_DrawSiegeMessageNonMenu( const char *str ) trap_SP_GetStringTextString(str+1, text, sizeof(text)); str = text; } - CG_CenterPrint(str, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH); + CG_CenterPrint(str, SCREEN_HEIGHT * 0.20, BIGCHAR_WIDTH); } /* @@ -4873,6 +4879,14 @@ static void CG_DrawCrosshair( vec3_t worldPoint, int chEntValid ) { return; } + /* + if ( cg_drawingRocketLockThisFrame + && cg.snap->ps.m_iVehicleNum ) + {//in vehicle, rocket lock-on replaces crosshair + return; + } + */ + if ( cg_crosshairHealth.integer ) { vec4_t hcolor; @@ -5371,6 +5385,31 @@ void CG_SaberClashFlare( void ) trap_R_RegisterShader( "gfx/effects/saberFlare" )); } +void CG_DottedLine( float x1, float y1, float x2, float y2, float dotSize, int numDots, vec4_t color, float alpha ) +{ + float x, y, xDiff, yDiff, xStep, yStep; + vec4_t colorRGBA; + int dotNum = 0; + + VectorCopy4( color, colorRGBA ); + colorRGBA[3] = alpha; + + trap_R_SetColor( colorRGBA ); + + xDiff = x2-x1; + yDiff = y2-y1; + xStep = xDiff/(float)numDots; + yStep = yDiff/(float)numDots; + + for ( dotNum = 0; dotNum < numDots; dotNum++ ) + { + x = x1 + (xStep*dotNum) - (dotSize*0.5f); + y = y1 + (yStep*dotNum) - (dotSize*0.5f); + + CG_DrawPic( x, y, dotSize, dotSize, cgs.media.whiteShader ); + } +} + void CG_BracketEntity( centity_t *cent, float radius ) { trace_t tr; @@ -5378,6 +5417,7 @@ void CG_BracketEntity( centity_t *cent, float radius ) float len, size, lineLength, lineWidth; float x, y; clientInfo_t *local; + qboolean isEnemy = qfalse; VectorSubtract( cent->lerpOrigin, cg.refdef.vieworg, dif ); len = VectorNormalize( dif ); @@ -5412,19 +5452,31 @@ void CG_BracketEntity( centity_t *cent, float radius ) if ( cent->currentState.m_iVehicleNum //vehicle has a driver && cgs.clientinfo[ cent->currentState.m_iVehicleNum-1 ].infoValid ) { - if ( cgs.clientinfo[ cent->currentState.m_iVehicleNum-1 ].team == local->team ) + if ( cgs.gametype < GT_TEAM ) + {//ffa? + isEnemy = qtrue; + trap_R_SetColor ( g_color_table[ColorIndex(COLOR_RED)] ); + } + else if ( cgs.clientinfo[ cent->currentState.m_iVehicleNum-1 ].team == local->team ) { trap_R_SetColor ( g_color_table[ColorIndex(COLOR_GREEN)] ); } else { + isEnemy = qtrue; trap_R_SetColor ( g_color_table[ColorIndex(COLOR_RED)] ); } } else if ( cent->currentState.teamowner ) { - if ( cent->currentState.teamowner != cg.predictedPlayerState.persistant[PERS_TEAM] ) + if ( cgs.gametype < GT_TEAM ) + {//ffa? + isEnemy = qtrue; + trap_R_SetColor ( g_color_table[ColorIndex(COLOR_RED)] ); + } + else if ( cent->currentState.teamowner != cg.predictedPlayerState.persistant[PERS_TEAM] ) {// on enemy team + isEnemy = qtrue; trap_R_SetColor ( g_color_table[ColorIndex(COLOR_RED)] ); } else @@ -5489,6 +5541,62 @@ void CG_BracketEntity( centity_t *cent, float radius ) //vert CG_DrawPic( x+size-lineWidth, y+size-lineLength, lineWidth, lineLength, cgs.media.whiteShader ); } + //Lead Indicator... + if ( cg_drawVehLeadIndicator.integer ) + {//draw the lead indicator + if ( isEnemy ) + {//an enemy object + if ( cent->currentState.NPC_class == CLASS_VEHICLE ) + {//enemy vehicle + if ( !VectorCompare( cent->currentState.pos.trDelta, vec3_origin ) ) + {//enemy vehicle is moving + if ( cg.predictedPlayerState.m_iVehicleNum ) + {//I'm in a vehicle + centity_t *veh = &cg_entities[cg.predictedPlayerState.m_iVehicleNum]; + if ( veh //vehicle cent + && veh->m_pVehicle//vehicle + && veh->m_pVehicle->m_pVehicleInfo//vehicle stats + && veh->m_pVehicle->m_pVehicleInfo->weapon[0].ID > VEH_WEAPON_BASE )//valid vehicle weapon + { + vehWeaponInfo_t *vehWeapon = &g_vehWeaponInfo[veh->m_pVehicle->m_pVehicleInfo->weapon[0].ID]; + if ( vehWeapon + && vehWeapon->bIsProjectile//primary weapon's shot is a projectile + && !vehWeapon->bHasGravity//primary weapon's shot is not affected by gravity + && !vehWeapon->fHoming//primary weapon's shot is not homing + && vehWeapon->fSpeed )//primary weapon's shot has speed + {//our primary weapon's projectile has a speed + vec3_t vehDiff, vehLeadPos; + float vehDist, eta; + float leadX, leadY; + + VectorSubtract( cent->lerpOrigin, cg.predictedVehicleState.origin, vehDiff ); + vehDist = VectorNormalize( vehDiff ); + eta = (vehDist/vehWeapon->fSpeed);//how many seconds it would take for my primary weapon's projectile to get from my ship to theirs + //now extrapolate their position that number of seconds into the future based on their velocity + VectorMA( cent->lerpOrigin, eta, cent->currentState.pos.trDelta, vehLeadPos ); + //now we have where we should be aiming at, project that onto the screen at a 2D co-ord + if ( !CG_WorldCoordToScreenCoordFloat(cent->lerpOrigin, &x, &y) ) + {//off-screen, don't draw it + return; + } + if ( !CG_WorldCoordToScreenCoordFloat(vehLeadPos, &leadX, &leadY) ) + {//off-screen, don't draw it + //just draw the line + CG_DottedLine( x, y, leadX, leadY, 1, 10, g_color_table[ColorIndex(COLOR_RED)], 0.5f ); + return; + } + //draw a line from the ship's cur pos to the lead pos + CG_DottedLine( x, y, leadX, leadY, 1, 10, g_color_table[ColorIndex(COLOR_RED)], 0.5f ); + //now draw the lead indicator + trap_R_SetColor ( g_color_table[ColorIndex(COLOR_RED)] ); + CG_DrawPic( leadX-8, leadY-8, 16, 16, trap_R_RegisterShader( "gfx/menus/radar/lead" ) ); + } + } + } + } + } + } + } } qboolean CG_InFighter( void ) @@ -5634,6 +5742,7 @@ static void CG_DrawActivePowers(void) } } +//static qboolean cg_drawingRocketLockThisFrame = qfalse; //-------------------------------------------------------------- static void CG_DrawRocketLocking( int lockEntNum, int lockTime ) //-------------------------------------------------------------- @@ -5648,6 +5757,8 @@ static void CG_DrawRocketLocking( int lockEntNum, int lockTime ) int dif = (cg.time - cg.snap->ps.rocketLockTime)/lockTimeInterval; int i; +// cg_drawingRocketLockThisFrame = qfalse; + if (!cg.snap->ps.rocketLockTime) { return; @@ -5775,6 +5886,11 @@ static void CG_DrawRocketLocking( int lockEntNum, int lockTime ) sz = (1.0f - sz) * (1.0f - sz) * 32 + 6; + if ( cg.snap->ps.m_iVehicleNum ) + { + sz *= 2.0f; + } + cy += sz * 0.5f; if ( dif < 0 ) @@ -5839,6 +5955,7 @@ static void CG_DrawRocketLocking( int lockEntNum, int lockTime ) CG_DrawPic( cx - sz, cy - sz * 2, sz * 2, sz * 2, trap_R_RegisterShaderNoMip( "gfx/2d/lock" )); } +// cg_drawingRocketLockThisFrame = qtrue; } } diff --git a/codemp/cgame/cg_ents.c b/codemp/cgame/cg_ents.c index 6ab6049..f8ef310 100644 --- a/codemp/cgame/cg_ents.c +++ b/codemp/cgame/cg_ents.c @@ -1446,7 +1446,14 @@ Ghoul2 Insert End if (cent->currentState.iModelScale) { //if the server says we have a custom scale then set it now. - cent->modelScale[0] = cent->modelScale[1] = cent->modelScale[2] = cent->currentState.iModelScale/100.0f; + if ( cent->currentState.legsFlip ) + {//scalar + cent->modelScale[0] = cent->modelScale[1] = cent->modelScale[2] = cent->currentState.iModelScale; + } + else + {//percentage + cent->modelScale[0] = cent->modelScale[1] = cent->modelScale[2] = cent->currentState.iModelScale/100.0f; + } VectorCopy(cent->modelScale, ent.modelScale); ScaleModelAxis(&ent); } @@ -2831,7 +2838,11 @@ static void CG_Mover( centity_t *cent ) { && (cg.time-cg.predictedVehicleState.hyperSpaceTime) < HYPERSPACE_TIME && (cg.time-cg.predictedVehicleState.hyperSpaceTime) > 1000 ) { - if ( (cg.predictedVehicleState.eFlags2&EF2_HYPERSPACE) ) + if ( cg.snap + && cg.snap->ps.pm_type == PM_INTERMISSION ) + {//in the intermission, stop drawing hyperspace ent + } + else if ( (cg.predictedVehicleState.eFlags2&EF2_HYPERSPACE) ) {//actually hyperspacing now float timeFrac = ((float)(cg.time-cg.predictedVehicleState.hyperSpaceTime-1000))/(HYPERSPACE_TIME-1000); if ( timeFrac < (HYPERSPACE_TELEPORT_FRAC+0.1f) ) @@ -2899,7 +2910,14 @@ Ghoul2 Insert End ent.hModel = cgs.gameModels[s1->modelindex2]; if (s1->iModelScale) { //custom model2 scale - ent.modelScale[0] = ent.modelScale[1] = ent.modelScale[2] = s1->iModelScale/100.0f; + if ( s1->legsFlip ) + {//scalar + ent.modelScale[0] = ent.modelScale[1] = ent.modelScale[2] = s1->iModelScale; + } + else + {//percentage + ent.modelScale[0] = ent.modelScale[1] = ent.modelScale[2] = s1->iModelScale/100.0f; + } ScaleModelAxis(&ent); } trap_R_AddRefEntityToScene(&ent); @@ -3090,8 +3108,10 @@ void CG_CalcEntityLerpPositions( centity_t *cent ) { // first see if we can interpolate between two snaps for // linear extrapolated clients - if ( cent->interpolate && cent->currentState.pos.trType == TR_LINEAR_STOP && - cent->currentState.number < MAX_CLIENTS) { + if ( cent->interpolate + && cent->currentState.pos.trType == TR_LINEAR_STOP + && cent->currentState.number < MAX_CLIENTS ) + { CG_InterpolateEntityPosition( cent ); goAway = qtrue; } @@ -3303,11 +3323,17 @@ static void CG_AddCEntity( centity_t *cent ) { { //don't render anything then if (cent->currentState.eType == ET_GENERAL || cent->currentState.eType == ET_PLAYER || - cent->currentState.eType == ET_NPC || cent->currentState.eType == ET_INVISIBLE) { return; } + if ( cent->currentState.eType == ET_NPC ) + {//NPC in intermission + if ( cent->currentState.NPC_class == CLASS_VEHICLE ) + {//don't render vehicles in intermissions, allow other NPCs for scripts + return; + } + } } // calculate the current origin diff --git a/codemp/cgame/cg_event.c b/codemp/cgame/cg_event.c index feeff94..4738a5a 100644 --- a/codemp/cgame/cg_event.c +++ b/codemp/cgame/cg_event.c @@ -13,6 +13,7 @@ #include "../ghoul2/G2.h" //========================================================================== +extern qboolean WP_SaberBladeUseSecondBladeStyle( saberInfo_t *saber, int bladeNum ); extern qboolean CG_VehicleWeaponImpact( centity_t *cent ); extern qboolean CG_InFighter( void ); extern qboolean CG_InATST( void ); @@ -106,10 +107,13 @@ static void CG_Obituary( entityState_t *ent ) { const char *targetInfo; const char *attackerInfo; char targetName[32]; + char targetVehName[32] = {0}; char attackerName[32]; + char attackerVehName[32] = {0}; + char attackerVehWeapName[32] = {0}; gender_t gender; clientInfo_t *ci; - + qboolean vehMessage = qfalse; target = ent->otherEntityNum; attacker = ent->otherEntityNum2; @@ -121,7 +125,7 @@ static void CG_Obituary( entityState_t *ent ) { ci = &cgs.clientinfo[target]; if ( attacker < 0 || attacker >= MAX_CLIENTS ) { - attacker = ENTITYNUM_WORLD; + //attacker = ENTITYNUM_WORLD; attackerInfo = NULL; } else { attackerInfo = CG_ConfigString( CS_PLAYERS + attacker ); @@ -134,30 +138,85 @@ static void CG_Obituary( entityState_t *ent ) { Q_strncpyz( targetName, Info_ValueForKey( targetInfo, "n" ), sizeof(targetName) - 2); strcat( targetName, S_COLOR_WHITE ); + // check for target in a vehicle + if ( ent->lookTarget > VEHICLE_BASE && ent->lookTarget < MAX_VEHICLES && g_vehicleInfo[ent->lookTarget].name ) + { + Q_strncpyz( targetVehName, g_vehicleInfo[ent->lookTarget].name, sizeof(targetVehName) - 2 ); + } + + // check for attacker in a vehicle + if ( ent->brokenLimbs >= MAX_CLIENTS ) + { + centity_t *attVehCent = &cg_entities[ent->brokenLimbs]; + if ( attVehCent && attVehCent->m_pVehicle && attVehCent->m_pVehicle->m_pVehicleInfo ) + { + if ( attVehCent->m_pVehicle->m_pVehicleInfo->name ) + { + Q_strncpyz( attackerVehName, attVehCent->m_pVehicle->m_pVehicleInfo->name, sizeof(attackerVehName) - 2 ); + } + } + } + + //check for specific vehicle weapon + if ( ent->weapon > 0 ) + { + if ( g_vehWeaponInfo[ent->weapon-1].name ) + { + Q_strncpyz( attackerVehWeapName, g_vehWeaponInfo[ent->weapon-1].name, sizeof(attackerVehWeapName) - 2 ); + } + } + // check for single client messages - switch( mod ) { - case MOD_SUICIDE: - case MOD_FALLING: - case MOD_CRUSH: - case MOD_WATER: - case MOD_SLIME: - case MOD_LAVA: - case MOD_TRIGGER_HURT: - message = "DIED_GENERIC"; - break; - case MOD_TARGET_LASER: - message = "DIED_LASER"; - break; - default: - message = NULL; - break; + if ( ent->saberInFlight ) + {//asteroid->vehicle collision + switch ( Q_irand( 0, 2 ) ) + { + default: + case 0: + message = "DIED_ASTEROID1"; + break; + case 1: + message = "DIED_ASTEROID2"; + break; + case 2: + message = "DIED_ASTEROID3"; + break; + } + vehMessage = qtrue; + } + else + { + switch( mod ) { + case MOD_VEHICLE: + case MOD_SUICIDE: + case MOD_FALLING: + case MOD_COLLISION: + case MOD_VEH_EXPLOSION: + case MOD_CRUSH: + case MOD_WATER: + case MOD_SLIME: + case MOD_LAVA: + case MOD_TRIGGER_HURT: + message = "DIED_GENERIC"; + break; + case MOD_TARGET_LASER: + vehMessage = qtrue; + message = "DIED_TURBOLASER"; + break; + default: + message = NULL; + break; + } } // Attacker killed themselves. Ridicule them for it. - if (attacker == target) { + if (attacker == target) + { + vehMessage = qfalse; gender = ci->gender; - switch (mod) { + switch (mod) + { case MOD_BRYAR_PISTOL: case MOD_BRYAR_PISTOL_ALT: case MOD_BLASTER: @@ -229,11 +288,13 @@ static void CG_Obituary( entityState_t *ent ) { goto clientkilled; } - if (message) { + if (message) + { gender = ci->gender; if (!message[0]) { + vehMessage = qfalse; if ( gender == GENDER_FEMALE ) message = "SUICIDE_GENERICDEATH_FEMALE"; else if ( gender == GENDER_NEUTER ) @@ -241,7 +302,14 @@ static void CG_Obituary( entityState_t *ent ) { else message = "SUICIDE_GENERICDEATH_MALE"; } - message = (char *)CG_GetStringEdString("MP_INGAME", message); + if ( vehMessage ) + { + message = (char *)CG_GetStringEdString("MP_INGAMEVEH", message); + } + else + { + message = (char *)CG_GetStringEdString("MP_INGAME", message); + } CG_Printf( "%s %s\n", targetName, message); return; @@ -310,7 +378,7 @@ clientkilled: // check for double client messages if ( !attackerInfo ) { - attacker = ENTITYNUM_WORLD; + //attacker = ENTITYNUM_WORLD; strcpy( attackerName, "noname" ); } else { Q_strncpyz( attackerName, Info_ValueForKey( attackerInfo, "n" ), sizeof(attackerName) - 2); @@ -391,6 +459,48 @@ clientkilled: message = "KILLED_DETPACK"; break; case MOD_VEHICLE: + vehMessage = qtrue; + switch ( ent->generic1 ) + { + case WP_BLASTER://primary blasters + switch ( Q_irand( 0, 2 ) ) + { + case 2: + message = "KILLED_VEH_BLASTER3"; + break; + case 1: + message = "KILLED_VEH_BLASTER2"; + break; + default: + message = "KILLED_VEH_BLASTER1"; + break; + } + break; + case WP_ROCKET_LAUNCHER://missile + if ( Q_irand( 0, 1 ) ) + { + message = "KILLED_VEH_MISSILE2"; + } + else + { + message = "KILLED_VEH_MISSILE1"; + } + break; + case WP_THERMAL://bomb + message = "KILLED_VEH_BOMB"; + break; + case WP_DEMP2://ion cannon + message = "KILLED_VEH_ION"; + break; + case WP_TURRET://turret + message = "KILLED_VEH_TURRET"; + break; + default: + vehMessage = qfalse; + message = "KILLED_GENERIC"; + break; + } + break; case MOD_CONC: case MOD_CONC_ALT: message = "KILLED_GENERIC"; @@ -410,19 +520,84 @@ clientkilled: case MOD_FALLING: message = "KILLED_FORCETOSS"; break; + case MOD_COLLISION: + case MOD_VEH_EXPLOSION: + switch ( Q_irand( 0, 2 ) ) + { + default: + case 0: + message = "KILLED_VEH_COLLISION1"; + break; + case 1: + message = "KILLED_VEH_COLLISION2"; + break; + case 2: + message = "KILLED_VEH_COLLISION3"; + break; + } + vehMessage = qtrue; + break; case MOD_TRIGGER_HURT: message = "KILLED_GENERIC";//"KILLED_FORCETOSS"; break; + case MOD_TARGET_LASER: + if ( Q_irand(0,1) ) + { + message = "KILLED_TURRET1"; + } + else + { + message = "KILLED_TURRET2"; + } + vehMessage = qtrue; + break; default: message = "KILLED_GENERIC"; break; } - if (message) { - message = (char *)CG_GetStringEdString("MP_INGAME", message); + if (message) + { + if ( vehMessage ) + { + message = (char *)CG_GetStringEdString("MP_INGAMEVEH", message); + } + else + { + message = (char *)CG_GetStringEdString("MP_INGAME", message); + } - CG_Printf( "%s %s %s\n", - targetName, message, attackerName); + CG_Printf( "%s ", targetName); + if ( targetVehName[0] ) + { + CG_Printf( "(%s) ", targetVehName); + } + if ( mod == MOD_TARGET_LASER ) + {//no attacker name, just a turbolaser or other kind of turret... + CG_Printf( "%s", message); + } + else + { + CG_Printf( "%s %s", message, attackerName); + + if ( attackerVehName[0] + && attackerVehWeapName[0] ) + { + CG_Printf( " (%s %s)", attackerVehName, attackerVehWeapName ); + } + else + { + if ( attackerVehName[0] ) + { + CG_Printf( " (%s)", attackerVehName ); + } + else if ( attackerVehWeapName[0] ) + { + CG_Printf(" (%s)", attackerVehWeapName ); + } + } + } + CG_Printf( "\n" ); return; } } @@ -2147,147 +2322,271 @@ void CG_EntityEvent( centity_t *cent, vec3_t position ) { case EV_SABER_ATTACK: DEBUGNAME("EV_SABER_ATTACK"); - trap_S_StartSound(es->pos.trBase, es->number, CHAN_WEAPON, trap_S_RegisterSound(va("sound/weapons/saber/saberhup%i.wav", Q_irand(1, 8)))); + { + qhandle_t swingSound = trap_S_RegisterSound(va("sound/weapons/saber/saberhup%i.wav", Q_irand(1, 8))); + clientInfo_t *client = NULL; + if ( cg_entities[es->number].currentState.eType == ET_NPC ) + { + client = cg_entities[es->number].npcClient; + } + else if ( es->number < MAX_CLIENTS ) + { + client = &cgs.clientinfo[es->number]; + } + if ( client && client->infoValid && client->saber[0].swingSound[0] ) + {//custom swing sound + swingSound = client->saber[0].swingSound[Q_irand(0,2)]; + } + trap_S_StartSound(es->pos.trBase, es->number, CHAN_WEAPON, swingSound ); + } break; case EV_SABER_HIT: DEBUGNAME("EV_SABER_HIT"); - if (es->eventParm == 16) - { //Make lots of sparks, something special happened - vec3_t fxDir; - VectorCopy(es->angles, fxDir); - if (!fxDir[0] && !fxDir[1] && !fxDir[2]) - { - fxDir[1] = 1; - } - trap_S_StartSound(es->origin, es->number, CHAN_AUTO, trap_S_RegisterSound(va("sound/weapons/saber/saberhit%i.wav", Q_irand(1, 3)))); - trap_FX_PlayEffectID( cgs.effects.mSaberBloodSparks, es->origin, fxDir, -1, -1 ); - trap_FX_PlayEffectID( cgs.effects.mSaberBloodSparks, es->origin, fxDir, -1, -1 ); - trap_FX_PlayEffectID( cgs.effects.mSaberBloodSparks, es->origin, fxDir, -1, -1 ); - trap_FX_PlayEffectID( cgs.effects.mSaberBloodSparks, es->origin, fxDir, -1, -1 ); - trap_FX_PlayEffectID( cgs.effects.mSaberBloodSparks, es->origin, fxDir, -1, -1 ); - trap_FX_PlayEffectID( cgs.effects.mSaberBloodSparks, es->origin, fxDir, -1, -1 ); - } - else if (es->eventParm) - { //hit a person - vec3_t fxDir; - VectorCopy(es->angles, fxDir); - if (!fxDir[0] && !fxDir[1] && !fxDir[2]) - { - fxDir[1] = 1; - } - trap_S_StartSound(es->origin, es->number, CHAN_AUTO, trap_S_RegisterSound(va("sound/weapons/saber/saberhit%i.wav", Q_irand(1, 3)))); - if ( es->eventParm == 3 ) - { // moderate or big hits. - trap_FX_PlayEffectID( cgs.effects.mSaberBloodSparksSmall, es->origin, fxDir, -1, -1 ); - } - else if ( es->eventParm == 2 ) - { // this is for really big hits. - trap_FX_PlayEffectID( cgs.effects.mSaberBloodSparksMid, es->origin, fxDir, -1, -1 ); - } - else - { // this should really just be done in the effect itself, no? - trap_FX_PlayEffectID( cgs.effects.mSaberBloodSparks, es->origin, fxDir, -1, -1 ); - trap_FX_PlayEffectID( cgs.effects.mSaberBloodSparks, es->origin, fxDir, -1, -1 ); - trap_FX_PlayEffectID( cgs.effects.mSaberBloodSparks, es->origin, fxDir, -1, -1 ); - } - } - else - { //hit something else - vec3_t fxDir; - VectorCopy(es->angles, fxDir); - if (!fxDir[0] && !fxDir[1] && !fxDir[2]) - { - fxDir[1] = 1; - } - //old jk2mp method - /* - trap_S_StartSound(es->origin, es->number, CHAN_AUTO, trap_S_RegisterSound("sound/weapons/saber/saberhit.wav")); - trap_FX_PlayEffectID( trap_FX_RegisterEffect("saber/spark.efx"), es->origin, fxDir, -1, -1 ); - */ - - trap_FX_PlayEffectID( cgs.effects.mSaberCut, es->origin, fxDir, -1, -1 ); - } - - //rww - this means we have the number of the ent being hit and the ent that owns the saber doing - //the hit. This being the case, we can store these indecies and the current time in order to do - //some visual tricks on the client between frames to make it look like we're actually continuing - //to hit between server frames. - if (es->otherEntityNum != ENTITYNUM_NONE && es->otherEntityNum2 != ENTITYNUM_NONE) { - centity_t *saberOwner; + int hitPersonFxID = cgs.effects.mSaberBloodSparks; + int hitPersonSmallFxID = cgs.effects.mSaberBloodSparksSmall; + int hitPersonMidFxID = cgs.effects.mSaberBloodSparksMid; + int hitOtherFxID = cgs.effects.mSaberCut; + int hitSound = trap_S_RegisterSound(va("sound/weapons/saber/saberhit%i.wav", Q_irand(1, 3))); + + if ( es->otherEntityNum2 >= 0 + && es->otherEntityNum2 < ENTITYNUM_NONE ) + {//we have a specific person who is causing this effect, see if we should override it with any custom saber effects/sounds + clientInfo_t *client = NULL; + if ( cg_entities[es->otherEntityNum2].currentState.eType == ET_NPC ) + { + client = cg_entities[es->otherEntityNum2].npcClient; + } + else if ( es->otherEntityNum2 < MAX_CLIENTS ) + { + client = &cgs.clientinfo[es->otherEntityNum2]; + } + if ( client && client->infoValid ) + { + int saberNum = es->weapon; + int bladeNum = es->legsAnim; + if ( WP_SaberBladeUseSecondBladeStyle( &client->saber[saberNum], bladeNum ) ) + {//use second blade style values + if ( client->saber[saberNum].hitPersonEffect2 ) + {//custom hit person effect + hitPersonFxID = hitPersonSmallFxID = hitPersonMidFxID = client->saber[saberNum].hitPersonEffect2; + } + if ( client->saber[saberNum].hitOtherEffect2 ) + {//custom hit other effect + hitOtherFxID = client->saber[saberNum].hitOtherEffect2; + } + if ( client->saber[saberNum].hit2Sound[0] ) + {//custom hit sound + hitSound = client->saber[saberNum].hit2Sound[Q_irand(0,2)]; + } + } + else + {//use first blade style values + if ( client->saber[saberNum].hitPersonEffect ) + {//custom hit person effect + hitPersonFxID = hitPersonSmallFxID = hitPersonMidFxID = client->saber[saberNum].hitPersonEffect; + } + if ( client->saber[saberNum].hitOtherEffect ) + {//custom hit other effect + hitOtherFxID = client->saber[0].hitOtherEffect; + } + if ( client->saber[saberNum].hitSound[0] ) + {//custom hit sound + hitSound = client->saber[saberNum].hitSound[Q_irand(0,2)]; + } + } + } + } - saberOwner = &cg_entities[es->otherEntityNum2]; - - saberOwner->serverSaberHitIndex = es->otherEntityNum; - saberOwner->serverSaberHitTime = cg.time; - - if (es->eventParm) - { - saberOwner->serverSaberFleshImpact = qtrue; + if (es->eventParm == 16) + { //Make lots of sparks, something special happened + vec3_t fxDir; + VectorCopy(es->angles, fxDir); + if (!fxDir[0] && !fxDir[1] && !fxDir[2]) + { + fxDir[1] = 1; + } + trap_S_StartSound(es->origin, es->number, CHAN_AUTO, hitSound ); + trap_FX_PlayEffectID( hitPersonFxID, es->origin, fxDir, -1, -1 ); + trap_FX_PlayEffectID( hitPersonFxID, es->origin, fxDir, -1, -1 ); + trap_FX_PlayEffectID( hitPersonFxID, es->origin, fxDir, -1, -1 ); + trap_FX_PlayEffectID( hitPersonFxID, es->origin, fxDir, -1, -1 ); + trap_FX_PlayEffectID( hitPersonFxID, es->origin, fxDir, -1, -1 ); + trap_FX_PlayEffectID( hitPersonFxID, es->origin, fxDir, -1, -1 ); + } + else if (es->eventParm) + { //hit a person + vec3_t fxDir; + VectorCopy(es->angles, fxDir); + if (!fxDir[0] && !fxDir[1] && !fxDir[2]) + { + fxDir[1] = 1; + } + trap_S_StartSound(es->origin, es->number, CHAN_AUTO, hitSound ); + if ( es->eventParm == 3 ) + { // moderate or big hits. + trap_FX_PlayEffectID( hitPersonSmallFxID, es->origin, fxDir, -1, -1 ); + } + else if ( es->eventParm == 2 ) + { // this is for really big hits. + trap_FX_PlayEffectID( hitPersonMidFxID, es->origin, fxDir, -1, -1 ); + } + else + { // this should really just be done in the effect itself, no? + trap_FX_PlayEffectID( hitPersonFxID, es->origin, fxDir, -1, -1 ); + trap_FX_PlayEffectID( hitPersonFxID, es->origin, fxDir, -1, -1 ); + trap_FX_PlayEffectID( hitPersonFxID, es->origin, fxDir, -1, -1 ); + } } else + { //hit something else + vec3_t fxDir; + VectorCopy(es->angles, fxDir); + if (!fxDir[0] && !fxDir[1] && !fxDir[2]) + { + fxDir[1] = 1; + } + //old jk2mp method + /* + trap_S_StartSound(es->origin, es->number, CHAN_AUTO, trap_S_RegisterSound("sound/weapons/saber/saberhit.wav")); + trap_FX_PlayEffectID( trap_FX_RegisterEffect("saber/spark.efx"), es->origin, fxDir, -1, -1 ); + */ + + trap_FX_PlayEffectID( hitOtherFxID, es->origin, fxDir, -1, -1 ); + } + + //rww - this means we have the number of the ent being hit and the ent that owns the saber doing + //the hit. This being the case, we can store these indecies and the current time in order to do + //some visual tricks on the client between frames to make it look like we're actually continuing + //to hit between server frames. + if (es->otherEntityNum != ENTITYNUM_NONE && es->otherEntityNum2 != ENTITYNUM_NONE) { - saberOwner->serverSaberFleshImpact = qfalse; + centity_t *saberOwner; + + saberOwner = &cg_entities[es->otherEntityNum2]; + + saberOwner->serverSaberHitIndex = es->otherEntityNum; + saberOwner->serverSaberHitTime = cg.time; + + if (es->eventParm) + { + saberOwner->serverSaberFleshImpact = qtrue; + } + else + { + saberOwner->serverSaberFleshImpact = qfalse; + } } } break; case EV_SABER_BLOCK: DEBUGNAME("EV_SABER_BLOCK"); + { + if (es->eventParm) + { //saber block + qboolean cullPass = qfalse; + int blockFXID = cgs.effects.mSaberBlock; + qhandle_t blockSound = trap_S_RegisterSound(va( "sound/weapons/saber/saberblock%d.wav", Q_irand(1, 9) )); + qboolean noFlare = qfalse; - if (es->eventParm) - { //saber block - qboolean cullPass = qfalse; - - if (cg.mInRMG) - { - trace_t tr; - vec3_t vecSub; - - VectorSubtract(cg.refdef.vieworg, es->origin, vecSub); - - if (VectorLength(vecSub) < 5000) - { - CG_Trace(&tr, cg.refdef.vieworg, NULL, NULL, es->origin, ENTITYNUM_NONE, CONTENTS_TERRAIN|CONTENTS_SOLID); - - if (tr.fraction == 1.0 || tr.entityNum < MAX_CLIENTS) + if ( es->otherEntityNum2 >= 0 + && es->otherEntityNum2 < ENTITYNUM_NONE ) + {//we have a specific person who is causing this effect, see if we should override it with any custom saber effects/sounds + clientInfo_t *client = NULL; + if ( cg_entities[es->otherEntityNum2].currentState.eType == ET_NPC ) { - cullPass = qtrue; + client = cg_entities[es->otherEntityNum2].npcClient; + } + else if ( es->otherEntityNum2 < MAX_CLIENTS ) + { + client = &cgs.clientinfo[es->otherEntityNum2]; + } + if ( client && client->infoValid ) + { + int saberNum = es->weapon; + int bladeNum = es->legsAnim; + if ( WP_SaberBladeUseSecondBladeStyle( &client->saber[saberNum], bladeNum ) ) + {//use second blade style values + if ( client->saber[saberNum].blockEffect2 ) + {//custom saber block effect + blockFXID = client->saber[saberNum].blockEffect2; + } + if ( client->saber[saberNum].block2Sound[0] ) + {//custom hit sound + blockSound = client->saber[saberNum].block2Sound[Q_irand(0,2)]; + } + } + else + { + if ( client->saber[saberNum].blockEffect ) + {//custom saber block effect + blockFXID = client->saber[saberNum].blockEffect; + } + if ( client->saber[saberNum].blockSound[0] ) + {//custom hit sound + blockSound = client->saber[saberNum].blockSound[Q_irand(0,2)]; + } + } + if ( (client->saber[saberNum].saberFlags2&SFL2_NO_CLASH_FLARE) ) + { + noFlare = qtrue; + } + } + } + if (cg.mInRMG) + { + trace_t tr; + vec3_t vecSub; + + VectorSubtract(cg.refdef.vieworg, es->origin, vecSub); + + if (VectorLength(vecSub) < 5000) + { + CG_Trace(&tr, cg.refdef.vieworg, NULL, NULL, es->origin, ENTITYNUM_NONE, CONTENTS_TERRAIN|CONTENTS_SOLID); + + if (tr.fraction == 1.0 || tr.entityNum < MAX_CLIENTS) + { + cullPass = qtrue; + } + } + } + else + { + cullPass = qtrue; + } + + if (cullPass) + { + vec3_t fxDir; + + VectorCopy(es->angles, fxDir); + if (!fxDir[0] && !fxDir[1] && !fxDir[2]) + { + fxDir[1] = 1; + } + trap_S_StartSound(es->origin, es->number, CHAN_AUTO, blockSound ); + trap_FX_PlayEffectID( blockFXID, es->origin, fxDir, -1, -1 ); + + if ( !noFlare ) + { + cg_saberFlashTime = cg.time-50; + VectorCopy( es->origin, cg_saberFlashPos ); } } } else - { - cullPass = qtrue; - } - - if (cullPass) - { + { //projectile block vec3_t fxDir; - VectorCopy(es->angles, fxDir); if (!fxDir[0] && !fxDir[1] && !fxDir[2]) { fxDir[1] = 1; } - trap_S_StartSound(es->origin, es->number, CHAN_AUTO, trap_S_RegisterSound(va( "sound/weapons/saber/saberblock%d.wav", Q_irand(1, 9) ))); - trap_FX_PlayEffectID( cgs.effects.mSaberBlock, es->origin, fxDir, -1, -1 ); - - cg_saberFlashTime = cg.time-50; - VectorCopy( es->origin, cg_saberFlashPos ); + trap_FX_PlayEffectID(cgs.effects.mBlasterDeflect, es->origin, fxDir, -1, -1); } } - else - { //projectile block - vec3_t fxDir; - VectorCopy(es->angles, fxDir); - if (!fxDir[0] && !fxDir[1] && !fxDir[2]) - { - fxDir[1] = 1; - } - trap_FX_PlayEffectID(cgs.effects.mBlasterDeflect, es->origin, fxDir, -1, -1); - } break; case EV_SABER_CLASHFLARE: diff --git a/codemp/cgame/cg_info.c b/codemp/cgame/cg_info.c index f7795c5..9bf47cf 100644 --- a/codemp/cgame/cg_info.c +++ b/codemp/cgame/cg_info.c @@ -318,7 +318,7 @@ void CG_DrawInformation( void ) { valueNOFP = atoi( Info_ValueForKey( info, "g_forcePowerDisable" ) ); value = atoi( Info_ValueForKey( info, "g_maxForceRank" ) ); - if ( value && !valueNOFP ) { + if ( value && !valueNOFP && (value < NUM_FORCE_MASTERY_LEVELS) ) { char fmStr[1024]; trap_SP_GetStringTextString("MP_INGAME_MAXFORCERANK",fmStr, sizeof(fmStr)); diff --git a/codemp/cgame/cg_local.h b/codemp/cgame/cg_local.h index 9085783..778439a 100644 --- a/codemp/cgame/cg_local.h +++ b/codemp/cgame/cg_local.h @@ -245,8 +245,8 @@ typedef struct { // char headModelName[MAX_QPATH]; // char headSkinName[MAX_QPATH]; char forcePowers[MAX_QPATH]; - char redTeam[MAX_TEAMNAME]; - char blueTeam[MAX_TEAMNAME]; +// char redTeam[MAX_TEAMNAME]; +// char blueTeam[MAX_TEAMNAME]; char teamName[MAX_TEAMNAME]; @@ -1130,6 +1130,7 @@ typedef struct { qhandle_t purpleSaberGlowShader; qhandle_t purpleSaberCoreShader; qhandle_t saberBlurShader; + qhandle_t swordTrailShader; qhandle_t yellowDroppedSaberShader; @@ -1544,8 +1545,8 @@ typedef struct { int fDisable; char mapname[MAX_QPATH]; - char redTeam[MAX_QPATH]; - char blueTeam[MAX_QPATH]; +// char redTeam[MAX_QPATH]; +// char blueTeam[MAX_QPATH]; int voteTime; int voteYes; @@ -1650,6 +1651,7 @@ extern vmCvar_t cg_drawAmmoWarning; extern vmCvar_t cg_drawCrosshair; extern vmCvar_t cg_drawCrosshairNames; extern vmCvar_t cg_drawRadar; +extern vmCvar_t cg_drawVehLeadIndicator; extern vmCvar_t cg_drawAutomap; extern vmCvar_t cg_drawScores; extern vmCvar_t cg_dynamicCrosshair; @@ -1715,6 +1717,8 @@ extern vmCvar_t cg_fpls; extern vmCvar_t cg_ghoul2Marks; +extern vmCvar_t cg_optvehtrace; + extern vmCvar_t cg_saberDynamicMarks; extern vmCvar_t cg_saberDynamicMarkTime; @@ -1780,16 +1784,13 @@ extern vmCvar_t cg_smallFont; extern vmCvar_t cg_bigFont; extern vmCvar_t cg_noTaunt; extern vmCvar_t cg_noProjectileTrail; -extern vmCvar_t cg_trueLightning; +//extern vmCvar_t cg_trueLightning; -extern vmCvar_t cg_redTeamName; -extern vmCvar_t cg_blueTeamName; +//extern vmCvar_t cg_redTeamName; +//extern vmCvar_t cg_blueTeamName; extern vmCvar_t cg_currentSelectedPlayer; extern vmCvar_t cg_currentSelectedPlayerName; -extern vmCvar_t cg_singlePlayer; -extern vmCvar_t cg_enableDust; -extern vmCvar_t cg_enableBreath; -extern vmCvar_t cg_singlePlayerActive; +//extern vmCvar_t cg_singlePlayerActive; extern vmCvar_t cg_recordSPDemo; extern vmCvar_t cg_recordSPDemoName; @@ -2505,6 +2506,7 @@ void FX_BlasterWeaponHitPlayer( vec3_t origin, vec3_t normal, qboolean humanoid #include "../namespace_begin.h" void trap_G2API_CollisionDetect ( CollisionRecord_t *collRecMap, void* ghoul2, const vec3_t angles, const vec3_t position,int frameNumber, int entNum, const vec3_t rayStart, const vec3_t rayEnd, const vec3_t scale, int traceFlags, int useLod, float fRadius ); +void trap_G2API_CollisionDetectCache ( CollisionRecord_t *collRecMap, void* ghoul2, const vec3_t angles, const vec3_t position,int frameNumber, int entNum, const vec3_t rayStart, const vec3_t rayEnd, const vec3_t scale, int traceFlags, int useLod, float fRadius ); /* Ghoul2 Insert Start diff --git a/codemp/cgame/cg_main.c b/codemp/cgame/cg_main.c index 74cd368..1f2c39f 100644 --- a/codemp/cgame/cg_main.c +++ b/codemp/cgame/cg_main.c @@ -153,6 +153,7 @@ extern int cg_autoMapInputTime; extern vec3_t cg_autoMapAngle; void CG_MiscEnt(void); +void CG_DoCameraShake( vec3_t origin, float intensity, int radius, int time ); //do we have any force powers that we would normally need to cycle to? qboolean CG_NoUseableForce(void) @@ -342,6 +343,14 @@ int vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int a CG_MiscEnt(); return 0; + case CG_FX_CAMERASHAKE: + { + TCGCameraShake *data = (TCGCameraShake *)cg.sharedBuffer; + + CG_DoCameraShake( data->mOrigin, data->mIntensity, data->mRadius, data->mTime ); + } + return 0; + default: CG_Error( "vmMain: unknown command %i", command ); break; @@ -708,6 +717,7 @@ vmCvar_t cg_drawAmmoWarning; vmCvar_t cg_drawCrosshair; vmCvar_t cg_drawCrosshairNames; vmCvar_t cg_drawRadar; +vmCvar_t cg_drawVehLeadIndicator; vmCvar_t cg_dynamicCrosshair; vmCvar_t cg_dynamicCrosshairPrecision; vmCvar_t cg_drawRewards; @@ -773,6 +783,8 @@ vmCvar_t cg_fpls; vmCvar_t cg_ghoul2Marks; +vmCvar_t cg_optvehtrace; + vmCvar_t cg_saberDynamicMarks; vmCvar_t cg_saberDynamicMarkTime; @@ -839,7 +851,7 @@ vmCvar_t cg_timescaleFadeSpeed; vmCvar_t cg_timescale; vmCvar_t cg_noTaunt; vmCvar_t cg_noProjectileTrail; -vmCvar_t cg_trueLightning; +//vmCvar_t cg_trueLightning; /* Ghoul2 Insert Start */ @@ -847,14 +859,11 @@ vmCvar_t cg_debugBB; /* Ghoul2 Insert End */ -vmCvar_t cg_redTeamName; -vmCvar_t cg_blueTeamName; +//vmCvar_t cg_redTeamName; +//vmCvar_t cg_blueTeamName; vmCvar_t cg_currentSelectedPlayer; vmCvar_t cg_currentSelectedPlayerName; -vmCvar_t cg_singlePlayer; -vmCvar_t cg_enableDust; -vmCvar_t cg_enableBreath; -vmCvar_t cg_singlePlayerActive; +//vmCvar_t cg_singlePlayerActive; vmCvar_t cg_recordSPDemo; vmCvar_t cg_recordSPDemoName; vmCvar_t cg_showVehBounds; @@ -892,6 +901,7 @@ static cvarTable_t cvarTable[] = { // bk001129 { &cg_drawCrosshair, "cg_drawCrosshair", "1", CVAR_ARCHIVE }, { &cg_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE }, { &cg_drawRadar, "cg_drawRadar", "1", CVAR_ARCHIVE }, + { &cg_drawVehLeadIndicator, "cg_drawVehLeadIndicator", "1", CVAR_ARCHIVE }, { &cg_drawScores, "cg_drawScores", "1", CVAR_ARCHIVE }, { &cg_dynamicCrosshair, "cg_dynamicCrosshair", "1", CVAR_ARCHIVE }, //Enables ghoul2 traces for crosshair traces.. more precise when pointing at others, but slower. @@ -957,6 +967,8 @@ static cvarTable_t cvarTable[] = { // bk001129 { &cg_ghoul2Marks, "cg_ghoul2Marks", "16", 0 }, + { &cg_optvehtrace, "com_optvehtrace", "0", 0 }, + { &cg_saberDynamicMarks, "cg_saberDynamicMarks", "0", 0 }, { &cg_saberDynamicMarkTime, "cg_saberDynamicMarkTime", "60000", 0 }, @@ -1002,14 +1014,11 @@ static cvarTable_t cvarTable[] = { // bk001129 { &cg_blood, "com_blood", "1", CVAR_ARCHIVE }, { &cg_synchronousClients, "g_synchronousClients", "0", 0 }, // communicated by systeminfo - { &cg_redTeamName, "g_redteam", DEFAULT_REDTEAM_NAME, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO }, - { &cg_blueTeamName, "g_blueteam", DEFAULT_BLUETEAM_NAME, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO }, +// { &cg_redTeamName, "g_redteam", DEFAULT_REDTEAM_NAME, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO }, +// { &cg_blueTeamName, "g_blueteam", DEFAULT_BLUETEAM_NAME, CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO }, { &cg_currentSelectedPlayer, "cg_currentSelectedPlayer", "0", CVAR_ARCHIVE}, { &cg_currentSelectedPlayerName, "cg_currentSelectedPlayerName", "", CVAR_ARCHIVE}, - { &cg_singlePlayer, "ui_singlePlayerActive", "0", CVAR_USERINFO}, - { &cg_enableDust, "g_enableDust", "0", 0}, - { &cg_enableBreath, "g_enableBreath", "0", 0}, - { &cg_singlePlayerActive, "ui_singlePlayerActive", "0", CVAR_USERINFO}, +// { &cg_singlePlayerActive, "ui_singlePlayerActive", "0", CVAR_USERINFO}, { &cg_recordSPDemo, "ui_recordSPDemo", "0", CVAR_ARCHIVE}, { &cg_recordSPDemoName, "ui_recordSPDemoName", "", CVAR_ARCHIVE}, @@ -1018,16 +1027,16 @@ static cvarTable_t cvarTable[] = { // bk001129 { &cg_timescaleFadeEnd, "cg_timescaleFadeEnd", "1", 0}, { &cg_timescaleFadeSpeed, "cg_timescaleFadeSpeed", "0", 0}, { &cg_timescale, "timescale", "1", 0}, - { &cg_scorePlum, "cg_scorePlums", "1", CVAR_USERINFO | CVAR_ARCHIVE}, - { &cg_hudFiles, "cg_hudFiles", "ui/jahud.txt", CVAR_USERINFO | CVAR_ARCHIVE}, - { &cg_smoothClients, "cg_smoothClients", "1", CVAR_USERINFO | CVAR_ARCHIVE}, + { &cg_scorePlum, "cg_scorePlums", "1", CVAR_ARCHIVE}, + { &cg_hudFiles, "cg_hudFiles", "ui/jahud.txt", CVAR_ARCHIVE}, + { &cg_smoothClients, "cg_smoothClients", "1", CVAR_ARCHIVE}, { &cg_cameraMode, "com_cameraMode", "0", CVAR_CHEAT}, { &pmove_fixed, "pmove_fixed", "0", 0}, { &pmove_msec, "pmove_msec", "8", 0}, { &cg_noTaunt, "cg_noTaunt", "0", CVAR_ARCHIVE}, { &cg_noProjectileTrail, "cg_noProjectileTrail", "0", CVAR_ARCHIVE}, - { &cg_trueLightning, "cg_trueLightning", "0.0", CVAR_ARCHIVE}, +// { &cg_trueLightning, "cg_trueLightning", "0.0", CVAR_ARCHIVE}, { &cg_showVehBounds, "cg_showVehBounds", "0", 0}, { &ui_myteam, "ui_myteam", "0", CVAR_ROM|CVAR_INTERNAL}, @@ -1493,6 +1502,7 @@ static void CG_RegisterSounds( void ) { cgs.media.purpleSaberGlowShader = trap_R_RegisterShader( "gfx/effects/sabers/purple_glow" ); cgs.media.purpleSaberCoreShader = trap_R_RegisterShader( "gfx/effects/sabers/purple_line" ); cgs.media.saberBlurShader = trap_R_RegisterShader( "gfx/effects/sabers/saberBlur" ); + cgs.media.swordTrailShader = trap_R_RegisterShader( "gfx/effects/sabers/swordTrail" ); cgs.media.forceCoronaShader = trap_R_RegisterShaderNoMip( "gfx/hud/force_swirl" ); @@ -3029,10 +3039,10 @@ static int CG_OwnerDrawWidth(int ownerDraw, float scale) { return CG_Text_Width(CG_GetKillerText(), scale, FONT_MEDIUM); break; case CG_RED_NAME: - return CG_Text_Width(cg_redTeamName.string, scale, FONT_MEDIUM); + return CG_Text_Width(DEFAULT_REDTEAM_NAME/*cg_redTeamName.string*/, scale, FONT_MEDIUM); break; case CG_BLUE_NAME: - return CG_Text_Width(cg_blueTeamName.string, scale, FONT_MEDIUM); + return CG_Text_Width(DEFAULT_BLUETEAM_NAME/*cg_blueTeamName.string*/, scale, FONT_MEDIUM); break; diff --git a/codemp/cgame/cg_players.c b/codemp/cgame/cg_players.c index d25f0f8..df4b6d7 100644 --- a/codemp/cgame/cg_players.c +++ b/codemp/cgame/cg_players.c @@ -13,6 +13,7 @@ extern int cgSiegeTeam2PlShader; extern void CG_AddRadarEnt(centity_t *cent); //cg_ents.c extern void CG_AddBracketedEnt(centity_t *cent); //cg_ents.c extern qboolean CG_InFighter( void ); +extern qboolean WP_SaberBladeUseSecondBladeStyle( saberInfo_t *saber, int bladeNum ); //for g2 surface routines @@ -619,6 +620,10 @@ retryModel: //jetpack bolted to must always be third. trap_G2API_AddBolt(ci->ghoul2Model, 0, "*chestg"); + //claw bolts + trap_G2API_AddBolt(ci->ghoul2Model, 0, "*r_hand_cap_r_arm"); + trap_G2API_AddBolt(ci->ghoul2Model, 0, "*l_hand_cap_l_arm"); + ci->bolt_head = trap_G2API_AddBolt(ci->ghoul2Model, 0, "*head_top"); if (ci->bolt_head == -1) { @@ -1038,9 +1043,9 @@ void CG_LoadClientInfo( clientInfo_t *ci ) { teamname[0] = 0; if( cgs.gametype >= GT_TEAM) { if( ci->team == TEAM_BLUE ) { - Q_strncpyz(teamname, cg_blueTeamName.string, sizeof(teamname) ); + Q_strncpyz(teamname, DEFAULT_BLUETEAM_NAME/*cg_blueTeamName.string*/, sizeof(teamname) ); } else { - Q_strncpyz(teamname, cg_redTeamName.string, sizeof(teamname) ); + Q_strncpyz(teamname, DEFAULT_REDTEAM_NAME/*cg_redTeamName.string*/, sizeof(teamname) ); } } if( teamname[0] ) { @@ -1158,7 +1163,14 @@ static void CG_InitG2SaberData(int saberNum, clientInfo_t *ci) trap_G2API_SetSkin(ci->ghoul2Weapons[saberNum], 0, ci->saber[saberNum].skin, ci->saber[saberNum].skin); } - trap_G2API_SetBoltInfo(ci->ghoul2Weapons[saberNum], 0, saberNum); + if (ci->saber[saberNum].saberFlags & SFL_BOLT_TO_WRIST) + { + trap_G2API_SetBoltInfo(ci->ghoul2Weapons[saberNum], 0, 3+saberNum); + } + else + { + trap_G2API_SetBoltInfo(ci->ghoul2Weapons[saberNum], 0, saberNum); + } while (k < ci->saber[saberNum].numBlades) { @@ -1291,8 +1303,8 @@ static qboolean CG_ScanForExistingClientInfo( clientInfo_t *ci, int clientNum ) && !Q_stricmp( ci->saber2Name, match->saber2Name) // && !Q_stricmp( ci->headModelName, match->headModelName ) // && !Q_stricmp( ci->headSkinName, match->headSkinName ) - && !Q_stricmp( ci->blueTeam, match->blueTeam ) - && !Q_stricmp( ci->redTeam, match->redTeam ) +// && !Q_stricmp( ci->blueTeam, match->blueTeam ) +// && !Q_stricmp( ci->redTeam, match->redTeam ) && (cgs.gametype < GT_TEAM || ci->team == match->team) && ci->siegeIndex == match->siegeIndex && match->ghoul2Model @@ -1583,11 +1595,11 @@ void CG_NewClientInfo( int clientNum, qboolean entitiesInitialized ) { v = Info_ValueForKey( configstring, "tl" ); newInfo.teamLeader = atoi(v); - v = Info_ValueForKey( configstring, "g_redteam" ); - Q_strncpyz(newInfo.redTeam, v, MAX_TEAMNAME); +// v = Info_ValueForKey( configstring, "g_redteam" ); +// Q_strncpyz(newInfo.redTeam, v, MAX_TEAMNAME); - v = Info_ValueForKey( configstring, "g_blueteam" ); - Q_strncpyz(newInfo.blueTeam, v, MAX_TEAMNAME); +// v = Info_ValueForKey( configstring, "g_blueteam" ); +// Q_strncpyz(newInfo.blueTeam, v, MAX_TEAMNAME); // model v = Info_ValueForKey( configstring, "model" ); @@ -2225,6 +2237,10 @@ static void CG_PlayerFootsteps( centity_t *cent, footstepType_t footStepType ) void CG_PlayerAnimEventDo( centity_t *cent, animevent_t *animEvent ) { soundChannel_t channel = CHAN_AUTO; + clientInfo_t *client = NULL; + qhandle_t swingSound = 0; + qhandle_t spinSound = 0; + if ( !cent || !animEvent ) { return; @@ -2243,6 +2259,85 @@ void CG_PlayerAnimEventDo( centity_t *cent, animevent_t *animEvent ) } } break; + case AEV_SABER_SWING: + if (cent->currentState.eType == ET_NPC) + { + client = cent->npcClient; + assert(client); + } + else + { + client = &cgs.clientinfo[cent->currentState.clientNum]; + } + if ( client && client->infoValid && client->saber[animEvent->eventData[AED_SABER_SWING_SABERNUM]].swingSound[0] ) + {//custom swing sound + swingSound = client->saber[0].swingSound[Q_irand(0,2)]; + } + else + { + int randomSwing = 1; + switch ( animEvent->eventData[AED_SABER_SWING_TYPE] ) + { + default: + case 0://SWING_FAST + randomSwing = Q_irand( 1, 3 ); + break; + case 1://SWING_MEDIUM + randomSwing = Q_irand( 4, 6 ); + break; + case 2://SWING_STRONG + randomSwing = Q_irand( 7, 9 ); + break; + } + swingSound = trap_S_RegisterSound(va("sound/weapons/saber/saberhup%i.wav", randomSwing)); + } + trap_S_StartSound(cent->currentState.pos.trBase, cent->currentState.number, CHAN_AUTO, swingSound ); + break; + case AEV_SABER_SPIN: + if (cent->currentState.eType == ET_NPC) + { + client = cent->npcClient; + assert(client); + } + else + { + client = &cgs.clientinfo[cent->currentState.clientNum]; + } + if ( client + && client->infoValid + && client->saber[AED_SABER_SPIN_SABERNUM].spinSound ) + {//use override + spinSound = client->saber[AED_SABER_SPIN_SABERNUM].spinSound; + } + else + { + switch ( animEvent->eventData[AED_SABER_SPIN_TYPE] ) + { + case 0://saberspinoff + spinSound = trap_S_RegisterSound( "sound/weapons/saber/saberspinoff.wav" ); + break; + case 1://saberspin + spinSound = trap_S_RegisterSound( "sound/weapons/saber/saberspin.wav" ); + break; + case 2://saberspin1 + spinSound = trap_S_RegisterSound( "sound/weapons/saber/saberspin1.wav" ); + break; + case 3://saberspin2 + spinSound = trap_S_RegisterSound( "sound/weapons/saber/saberspin2.wav" ); + break; + case 4://saberspin3 + spinSound = trap_S_RegisterSound( "sound/weapons/saber/saberspin3.wav" ); + break; + default://random saberspin1-3 + spinSound = trap_S_RegisterSound( va( "sound/weapons/saber/saberspin%d.wav", Q_irand(1,3)) ); + break; + } + } + if ( spinSound ) + { + trap_S_StartSound( NULL, cent->currentState.clientNum, CHAN_AUTO, spinSound ); + } + break; case AEV_FOOTSTEP: CG_PlayerFootsteps( cent, (footstepType_t)animEvent->eventData[AED_FOOTSTEP_TYPE] ); break; @@ -2496,6 +2591,7 @@ void CG_PlayerAnimEvents( int animFileIndex, int eventFileIndex, qboolean torso, switch ( animEvents[i].eventType ) { case AEV_SOUND: + case AEV_SOUNDCHAN: // Determine probability of playing sound if (!animEvents[i].eventData[AED_SOUND_PROBABILITY]) // 100% { @@ -2506,6 +2602,28 @@ void CG_PlayerAnimEvents( int animFileIndex, int eventFileIndex, qboolean torso, doEvent = qtrue; } break; + case AEV_SABER_SWING: + // Determine probability of playing sound + if (!animEvents[i].eventData[AED_SABER_SWING_PROBABILITY]) // 100% + { + doEvent = qtrue; + } + else if (animEvents[i].eventData[AED_SABER_SWING_PROBABILITY] > Q_irand(0, 99) ) + { + doEvent = qtrue; + } + break; + case AEV_SABER_SPIN: + // Determine probability of playing sound + if (!animEvents[i].eventData[AED_SABER_SPIN_PROBABILITY]) // 100% + { + doEvent = qtrue; + } + else if (animEvents[i].eventData[AED_SABER_SPIN_PROBABILITY] > Q_irand(0, 99) ) + { + doEvent = qtrue; + } + break; case AEV_FOOTSTEP: // Determine probability of playing sound if (!animEvents[i].eventData[AED_FOOTSTEP_PROBABILITY]) // 100% @@ -2748,7 +2866,7 @@ static void CG_SetLerpFrameAnimation( centity_t *cent, clientInfo_t *ci, lerpFra animSpeed *= animSpeedMult; - BG_SaberStartTransAnim(cent->currentState.fireflag, newAnimation, &animSpeed, cent->currentState.brokenLimbs); + BG_SaberStartTransAnim(cent->currentState.number, cent->currentState.fireflag, cent->currentState.weapon, newAnimation, &animSpeed, cent->currentState.brokenLimbs); if (torsoOnly) { @@ -5124,6 +5242,11 @@ static void CG_DoSaberLight( saberInfo_t *saber ) { return; } + + if ( (saber->saberFlags2&SFL2_NO_DLIGHT) ) + {//no dlight! + return; + } for ( i = 0; i < saber->numBlades; i++ ) { @@ -5534,7 +5657,17 @@ qboolean CG_G2TraceCollide(trace_t *tr, vec3_t const mins, vec3_t const maxs, co angles[ROLL] = angles[PITCH] = 0; angles[YAW] = g2Hit->lerpAngles[YAW]; - trap_G2API_CollisionDetect ( G2Trace, g2Hit->ghoul2, angles, g2Hit->lerpOrigin, cg.time, g2Hit->currentState.number, lastValidStart, lastValidEnd, g2Hit->modelScale, 0, cg_g2TraceLod.integer, fRadius ); + if (cg_optvehtrace.integer && + g2Hit->currentState.eType == ET_NPC && + g2Hit->currentState.NPC_class == CLASS_VEHICLE && + g2Hit->m_pVehicle) + { + trap_G2API_CollisionDetectCache ( G2Trace, g2Hit->ghoul2, angles, g2Hit->lerpOrigin, cg.time, g2Hit->currentState.number, lastValidStart, lastValidEnd, g2Hit->modelScale, 0, cg_g2TraceLod.integer, fRadius ); + } + else + { + trap_G2API_CollisionDetect ( G2Trace, g2Hit->ghoul2, angles, g2Hit->lerpOrigin, cg.time, g2Hit->currentState.number, lastValidStart, lastValidEnd, g2Hit->modelScale, 0, cg_g2TraceLod.integer, fRadius ); + } if (G2Trace[0].mEntityNum != g2Hit->currentState.number) { @@ -5662,7 +5795,7 @@ void CG_AddGhoul2Mark(int shader, float size, vec3_t start, vec3_t end, int entn trap_G2API_AddSkinGore(ghoul2, &goreSkin); } -void CG_SaberCompWork(vec3_t start, vec3_t end, centity_t *owner) +void CG_SaberCompWork(vec3_t start, vec3_t end, centity_t *owner, int saberNum, int bladeNum) { trace_t trace; vec3_t startTr; @@ -5670,6 +5803,7 @@ void CG_SaberCompWork(vec3_t start, vec3_t end, centity_t *owner) qboolean backWards = qfalse; qboolean doneWithTraces = qfalse; qboolean doEffect = qfalse; + clientInfo_t *client = NULL; if ((cg.time - owner->serverSaberHitTime) > CG_MAX_SABER_COMP_TIME) { @@ -5718,13 +5852,57 @@ void CG_SaberCompWork(vec3_t start, vec3_t end, centity_t *owner) !trEnt->m_pVehicle || trEnt->m_pVehicle->m_pVehicleInfo->type != VH_FIGHTER) { //don't do on fighters cause they have crazy full axial angles + int weaponMarkShader = 0, markShader = cgs.media.bdecal_saberglow; + VectorSubtract(endTr, trace.endpos, ePos); VectorNormalize(ePos); VectorMA(trace.endpos, 4.0f, ePos, ePos); - CG_AddGhoul2Mark(cgs.media.bdecal_saberglow, flrand(3.0f, 4.0f), + if (owner->currentState.eType == ET_NPC) + { + client = owner->npcClient; + } + else + { + client = &cgs.clientinfo[owner->currentState.clientNum]; + } + if ( client + && client->infoValid ) + { + if ( WP_SaberBladeUseSecondBladeStyle( &client->saber[saberNum], bladeNum ) ) + { + if ( client->saber[saberNum].g2MarksShader2 ) + {//we have a shader to use instead of the standard mark shader + markShader = client->saber[saberNum].g2MarksShader2; + } + if ( client->saber[saberNum].g2WeaponMarkShader2 ) + {//we have a shader to use as a splashback onto the weapon model + weaponMarkShader = client->saber[saberNum].g2WeaponMarkShader2; + } + } + else + { + if ( client->saber[saberNum].g2MarksShader ) + {//we have a shader to use instead of the standard mark shader + markShader = client->saber[saberNum].g2MarksShader; + } + if ( client->saber[saberNum].g2WeaponMarkShader ) + {//we have a shader to use as a splashback onto the weapon model + weaponMarkShader = client->saber[saberNum].g2WeaponMarkShader; + } + } + } + CG_AddGhoul2Mark(markShader, flrand(3.0f, 4.0f), trace.endpos, ePos, trace.entityNum, trEnt->lerpOrigin, trEnt->lerpAngles[YAW], trEnt->ghoul2, trEnt->modelScale, Q_irand(5000, 10000)); + if ( weaponMarkShader ) + { + vec3_t splashBackDir; + VectorScale( ePos, -1 , splashBackDir ); + CG_AddGhoul2Mark(weaponMarkShader, flrand(0.5f, 2.0f), + trace.endpos, splashBackDir, owner->currentState.clientNum, owner->lerpOrigin, owner->lerpAngles[YAW], + owner->ghoul2, owner->modelScale, Q_irand(5000, 10000)); + } } } } @@ -5737,6 +5915,42 @@ void CG_SaberCompWork(vec3_t start, vec3_t end, centity_t *owner) if (doEffect) { + int hitPersonFxID = cgs.effects.mSaberBloodSparks; + int hitOtherFxID = cgs.effects.mSaberCut; + + if (owner->currentState.eType == ET_NPC) + { + client = owner->npcClient; + } + else + { + client = &cgs.clientinfo[owner->currentState.clientNum]; + } + if ( client && client->infoValid ) + { + if ( WP_SaberBladeUseSecondBladeStyle( &client->saber[saberNum], bladeNum ) ) + {//use second blade style values + if ( client->saber[saberNum].hitPersonEffect2 ) + { + hitPersonFxID = client->saber[saberNum].hitPersonEffect2; + } + if ( client->saber[saberNum].hitOtherEffect2 ) + {//custom hit other effect + hitOtherFxID = client->saber[saberNum].hitOtherEffect2; + } + } + else + {//use first blade style values + if ( client->saber[saberNum].hitPersonEffect ) + { + hitPersonFxID = client->saber[saberNum].hitPersonEffect; + } + if ( client->saber[saberNum].hitOtherEffect ) + {//custom hit other effect + hitOtherFxID = client->saber[saberNum].hitOtherEffect; + } + } + } if (!trace.plane.normal[0] && !trace.plane.normal[1] && !trace.plane.normal[2]) { //who cares, just shoot it somewhere. trace.plane.normal[1] = 1; @@ -5744,12 +5958,12 @@ void CG_SaberCompWork(vec3_t start, vec3_t end, centity_t *owner) if (owner->serverSaberFleshImpact) { //do standard player/live ent hit sparks - trap_FX_PlayEffectID( cgs.effects.mSaberBloodSparks, trace.endpos, trace.plane.normal, -1, -1 ); + trap_FX_PlayEffectID( hitPersonFxID, trace.endpos, trace.plane.normal, -1, -1 ); //trap_S_StartSound(trace.endpos, trace.entityNum, CHAN_AUTO, trap_S_RegisterSound(va("sound/weapons/saber/saberhit%i.wav", Q_irand(1, 3)))); } else { //do the cut effect - trap_FX_PlayEffectID( cgs.effects.mSaberCut, trace.endpos, trace.plane.normal, -1, -1 ); + trap_FX_PlayEffectID( hitOtherFxID, trace.endpos, trace.plane.normal, -1, -1 ); } doEffect = qfalse; } @@ -5792,6 +6006,7 @@ void CG_AddSaberBlade( centity_t *cent, centity_t *scent, refEntity_t *saber, in vec3_t futureAngles; effectTrailArgStruct_t fx; int scolor = 0; + int useModelIndex = 0; if (cent->currentState.eType == ET_NPC) { @@ -5815,15 +6030,32 @@ void CG_AddSaberBlade( centity_t *cent, centity_t *scent, refEntity_t *saber, in futureAngles[PITCH] = angles[PITCH]; futureAngles[ROLL] = angles[ROLL]; - //Assume bladeNum is equal to the bolt index because bolts should be added in order of the blades. - if (fromSaber) + + if ( fromSaber ) { - trap_G2API_GetBoltMatrix(scent->ghoul2, 0, bladeNum, &boltMatrix, futureAngles, origin, cg.time, cgs.gameModels, scent->modelScale); + useModelIndex = 0; } else { - trap_G2API_GetBoltMatrix(scent->ghoul2, saberNum+1, bladeNum, &boltMatrix, futureAngles, origin, cg.time, cgs.gameModels, scent->modelScale); + useModelIndex = saberNum+1; } + //Assume bladeNum is equal to the bolt index because bolts should be added in order of the blades. + //if there is an effect on this blade, play it + if ( !WP_SaberBladeUseSecondBladeStyle( &client->saber[saberNum], bladeNum ) + && client->saber[saberNum].bladeEffect ) + { + trap_FX_PlayBoltedEffectID(client->saber[saberNum].bladeEffect, scent->lerpOrigin, + scent->ghoul2, bladeNum, scent->currentState.number, useModelIndex, -1, qfalse); + } + else if ( WP_SaberBladeUseSecondBladeStyle( &client->saber[saberNum], bladeNum ) + && client->saber[saberNum].bladeEffect2 ) + { + trap_FX_PlayBoltedEffectID(client->saber[saberNum].bladeEffect2, scent->lerpOrigin, + scent->ghoul2, bladeNum, scent->currentState.number, useModelIndex, -1, qfalse); + } + //get the boltMatrix + trap_G2API_GetBoltMatrix(scent->ghoul2, useModelIndex, bladeNum, &boltMatrix, futureAngles, origin, cg.time, cgs.gameModels, scent->modelScale); + // work the matrix axis stuff into the original axis and origins used. BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, org_); BG_GiveMeVectorFromMatrix(&boltMatrix, NEGATIVE_Y, axis_[0]); @@ -5901,7 +6133,7 @@ void CG_AddSaberBlade( centity_t *cent, centity_t *scent, refEntity_t *saber, in if (client->saber[saberNum].blade[bladeNum].storageTime < cg.time) { //debounce it in case our framerate is absurdly high. Using storageTime since it's not used for anything else in the client. - CG_SaberCompWork(org_, trace.endpos, cent); + CG_SaberCompWork(org_, trace.endpos, cent, saberNum, bladeNum); client->saber[saberNum].blade[bladeNum].storageTime = cg.time + 5; } @@ -5926,9 +6158,16 @@ void CG_AddSaberBlade( centity_t *cent, centity_t *scent, refEntity_t *saber, in { trDir[1] = 1; } - if (!(trace.surfaceFlags & SURF_NOIMPACT) ) // never spark on sky + + if ( (client->saber[saberNum].saberFlags2&SFL2_NO_WALL_MARKS) ) + {//don't actually draw the marks/impact effects + } + else { - trap_FX_PlayEffectID( cgs.effects.mSparks, trace.endpos, trDir, -1, -1 ); + if (!(trace.surfaceFlags & SURF_NOIMPACT) ) // never spark on sky + { + trap_FX_PlayEffectID( cgs.effects.mSparks, trace.endpos, trDir, -1, -1 ); + } } //Stop saber? (it wouldn't look right if it was stuck through a thin wall and unable to hurt players on the other side) @@ -5937,29 +6176,35 @@ void CG_AddSaberBlade( centity_t *cent, centity_t *scent, refEntity_t *saber, in VectorCopy(trace.endpos, end); - // All I need is a bool to mark whether I have a previous point to work with. - //....come up with something better.. - if ( client->saber[saberNum].blade[bladeNum].trail.haveOldPos[i] ) - { - if ( trace.entityNum == ENTITYNUM_WORLD || cg_entities[trace.entityNum].currentState.eType == ET_TERRAIN || (cg_entities[trace.entityNum].currentState.eFlags & EF_PERMANENT) ) - {//only put marks on architecture - // Let's do some cool burn/glowing mark bits!!! - CG_CreateSaberMarks( client->saber[saberNum].blade[bladeNum].trail.oldPos[i], trace.endpos, trace.plane.normal ); - - //make a sound - if ( cg.time - client->saber[saberNum].blade[bladeNum].hitWallDebounceTime >= 100 ) - {//ugh, need to have a real sound debouncer... or do this game-side - client->saber[saberNum].blade[bladeNum].hitWallDebounceTime = cg.time; - trap_S_StartSound ( trace.endpos, -1, CHAN_WEAPON, trap_S_RegisterSound( va("sound/weapons/saber/saberhitwall%i", Q_irand(1, 3)) ) ); - } - } + if ( (client->saber[saberNum].saberFlags2&SFL2_NO_WALL_MARKS) ) + {//don't actually draw the marks } else - { - // if we impact next frame, we'll mark a slash mark - client->saber[saberNum].blade[bladeNum].trail.haveOldPos[i] = qtrue; - // CG_ImpactMark( cgs.media.rivetMarkShader, client->saber[saberNum].blade[bladeNum].trail.oldPos[i], client->saber[saberNum].blade[bladeNum].trail.oldNormal[i], - // 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, qfalse, 1.1f, qfalse ); + {//draw marks if we hit a wall + // All I need is a bool to mark whether I have a previous point to work with. + //....come up with something better.. + if ( client->saber[saberNum].blade[bladeNum].trail.haveOldPos[i] ) + { + if ( trace.entityNum == ENTITYNUM_WORLD || cg_entities[trace.entityNum].currentState.eType == ET_TERRAIN || (cg_entities[trace.entityNum].currentState.eFlags & EF_PERMANENT) ) + {//only put marks on architecture + // Let's do some cool burn/glowing mark bits!!! + CG_CreateSaberMarks( client->saber[saberNum].blade[bladeNum].trail.oldPos[i], trace.endpos, trace.plane.normal ); + + //make a sound + if ( cg.time - client->saber[saberNum].blade[bladeNum].hitWallDebounceTime >= 100 ) + {//ugh, need to have a real sound debouncer... or do this game-side + client->saber[saberNum].blade[bladeNum].hitWallDebounceTime = cg.time; + trap_S_StartSound ( trace.endpos, -1, CHAN_WEAPON, trap_S_RegisterSound( va("sound/weapons/saber/saberhitwall%i", Q_irand(1, 3)) ) ); + } + } + } + else + { + // if we impact next frame, we'll mark a slash mark + client->saber[saberNum].blade[bladeNum].trail.haveOldPos[i] = qtrue; + // CG_ImpactMark( cgs.media.rivetMarkShader, client->saber[saberNum].blade[bladeNum].trail.oldPos[i], client->saber[saberNum].blade[bladeNum].trail.oldNormal[i], + // 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, qfalse, 1.1f, qfalse ); + } } // stash point so we can connect-the-dots later @@ -5989,6 +6234,14 @@ CheckTrail: goto JustDoIt; } + if ( (!WP_SaberBladeUseSecondBladeStyle( &client->saber[saberNum], bladeNum ) && client->saber[saberNum].trailStyle > 1 ) + || ( WP_SaberBladeUseSecondBladeStyle( &client->saber[saberNum], bladeNum ) && client->saber[saberNum].trailStyle2 > 1 ) ) + {//don't actually draw the trail at all + goto JustDoIt; + } + + //FIXME: if trailStyle is 1, use the motion blur instead + saberTrail = &client->saber[saberNum].blade[bladeNum].trail; saberTrail->duration = saberMoveData[cent->currentState.saberMove].trailLength; @@ -6109,6 +6362,26 @@ CheckTrail: { //don't draw it if the last time is way out of date float oldAlpha = 1.0f - ( diff / trailDur ); + if (cg_saberTrail.integer == 2 && cg_shadows.integer != 2 && cgs.glconfig.stencilBits >= 4) + {//does other stuff below + } + else + { + if ( (!WP_SaberBladeUseSecondBladeStyle( &client->saber[saberNum], bladeNum ) && client->saber[saberNum].trailStyle == 1 ) + || ( WP_SaberBladeUseSecondBladeStyle( &client->saber[saberNum], bladeNum ) && client->saber[saberNum].trailStyle2 == 1 ) ) + {//motion trail + fx.mShader = cgs.media.swordTrailShader; + VectorSet( rgb1, 32.0f, 32.0f, 32.0f ); // make the sith sword trail pretty faint + trailDur *= 2.0f; // stay around twice as long? + } + else + { + fx.mShader = cgs.media.saberBlurShader; + } + fx.mKillTime = trailDur; + fx.mSetFlags = FX_USE_ALPHA; + } + // New muzzle VectorCopy( rgb1, fx.mVerts[0].rgb ); fx.mVerts[0].alpha = 255.0f; @@ -6161,12 +6434,14 @@ CheckTrail: fx.mShader = 2; //2 is always refractive shader fx.mSetFlags = FX_USE_ALPHA; } + /* else { fx.mShader = cgs.media.saberBlurShader; fx.mKillTime = trailDur; fx.mSetFlags = FX_USE_ALPHA; } + */ trap_FX_AddPrimitive(&fx); } @@ -6187,12 +6462,21 @@ JustDoIt: return; } + if ( (client->saber[saberNum].saberFlags2&SFL2_NO_BLADE) ) + {//don't actually draw the blade at all + if ( client->saber[saberNum].numBlades < 3 + && !(client->saber[saberNum].saberFlags2&SFL2_NO_DLIGHT) ) + {//hmm, but still add the dlight + CG_DoSaberLight( &client->saber[saberNum] ); + } + return; + } // Pass in the renderfx flags attached to the saber weapon model...this is done so that saber glows // will get rendered properly in a mirror...not sure if this is necessary?? //CG_DoSaber( org_, axis_[0], saberLen, client->saber[saberNum].blade[bladeNum].lengthMax, client->saber[saberNum].blade[bladeNum].radius, // scolor, renderfx, (qboolean)(saberNum==0&&bladeNum==0) ); CG_DoSaber( org_, axis_[0], saberLen, client->saber[saberNum].blade[bladeNum].lengthMax, client->saber[saberNum].blade[bladeNum].radius, - scolor, renderfx, (qboolean)(client->saber[saberNum].numBlades < 3) ); + scolor, renderfx, (qboolean)(client->saber[saberNum].numBlades < 3 && !(client->saber[saberNum].saberFlags2&SFL2_NO_DLIGHT)) ); } int CG_IsMindTricked(int trickIndex1, int trickIndex2, int trickIndex3, int trickIndex4, int client) @@ -6919,6 +7203,9 @@ void CG_G2AnimEntModelLoad(centity_t *cent) //jetpack bolted to must always be third. trap_G2API_AddBolt(cent->ghoul2, 0, "*chestg"); + //claw bolts + trap_G2API_AddBolt(cent->ghoul2, 0, "*r_hand_cap_r_arm"); + trap_G2API_AddBolt(cent->ghoul2, 0, "*l_hand_cap_l_arm"); if (strstr(GLAName, "players/rockettrooper/")) { @@ -6979,10 +7266,15 @@ void CG_G2AnimEntModelLoad(centity_t *cent) static void CG_CreateSurfaceDebris(centity_t *cent, int surfNum, int fxID, qboolean throwPart) { int lostPartFX = 0; - int b; + int b = -1; vec3_t v, d; mdxaBone_t boltMatrix; - const char *surfName = bgToggleableSurfaces[surfNum]; + const char *surfName = NULL; + + if ( surfNum > 0 ) + { + surfName = bgToggleableSurfaces[surfNum]; + } if (!cent->ghoul2) { //oh no @@ -7039,21 +7331,25 @@ static void CG_CreateSurfaceDebris(centity_t *cent, int surfNum, int fxID, qbool lostPartFX = cent->m_pVehicle->m_pVehicleInfo->iNoseFX; } } - else + else if ( surfName ) { b = trap_G2API_AddBolt(cent->ghoul2, 0, surfName); } - if (b == -1) - { //couldn't find this surface apparently - return; + if (b == -1 || surfNum == -1) + { //couldn't find this surface apparently, so play on origin? + VectorCopy( cent->lerpOrigin, v ); + AngleVectors( cent->lerpAngles, d, NULL, NULL ); + VectorNormalize( d ); + } + else + { + //now let's get the position and direction of this surface and make a big explosion + trap_G2API_GetBoltMatrix(cent->ghoul2, 0, b, &boltMatrix, cent->lerpAngles, cent->lerpOrigin, cg.time, + cgs.gameModels, cent->modelScale); + BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, v); + BG_GiveMeVectorFromMatrix(&boltMatrix, POSITIVE_Z, d); } - - //now let's get the position and direction of this surface and make a big explosion - trap_G2API_GetBoltMatrix(cent->ghoul2, 0, b, &boltMatrix, cent->lerpAngles, cent->lerpOrigin, cg.time, - cgs.gameModels, cent->modelScale); - BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, v); - BG_GiveMeVectorFromMatrix(&boltMatrix, POSITIVE_Z, d); trap_FX_PlayEffectID(fxID, v, d, -1, -1); if ( throwPart && lostPartFX ) @@ -7313,6 +7609,10 @@ void CG_ForceFPLSPlayerModel(centity_t *cent, clientInfo_t *ci) //jetpack bolted to must always be third. trap_G2API_AddBolt(ci->ghoul2Model, 0, "*chestg"); + //claw bolts + trap_G2API_AddBolt(ci->ghoul2Model, 0, "*r_hand_cap_r_arm"); + trap_G2API_AddBolt(ci->ghoul2Model, 0, "*l_hand_cap_l_arm"); + ci->bolt_head = trap_G2API_AddBolt(ci->ghoul2Model, 0, "*head_top"); if (ci->bolt_head == -1) { @@ -7756,6 +8056,7 @@ static CGAME_INLINE void CG_VehicleEffects(centity_t *cent) // Animals don't exude any effects... if ( pVehNPC->m_pVehicleInfo->type != VH_ANIMAL ) { + qboolean didFireTrail = qfalse; if (pVehNPC->m_pVehicleInfo->surfDestruction && cent->ghoul2) { //see if anything has been blown off int i = 0; @@ -7774,6 +8075,7 @@ static CGAME_INLINE void CG_VehicleEffects(centity_t *cent) //create some flames CG_CreateSurfaceDebris(cent, i, cgs.effects.mShipDestBurning, qfalse); + didFireTrail = qtrue; } } @@ -7785,6 +8087,10 @@ static CGAME_INLINE void CG_VehicleEffects(centity_t *cent) return; } } + if ( !didFireTrail && (cent->currentState.eFlags&EF_DEAD) ) + {//spiralling out of control anyway + CG_CreateSurfaceDebris(cent, -1, cgs.effects.mShipDestBurning, qfalse); + } if ( pVehNPC->m_iLastFXTime <= cg.time ) {//until we attach it, we need to debounce this @@ -8152,6 +8458,13 @@ void CG_Player( centity_t *cent ) { if (cent->currentState.iModelScale) { //if the server says we have a custom scale then set it now. cent->modelScale[0] = cent->modelScale[1] = cent->modelScale[2] = cent->currentState.iModelScale/100.0f; + if ( cent->currentState.NPC_class != CLASS_VEHICLE ) + { + if (cent->modelScale[2] && cent->modelScale[2] != 1.0f) + { + cent->lerpOrigin[2] += 24 * (cent->modelScale[2] - 1); + } + } } else { @@ -8292,6 +8605,10 @@ void CG_Player( centity_t *cent ) { //jetpack bolted to must always be third. trap_G2API_AddBolt(cent->npcClient->ghoul2Model, 0, "*chestg"); + //claw bolts + trap_G2API_AddBolt(cent->npcClient->ghoul2Model, 0, "*r_hand_cap_r_arm"); + trap_G2API_AddBolt(cent->npcClient->ghoul2Model, 0, "*l_hand_cap_l_arm"); + cent->npcClient->bolt_head = trap_G2API_AddBolt(cent->npcClient->ghoul2Model, 0, "*head_top"); if (cent->npcClient->bolt_head == -1) { @@ -8390,7 +8707,14 @@ void CG_Player( centity_t *cent ) { if (cg.predictedPlayerState.pm_type == PM_INTERMISSION) { //don't show all this shit during intermission - return; + if ( cent->currentState.eType == ET_NPC + && cent->currentState.NPC_class != CLASS_VEHICLE ) + {//NPC in intermission + } + else + {//don't render players or vehicles in intermissions, allow other NPCs for scripts + return; + } } CG_VehicleEffects(cent); @@ -9873,7 +10197,7 @@ stillDoSaber: if (!saberEnt->currentState.saberInFlight && saberEnt->currentState.bolt2 != 123) { //owner is pulling is back - if ( !ci->saber[0].returnDamage + if ( !(ci->saber[0].saberFlags&SFL_RETURN_DAMAGE) || cent->currentState.saberHolstered ) { vec3_t owndir; @@ -10216,9 +10540,9 @@ stillDoSaber: if (cent->currentState.number != cg.snap->ps.duelIndex && cent->currentState.number != cg.snap->ps.clientNum) { //everyone not involved in the duel is drawn very dark - legs.shaderRGBA[0] = 50; - legs.shaderRGBA[1] = 50; - legs.shaderRGBA[2] = 50; + legs.shaderRGBA[0] /= 5.0f; + legs.shaderRGBA[1] /= 5.0f; + legs.shaderRGBA[2] /= 5.0f; legs.renderfx |= RF_RGB_TINT; } else @@ -10245,31 +10569,23 @@ stillDoSaber: subLen = 1020; } - legs.shaderRGBA[0] = 255 - subLen/4; - legs.shaderRGBA[1] = 255 - subLen/4; - legs.shaderRGBA[2] = 255 - subLen/4; - - if (legs.shaderRGBA[2] < 1) legs.shaderRGBA[2] = 1; + { + const unsigned char savRGBA[3] = {legs.shaderRGBA[0],legs.shaderRGBA[1],legs.shaderRGBA[2]}; + legs.shaderRGBA[0] = max(255-subLen/4,1); + legs.shaderRGBA[1] = max(255-subLen/4,1); + legs.shaderRGBA[2] = max(255-subLen/4,1); legs.renderfx &= ~RF_RGB_TINT; legs.renderfx &= ~RF_FORCE_ENT_ALPHA; legs.customShader = cgs.media.forceShell; - trap_R_AddRefEntityToScene( &legs ); + trap_R_AddRefEntityToScene( &legs ); //draw the shell - legs.customShader = 0; + legs.customShader = 0; //reset to player model - legs.shaderRGBA[0] = 255 - subLen/8; - legs.shaderRGBA[1] = 255 - subLen/8; - legs.shaderRGBA[2] = 255 - subLen/8; - - if (legs.shaderRGBA[2] < 1) - { - legs.shaderRGBA[2] = 1; - } - if (legs.shaderRGBA[2] > 255) - { - legs.shaderRGBA[2] = 255; + legs.shaderRGBA[0] = max(savRGBA[0]-subLen/8,1); + legs.shaderRGBA[1] = max(savRGBA[1]-subLen/8,1); + legs.shaderRGBA[2] = max(savRGBA[2]-subLen/8,1); } if (subLen <= 1024) @@ -10811,6 +11127,16 @@ void CG_ResetPlayerEntity( centity_t *cent ) if (cent->currentState.eType == ET_NPC) { + if (cent->currentState.NPC_class == CLASS_VEHICLE && + cent->m_pVehicle && + cent->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER && + cg.predictedPlayerState.m_iVehicleNum && + cent->currentState.number == cg.predictedPlayerState.m_iVehicleNum) + { //holy hackery, batman! + //I don't think this will break anything. But really, do I ever? + return; + } + if (!cent->npcClient) { CG_CreateNPCClient(¢->npcClient); //allocate memory for it diff --git a/codemp/cgame/cg_predict.c b/codemp/cgame/cg_predict.c index 3fca6cd..bdee1e7 100644 --- a/codemp/cgame/cg_predict.c +++ b/codemp/cgame/cg_predict.c @@ -1477,7 +1477,7 @@ void CG_PredictPlayerState( void ) { !CG_Piloting(cg.predictedPlayerState.m_iVehicleNum)) { //a passenger on this vehicle, bolt them in centity_t *veh = &cg_entities[cg.predictedPlayerState.m_iVehicleNum]; - VectorCopy(veh->lerpAngles, cg.predictedPlayerState.viewangles); + //VectorCopy(veh->lerpAngles, cg.predictedPlayerState.viewangles); VectorCopy(veh->lerpOrigin, cg.predictedPlayerState.origin); } diff --git a/codemp/cgame/cg_public.h b/codemp/cgame/cg_public.h index a8e435e..04d6ae5 100644 --- a/codemp/cgame/cg_public.h +++ b/codemp/cgame/cg_public.h @@ -263,6 +263,7 @@ Ghoul2 Insert Start CG_G2_INITGHOUL2MODEL, CG_G2_SETSKIN, CG_G2_COLLISIONDETECT, + CG_G2_COLLISIONDETECTCACHE, CG_G2_CLEANMODELS, CG_G2_ANGLEOVERRIDE, CG_G2_PLAYANIM, @@ -434,6 +435,8 @@ typedef enum { CG_MISC_ENT, //rwwRMG - added CG_GET_SORTED_FORCE_POWER, + + CG_FX_CAMERASHAKE,//mcg post-gold added } cgameExport_t; typedef struct diff --git a/codemp/cgame/cg_servercmds.c b/codemp/cgame/cg_servercmds.c index eb8faab..7cd1ea5 100644 --- a/codemp/cgame/cg_servercmds.c +++ b/codemp/cgame/cg_servercmds.c @@ -139,10 +139,10 @@ void CG_ParseServerinfo( void ) { trap_Cvar_Set ( "ui_about_mapname", mapname ); Com_sprintf( cgs.mapname, sizeof( cgs.mapname ), "maps/%s.bsp", mapname ); - Q_strncpyz( cgs.redTeam, Info_ValueForKey( info, "g_redTeam" ), sizeof(cgs.redTeam) ); - trap_Cvar_Set("g_redTeam", cgs.redTeam); - Q_strncpyz( cgs.blueTeam, Info_ValueForKey( info, "g_blueTeam" ), sizeof(cgs.blueTeam) ); - trap_Cvar_Set("g_blueTeam", cgs.blueTeam); +// Q_strncpyz( cgs.redTeam, Info_ValueForKey( info, "g_redTeam" ), sizeof(cgs.redTeam) ); +// trap_Cvar_Set("g_redTeam", cgs.redTeam); +// Q_strncpyz( cgs.blueTeam, Info_ValueForKey( info, "g_blueTeam" ), sizeof(cgs.blueTeam) ); +// trap_Cvar_Set("g_blueTeam", cgs.blueTeam); trap_Cvar_Set ( "ui_about_gametype", va("%i", cgs.gametype ) ); trap_Cvar_Set ( "ui_about_fraglimit", va("%i", cgs.fraglimit ) ); @@ -1532,7 +1532,7 @@ static void CG_ServerCommand( void ) { x++; } trap_SP_GetStringTextString(x, strEd, MAX_STRINGED_SV_STRING); - CG_CenterPrint( strEd, SCREEN_HEIGHT * 0.30, BIGCHAR_WIDTH ); + CG_CenterPrint( strEd, SCREEN_HEIGHT * 0.20, BIGCHAR_WIDTH ); return; } diff --git a/codemp/cgame/cg_syscalls.c b/codemp/cgame/cg_syscalls.c index 99426cd..aa6ddfb 100644 --- a/codemp/cgame/cg_syscalls.c +++ b/codemp/cgame/cg_syscalls.c @@ -835,6 +835,24 @@ void trap_G2API_CollisionDetect ( syscall ( CG_G2_COLLISIONDETECT, collRecMap, ghoul2, angles, position, frameNumber, entNum, rayStart, rayEnd, scale, traceFlags, useLod, PASSFLOAT(fRadius) ); } +void trap_G2API_CollisionDetectCache ( + CollisionRecord_t *collRecMap, + void* ghoul2, + const vec3_t angles, + const vec3_t position, + int frameNumber, + int entNum, + const vec3_t rayStart, + const vec3_t rayEnd, + const vec3_t scale, + int traceFlags, + int useLod, + float fRadius + ) +{ + syscall ( CG_G2_COLLISIONDETECTCACHE, collRecMap, ghoul2, angles, position, frameNumber, entNum, rayStart, rayEnd, scale, traceFlags, useLod, PASSFLOAT(fRadius) ); +} + void trap_G2API_CleanGhoul2Models(void **ghoul2Ptr) { syscall(CG_G2_CLEANMODELS, ghoul2Ptr); diff --git a/codemp/cgame/cg_view.c b/codemp/cgame/cg_view.c index 1725da4..0caec14 100644 --- a/codemp/cgame/cg_view.c +++ b/codemp/cgame/cg_view.c @@ -794,7 +794,10 @@ static void CG_OffsetThirdPersonView( void ) cameraLastFrame=cg.time; } - +void CG_GetVehicleCamPos( vec3_t camPos ) +{ + VectorCopy( cg.refdef.vieworg, camPos ); +} /* =============== @@ -1488,6 +1491,11 @@ qboolean CG_CheckPassengerTurretView( void ) {// valid turret if ( vehCent->m_pVehicle->m_pVehicleInfo->turret[turretNum].passengerNum == cg.predictedPlayerState.generic1 ) {//I control this turret + //Ah, crap, just look around freely... below method is way too wiggy + VectorCopy( cg.predictedPlayerState.origin, cg.refdef.vieworg ); + VectorCopy( cg.predictedPlayerState.viewangles, cg.refdef.viewangles ); + return qtrue; + /* int boltIndex = -1; qboolean hackPosAndAngle = qfalse; if ( vehCent->m_pVehicle->m_iGunnerViewTag[turretNum] != -1 ) @@ -1537,6 +1545,7 @@ qboolean CG_CheckPassengerTurretView( void ) } return qtrue; } + */ } } } @@ -1602,6 +1611,7 @@ static int CG_CalcViewValues( void ) { if ( !manningTurret ) {//not manning a turret on a vehicle VectorCopy( ps->origin, cg.refdef.vieworg ); +#ifdef VEH_CONTROL_SCHEME_4 if ( cg.predictedPlayerState.m_iVehicleNum )//in a vehicle { Vehicle_t *pVeh = cg_entities[cg.predictedPlayerState.m_iVehicleNum].m_pVehicle; @@ -1620,13 +1630,14 @@ static int CG_CalcViewValues( void ) { { VectorCopy( ps->viewangles, cg.refdef.viewangles ); } - /* + } +#else// VEH_CONTROL_SCHEME_4 if ( cg.predictedPlayerState.m_iVehicleNum //in a vehicle && BG_UnrestrainedPitchRoll( &cg.predictedPlayerState, cg_entities[cg.predictedPlayerState.m_iVehicleNum].m_pVehicle ) )//can roll/pitch without restriction {//use the vehicle's viewangles to render view! VectorCopy( cg.predictedVehicleState.viewangles, cg.refdef.viewangles ); - */ } +#endif// VEH_CONTROL_SCHEME_4 else { VectorCopy( ps->viewangles, cg.refdef.viewangles ); @@ -1660,7 +1671,9 @@ static int CG_CalcViewValues( void ) { CG_EmplacedView(cg_entities[cg.snap->ps.emplacedIndex].currentState.angles); } - if ( !manningTurret ) + //FIX: okay, if manning a turret, let view turn freely, + // and use the vehicle chase camera info to place vieworg + //if ( !manningTurret ) { if ( cg.predictedPlayerState.m_iVehicleNum //in a vehicle && BG_UnrestrainedPitchRoll( &cg.predictedPlayerState, cg_entities[cg.predictedPlayerState.m_iVehicleNum].m_pVehicle ) )//can roll/pitch without restriction @@ -2113,6 +2126,28 @@ FF_XboxShake(intensity, duration); #endif } +void CG_DoCameraShake( vec3_t origin, float intensity, int radius, int time ) +{ + //FIXME: When exactly is the vieworg calculated in relation to the rest of the frame?s + + vec3_t dir; + float dist, intensityScale; + float realIntensity; + + VectorSubtract( cg.refdef.vieworg, origin, dir ); + dist = VectorNormalize( dir ); + + //Use the dir to add kick to the explosion + + if ( dist > radius ) + return; + + intensityScale = 1 - ( dist / (float) radius ); + realIntensity = intensity * intensityScale; + + CGCam_Shake( realIntensity, time ); +} + void CGCam_SetMusicMult( float multiplier, int duration ) { if (multiplier < 0.1f) @@ -2415,10 +2450,12 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo float mSensitivity = cg.zoomSensitivity; float mPitchOverride = 0.0f; float mYawOverride = 0.0f; + static centity_t *veh = NULL; +#ifdef VEH_CONTROL_SCHEME_4 float mSensitivityOverride = 0.0f; qboolean bUseFighterPitch = qfalse; - static centity_t *veh = NULL; qboolean isFighter = qfalse; +#endif if (cgQueueLoad) { //do this before you start messing around with adding ghoul2 refents and crap @@ -2514,6 +2551,7 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo { //lower sens for emplaced guns and vehicles mSensitivity = 0.2f; } +#ifdef VEH_CONTROL_SCHEME_4 else if (cg.predictedPlayerState.m_iVehicleNum//in a vehicle && !cg.predictedPlayerState.generic1 )//not as a passenger { @@ -2532,6 +2570,7 @@ void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demo } if ( !isFighter ) +#endif //VEH_CONTROL_SCHEME_4 { if (cg.predictedPlayerState.m_iVehicleNum) { diff --git a/codemp/cgame/mssccprj.scc b/codemp/cgame/mssccprj.scc index 29690e0..78747a6 100644 --- a/codemp/cgame/mssccprj.scc +++ b/codemp/cgame/mssccprj.scc @@ -1,5 +1,5 @@ SCC = This is a Source Code Control file [JK2_cgame.vcproj] -SCC_Aux_Path = "\\ravendata1\vss\central_code" +SCC_Aux_Path = "\\ravendata1\VSS\central_code" SCC_Project_Name = "$/jedi/codemp/cgame", ICAAAAAA diff --git a/codemp/cgame/vssver.scc b/codemp/cgame/vssver.scc index 816c8ab..6739b60 100644 Binary files a/codemp/cgame/vssver.scc and b/codemp/cgame/vssver.scc differ diff --git a/codemp/client/FxSystem.cpp b/codemp/client/FxSystem.cpp index 9bb5a51..110a25b 100644 --- a/codemp/client/FxSystem.cpp +++ b/codemp/client/FxSystem.cpp @@ -89,8 +89,7 @@ void SFxHelper::CameraShake( vec3_t origin, float intensity, int radius, int tim data->mRadius = radius; data->mTime = time; -// VM_Call( cgvm, CG_FX_CAMERASHAKE ); - //FIXME + VM_Call( cgvm, CG_FX_CAMERASHAKE ); } //------------------------------------------------------ diff --git a/codemp/client/OpenAL/vssver.scc b/codemp/client/OpenAL/vssver.scc index b5e63e3..2aa5686 100644 Binary files a/codemp/client/OpenAL/vssver.scc and b/codemp/client/OpenAL/vssver.scc differ diff --git a/codemp/client/cl_cgame.cpp b/codemp/client/cl_cgame.cpp index 0b86ded..6460965 100644 --- a/codemp/client/cl_cgame.cpp +++ b/codemp/client/cl_cgame.cpp @@ -1351,6 +1351,21 @@ Ghoul2 Insert Start VMF(12) ); return 0; + case CG_G2_COLLISIONDETECTCACHE: + G2API_CollisionDetectCache ( (CollisionRecord_t*)VMA(1), *((CGhoul2Info_v *)args[2]), + (const float*)VMA(3), + (const float*)VMA(4), + args[5], + args[6], + (float*)VMA(7), + (float*)VMA(8), + (float*)VMA(9), + G2VertSpaceClient, + args[10], + args[11], + VMF(12) ); + return 0; + case CG_G2_ANGLEOVERRIDE: return G2API_SetBoneAngles(*((CGhoul2Info_v *)args[1]), args[2], (const char *)VMA(3), (float *)VMA(4), args[5], (const Eorientations) args[6], (const Eorientations) args[7], (const Eorientations) args[8], diff --git a/codemp/client/cl_input.cpp b/codemp/client/cl_input.cpp index 0bf6dd6..fb8b0df 100644 --- a/codemp/client/cl_input.cpp +++ b/codemp/client/cl_input.cpp @@ -16,7 +16,12 @@ float cl_mYawOverride = 0.0f; float cl_mSensitivityOverride = 0.0f; qboolean cl_bUseFighterPitch = qfalse; qboolean cl_crazyShipControls = qfalse; + +#ifdef VEH_CONTROL_SCHEME_4 #define OVERRIDE_MOUSE_SENSITIVITY 5.0f//20.0f = 180 degree turn in one mouse swipe across keyboard +#else// VEH_CONTROL_SCHEME_4 +#define OVERRIDE_MOUSE_SENSITIVITY 10.0f//20.0f = 180 degree turn in one mouse swipe across keyboard +#endif// VEH_CONTROL_SCHEME_4 /* =============================================================================== diff --git a/codemp/client/cl_keys.cpp b/codemp/client/cl_keys.cpp index 9f639a5..c9e76ff 100644 --- a/codemp/client/cl_keys.cpp +++ b/codemp/client/cl_keys.cpp @@ -1505,11 +1505,7 @@ void CL_KeyEvent (int key, qboolean down, unsigned time) { // kg.keys can still be used for bound actions if ( down && /*( key < 128 || key == A_MOUSE1 ) && */ -#ifdef _XBOX // No demos on Xbox ( cls.state == CA_CINEMATIC ) && -#else - ( clc.demoplaying || cls.state == CA_CINEMATIC ) && -#endif !cls.keyCatchers) { if (Cvar_VariableValue ("com_cameraMode") == 0) { diff --git a/codemp/client/cl_main.cpp b/codemp/client/cl_main.cpp index 9c9af3d..46c8218 100644 --- a/codemp/client/cl_main.cpp +++ b/codemp/client/cl_main.cpp @@ -971,6 +971,7 @@ void CL_RequestMotd( void ) { Info_SetValueForKey( info, "challenge", cls.updateChallenge ); Info_SetValueForKey( info, "renderer", cls.glconfig.renderer_string ); + Info_SetValueForKey( info, "rvendor", cls.glconfig.vendor_string ); Info_SetValueForKey( info, "version", com_version->string ); Info_SetValueForKey( info, "cputype", Cvar_VariableString("sys_cpustring") ); @@ -2636,15 +2637,16 @@ void CL_Init( void ) { Cvar_Get ("snaps", "20", CVAR_USERINFO | CVAR_ARCHIVE ); Cvar_Get ("model", "kyle/default", CVAR_USERINFO | CVAR_ARCHIVE ); Cvar_Get ("forcepowers", "7-1-032330000000001333", CVAR_USERINFO | CVAR_ARCHIVE ); - Cvar_Get ("g_redTeam", "Empire", CVAR_SERVERINFO | CVAR_ARCHIVE); - Cvar_Get ("g_blueTeam", "Rebellion", CVAR_SERVERINFO | CVAR_ARCHIVE); +// Cvar_Get ("g_redTeam", "Empire", CVAR_SERVERINFO | CVAR_ARCHIVE); +// Cvar_Get ("g_blueTeam", "Rebellion", CVAR_SERVERINFO | CVAR_ARCHIVE); Cvar_Get ("color1", "4", CVAR_USERINFO | CVAR_ARCHIVE ); Cvar_Get ("color2", "4", CVAR_USERINFO | CVAR_ARCHIVE ); Cvar_Get ("handicap", "100", CVAR_USERINFO | CVAR_ARCHIVE ); Cvar_Get ("teamtask", "0", CVAR_USERINFO ); Cvar_Get ("sex", "male", CVAR_USERINFO | CVAR_ARCHIVE ); +#ifdef USE_CD_KEY Cvar_Get ("cl_anonymous", "0", CVAR_USERINFO | CVAR_ARCHIVE ); - +#endif Cvar_Get ("password", "", CVAR_USERINFO); Cvar_Get ("cg_predictItems", "1", CVAR_USERINFO | CVAR_ARCHIVE ); @@ -2845,7 +2847,7 @@ void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) { prot = atoi( Info_ValueForKey( infoString, "protocol" ) ); if ( prot != PROTOCOL_VERSION ) { Com_DPrintf( "Different protocol info packet: %s\n", infoString ); -// return; + return; } #ifdef _XBOX @@ -3085,6 +3087,10 @@ void CL_ServerStatusResponse( netadr_t from, msg_t *msg ) { Com_sprintf(&serverStatus->string[len], sizeof(serverStatus->string)-len, "%s", s); if (serverStatus->print) { + Com_Printf( "Server (%i.%i.%i.%i:%i)\n", + serverStatus->address.ip[0], serverStatus->address.ip[1], + serverStatus->address.ip[2], serverStatus->address.ip[3], + BigShort( serverStatus->address.port ) ); Com_Printf("Server settings:\n"); // print cvars while (*s) { diff --git a/codemp/client/cl_scrn.cpp b/codemp/client/cl_scrn.cpp index ec12b2b..9964527 100644 --- a/codemp/client/cl_scrn.cpp +++ b/codemp/client/cl_scrn.cpp @@ -344,9 +344,9 @@ void SCR_DrawDebugGraph (void) // // draw the graph // - w = cls.glconfig.vidWidth; + w = 640; x = 0; - y = cls.glconfig.vidHeight; + y = 480; re.SetColor( g_color_table[0] ); re.DrawStretchPic(x, y - cl_graphheight->integer, w, cl_graphheight->integer, 0, 0, 0, 0, cls.whiteShader ); diff --git a/codemp/client/cl_ui.cpp b/codemp/client/cl_ui.cpp index b0fd9f8..8c006ef 100644 --- a/codemp/client/cl_ui.cpp +++ b/codemp/client/cl_ui.cpp @@ -1270,6 +1270,7 @@ Ghoul2 Insert Start case UI_G2_COLLISIONDETECT: + case UI_G2_COLLISIONDETECTCACHE: return 0; //not supported for ui case UI_G2_ANGLEOVERRIDE: diff --git a/codemp/client/eax/vssver.scc b/codemp/client/eax/vssver.scc index 980e029..c10ae54 100644 Binary files a/codemp/client/eax/vssver.scc and b/codemp/client/eax/vssver.scc differ diff --git a/codemp/client/snd_dma.cpp b/codemp/client/snd_dma.cpp index 0d340e3..bdfcc58 100644 --- a/codemp/client/snd_dma.cpp +++ b/codemp/client/snd_dma.cpp @@ -536,6 +536,19 @@ void S_Init( void ) { // Sources / Channels are not sending to any Slots (other than the Listener / Primary FX Slot) s_channels[i].lSlotID = -1; + if (s_bEAX) + { + // Remove the RoomAuto flag from each Source (to remove Reverb Engine Statistical + // model that is assuming units are in metres) + // Without this call reverb sends from the sources will attenuate too quickly + // with distance, especially for the non-primary reverb zones. + + unsigned long ulFlags = 0; + + s_eaxSet(&EAXPROPERTYID_EAX40_Source, EAXSOURCE_FLAGS, + s_channels[i].alSource, &ulFlags, sizeof(ulFlags)); + } + s_numChannels++; } @@ -6156,21 +6169,11 @@ void UpdateEAXListener() } } + lVolume = 0; for (i = 0; i < s_NumFXSlots; i++) { - if (s_FXSlotInfo[i].lEnvID == s_EnvironmentID) - { - lVolume = 0; - if (s_eaxSet(&s_FXSlotInfo[i].FXSlotGuid, EAXFXSLOT_VOLUME, NULL, &lVolume, sizeof(long))!=AL_NO_ERROR) - OutputDebugString("Failed to set Listener's FX Slot Volume to 0\n"); - } - else - { - // This will change to lower the volume based on distance from aperture ... - lVolume = -600; - if (s_eaxSet(&s_FXSlotInfo[i].FXSlotGuid, EAXFXSLOT_VOLUME, NULL, &lVolume, sizeof(long))!=AL_NO_ERROR) - OutputDebugString("Failed to set FX Slot Volume to 0\n"); - } + if (s_eaxSet(&s_FXSlotInfo[i].FXSlotGuid, EAXFXSLOT_VOLUME, NULL, &lVolume, sizeof(long))!=AL_NO_ERROR) + OutputDebugString("Failed to set FX Slot Volume to 0\n"); } } diff --git a/codemp/client/vssver.scc b/codemp/client/vssver.scc index bfad7ab..97c54c3 100644 Binary files a/codemp/client/vssver.scc and b/codemp/client/vssver.scc differ diff --git a/codemp/encryption/vssver.scc b/codemp/encryption/vssver.scc index 0b49e26..aa36319 100644 Binary files a/codemp/encryption/vssver.scc and b/codemp/encryption/vssver.scc differ diff --git a/codemp/ff/vssver.scc b/codemp/ff/vssver.scc index f018f4c..bd49a4f 100644 Binary files a/codemp/ff/vssver.scc and b/codemp/ff/vssver.scc differ diff --git a/codemp/game/FighterNPC.c b/codemp/game/FighterNPC.c index c694b76..e3e7fb1 100644 --- a/codemp/game/FighterNPC.c +++ b/codemp/game/FighterNPC.c @@ -88,6 +88,9 @@ extern qboolean BG_UnrestrainedPitchRoll( playerState_t *ps, Vehicle_t *pVeh ); extern void BG_SetAnim(playerState_t *ps, animation_t *animations, int setAnimParts,int anim,int setAnimFlags, int blendTime); extern int BG_GetTime(void); +#ifdef QAGAME //including game headers on cgame is FORBIDDEN ^_^ +extern void G_DamageFromKiller( gentity_t *pEnt, gentity_t *pVehEnt, gentity_t *attacker, vec3_t org, int damage, int dflags, int mod ); +#endif #endif extern void BG_ExternThisSoICanRecompileInDebug( Vehicle_t *pVeh, playerState_t *riderPS ); @@ -374,6 +377,7 @@ static void ProcessMoveCommands( Vehicle_t *pVeh ) float speedInc, speedIdleDec, speedIdle, speedIdleAccel, speedMin, speedMax; bgEntity_t *parent = pVeh->m_pParentEntity; qboolean isLandingOrLaunching = qfalse; + /* #ifndef _JK2MP//SP int curTime = level.time; #elif QAGAME//MP GAME @@ -382,6 +386,10 @@ static void ProcessMoveCommands( Vehicle_t *pVeh ) //FIXME: pass in ucmd? Not sure if this is reliable... int curTime = pm->cmd.serverTime; #endif + */ + //this function should only be called from pmove.. if it gets called elsehwere, + //obviously this will explode. + int curTime = pm->cmd.serverTime; #ifdef _JK2MP playerState_t *parentPS = parent->playerState; @@ -496,33 +504,14 @@ static void ProcessMoveCommands( Vehicle_t *pVeh ) if ((curTime - pVeh->m_iTurboTime)>pVeh->m_pVehicleInfo->turboRecharge) { pVeh->m_iTurboTime = (curTime + pVeh->m_pVehicleInfo->turboDuration); - if (pVeh->m_pVehicleInfo->iTurboStartFX) - { - int i; - for (i=0; im_iExhaustTag[i]==-1) - { - break; - } - #ifndef _JK2MP//SP - G_PlayEffect(pVeh->m_pVehicleInfo->iTurboStartFX, pVeh->m_pParentEntity->playerModel, pVeh->m_iExhaustTag[i], pVeh->m_pParentEntity->s.number, pVeh->m_pParentEntity->currentOrigin ); - #else - //TODO: MP Play Effect? - #endif - } - } + +#ifdef QAGAME//MP GAME-side //NOTE: turbo sound can't be part of effect if effect is played on every muzzle! if ( pVeh->m_pVehicleInfo->soundTurbo ) { -#ifndef _JK2MP//SP - G_SoundIndexOnEnt( pVeh->m_pParentEntity, CHAN_AUTO, pVeh->m_pVehicleInfo->soundTurbo ); -#elif QAGAME//MP GAME-side G_EntitySound( ((gentity_t *)(pVeh->m_pParentEntity)), CHAN_AUTO, pVeh->m_pVehicleInfo->soundTurbo ); -#elif CGAME//MP CGAME-side - //trap_S_StartSound( NULL, pVeh->m_pParentEntity->s.number, CHAN_AUTO, pVeh->m_pVehicleInfo->soundTurbo ); -#endif } +#endif } } speedInc = pVeh->m_pVehicleInfo->acceleration * pVeh->m_fTimeModifier; @@ -530,7 +519,10 @@ static void ProcessMoveCommands( Vehicle_t *pVeh ) {//going turbo speed speedMax = pVeh->m_pVehicleInfo->turboSpeed; //double our acceleration - speedInc *= 2.0f; + //speedInc *= 2.0f; + //no no no! this would el breako el predictiono! we want the following... -rww + speedInc = (pVeh->m_pVehicleInfo->acceleration*2.0f) * pVeh->m_fTimeModifier; + //force us to move forward pVeh->m_ucmd.forwardmove = 127; #ifdef _JK2MP//SP can cheat and just check m_iTurboTime directly... :) @@ -737,7 +729,8 @@ static void ProcessMoveCommands( Vehicle_t *pVeh ) && pVeh->m_pVehicleInfo->Inhabited( pVeh )//has to have a driver in order to be capable of landing #endif && !pVeh->m_iRemovedSurfaces - && parentPS->electrifyTimeelectrifyTime < curTime + && parentPS->vehTurnaroundTime < curTime && (pVeh->m_LandTrace.fraction >= 1.0f//no grounf ||pVeh->m_LandTrace.plane.normal[2] < MIN_LANDING_SLOPE//can't land here ||parentPS->speed>MIN_LANDING_SPEED)//going too fast to land @@ -786,7 +779,7 @@ static void ProcessMoveCommands( Vehicle_t *pVeh ) //strafing takes away from forward speed? If so, strafePerc above should use speedMax //parentPS->speed *= (1.0f-pVeh->m_pVehicleInfo->strafePerc); } - else//if ( parentPS->hackingTimef ) + else//if ( parentPS->hackingTime ) { if ( parentPS->hackingTime > 0 ) { @@ -1000,7 +993,7 @@ static void FighterDamageRoutine( Vehicle_t *pVeh, bgEntity_t *parent, playerSta { //pVeh->m_ucmd.forwardmove = 0; //FIXME: don't bias towards pitching down when in space... - if ( !(pVeh->m_pParentEntity->s.number%2) ) + if ( !(pVeh->m_pParentEntity->s.number%3) ) {//NOT everyone should do this pVeh->m_vOrientation[PITCH] += pVeh->m_fTimeModifier; if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) ) @@ -1011,7 +1004,7 @@ static void FighterDamageRoutine( Vehicle_t *pVeh, bgEntity_t *parent, playerSta } } } - else if ( !(pVeh->m_pParentEntity->s.number%3) ) + else if ( !(pVeh->m_pParentEntity->s.number%4) ) { pVeh->m_vOrientation[PITCH] -= pVeh->m_fTimeModifier; if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) ) @@ -1029,20 +1022,12 @@ static void FighterDamageRoutine( Vehicle_t *pVeh, bgEntity_t *parent, playerSta if ( pVeh->m_LandTrace.fraction < 1.0f ) { //if you land at all when pieces of your ship are missing, then die gentity_t *parent = (gentity_t *)pVeh->m_pParentEntity; - gentity_t *killer = parent; #ifdef _JK2MP//only have this info in MP... - if (parent->client->ps.otherKiller < ENTITYNUM_WORLD && - parent->client->ps.otherKillerTime > level.time) - { - gentity_t *potentialKiller = &g_entities[parent->client->ps.otherKiller]; - - if (potentialKiller->inuse && potentialKiller->client) - { //he's valid I guess - killer = potentialKiller; - } - } -#endif + G_DamageFromKiller( parent, parent, NULL, parent->client->ps.origin, 999999, DAMAGE_NO_ARMOR, MOD_SUICIDE ); +#else + gentity_t *killer = parent; G_Damage(parent, killer, killer, vec3_origin, parent->client->ps.origin, 99999, DAMAGE_NO_ARMOR, MOD_SUICIDE); +#endif } #endif @@ -1060,7 +1045,7 @@ static void FighterDamageRoutine( Vehicle_t *pVeh, bgEntity_t *parent, playerSta factor *= 2.0f; } - if ( !(pVeh->m_pParentEntity->s.number%4)||!(pVeh->m_pParentEntity->s.number%5) ) + if ( !(pVeh->m_pParentEntity->s.number%2)||!(pVeh->m_pParentEntity->s.number%6) ) {//won't yaw, so increase roll factor factor *= 4.0f; } @@ -1077,7 +1062,7 @@ static void FighterDamageRoutine( Vehicle_t *pVeh, bgEntity_t *parent, playerSta factor *= 2.0f; } - if ( !(pVeh->m_pParentEntity->s.number%4)||!(pVeh->m_pParentEntity->s.number%5) ) + if ( !(pVeh->m_pParentEntity->s.number%2)||!(pVeh->m_pParentEntity->s.number%6) ) {//won't yaw, so increase roll factor factor *= 4.0f; } @@ -1094,7 +1079,7 @@ static void FighterDamageRoutine( Vehicle_t *pVeh, bgEntity_t *parent, playerSta factor *= 2.0f; } - if ( !(pVeh->m_pParentEntity->s.number%4)||!(pVeh->m_pParentEntity->s.number%5) ) + if ( !(pVeh->m_pParentEntity->s.number%2)||!(pVeh->m_pParentEntity->s.number%6) ) {//won't yaw, so increase roll factor factor *= 4.0f; } @@ -1104,6 +1089,9 @@ static void FighterDamageRoutine( Vehicle_t *pVeh, bgEntity_t *parent, playerSta } #ifdef _JK2MP + +#ifdef VEH_CONTROL_SCHEME_4 + #define FIGHTER_TURNING_MULTIPLIER 0.8f//was 1.6f //magic number hackery #define FIGHTER_TURNING_DEADZONE 0.25f//no turning if offset is this much void FighterRollAdjust(Vehicle_t *pVeh, playerState_t *riderPS, playerState_t *parentPS) @@ -1178,9 +1166,6 @@ void FighterRollAdjust(Vehicle_t *pVeh, playerState_t *riderPS, playerState_t *p void FighterYawAdjust(Vehicle_t *pVeh, playerState_t *riderPS, playerState_t *parentPS) { -/* - float angDif = AngleSubtract(pVeh->m_vOrientation[YAW], riderPS->viewangles[YAW]); -*/ float angDif = AngleSubtract(pVeh->m_vPrevRiderViewAngles[YAW],riderPS->viewangles[YAW]);///2.0f;//AngleSubtract(pVeh->m_vPrevRiderViewAngles[YAW], riderPS->viewangles[YAW]); if ( fabs( angDif ) < FIGHTER_TURNING_DEADZONE ) { @@ -1246,9 +1231,6 @@ void FighterYawAdjust(Vehicle_t *pVeh, playerState_t *riderPS, playerState_t *pa void FighterPitchAdjust(Vehicle_t *pVeh, playerState_t *riderPS, playerState_t *parentPS) { -/* - float angDif = AngleSubtract(pVeh->m_vOrientation[PITCH], riderPS->viewangles[PITCH]); -*/ float angDif = AngleSubtract(0,riderPS->viewangles[PITCH]);//AngleSubtract(pVeh->m_vPrevRiderViewAngles[PITCH], riderPS->viewangles[PITCH]); if ( fabs( angDif ) < FIGHTER_TURNING_DEADZONE ) { @@ -1312,6 +1294,61 @@ void FighterPitchAdjust(Vehicle_t *pVeh, playerState_t *riderPS, playerState_t * } } +#else// VEH_CONTROL_SCHEME_4 + +void FighterYawAdjust(Vehicle_t *pVeh, playerState_t *riderPS, playerState_t *parentPS) +{ + float angDif = AngleSubtract(pVeh->m_vOrientation[YAW], riderPS->viewangles[YAW]); + + if (parentPS && parentPS->speed) + { + float s = parentPS->speed; + float maxDif = pVeh->m_pVehicleInfo->turningSpeed*0.8f; //magic number hackery + + if (s < 0.0f) + { + s = -s; + } + angDif *= s/pVeh->m_pVehicleInfo->speedMax; + if (angDif > maxDif) + { + angDif = maxDif; + } + else if (angDif < -maxDif) + { + angDif = -maxDif; + } + pVeh->m_vOrientation[YAW] = AngleNormalize180(pVeh->m_vOrientation[YAW] - angDif*(pVeh->m_fTimeModifier*0.2f)); + } +} + +void FighterPitchAdjust(Vehicle_t *pVeh, playerState_t *riderPS, playerState_t *parentPS) +{ + float angDif = AngleSubtract(pVeh->m_vOrientation[PITCH], riderPS->viewangles[PITCH]); + + if (parentPS && parentPS->speed) + { + float s = parentPS->speed; + float maxDif = pVeh->m_pVehicleInfo->turningSpeed*0.8f; //magic number hackery + + if (s < 0.0f) + { + s = -s; + } + angDif *= s/pVeh->m_pVehicleInfo->speedMax; + if (angDif > maxDif) + { + angDif = maxDif; + } + else if (angDif < -maxDif) + { + angDif = -maxDif; + } + pVeh->m_vOrientation[PITCH] = AngleNormalize360(pVeh->m_vOrientation[PITCH] - angDif*(pVeh->m_fTimeModifier*0.2f)); + } +} +#endif// VEH_CONTROL_SCHEME_4 + void FighterPitchClamp(Vehicle_t *pVeh, playerState_t *riderPS, playerState_t *parentPS, int curTime ) { if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) ) @@ -1331,7 +1368,8 @@ void FighterPitchClamp(Vehicle_t *pVeh, playerState_t *riderPS, playerState_t *p } } } -#endif + +#endif// _JK2MP //MP RULE - ALL PROCESSORIENTCOMMANDS FUNCTIONS MUST BE BG-COMPATIBLE!!! //If you really need to violate this rule for SP, then use ifdefs. @@ -1394,6 +1432,8 @@ static void ProcessOrientCommands( Vehicle_t *pVeh ) #endif #ifdef _JK2MP + +#ifdef VEH_CONTROL_SCHEME_4 if ( parentPS->hyperSpaceTime && (curTime - parentPS->hyperSpaceTime) < HYPERSPACE_TIME ) {//Going to Hyperspace @@ -1416,13 +1456,27 @@ static void ProcessOrientCommands( Vehicle_t *pVeh ) FighterPitchClamp( pVeh, riderPS, parentPS, curTime ); return; } -#endif + +#else// VEH_CONTROL_SCHEME_4 + + if ( parentPS->hyperSpaceTime + && (curTime - parentPS->hyperSpaceTime) < HYPERSPACE_TIME ) + {//Going to Hyperspace + VectorCopy( riderPS->viewangles, pVeh->m_vOrientation ); + VectorCopy( riderPS->viewangles, parentPS->viewangles ); + return; + } +#endif// VEH_CONTROL_SCHEME_4 + +#endif//_JK2MP if ( pVeh->m_iDropTime >= curTime ) {//you can only YAW during this parentPS->viewangles[YAW] = pVeh->m_vOrientation[YAW] = riderPS->viewangles[YAW]; +#ifdef VEH_CONTROL_SCHEME_4 VectorClear( pVeh->m_vPrevRiderViewAngles ); pVeh->m_vPrevRiderViewAngles[YAW] = AngleNormalize180(riderPS->viewangles[YAW]); +#endif// VEH_CONTROL_SCHEME_4 return; } @@ -1519,19 +1573,25 @@ static void ProcessOrientCommands( Vehicle_t *pVeh ) pVeh->m_vOrientation[YAW] = riderPS->viewangles[YAW];//*pVeh->m_LandTrace.fraction; #endif } +#ifdef VEH_CONTROL_SCHEME_4 else { VectorClear( pVeh->m_vPrevRiderViewAngles ); pVeh->m_vPrevRiderViewAngles[YAW] = AngleNormalize180(riderPS->viewangles[YAW]); } +#endif// VEH_CONTROL_SCHEME_4 } else if ( (pVeh->m_iRemovedSurfaces||parentPS->electrifyTime>=curTime)//spiralling out of control - && (!(pVeh->m_pParentEntity->s.number%4)||!(pVeh->m_pParentEntity->s.number%5)) ) + && (!(pVeh->m_pParentEntity->s.number%2)||!(pVeh->m_pParentEntity->s.number%6)) ) {//no yaw control } else if ( pVeh->m_pPilot && pVeh->m_pPilot->s.number < MAX_CLIENTS && parentPS->speed > 0.0f )//&& !( pVeh->m_ucmd.forwardmove > 0 && pVeh->m_LandTrace.fraction != 1.0f ) ) { - if ( 0 && BG_UnrestrainedPitchRoll( riderPS, pVeh ) ) +#ifdef VEH_CONTROL_SCHEME_4 + if ( 0 ) +#else// VEH_CONTROL_SCHEME_4 + if ( BG_UnrestrainedPitchRoll( riderPS, pVeh ) ) +#endif// VEH_CONTROL_SCHEME_4 { VectorCopy( riderPS->viewangles, pVeh->m_vOrientation ); VectorCopy( riderPS->viewangles, parentPS->viewangles ); @@ -1585,7 +1645,9 @@ static void ProcessOrientCommands( Vehicle_t *pVeh ) #ifdef _JK2MP FighterPitchAdjust(pVeh, riderPS, parentPS); +#ifdef VEH_CONTROL_SCHEME_4 FighterPitchClamp( pVeh, riderPS, parentPS, curTime ); +#endif// VEH_CONTROL_SCHEME_4 #else pVeh->m_vOrientation[PITCH] = riderPS->viewangles[PITCH]; #endif @@ -1607,6 +1669,7 @@ static void ProcessOrientCommands( Vehicle_t *pVeh ) //cap it reasonably //NOTE: was hardcoded to 40.0f, now using extern data +#ifdef VEH_CONTROL_SCHEME_4 if ( !BG_UnrestrainedPitchRoll( riderPS, pVeh ) ) { if ( pVeh->m_pVehicleInfo->rollLimit != -1 ) @@ -1621,6 +1684,19 @@ static void ProcessOrientCommands( Vehicle_t *pVeh ) } } } +#else// VEH_CONTROL_SCHEME_4 + if ( pVeh->m_pVehicleInfo->rollLimit != -1 ) + { + if (curRoll > pVeh->m_pVehicleInfo->rollLimit ) + { + curRoll = pVeh->m_pVehicleInfo->rollLimit; + } + else if (curRoll < -pVeh->m_pVehicleInfo->rollLimit) + { + curRoll = -pVeh->m_pVehicleInfo->rollLimit; + } + } +#endif// VEH_CONTROL_SCHEME_4 } } } @@ -1706,7 +1782,7 @@ static void ProcessOrientCommands( Vehicle_t *pVeh ) if ( pVeh->m_vOrientation[ROLL] ) { //continually adjust the yaw based on the roll.. if ( (pVeh->m_iRemovedSurfaces||parentPS->electrifyTime>=curTime)//spiralling out of control - && (!(pVeh->m_pParentEntity->s.number%4)||!(pVeh->m_pParentEntity->s.number%5)) ) + && (!(pVeh->m_pParentEntity->s.number%2)||!(pVeh->m_pParentEntity->s.number%6)) ) {//leave YAW alone } else @@ -1776,7 +1852,6 @@ static void AnimateVehicle( Vehicle_t *pVeh ) int curTime = pm->cmd.serverTime; #endif -#ifdef _JK2MP if ( parentPS->hyperSpaceTime && curTime - parentPS->hyperSpaceTime < HYPERSPACE_TIME ) {//Going to Hyperspace @@ -1788,7 +1863,6 @@ static void AnimateVehicle( Vehicle_t *pVeh ) } } else -#endif { isLanding = FighterIsLanding( pVeh, parentPS ); isLanded = FighterIsLanded( pVeh, parentPS ); diff --git a/codemp/game/NPC_AI_Jedi.c b/codemp/game/NPC_AI_Jedi.c index 9667768..0643fa5 100644 --- a/codemp/game/NPC_AI_Jedi.c +++ b/codemp/game/NPC_AI_Jedi.c @@ -2049,6 +2049,36 @@ evasionType_t Jedi_CheckFlipEvasions( gentity_t *self, float rightdot, float zdi trace_t trace; int parts, anim; float speed, checkDist; + qboolean allowCartWheels = qtrue; + qboolean allowWallFlips = qtrue; + + if ( self->client->ps.weapon == WP_SABER ) + { + if ( self->client->saber[0].model + && self->client->saber[0].model[0] + && (self->client->saber[0].saberFlags&SFL_NO_CARTWHEELS) ) + { + allowCartWheels = qfalse; + } + else if ( self->client->saber[1].model + && self->client->saber[1].model[0] + && (self->client->saber[1].saberFlags&SFL_NO_CARTWHEELS) ) + { + allowCartWheels = qfalse; + } + if ( self->client->saber[0].model + && self->client->saber[0].model[0] + && (self->client->saber[0].saberFlags&SFL_NO_WALL_FLIPS) ) + { + allowWallFlips = qfalse; + } + else if ( self->client->saber[1].model + && self->client->saber[1].model[0] + && (self->client->saber[1].saberFlags&SFL_NO_WALL_FLIPS) ) + { + allowWallFlips = qfalse; + } + } VectorSet(mins, self->r.mins[0],self->r.mins[1],0); VectorSet(maxs, self->r.maxs[0],self->r.maxs[1],24); @@ -2092,7 +2122,7 @@ evasionType_t Jedi_CheckFlipEvasions( gentity_t *self, float rightdot, float zdi //trace in the dir that we want to go VectorMA( self->r.currentOrigin, checkDist, right, traceto ); trap_Trace( &trace, self->r.currentOrigin, mins, maxs, traceto, self->s.number, CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP ); - if ( trace.fraction >= 1.0f ) + if ( trace.fraction >= 1.0f && allowCartWheels ) {//it's clear, let's do it //FIXME: check for drops? vec3_t fwdAngles, jumpRt; @@ -2145,41 +2175,44 @@ evasionType_t Jedi_CheckFlipEvasions( gentity_t *self, float rightdot, float zdi trap_Trace( &trace, self->r.currentOrigin, mins, maxs, traceto, self->s.number, CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_BOTCLIP ); if ( trace.fraction >= 1.0f ) {//it's clear, let's do it - int parts; + if ( allowWallFlips ) + {//okay to do wall-flips with this saber + int parts; - //FIXME: check for drops? - //turn the cartwheel into a wallflip in the other dir - if ( rightdot > 0 ) - { - anim = BOTH_WALL_FLIP_LEFT; - self->client->ps.velocity[0] = self->client->ps.velocity[1] = 0; - VectorMA( self->client->ps.velocity, 150, right, self->client->ps.velocity ); - } - else - { - anim = BOTH_WALL_FLIP_RIGHT; - self->client->ps.velocity[0] = self->client->ps.velocity[1] = 0; - VectorMA( self->client->ps.velocity, -150, right, self->client->ps.velocity ); - } - self->client->ps.velocity[2] = forceJumpStrength[FORCE_LEVEL_2]/2.25f; - //animate me - parts = SETANIM_LEGS; - if ( !self->client->ps.weaponTime ) - { - parts = SETANIM_BOTH; - } - NPC_SetAnim( self, parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); - self->client->ps.fd.forceJumpZStart = self->r.currentOrigin[2];//so we don't take damage if we land at same height - //self->client->ps.pm_flags |= (PMF_JUMPING|PMF_SLOW_MO_FALL); - if ( self->client->NPC_class == CLASS_BOBAFETT ) - { - G_AddEvent( self, EV_JUMP, 0 ); - } - else - { - G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/jump.wav" ); - } - return EVASION_OTHER; + //FIXME: check for drops? + //turn the cartwheel into a wallflip in the other dir + if ( rightdot > 0 ) + { + anim = BOTH_WALL_FLIP_LEFT; + self->client->ps.velocity[0] = self->client->ps.velocity[1] = 0; + VectorMA( self->client->ps.velocity, 150, right, self->client->ps.velocity ); + } + else + { + anim = BOTH_WALL_FLIP_RIGHT; + self->client->ps.velocity[0] = self->client->ps.velocity[1] = 0; + VectorMA( self->client->ps.velocity, -150, right, self->client->ps.velocity ); + } + self->client->ps.velocity[2] = forceJumpStrength[FORCE_LEVEL_2]/2.25f; + //animate me + parts = SETANIM_LEGS; + if ( !self->client->ps.weaponTime ) + { + parts = SETANIM_BOTH; + } + NPC_SetAnim( self, parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + self->client->ps.fd.forceJumpZStart = self->r.currentOrigin[2];//so we don't take damage if we land at same height + //self->client->ps.pm_flags |= (PMF_JUMPING|PMF_SLOW_MO_FALL); + if ( self->client->NPC_class == CLASS_BOBAFETT ) + { + G_AddEvent( self, EV_JUMP, 0 ); + } + else + { + G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/jump.wav" ); + } + return EVASION_OTHER; + } } else {//boxed in on both sides @@ -2212,36 +2245,55 @@ evasionType_t Jedi_CheckFlipEvasions( gentity_t *self, float rightdot, float zdi //Try wall run? if ( bestCheckDist ) {//one of the walls was close enough to wall-run on - int parts; + qboolean allowWallRuns = qtrue; + if ( self->client->ps.weapon == WP_SABER ) + { + if ( self->client->saber[0].model + && self->client->saber[0].model[0] + && (self->client->saber[0].saberFlags&SFL_NO_WALL_RUNS) ) + { + allowWallRuns = qfalse; + } + else if ( self->client->saber[1].model + && self->client->saber[1].model[0] + && (self->client->saber[1].saberFlags&SFL_NO_WALL_RUNS) ) + { + allowWallRuns = qfalse; + } + } + if ( allowWallRuns ) + {//okay to do wallruns with this saber + int parts; - //FIXME: check for long enough wall and a drop at the end? - if ( bestCheckDist > 0 ) - {//it was to the right - anim = BOTH_WALL_RUN_RIGHT; + //FIXME: check for long enough wall and a drop at the end? + if ( bestCheckDist > 0 ) + {//it was to the right + anim = BOTH_WALL_RUN_RIGHT; + } + else + {//it was to the left + anim = BOTH_WALL_RUN_LEFT; + } + self->client->ps.velocity[2] = forceJumpStrength[FORCE_LEVEL_2]/2.25f; + //animate me + parts = SETANIM_LEGS; + if ( !self->client->ps.weaponTime ) + { + parts = SETANIM_BOTH; + } + NPC_SetAnim( self, parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); + self->client->ps.fd.forceJumpZStart = self->r.currentOrigin[2];//so we don't take damage if we land at same height + //self->client->ps.pm_flags |= (PMF_JUMPING|PMF_SLOW_MO_FALL); + if ( self->client->NPC_class == CLASS_BOBAFETT ) + { + G_AddEvent( self, EV_JUMP, 0 ); + } + else + { + G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/jump.wav" ); + } + return EVASION_OTHER; } - else - {//it was to the left - anim = BOTH_WALL_RUN_LEFT; - } - self->client->ps.velocity[2] = forceJumpStrength[FORCE_LEVEL_2]/2.25f; - //animate me - parts = SETANIM_LEGS; - if ( !self->client->ps.weaponTime ) - { - parts = SETANIM_BOTH; - } - NPC_SetAnim( self, parts, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD ); - self->client->ps.fd.forceJumpZStart = self->r.currentOrigin[2];//so we don't take damage if we land at same height - //self->client->ps.pm_flags |= (PMF_JUMPING|PMF_SLOW_MO_FALL); - if ( self->client->NPC_class == CLASS_BOBAFETT ) - { - G_AddEvent( self, EV_JUMP, 0 ); - } - else - { - G_SoundOnEnt( self, CHAN_BODY, "sound/weapons/force/jump.wav" ); - } - return EVASION_OTHER; } //else check for wall in front, do backflip off wall } diff --git a/codemp/game/NPC_combat.c b/codemp/game/NPC_combat.c index e623b3a..c476469 100644 --- a/codemp/game/NPC_combat.c +++ b/codemp/game/NPC_combat.c @@ -575,6 +575,7 @@ void ChangeWeapon( gentity_t *ent, int newWeapon ) } ent->client->ps.weapon = newWeapon; + ent->client->pers.cmd.weapon = newWeapon; ent->NPC->shotTime = 0; ent->NPC->burstCount = 0; ent->NPC->attackHold = 0; diff --git a/codemp/game/NPC_spawn.c b/codemp/game/NPC_spawn.c index 5d68ad8..59a4f8c 100644 --- a/codemp/game/NPC_spawn.c +++ b/codemp/game/NPC_spawn.c @@ -1244,6 +1244,12 @@ void NPC_Begin (gentity_t *ent) //SP way: //droidEnt->s.m_iVehicleNum = ent->s.number; //droidEnt->owner = ent; + //set team + droidEnt->alliedTeam = ent->alliedTeam; + droidEnt->teamnodmg = ent->teamnodmg; + droidEnt->client->sess.sessionTeam = ent->client->sess.sessionTeam; + droidEnt->client->ps.persistant[PERS_TEAM] = ent->client->ps.persistant[PERS_TEAM]; + //position VectorCopy( ent->r.currentOrigin, droidEnt->s.origin ); VectorCopy( ent->r.currentOrigin, droidEnt->client->ps.origin ); G_SetOrigin( droidEnt, droidEnt->s.origin ); @@ -1467,21 +1473,18 @@ gentity_t *NPC_Spawn_Do( gentity_t *ent ) ent->NPC_type = Q_strlwr( G_NewString( ent->NPC_type ) ); } - /* - if ( ent->svFlags & SVF_NO_BASIC_SOUNDS ) + if ( ent->r.svFlags & SVF_NO_BASIC_SOUNDS ) { - newent->svFlags |= SVF_NO_BASIC_SOUNDS; + newent->r.svFlags |= SVF_NO_BASIC_SOUNDS; } - if ( ent->svFlags & SVF_NO_COMBAT_SOUNDS ) + if ( ent->r.svFlags & SVF_NO_COMBAT_SOUNDS ) { - newent->svFlags |= SVF_NO_COMBAT_SOUNDS; + newent->r.svFlags |= SVF_NO_COMBAT_SOUNDS; } - if ( ent->svFlags & SVF_NO_EXTRA_SOUNDS ) + if ( ent->r.svFlags & SVF_NO_EXTRA_SOUNDS ) { - newent->svFlags |= SVF_NO_EXTRA_SOUNDS; + newent->r.svFlags |= SVF_NO_EXTRA_SOUNDS; } - */ - //rwwFIXMEFIXME: Use all these flags? if ( ent->message ) {//has a key @@ -1617,7 +1620,7 @@ gentity_t *NPC_Spawn_Do( gentity_t *ent ) } newent->NPC->defaultBehavior = newent->NPC->behaviorState = BS_WAIT; newent->classname = "NPC"; - // newent->svFlags |= SVF_NOPUSH; + // newent->r.svFlags |= SVF_NOPUSH; } } //===================================================================== @@ -1947,6 +1950,10 @@ teamnodmg - team that NPC does not take damage from (turrets and other auto-defe 0 - none 1 - red 2 - blue + +"noBasicSounds" - set to 1 to prevent loading and usage of basic sounds (pain, death, etc) +"noCombatSounds" - set to 1 to prevent loading and usage of combat sounds (anger, victory, etc.) +"noExtraSounds" - set to 1 to prevent loading and usage of "extra" sounds (chasing the enemy - detecting them, flanking them... also jedi combat sounds) */ //void NPC_PrecacheModels ( char *NPCName ); extern void NPC_PrecacheAnimationCFG( const char *NPC_type ); @@ -1987,25 +1994,22 @@ void SP_NPC_spawner( gentity_t *self) self->count = 1; } - /* {//Stop loading of certain extra sounds static int garbage; if ( G_SpawnInt( "noBasicSounds", "0", &garbage ) ) { - self->svFlags |= SVF_NO_BASIC_SOUNDS; + self->r.svFlags |= SVF_NO_BASIC_SOUNDS; } if ( G_SpawnInt( "noCombatSounds", "0", &garbage ) ) { - self->svFlags |= SVF_NO_COMBAT_SOUNDS; + self->r.svFlags |= SVF_NO_COMBAT_SOUNDS; } if ( G_SpawnInt( "noExtraSounds", "0", &garbage ) ) { - self->svFlags |= SVF_NO_EXTRA_SOUNDS; + self->r.svFlags |= SVF_NO_EXTRA_SOUNDS; } } - */ - //rwwFIXMEFIXME: Use these flags? if ( !self->wait ) { @@ -2026,7 +2030,7 @@ void SP_NPC_spawner( gentity_t *self) /* if ( self->delay > 0 ) { - self->svFlags |= SVF_NPC_PRECACHE; + self->r.svFlags |= SVF_NPC_PRECACHE; } */ //rwwFIXMEFIXME: support for this flag? @@ -2040,7 +2044,7 @@ void SP_NPC_spawner( gentity_t *self) if ( self->targetname ) {//Wait for triggering self->use = NPC_Spawn; - // self->svFlags |= SVF_NPC_PRECACHE;//FIXME: precache my weapons somehow? + // self->r.svFlags |= SVF_NPC_PRECACHE;//FIXME: precache my weapons somehow? //NPC_PrecacheModels( self->NPC_type ); } @@ -4155,7 +4159,7 @@ void NPC_Kill_f( void ) } } /* - else if ( player && (player->svFlags&SVF_NPC_PRECACHE) ) + else if ( player && (player->r.svFlags&SVF_NPC_PRECACHE) ) {//a spawner Com_Printf( S_COLOR_GREEN"Removing NPC spawner %s named %s\n", player->NPC_type, player->targetname ); G_FreeEntity( player ); diff --git a/codemp/game/NPC_stats.c b/codemp/game/NPC_stats.c index 4941402..583857c 100644 --- a/codemp/game/NPC_stats.c +++ b/codemp/game/NPC_stats.c @@ -751,8 +751,7 @@ void NPC_Precache ( gentity_t *spawner ) if ( COM_ParseString( &p, &value ) ) { continue; } - //if ( !(spawner->svFlags&SVF_NO_BASIC_SOUNDS) ) - if (1) + if ( !(spawner->r.svFlags&SVF_NO_BASIC_SOUNDS) ) { //FIXME: store this in some sound field or parse in the soundTable like the animTable... Q_strncpyz( sound, value, sizeof( sound ) ); @@ -771,8 +770,7 @@ void NPC_Precache ( gentity_t *spawner ) if ( COM_ParseString( &p, &value ) ) { continue; } - //if ( !(spawner->svFlags&SVF_NO_COMBAT_SOUNDS) ) - if (1) + if ( !(spawner->r.svFlags&SVF_NO_COMBAT_SOUNDS) ) { //FIXME: store this in some sound field or parse in the soundTable like the animTable... Q_strncpyz( sound, value, sizeof( sound ) ); @@ -791,8 +789,7 @@ void NPC_Precache ( gentity_t *spawner ) if ( COM_ParseString( &p, &value ) ) { continue; } - //if ( !(spawner->svFlags&SVF_NO_EXTRA_SOUNDS) ) - if (1) + if ( !(spawner->r.svFlags&SVF_NO_EXTRA_SOUNDS) ) { //FIXME: store this in some sound field or parse in the soundTable like the animTable... Q_strncpyz( sound, value, sizeof( sound ) ); @@ -811,8 +808,7 @@ void NPC_Precache ( gentity_t *spawner ) if ( COM_ParseString( &p, &value ) ) { continue; } - //if ( !(spawner->svFlags&SVF_NO_EXTRA_SOUNDS) ) - if (1) + if ( !(spawner->r.svFlags&SVF_NO_EXTRA_SOUNDS) ) { //FIXME: store this in some sound field or parse in the soundTable like the animTable... Q_strncpyz( sound, value, sizeof( sound ) ); @@ -837,7 +833,7 @@ void NPC_Precache ( gentity_t *spawner ) curWeap = GetIDForString( WPTable, value ); - if (curWeap >= 0 && curWeap < WP_NUM_WEAPONS) + if (curWeap > WP_NONE && curWeap < WP_NUM_WEAPONS) { RegisterItem(BG_FindItemForWeapon((weapon_t)curWeap)); } @@ -2148,8 +2144,7 @@ qboolean NPC_ParseParms( const char *NPCName, gentity_t *NPC ) { continue; } - //if ( !(NPC->svFlags&SVF_NO_BASIC_SOUNDS) ) - if (1) + if ( !(NPC->r.svFlags&SVF_NO_BASIC_SOUNDS) ) { //FIXME: store this in some sound field or parse in the soundTable like the animTable... Q_strncpyz( sound, value, sizeof( sound ) ); @@ -2171,8 +2166,7 @@ qboolean NPC_ParseParms( const char *NPCName, gentity_t *NPC ) { continue; } - //if ( !(NPC->svFlags&SVF_NO_COMBAT_SOUNDS) ) - if (1) + if ( !(NPC->r.svFlags&SVF_NO_COMBAT_SOUNDS) ) { //FIXME: store this in some sound field or parse in the soundTable like the animTable... Q_strncpyz( sound, value, sizeof( sound ) ); @@ -2193,8 +2187,7 @@ qboolean NPC_ParseParms( const char *NPCName, gentity_t *NPC ) { continue; } - //if ( !(NPC->svFlags&SVF_NO_EXTRA_SOUNDS) ) - if (1) + if ( !(NPC->r.svFlags&SVF_NO_EXTRA_SOUNDS) ) { //FIXME: store this in some sound field or parse in the soundTable like the animTable... Q_strncpyz( sound, value, sizeof( sound ) ); @@ -2215,8 +2208,7 @@ qboolean NPC_ParseParms( const char *NPCName, gentity_t *NPC ) { continue; } - //if ( !(NPC->svFlags&SVF_NO_EXTRA_SOUNDS) ) - if (1) + if ( !(NPC->r.svFlags&SVF_NO_EXTRA_SOUNDS) ) { //FIXME: store this in some sound field or parse in the soundTable like the animTable... Q_strncpyz( sound, value, sizeof( sound ) ); @@ -2375,13 +2367,13 @@ qboolean NPC_ParseParms( const char *NPCName, gentity_t *NPC ) continue; } - if ( !NPC->client->saber[0].twoHanded ) + if ( !(NPC->client->saber[0].saberFlags&SFL_TWO_HANDED) ) {//can't use a second saber if first one is a two-handed saber...? char *saberName = (char *)BG_TempAlloc(4096);//G_NewString( value ); strcpy(saberName, value); WP_SaberParseParms( saberName, &NPC->client->saber[1] ); - if ( NPC->client->saber[1].twoHanded ) + if ( (NPC->client->saber[1].saberFlags&SFL_TWO_HANDED) ) {//tsk tsk, can't use a twoHanded saber as second saber WP_RemoveSaber( NPC->client->saber, 1 ); } @@ -3288,8 +3280,11 @@ void NPC_LoadParms( void ) trap_FS_Read(npcParseBuffer, len, f); npcParseBuffer[len] = 0; + len = COM_Compress( npcParseBuffer ); + strcat( marker, npcParseBuffer ); strcat(marker, "\n"); + len++; trap_FS_FCloseFile(f); totallen += len; diff --git a/codemp/game/bg_misc.c b/codemp/game/bg_misc.c index 2efcdf9..37642ca 100644 --- a/codemp/game/bg_misc.c +++ b/codemp/game/bg_misc.c @@ -2743,7 +2743,11 @@ int BG_EmplacedView(vec3_t baseAngles, vec3_t angles, float *newYaw, float const //I don't much care for hardcoded strings, but this seems the best way to go. qboolean BG_IsValidCharacterModel(const char *modelName, const char *skinName) { - if (!Q_stricmp(modelName, "kyle")) + if (!Q_stricmp(skinName, "menu")) + { + return qfalse; + } + else if (!Q_stricmp(modelName, "kyle")) { if (!Q_stricmp(skinName, "fpls")) { @@ -2763,16 +2767,7 @@ qboolean BG_IsValidCharacterModel(const char *modelName, const char *skinName) qboolean BG_ValidateSkinForTeam( const char *modelName, char *skinName, int team, float *colors ) { - char trunc[6]; - int i = 0; - while (i < 5) - { - trunc[i] = modelName[i]; - i++; - } - trunc[i] = 0; - - if (!Q_stricmp(trunc, "jedi_")) + if (!Q_stricmpn(modelName, "jedi_",5)) { //argh, it's a custom player skin! if (team == TEAM_RED && colors) { diff --git a/codemp/game/bg_panimate.c b/codemp/game/bg_panimate.c index e73a979..bf529c3 100644 --- a/codemp/game/bg_panimate.c +++ b/codemp/game/bg_panimate.c @@ -17,6 +17,7 @@ extern int trap_FX_RegisterEffect( const char *file); #include "../namespace_end.h" #endif +extern saberInfo_t *BG_MySaber( int clientNum, int saberNum ); /* ============================================================================== BEGIN: Animation utility functions (sequence checking) @@ -215,6 +216,14 @@ qboolean BG_DirectFlippingAnim( int anim ) return qfalse; } +qboolean BG_SaberInAttackPure( int move ) +{ + if ( move >= LS_A_TL2BR && move <= LS_A_T2B ) + { + return qtrue; + } + return qfalse; +} qboolean BG_SaberInAttack( int move ) { if ( move >= LS_A_TL2BR && move <= LS_A_T2B ) @@ -1754,6 +1763,8 @@ stringID_table_t animEventTypeTable[MAX_ANIM_EVENTS+1] = ENUM2STRING(AEV_FIRE), //# animID AEV_FIRE framenum altfire chancetofire ENUM2STRING(AEV_MOVE), //# animID AEV_MOVE framenum forwardpush rightpush uppush ENUM2STRING(AEV_SOUNDCHAN), //# animID AEV_SOUNDCHAN framenum CHANNEL soundpath randomlow randomhi chancetoplay + ENUM2STRING(AEV_SABER_SWING), //# animID AEV_SABER_SWING framenum CHANNEL randomlow randomhi chancetoplay + ENUM2STRING(AEV_SABER_SPIN), //# animID AEV_SABER_SPIN framenum CHANNEL chancetoplay //must be terminated NULL,-1 }; @@ -1990,6 +2001,56 @@ void ParseAnimationEvtBlock(const char *aeb_filename, animevent_t *animEvents, a break; } animEvents[curAnimEvent].eventData[AED_SOUND_PROBABILITY] = atoi( token ); + + //last part - cheat and check and see if it's a special overridable saber sound we know of... + if ( !Q_stricmpn( "sound/weapons/saber/saberhup", stringData, 28 ) ) + {//a saber swing + animEvents[curAnimEvent].eventType = AEV_SABER_SWING; + animEvents[curAnimEvent].eventData[AED_SABER_SWING_SABERNUM] = 0;//since we don't know which one they meant if we're hacking this, always use first saber + animEvents[curAnimEvent].eventData[AED_SABER_SWING_PROBABILITY] = animEvents[curAnimEvent].eventData[AED_SOUND_PROBABILITY]; + if ( lowestVal < 4 ) + {//fast swing + animEvents[curAnimEvent].eventData[AED_SABER_SWING_TYPE] = 0;//SWING_FAST; + } + else if ( lowestVal < 7 ) + {//medium swing + animEvents[curAnimEvent].eventData[AED_SABER_SWING_TYPE] = 1;//SWING_MEDIUM; + } + else + {//strong swing + animEvents[curAnimEvent].eventData[AED_SABER_SWING_TYPE] = 2;//SWING_STRONG; + } + } + else if ( !Q_stricmpn( "sound/weapons/saber/saberspin", stringData, 29 ) ) + {//a saber spin + animEvents[curAnimEvent].eventType = AEV_SABER_SPIN; + animEvents[curAnimEvent].eventData[AED_SABER_SPIN_SABERNUM] = 0;//since we don't know which one they meant if we're hacking this, always use first saber + animEvents[curAnimEvent].eventData[AED_SABER_SPIN_PROBABILITY] = animEvents[curAnimEvent].eventData[AED_SOUND_PROBABILITY]; + if ( stringData[29] == 'o' ) + {//saberspinoff + animEvents[curAnimEvent].eventData[AED_SABER_SPIN_TYPE] = 0; + } + else if ( stringData[29] == '1' ) + {//saberspin1 + animEvents[curAnimEvent].eventData[AED_SABER_SPIN_TYPE] = 2; + } + else if ( stringData[29] == '2' ) + {//saberspin2 + animEvents[curAnimEvent].eventData[AED_SABER_SPIN_TYPE] = 3; + } + else if ( stringData[29] == '3' ) + {//saberspin3 + animEvents[curAnimEvent].eventData[AED_SABER_SPIN_TYPE] = 4; + } + else if ( stringData[29] == '%' ) + {//saberspin%d + animEvents[curAnimEvent].eventData[AED_SABER_SPIN_TYPE] = 5; + } + else + {//just plain saberspin + animEvents[curAnimEvent].eventData[AED_SABER_SPIN_TYPE] = 1; + } + } break; case AEV_FOOTSTEP: //# animID AEV_FOOTSTEP framenum footstepType //get footstep type @@ -2123,8 +2184,13 @@ int BG_ParseAnimationEvtFile( const char *as_filename, int animFileIndex, int ev assert(animFileIndex < MAX_ANIM_FILES); assert(eventFileIndex < MAX_ANIM_FILES); - if (eventFileIndex == -1) - { + if ( animFileIndex < 0 || animFileIndex >= MAX_ANIM_FILES ) + {//WTF??!! + return 0; + } + + if ( eventFileIndex < 0 || eventFileIndex >= MAX_ANIM_FILES ) + {//WTF??!! forcedIndex = 0; } else @@ -2664,8 +2730,27 @@ void PM_SetTorsoAnimTimer(int time ) BG_SetTorsoAnimTimer(pm->ps, time); } -void BG_SaberStartTransAnim( int saberAnimLevel, int anim, float *animSpeed, int broken ) +void BG_SaberStartTransAnim( int clientNum, int saberAnimLevel, int weapon, int anim, float *animSpeed, int broken ) { + if ( anim >= BOTH_A1_T__B_ && anim <= BOTH_ROLL_STAB ) + { + if ( weapon == WP_SABER ) + { + saberInfo_t *saber = BG_MySaber( clientNum, 0 ); + if ( saber + && saber->animSpeedScale != 1.0f ) + { + *animSpeed *= saber->animSpeedScale; + } + saber = BG_MySaber( clientNum, 1 ); + if ( saber + && saber->animSpeedScale != 1.0f ) + { + *animSpeed *= saber->animSpeedScale; + } + } + } + if ( ( (anim) >= BOTH_T1_BR__R && (anim) <= BOTH_T1_BL_TL ) || ( (anim) >= BOTH_T2_BR__R && @@ -2729,7 +2814,7 @@ void BG_SetAnimFinal(playerState_t *ps, animation_t *animations, //NOTE: Setting blendTime here breaks actual blending.. blendTime = 0; - BG_SaberStartTransAnim(ps->fd.saberAnimLevel, anim, &editAnimSpeed, ps->brokenLimbs); + BG_SaberStartTransAnim(ps->clientNum, ps->fd.saberAnimLevel, ps->weapon, anim, &editAnimSpeed, ps->brokenLimbs); // Set torso anim if (setAnimParts & SETANIM_TORSO) diff --git a/codemp/game/bg_pmove.c b/codemp/game/bg_pmove.c index 02bd437..450ac5d 100644 --- a/codemp/game/bg_pmove.c +++ b/codemp/game/bg_pmove.c @@ -25,6 +25,7 @@ extern void trap_FX_PlayEffect( const char *file, vec3_t org, vec3_t fwd, int vo extern qboolean BG_FullBodyTauntAnim( int anim ); extern float PM_WalkableGroundDistance(void); extern qboolean PM_GroundSlideOkay( float zNormal ); +extern saberInfo_t *BG_MySaber( int clientNum, int saberNum ); pmove_t *pm; pml_t pml; @@ -260,6 +261,8 @@ qboolean PM_INLINE PM_IsRocketTrooper(void) int PM_GetSaberStance(void) { int anim = BOTH_STAND2; + saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 ); + saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 ); if (!pm->ps->saberEntityNum) { //lost it @@ -271,6 +274,25 @@ int PM_GetSaberStance(void) return BOTH_STAND1; } + if ( saber1 + && saber1->readyAnim != -1 ) + { + return saber1->readyAnim; + } + + if ( saber2 + && saber2->readyAnim != -1 ) + { + return saber2->readyAnim; + } + + if ( saber1 + && saber2 + && !pm->ps->saberHolstered ) + {//dual sabers, both on + return BOTH_SABERDUAL_STANCE; + } + switch ( pm->ps->fd.saberAnimLevel ) { case SS_DUAL: @@ -279,16 +301,16 @@ int PM_GetSaberStance(void) case SS_STAFF: anim = BOTH_SABERSTAFF_STANCE; break; - case FORCE_LEVEL_1: - case FORCE_LEVEL_5: + case SS_FAST: + case SS_TAVION: anim = BOTH_SABERFAST_STANCE; break; - case FORCE_LEVEL_3: + case SS_STRONG: anim = BOTH_SABERSLOW_STANCE; break; - case FORCE_LEVEL_0: - case FORCE_LEVEL_2: - case FORCE_LEVEL_4: + case SS_NONE: + case SS_MEDIUM: + case SS_DESANN: default: anim = BOTH_STAND2; break; @@ -1765,6 +1787,8 @@ PM_CheckJump */ static qboolean PM_CheckJump( void ) { + qboolean allowFlips = qtrue; + if (pm->ps->clientNum >= MAX_CLIENTS) { bgEntity_t *pEnt = pm_entSelf; @@ -1798,6 +1822,22 @@ static qboolean PM_CheckJump( void ) return qfalse; } + if ( pm->ps->weapon == WP_SABER ) + { + saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 ); + saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 ); + if ( saber1 + && (saber1->saberFlags&SFL_NO_FLIPS) ) + { + allowFlips = qfalse; + } + if ( saber2 + && (saber2->saberFlags&SFL_NO_FLIPS) ) + { + allowFlips = qfalse; + } + } + if (pm->ps->groundEntityNum != ENTITYNUM_NONE || pm->ps->origin[2] < pm->ps->fd.forceJumpZStart) { pm->ps->fd.forcePowersActive &= ~(1<cmd.forwardmove > 0 ) + if ( allowFlips ) { - anim = BOTH_FLIP_F; + if ( pm->cmd.forwardmove > 0 ) + { + anim = BOTH_FLIP_F; + } + else if ( pm->cmd.forwardmove < 0 ) + { + anim = BOTH_FLIP_B; + } + else if ( pm->cmd.rightmove > 0 ) + { + anim = BOTH_FLIP_R; + } + else if ( pm->cmd.rightmove < 0 ) + { + anim = BOTH_FLIP_L; + } } - else if ( pm->cmd.forwardmove < 0 ) + else { - anim = BOTH_FLIP_B; - } - else if ( pm->cmd.rightmove > 0 ) - { - anim = BOTH_FLIP_R; - } - else if ( pm->cmd.rightmove < 0 ) - { - anim = BOTH_FLIP_L; + if ( pm->cmd.forwardmove > 0 ) + { + anim = BOTH_FORCEINAIR1; + } + else if ( pm->cmd.forwardmove < 0 ) + { + anim = BOTH_FORCEINAIRBACK1; + } + else if ( pm->cmd.rightmove > 0 ) + { + anim = BOTH_FORCEINAIRRIGHT1; + } + else if ( pm->cmd.rightmove < 0 ) + { + anim = BOTH_FORCEINAIRLEFT1; + } } if ( pm->ps->weaponTime ) {//FIXME: really only care if we're in a saber attack anim... @@ -1883,7 +1944,8 @@ static qboolean PM_CheckJump( void ) (pm->ps->legsAnim) != BOTH_FLIP_F &&//not already flipping (pm->ps->legsAnim) != BOTH_FLIP_B && (pm->ps->legsAnim) != BOTH_FLIP_R && - (pm->ps->legsAnim) != BOTH_FLIP_L ) + (pm->ps->legsAnim) != BOTH_FLIP_L + && allowFlips ) { int anim = BOTH_FORCEINAIR1; int parts = SETANIM_BOTH; @@ -2060,6 +2122,56 @@ static qboolean PM_CheckJump( void ) !BG_HasYsalamiri(pm->gametype, pm->ps) && BG_CanUseFPNow(pm->gametype, pm->ps, pm->cmd.serverTime, FP_LEVITATION) ) { + qboolean allowWallRuns = qtrue; + qboolean allowWallFlips = qtrue; + qboolean allowFlips = qtrue; + qboolean allowWallGrabs = qtrue; + if ( pm->ps->weapon == WP_SABER ) + { + saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 ); + saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 ); + if ( saber1 + && (saber1->saberFlags&SFL_NO_WALL_RUNS) ) + { + allowWallRuns = qfalse; + } + if ( saber2 + && (saber2->saberFlags&SFL_NO_WALL_RUNS) ) + { + allowWallRuns = qfalse; + } + if ( saber1 + && (saber1->saberFlags&SFL_NO_WALL_FLIPS) ) + { + allowWallFlips = qfalse; + } + if ( saber2 + && (saber2->saberFlags&SFL_NO_WALL_FLIPS) ) + { + allowWallFlips = qfalse; + } + if ( saber1 + && (saber1->saberFlags&SFL_NO_FLIPS) ) + { + allowFlips = qfalse; + } + if ( saber2 + && (saber2->saberFlags&SFL_NO_FLIPS) ) + { + allowFlips = qfalse; + } + if ( saber1 + && (saber1->saberFlags&SFL_NO_WALL_GRAB) ) + { + allowWallGrabs = qfalse; + } + if ( saber2 + && (saber2->saberFlags&SFL_NO_WALL_GRAB) ) + { + allowWallGrabs = qfalse; + } + } + if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) {//on the ground //check for left-wall and right-wall special jumps @@ -2069,32 +2181,47 @@ static qboolean PM_CheckJump( void ) {//strafing right if ( pm->cmd.forwardmove > 0 ) {//wall-run - vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.0f; - anim = BOTH_WALL_RUN_RIGHT; + if ( allowWallRuns ) + { + vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.0f; + anim = BOTH_WALL_RUN_RIGHT; + } } else if ( pm->cmd.forwardmove == 0 ) {//wall-flip - vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.25f; - anim = BOTH_WALL_FLIP_RIGHT; + if ( allowWallFlips ) + { + vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.25f; + anim = BOTH_WALL_FLIP_RIGHT; + } } } else if ( pm->cmd.rightmove < 0 && pm->ps->fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 ) {//strafing left if ( pm->cmd.forwardmove > 0 ) {//wall-run - vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.0f; - anim = BOTH_WALL_RUN_LEFT; + if ( allowWallRuns ) + { + vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.0f; + anim = BOTH_WALL_RUN_LEFT; + } } else if ( pm->cmd.forwardmove == 0 ) {//wall-flip - vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.25f; - anim = BOTH_WALL_FLIP_LEFT; + if ( allowWallFlips ) + { + vertPush = forceJumpStrength[FORCE_LEVEL_2]/2.25f; + anim = BOTH_WALL_FLIP_LEFT; + } } } else if ( pm->cmd.forwardmove < 0 && !(pm->cmd.buttons&BUTTON_ATTACK) ) {//backflip - vertPush = JUMP_VELOCITY; - anim = BOTH_FLIP_BACK1;//BG_PickAnim( BOTH_FLIP_BACK1, BOTH_FLIP_BACK3 ); + if ( allowFlips ) + { + vertPush = JUMP_VELOCITY; + anim = BOTH_FLIP_BACK1;//BG_PickAnim( BOTH_FLIP_BACK1, BOTH_FLIP_BACK3 ); + } } vertPush += 128; //give them an extra shove @@ -2395,76 +2522,79 @@ static qboolean PM_CheckJump( void ) && PM_WalkableGroundDistance() <= 80 //unfortunately we do not have a happy ground timer like SP (this would use up more bandwidth if we wanted prediction workign right), so we'll just use the actual ground distance. && (pm->ps->legsAnim == BOTH_JUMP1 || pm->ps->legsAnim == BOTH_INAIR1 ) )//not in a flip or spin or anything {//run up wall, flip backwards - //FIXME: have to be moving... make sure it's opposite the wall... or at least forward? - int wallWalkAnim = BOTH_WALL_FLIP_BACK1; - int parts = SETANIM_LEGS; - int contents = MASK_SOLID;//MASK_PLAYERSOLID;//CONTENTS_SOLID; - //qboolean kick = qtrue; - if ( pm->ps->fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_2 ) + if ( allowWallRuns ) { - wallWalkAnim = BOTH_FORCEWALLRUNFLIP_START; - parts = SETANIM_BOTH; - //kick = qfalse; - } - else - { - if ( !pm->ps->weaponTime ) + //FIXME: have to be moving... make sure it's opposite the wall... or at least forward? + int wallWalkAnim = BOTH_WALL_FLIP_BACK1; + int parts = SETANIM_LEGS; + int contents = MASK_SOLID;//MASK_PLAYERSOLID;//CONTENTS_SOLID; + //qboolean kick = qtrue; + if ( pm->ps->fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_2 ) { + wallWalkAnim = BOTH_FORCEWALLRUNFLIP_START; parts = SETANIM_BOTH; + //kick = qfalse; } - } - //if ( PM_HasAnimation( pm->gent, wallWalkAnim ) ) - if (1) //sure, we have it! Because I SAID SO. - { - vec3_t fwd, traceto, mins, maxs, fwdAngles; - trace_t trace; - vec3_t idealNormal; - bgEntity_t *traceEnt; - - VectorSet(mins, pm->mins[0], pm->mins[1], 0.0f); - VectorSet(maxs, pm->maxs[0], pm->maxs[1], 24.0f); - VectorSet(fwdAngles, 0, pm->ps->viewangles[YAW], 0.0f); - - AngleVectors( fwdAngles, fwd, NULL, NULL ); - VectorMA( pm->ps->origin, 32, fwd, traceto ); - - pm->trace( &trace, pm->ps->origin, mins, maxs, traceto, pm->ps->clientNum, contents );//FIXME: clip brushes too? - VectorSubtract( pm->ps->origin, traceto, idealNormal ); - VectorNormalize( idealNormal ); - traceEnt = PM_BGEntForNum(trace.entityNum); - - if ( trace.fraction < 1.0f - &&((trace.entityNums.solid!=SOLID_BMODEL)||DotProduct(trace.plane.normal,idealNormal)>0.7) ) - {//there is a wall there - pm->ps->velocity[0] = pm->ps->velocity[1] = 0; - if ( wallWalkAnim == BOTH_FORCEWALLRUNFLIP_START ) + else + { + if ( !pm->ps->weaponTime ) { - pm->ps->velocity[2] = forceJumpStrength[FORCE_LEVEL_3]/2.0f; + parts = SETANIM_BOTH; } - else - { - VectorMA( pm->ps->velocity, -150, fwd, pm->ps->velocity ); - pm->ps->velocity[2] += 150.0f; - } - //animate me - PM_SetAnim( parts, wallWalkAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0 ); -// pm->ps->pm_flags |= PMF_JUMPING|PMF_SLOW_MO_FALL; - //again with the flags! - //G_SoundOnEnt( pm->gent, CHAN_BODY, "sound/weapons/force/jump.wav" ); - //yucky! - PM_SetForceJumpZStart(pm->ps->origin[2]);//so we don't take damage if we land at same height - pm->cmd.upmove = 0; - pm->ps->fd.forceJumpSound = 1; - BG_ForcePowerDrain( pm->ps, FP_LEVITATION, 5 ); + } + //if ( PM_HasAnimation( pm->gent, wallWalkAnim ) ) + if (1) //sure, we have it! Because I SAID SO. + { + vec3_t fwd, traceto, mins, maxs, fwdAngles; + trace_t trace; + vec3_t idealNormal; + bgEntity_t *traceEnt; - //kick if jumping off an ent - /* - if ( kick && traceEnt && (traceEnt->s.eType == ET_PLAYER || traceEnt->s.eType == ET_NPC) ) - { //kick that thang! - pm->ps->forceKickFlip = traceEnt->s.number+1; + VectorSet(mins, pm->mins[0], pm->mins[1], 0.0f); + VectorSet(maxs, pm->maxs[0], pm->maxs[1], 24.0f); + VectorSet(fwdAngles, 0, pm->ps->viewangles[YAW], 0.0f); + + AngleVectors( fwdAngles, fwd, NULL, NULL ); + VectorMA( pm->ps->origin, 32, fwd, traceto ); + + pm->trace( &trace, pm->ps->origin, mins, maxs, traceto, pm->ps->clientNum, contents );//FIXME: clip brushes too? + VectorSubtract( pm->ps->origin, traceto, idealNormal ); + VectorNormalize( idealNormal ); + traceEnt = PM_BGEntForNum(trace.entityNum); + + if ( trace.fraction < 1.0f + &&((trace.entityNums.solid!=SOLID_BMODEL)||DotProduct(trace.plane.normal,idealNormal)>0.7) ) + {//there is a wall there + pm->ps->velocity[0] = pm->ps->velocity[1] = 0; + if ( wallWalkAnim == BOTH_FORCEWALLRUNFLIP_START ) + { + pm->ps->velocity[2] = forceJumpStrength[FORCE_LEVEL_3]/2.0f; + } + else + { + VectorMA( pm->ps->velocity, -150, fwd, pm->ps->velocity ); + pm->ps->velocity[2] += 150.0f; + } + //animate me + PM_SetAnim( parts, wallWalkAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0 ); + // pm->ps->pm_flags |= PMF_JUMPING|PMF_SLOW_MO_FALL; + //again with the flags! + //G_SoundOnEnt( pm->gent, CHAN_BODY, "sound/weapons/force/jump.wav" ); + //yucky! + PM_SetForceJumpZStart(pm->ps->origin[2]);//so we don't take damage if we land at same height + pm->cmd.upmove = 0; + pm->ps->fd.forceJumpSound = 1; + BG_ForcePowerDrain( pm->ps, FP_LEVITATION, 5 ); + + //kick if jumping off an ent + /* + if ( kick && traceEnt && (traceEnt->s.eType == ET_PLAYER || traceEnt->s.eType == ET_NPC) ) + { //kick that thang! + pm->ps->forceKickFlip = traceEnt->s.number+1; + } + */ + pm->cmd.rightmove = pm->cmd.forwardmove= 0; } - */ - pm->cmd.rightmove = pm->cmd.forwardmove= 0; } } } @@ -2483,63 +2613,66 @@ static qboolean PM_CheckJump( void ) //&& (pm->ps->legsAnim == BOTH_JUMP1 || pm->ps->legsAnim == BOTH_INAIR1 ) )//not in a flip or spin or anything ) {//see if we're pushing at a wall and jump off it if so - //FIXME: make sure we have enough force power - //FIXME: check to see if we can go any higher - //FIXME: limit to a certain number of these in a row? - //FIXME: maybe don't require a ucmd direction, just check all 4? - //FIXME: should stick to the wall for a second, then push off... - vec3_t checkDir, traceto, mins, maxs, fwdAngles; - trace_t trace; - vec3_t idealNormal; - int anim = -1; - - VectorSet(mins, pm->mins[0], pm->mins[1], 0.0f); - VectorSet(maxs, pm->maxs[0], pm->maxs[1], 24.0f); - VectorSet(fwdAngles, 0, pm->ps->viewangles[YAW], 0.0f); - - if ( pm->cmd.rightmove ) + if ( allowWallGrabs ) { - if ( pm->cmd.rightmove > 0 ) + //FIXME: make sure we have enough force power + //FIXME: check to see if we can go any higher + //FIXME: limit to a certain number of these in a row? + //FIXME: maybe don't require a ucmd direction, just check all 4? + //FIXME: should stick to the wall for a second, then push off... + vec3_t checkDir, traceto, mins, maxs, fwdAngles; + trace_t trace; + vec3_t idealNormal; + int anim = -1; + + VectorSet(mins, pm->mins[0], pm->mins[1], 0.0f); + VectorSet(maxs, pm->maxs[0], pm->maxs[1], 24.0f); + VectorSet(fwdAngles, 0, pm->ps->viewangles[YAW], 0.0f); + + if ( pm->cmd.rightmove ) { - anim = BOTH_FORCEWALLREBOUND_RIGHT; - AngleVectors( fwdAngles, NULL, checkDir, NULL ); + if ( pm->cmd.rightmove > 0 ) + { + anim = BOTH_FORCEWALLREBOUND_RIGHT; + AngleVectors( fwdAngles, NULL, checkDir, NULL ); + } + else if ( pm->cmd.rightmove < 0 ) + { + anim = BOTH_FORCEWALLREBOUND_LEFT; + AngleVectors( fwdAngles, NULL, checkDir, NULL ); + VectorScale( checkDir, -1, checkDir ); + } } - else if ( pm->cmd.rightmove < 0 ) + else if ( pm->cmd.forwardmove > 0 ) { - anim = BOTH_FORCEWALLREBOUND_LEFT; - AngleVectors( fwdAngles, NULL, checkDir, NULL ); + anim = BOTH_FORCEWALLREBOUND_FORWARD; + AngleVectors( fwdAngles, checkDir, NULL, NULL ); + } + else if ( pm->cmd.forwardmove < 0 ) + { + anim = BOTH_FORCEWALLREBOUND_BACK; + AngleVectors( fwdAngles, checkDir, NULL, NULL ); VectorScale( checkDir, -1, checkDir ); } - } - else if ( pm->cmd.forwardmove > 0 ) - { - anim = BOTH_FORCEWALLREBOUND_FORWARD; - AngleVectors( fwdAngles, checkDir, NULL, NULL ); - } - else if ( pm->cmd.forwardmove < 0 ) - { - anim = BOTH_FORCEWALLREBOUND_BACK; - AngleVectors( fwdAngles, checkDir, NULL, NULL ); - VectorScale( checkDir, -1, checkDir ); - } - if ( anim != -1 ) - {//trace in the dir we're pushing in and see if there's a vertical wall there - bgEntity_t *traceEnt; + if ( anim != -1 ) + {//trace in the dir we're pushing in and see if there's a vertical wall there + bgEntity_t *traceEnt; - VectorMA( pm->ps->origin, 8, checkDir, traceto ); - pm->trace( &trace, pm->ps->origin, mins, maxs, traceto, pm->ps->clientNum, CONTENTS_SOLID );//FIXME: clip brushes too? - VectorSubtract( pm->ps->origin, traceto, idealNormal ); - VectorNormalize( idealNormal ); - traceEnt = PM_BGEntForNum(trace.entityNum); - if ( trace.fraction < 1.0f - &&fabs(trace.plane.normal[2]) <= 0.2f/*MAX_WALL_GRAB_SLOPE*/ - &&((trace.entityNums.solid!=SOLID_BMODEL)||DotProduct(trace.plane.normal,idealNormal)>0.7) ) - {//there is a wall there - float dot = DotProduct( pm->ps->velocity, trace.plane.normal ); - if ( dot < 1.0f ) - {//can't be heading *away* from the wall! - //grab it! - PM_GrabWallForJump( anim ); + VectorMA( pm->ps->origin, 8, checkDir, traceto ); + pm->trace( &trace, pm->ps->origin, mins, maxs, traceto, pm->ps->clientNum, CONTENTS_SOLID );//FIXME: clip brushes too? + VectorSubtract( pm->ps->origin, traceto, idealNormal ); + VectorNormalize( idealNormal ); + traceEnt = PM_BGEntForNum(trace.entityNum); + if ( trace.fraction < 1.0f + &&fabs(trace.plane.normal[2]) <= 0.2f/*MAX_WALL_GRAB_SLOPE*/ + &&((trace.entityNums.solid!=SOLID_BMODEL)||DotProduct(trace.plane.normal,idealNormal)>0.7) ) + {//there is a wall there + float dot = DotProduct( pm->ps->velocity, trace.plane.normal ); + if ( dot < 1.0f ) + {//can't be heading *away* from the wall! + //grab it! + PM_GrabWallForJump( anim ); + } } } } @@ -3187,7 +3320,6 @@ static void PM_WalkMove( void ) { return; } - if (pm->ps->pm_type != PM_SPECTATOR) { if ( PM_CheckJump () ) { @@ -3489,6 +3621,22 @@ static int PM_TryRoll( void ) return 0; } + if ( pm->ps->weapon == WP_SABER ) + { + saberInfo_t *saber = BG_MySaber( pm->ps->clientNum, 0 ); + if ( saber + && (saber->saberFlags&SFL_NO_ROLLS) ) + { + return 0; + } + saber = BG_MySaber( pm->ps->clientNum, 1 ); + if ( saber + && (saber->saberFlags&SFL_NO_ROLLS) ) + { + return 0; + } + } + VectorSet(mins, pm->mins[0],pm->mins[1],pm->mins[2]+STEPSIZE); VectorSet(maxs, pm->maxs[0],pm->maxs[1],pm->ps->crouchheight); @@ -5171,7 +5319,7 @@ static void PM_Footsteps( void ) { bobmove = 0.5; // ducked characters bob much faster - if ( ( PM_RunningAnim( pm->ps->legsAnim ) || PM_CanRollFromSoulCal( pm->ps ) ) && + if ( ( (PM_RunningAnim( pm->ps->legsAnim )&&VectorLengthSquared(pm->ps->velocity)>=40000/*200*200*/) || PM_CanRollFromSoulCal( pm->ps ) ) && !BG_InRoll(pm->ps, pm->ps->legsAnim) ) {//roll! rolled = PM_TryRoll(); @@ -5422,7 +5570,11 @@ static void PM_Footsteps( void ) { } else { - if ( BG_SabersOff( pm->ps ) ) + if ( pm->ps->weapon == WP_MELEE ) + { + desiredAnim = BOTH_WALK1; + } + else if ( BG_SabersOff( pm->ps ) ) { desiredAnim = BOTH_WALK1; } @@ -5595,6 +5747,16 @@ static void PM_WaterEvents( void ) { // FIXME? } } +void BG_ClearRocketLock( playerState_t *ps ) +{ + if ( ps ) + { + ps->rocketLockIndex = ENTITYNUM_NONE; + ps->rocketLastValidTime = 0; + ps->rocketLockTime = -1; + ps->rocketTargetTime = 0; + } +} /* =============== @@ -5626,6 +5788,8 @@ void PM_BeginWeaponChange( int weapon ) { pm->ps->weaponTime += 200; //PM_StartTorsoAnim( TORSO_DROPWEAP1 ); PM_SetAnim(SETANIM_TORSO, TORSO_DROPWEAP1, SETANIM_FLAG_OVERRIDE, 0); + + BG_ClearRocketLock( pm->ps ); } @@ -5660,6 +5824,53 @@ void PM_FinishWeaponChange( void ) { pm->ps->weaponTime += 250; } +#ifdef QAGAME +extern void WP_GetVehicleCamPos( gentity_t *ent, gentity_t *pilot, vec3_t camPos ); +#else +extern void CG_GetVehicleCamPos( vec3_t camPos ); +#endif +#define MAX_XHAIR_DIST_ACCURACY 20000.0f +int BG_VehTraceFromCamPos( trace_t *camTrace, bgEntity_t *bgEnt, const vec3_t entOrg, const vec3_t shotStart, const vec3_t end, vec3_t newEnd, vec3_t shotDir, float bestDist ) +{ + //NOTE: this MUST stay up to date with the method used in CG_ScanForCrosshairEntity (where it checks the doExtraVehTraceFromViewPos bool) + vec3_t viewDir2End, extraEnd, camPos; + float minAutoAimDist; + +#ifdef QAGAME + WP_GetVehicleCamPos( (gentity_t *)bgEnt, (gentity_t *)bgEnt->m_pVehicle->m_pPilot, camPos ); +#else + CG_GetVehicleCamPos( camPos ); +#endif + + minAutoAimDist = Distance( entOrg, camPos ) + (bgEnt->m_pVehicle->m_pVehicleInfo->length/2.0f) + 200.0f; + + VectorCopy( end, newEnd ); + VectorSubtract( end, camPos, viewDir2End ); + VectorNormalize( viewDir2End ); + VectorMA( camPos, MAX_XHAIR_DIST_ACCURACY, viewDir2End, extraEnd ); + +#ifdef QAGAME + trap_Trace( camTrace, camPos, vec3_origin, vec3_origin, extraEnd, + bgEnt->s.number, CONTENTS_SOLID|CONTENTS_BODY ); +#else + pm->trace( camTrace, camPos, vec3_origin, vec3_origin, extraEnd, + bgEnt->s.number, CONTENTS_SOLID|CONTENTS_BODY ); +#endif + + if ( !camTrace->allsolid + && !camTrace->startsolid + && camTrace->fraction < 1.0f + && (camTrace->fraction*MAX_XHAIR_DIST_ACCURACY) > minAutoAimDist + && ((camTrace->fraction*MAX_XHAIR_DIST_ACCURACY)-Distance( entOrg, camPos )) < bestDist ) + {//this trace hit *something* that's closer than the thing the main trace hit, so use this result instead + VectorCopy( camTrace->endpos, newEnd ); + VectorSubtract( newEnd, shotStart, shotDir ); + VectorNormalize( shotDir ); + return (camTrace->entityNum+1); + } + return 0; +} + void PM_RocketLock( float lockDist, qboolean vehicleLock ) { // Not really a charge weapon, but we still want to delay fire until the button comes up so that we can @@ -5695,6 +5906,19 @@ void PM_RocketLock( float lockDist, qboolean vehicleLock ) pm->trace(&tr, muzzlePoint, NULL, NULL, ang, pm->ps->clientNum, MASK_PLAYERSOLID); + if ( vehicleLock ) + {//vehicles also do a trace from the camera point if the main one misses + if ( tr.fraction >= 1.0f ) + { + trace_t camTrace; + vec3_t newEnd, shotDir; + if ( BG_VehTraceFromCamPos( &camTrace, PM_BGEntForNum(pm->ps->clientNum), pm->ps->origin, muzzlePoint, tr.endpos, newEnd, shotDir, (tr.fraction*lockDist) ) ) + { + memcpy( &tr, &camTrace, sizeof(tr) ); + } + } + } + if (tr.fraction != 1 && tr.entityNum < ENTITYNUM_NONE && tr.entityNum != pm->ps->clientNum) { bgEntity_t *bgEnt = PM_BGEntForNum(tr.entityNum); @@ -7601,6 +7825,7 @@ void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ) { // circularly clamp the angles with deltas for (i=0 ; i<3 ; i++) { temp = cmd->angles[i] + ps->delta_angles[i]; +#ifdef VEH_CONTROL_SCHEME_4 if ( pm_entVeh && pm_entVeh->m_pVehicle && pm_entVeh->m_pVehicle->m_pVehicleInfo @@ -7638,6 +7863,19 @@ void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ) { } } } +#else //VEH_CONTROL_SCHEME_4 + if ( pm_entVeh && BG_UnrestrainedPitchRoll( ps, pm_entVeh->m_pVehicle ) ) + {//in a fighter + /* + if ( i == ROLL ) + {//get roll from vehicle + ps->viewangles[ROLL] = pm_entVeh->playerState->viewangles[ROLL];//->m_pVehicle->m_vOrientation[ROLL]; + continue; + + } + */ + } +#endif // VEH_CONTROL_SCHEME_4 else { if ( i == PITCH ) { @@ -8092,6 +8330,8 @@ qboolean PM_SaberInTransition( int move ); void BG_AdjustClientSpeed(playerState_t *ps, usercmd_t *cmd, int svTime) { + saberInfo_t *saber; + if (ps->clientNum >= MAX_CLIENTS) { bgEntity_t *bgEnt = pm_entSelf; @@ -8149,7 +8389,6 @@ void BG_AdjustClientSpeed(playerState_t *ps, usercmd_t *cmd, int svTime) ps->speed *= 0.5f; } - if (ps->fd.forceGripCripple) { if (ps->fd.forcePowersActive & (1 << FP_RAGE)) @@ -8255,6 +8494,19 @@ void BG_AdjustClientSpeed(playerState_t *ps, usercmd_t *cmd, int svTime) } //Automatically slow down as the roll ends. } + + saber = BG_MySaber( ps->clientNum, 0 ); + if ( saber + && saber->moveSpeedScale != 1.0f ) + { + ps->speed *= saber->moveSpeedScale; + } + saber = BG_MySaber( ps->clientNum, 1 ); + if ( saber + && saber->moveSpeedScale != 1.0f ) + { + ps->speed *= saber->moveSpeedScale; + } } qboolean BG_InRollAnim( entityState_t *cent ) @@ -9398,7 +9650,11 @@ void PM_VehicleViewAngles(playerState_t *ps, bgEntity_t *veh, usercmd_t *ucmd) if ( veh->m_pVehicle->m_pPilot && veh->m_pVehicle->m_pPilot->s.number == ps->clientNum ) {//set the pilot's viewangles to the vehicle's viewangles - if ( 1 )//!BG_UnrestrainedPitchRoll( ps, veh->m_pVehicle ) ) +#ifdef VEH_CONTROL_SCHEME_4 + if ( 1 ) +#else //VEH_CONTROL_SCHEME_4 + if ( !BG_UnrestrainedPitchRoll( ps, veh->m_pVehicle ) ) +#endif //VEH_CONTROL_SCHEME_4 {//only if not if doing special free-roll/pitch control setAngles = qtrue; clampMin[PITCH] = -pVeh->m_pVehicleInfo->lookPitch; @@ -9414,6 +9670,9 @@ void PM_VehicleViewAngles(playerState_t *ps, bgEntity_t *veh, usercmd_t *ucmd) { if ( veh->m_pVehicle->m_pVehicleInfo->turret[i].passengerNum == ps->generic1 ) {//this turret is my station + //nevermind, don't clamp + return; + /* setAngles = qtrue; clampMin[PITCH] = veh->m_pVehicle->m_pVehicleInfo->turret[i].pitchClampUp; clampMax[PITCH] = veh->m_pVehicle->m_pVehicleInfo->turret[i].pitchClampDown; @@ -9421,6 +9680,7 @@ void PM_VehicleViewAngles(playerState_t *ps, bgEntity_t *veh, usercmd_t *ucmd) clampMax[YAW] = veh->m_pVehicle->m_pVehicleInfo->turret[i].yawClampLeft; clampMin[ROLL] = clampMax[ROLL] = 0; break; + */ } } } @@ -9549,6 +9809,7 @@ void PM_VehForcedTurning(bgEntity_t *veh) yawD *= 0.6f*pml.frametime; pitchD *= 0.6f*pml.frametime; +#ifdef VEH_CONTROL_SCHEME_4 veh->playerState->viewangles[YAW] = AngleSubtract(veh->playerState->viewangles[YAW], yawD); veh->playerState->viewangles[PITCH] = AngleSubtract(veh->playerState->viewangles[PITCH], pitchD); pm->ps->viewangles[YAW] = veh->playerState->viewangles[YAW]; @@ -9558,8 +9819,17 @@ void PM_VehForcedTurning(bgEntity_t *veh) PM_SetPMViewAngle(veh->playerState, veh->playerState->viewangles, &pm->cmd); VectorClear( veh->m_pVehicle->m_vPrevRiderViewAngles ); veh->m_pVehicle->m_vPrevRiderViewAngles[YAW] = AngleNormalize180(pm->ps->viewangles[YAW]); + +#else //VEH_CONTROL_SCHEME_4 + + pm->ps->viewangles[YAW] = AngleSubtract(pm->ps->viewangles[YAW], yawD); + pm->ps->viewangles[PITCH] = AngleSubtract(pm->ps->viewangles[PITCH], pitchD); + + PM_SetPMViewAngle(pm->ps, pm->ps->viewangles, &pm->cmd); +#endif //VEH_CONTROL_SCHEME_4 } +#ifdef VEH_CONTROL_SCHEME_4 void PM_VehFaceHyperspacePoint(bgEntity_t *veh) { @@ -9641,6 +9911,85 @@ void PM_VehFaceHyperspacePoint(bgEntity_t *veh) } } +#else //VEH_CONTROL_SCHEME_4 + +void PM_VehFaceHyperspacePoint(bgEntity_t *veh) +{ + + if (!veh || !veh->m_pVehicle) + { + return; + } + else + { + float timeFrac = ((float)(pm->cmd.serverTime-veh->playerState->hyperSpaceTime))/HYPERSPACE_TIME; + float turnRate, aDelta; + int i, matchedAxes = 0; + + pm->cmd.upmove = veh->m_pVehicle->m_ucmd.upmove = 127; + pm->cmd.forwardmove = veh->m_pVehicle->m_ucmd.forwardmove = 0; + pm->cmd.rightmove = veh->m_pVehicle->m_ucmd.rightmove = 0; + + turnRate = (90.0f*pml.frametime); + for ( i = 0; i < 3; i++ ) + { + aDelta = AngleSubtract(veh->playerState->hyperSpaceAngles[i], veh->m_pVehicle->m_vOrientation[i]); + if ( fabs( aDelta ) < turnRate ) + {//all is good + pm->ps->viewangles[i] = veh->playerState->hyperSpaceAngles[i]; + matchedAxes++; + } + else + { + aDelta = AngleSubtract(veh->playerState->hyperSpaceAngles[i], pm->ps->viewangles[i]); + if ( fabs( aDelta ) < turnRate ) + { + pm->ps->viewangles[i] = veh->playerState->hyperSpaceAngles[i]; + } + else if ( aDelta > 0 ) + { + if ( i == YAW ) + { + pm->ps->viewangles[i] = AngleNormalize360( pm->ps->viewangles[i]+turnRate ); + } + else + { + pm->ps->viewangles[i] = AngleNormalize180( pm->ps->viewangles[i]+turnRate ); + } + } + else + { + if ( i == YAW ) + { + pm->ps->viewangles[i] = AngleNormalize360( pm->ps->viewangles[i]-turnRate ); + } + else + { + pm->ps->viewangles[i] = AngleNormalize180( pm->ps->viewangles[i]-turnRate ); + } + } + } + } + + PM_SetPMViewAngle(pm->ps, pm->ps->viewangles, &pm->cmd); + + if ( timeFrac < HYPERSPACE_TELEPORT_FRAC ) + {//haven't gone through yet + if ( matchedAxes < 3 ) + {//not facing the right dir yet + //keep hyperspace time up to date + veh->playerState->hyperSpaceTime += pml.msec; + } + else if ( !(veh->playerState->eFlags2&EF2_HYPERSPACE)) + {//flag us as ready to hyperspace! + veh->playerState->eFlags2 |= EF2_HYPERSPACE; + } + } + } +} + +#endif //VEH_CONTROL_SCHEME_4 + void BG_VehicleAdjustBBoxForOrientation( Vehicle_t *veh, vec3_t origin, vec3_t mins, vec3_t maxs, int clientNum, int tracemask, void (*localTrace)(trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentMask)) diff --git a/codemp/game/bg_public.h b/codemp/game/bg_public.h index af6a4cb..ad83dcd 100644 --- a/codemp/game/bg_public.h +++ b/codemp/game/bg_public.h @@ -17,7 +17,7 @@ #define MAX_SPAWN_VARS_CHARS 4096 -#define GAME_VERSION "basejk-1" +#define GAME_VERSION "basejka-1" #define STEPSIZE 18 @@ -252,7 +252,7 @@ extern qboolean BGPAFtextLoaded; extern animation_t bgHumanoidAnimations[MAX_TOTALANIMATIONS]; #include "../namespace_end.h" -#define MAX_ANIM_FILES 16 +#define MAX_ANIM_FILES 64 #define MAX_ANIM_EVENTS 300 typedef enum @@ -292,6 +292,14 @@ extern stringID_table_t footstepTypeTable[NUM_FOOTSTEP_TYPES+1]; #define AED_MOVE_FWD 0 #define AED_MOVE_RT 1 #define AED_MOVE_UP 2 +//indices for AEV_SABER_SWING data +#define AED_SABER_SWING_SABERNUM 0 +#define AED_SABER_SWING_TYPE 1 +#define AED_SABER_SWING_PROBABILITY 2 +//indices for AEV_SABER_SPIN data +#define AED_SABER_SPIN_SABERNUM 0 +#define AED_SABER_SPIN_TYPE 1 //0 = saberspinoff, 1 = saberspin, 2-4 = saberspin1-saberspin3 +#define AED_SABER_SPIN_PROBABILITY 2 typedef enum {//NOTENOTE: Be sure to update animEventTypeTable and ParseAnimationEvtBlock(...) if you change this enum list! @@ -302,6 +310,8 @@ typedef enum AEV_FIRE, //# animID AEV_FIRE framenum altfire chancetofire AEV_MOVE, //# animID AEV_MOVE framenum forwardpush rightpush uppush AEV_SOUNDCHAN, //# animID AEV_SOUNDCHAN framenum CHANNEL soundpath randomlow randomhi chancetoplay + AEV_SABER_SWING, //# animID AEV_SABER_SWING framenum CHANNEL randomlow randomhi chancetoplay + AEV_SABER_SPIN, //# animID AEV_SABER_SPIN framenum CHANNEL chancetoplay AEV_NUM_AEV } animEventType_t; @@ -1073,6 +1083,8 @@ typedef enum { MOD_CRUSH, MOD_TELEFRAG, MOD_FALLING, + MOD_COLLISION, + MOD_VEH_EXPLOSION, MOD_SUICIDE, MOD_TARGET_LASER, MOD_TRIGGER_HURT, @@ -1275,6 +1287,8 @@ typedef struct #endif typedef enum { + //totally invalid + LS_INVALID = -1, // Invalid, or saber not armed LS_NONE = 0, @@ -1593,7 +1607,7 @@ qboolean BG_InDeathAnim( int anim ); qboolean BG_InSaberLockOld( int anim ); qboolean BG_InSaberLock( int anim ); -void BG_SaberStartTransAnim( int saberAnimLevel, int anim, float *animSpeed, int broken ); +void BG_SaberStartTransAnim( int clientNum, int saberAnimLevel, int weapon, int anim, float *animSpeed, int broken ); void BG_ForcePowerDrain( playerState_t *ps, forcePowers_t forcePower, int overrideAmt ); diff --git a/codemp/game/bg_saber.c b/codemp/game/bg_saber.c index 3301739..2234045 100644 --- a/codemp/game/bg_saber.c +++ b/codemp/game/bg_saber.c @@ -5,6 +5,7 @@ #include "../namespace_begin.h" extern qboolean BG_SabersOff( playerState_t *ps ); +saberInfo_t *BG_MySaber( int clientNum, int saberNum ); int PM_irand_timesync(int val1, int val2) { @@ -590,6 +591,19 @@ saberMoveName_t PM_CheckStabDown( void ) vec3_t trmins = {-15, -15, -15}; vec3_t trmaxs = {15, 15, 15}; + saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 ); + saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 ); + if ( saber1 + && (saber1->saberFlags&SFL_NO_STABDOWN) ) + { + return LS_NONE; + } + if ( saber2 + && (saber2->saberFlags&SFL_NO_STABDOWN) ) + { + return LS_NONE; + } + if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) {//sorry must be on ground! return LS_NONE; @@ -968,18 +982,21 @@ int PM_SaberLockWinAnim( qboolean victory, qboolean superBreak ) return winAnim; } -#ifdef QAGAME //including game headers on cgame is FORBIDDEN ^_^ - // Need to avoid nesting namespaces! #include "../namespace_end.h" +#ifdef QAGAME //including game headers on cgame is FORBIDDEN ^_^ #include "g_local.h" extern void NPC_SetAnim(gentity_t *ent, int setAnimParts, int anim, int setAnimFlags); extern gentity_t g_entities[]; -#include "../namespace_begin.h" +#elif defined CGAME + +#include "..\cgame\cg_local.h" //ahahahahhahahaha@$!$! #endif +#include "../namespace_begin.h" + int PM_SaberLockLoseAnim( playerState_t *genemy, qboolean victory, qboolean superBreak ) { int loseAnim = -1; @@ -1264,6 +1281,9 @@ void PM_SaberLockBreak( playerState_t *genemy, qboolean victory, int strength ) genemy->otherKiller = pm->ps->clientNum; genemy->otherKillerTime = pm->cmd.serverTime + 5000; genemy->otherKillerDebounceTime = pm->cmd.serverTime + 100; + //genemy->otherKillerMOD = MOD_UNKNOWN; + //genemy->otherKillerVehWeapon = 0; + //genemy->otherKillerWeaponType = WP_NONE; genemy->velocity[0] = oppDir[0]*(strength*40); genemy->velocity[1] = oppDir[1]*(strength*40); @@ -1641,6 +1661,37 @@ saberMoveName_t PM_SaberFlipOverAttackMove(void) // playerState_t *psData; // bgEntity_t *bgEnt; + saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 ); + saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 ); + //see if we have an overridden (or cancelled) lunge move + if ( saber1 + && saber1->jumpAtkFwdMove != LS_INVALID ) + { + if ( saber1->jumpAtkFwdMove != LS_NONE ) + { + return (saberMoveName_t)saber1->jumpAtkFwdMove; + } + } + if ( saber2 + && saber2->jumpAtkFwdMove != LS_INVALID ) + { + if ( saber2->jumpAtkFwdMove != LS_NONE ) + { + return (saberMoveName_t)saber2->jumpAtkFwdMove; + } + } + //no overrides, cancelled? + if ( saber1 + && saber1->jumpAtkFwdMove == LS_NONE ) + { + return LS_A_T2B;//LS_NONE; + } + if ( saber2 + && saber2->jumpAtkFwdMove == LS_NONE ) + { + return LS_A_T2B;//LS_NONE; + } + //just do it VectorCopy( pm->ps->viewangles, fwdAngles ); fwdAngles[PITCH] = fwdAngles[ROLL] = 0; AngleVectors( fwdAngles, jumpFwd, NULL, NULL ); @@ -1703,6 +1754,37 @@ saberMoveName_t PM_SaberFlipOverAttackMove(void) int PM_SaberBackflipAttackMove( void ) { + saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 ); + saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 ); + //see if we have an overridden (or cancelled) lunge move + if ( saber1 + && saber1->jumpAtkBackMove != LS_INVALID ) + { + if ( saber1->jumpAtkBackMove != LS_NONE ) + { + return (saberMoveName_t)saber1->jumpAtkBackMove; + } + } + if ( saber2 + && saber2->jumpAtkBackMove != LS_INVALID ) + { + if ( saber2->jumpAtkBackMove != LS_NONE ) + { + return (saberMoveName_t)saber2->jumpAtkBackMove; + } + } + //no overrides, cancelled? + if ( saber1 + && saber1->jumpAtkBackMove == LS_NONE ) + { + return LS_A_T2B;//LS_NONE; + } + if ( saber2 + && saber2->jumpAtkBackMove == LS_NONE ) + { + return LS_A_T2B;//LS_NONE; + } + //just do it pm->cmd.upmove = 127; pm->ps->velocity[2] = 500; return LS_A_BACKFLIP_ATK; @@ -1750,24 +1832,152 @@ qboolean PM_SomeoneInFront(trace_t *tr) return qfalse; } -saberMoveName_t PM_SaberLungeAttackMove( void ) +saberMoveName_t PM_SaberLungeAttackMove( qboolean noSpecials ) { vec3_t fwdAngles, jumpFwd; + saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 ); + saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 ); + //see if we have an overridden (or cancelled) lunge move + if ( saber1 + && saber1->lungeAtkMove != LS_INVALID ) + { + if ( saber1->lungeAtkMove != LS_NONE ) + { + return (saberMoveName_t)saber1->lungeAtkMove; + } + } + if ( saber2 + && saber2->lungeAtkMove != LS_INVALID ) + { + if ( saber2->lungeAtkMove != LS_NONE ) + { + return (saberMoveName_t)saber2->lungeAtkMove; + } + } + //no overrides, cancelled? + if ( saber1 + && saber1->lungeAtkMove == LS_NONE ) + { + return LS_A_T2B;//LS_NONE; + } + if ( saber2 + && saber2->lungeAtkMove == LS_NONE ) + { + return LS_A_T2B;//LS_NONE; + } + //just do it + if (pm->ps->fd.saberAnimLevel == SS_FAST) + { + VectorCopy( pm->ps->viewangles, fwdAngles ); + fwdAngles[PITCH] = fwdAngles[ROLL] = 0; + //do the lunge + AngleVectors( fwdAngles, jumpFwd, NULL, NULL ); + VectorScale( jumpFwd, 150, pm->ps->velocity ); + PM_AddEvent( EV_JUMP ); - VectorCopy( pm->ps->viewangles, fwdAngles ); - fwdAngles[PITCH] = fwdAngles[ROLL] = 0; - //do the lunge - AngleVectors( fwdAngles, jumpFwd, NULL, NULL ); - VectorScale( jumpFwd, 150, pm->ps->velocity ); - PM_AddEvent( EV_JUMP ); + return LS_A_LUNGE; + } + else if ( !noSpecials && pm->ps->fd.saberAnimLevel == SS_STAFF) + { + return LS_SPINATTACK; + } + else if ( !noSpecials ) + { + return LS_SPINATTACK_DUAL; + } + return LS_A_T2B; +} - return LS_A_LUNGE; +saberMoveName_t PM_SaberJumpAttackMove2( void ) +{ + saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 ); + saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 ); + //see if we have an overridden (or cancelled) lunge move + if ( saber1 + && saber1->jumpAtkFwdMove != LS_INVALID ) + { + if ( saber1->jumpAtkFwdMove != LS_NONE ) + { + return (saberMoveName_t)saber1->jumpAtkFwdMove; + } + } + if ( saber2 + && saber2->jumpAtkFwdMove != LS_INVALID ) + { + if ( saber2->jumpAtkFwdMove != LS_NONE ) + { + return (saberMoveName_t)saber2->jumpAtkFwdMove; + } + } + //no overrides, cancelled? + if ( saber1 + && saber1->jumpAtkFwdMove == LS_NONE ) + { + return LS_A_T2B;//LS_NONE; + } + if ( saber2 + && saber2->jumpAtkFwdMove == LS_NONE ) + { + return LS_A_T2B;//LS_NONE; + } + //just do it + if (pm->ps->fd.saberAnimLevel == SS_DUAL) + { + return PM_SaberDualJumpAttackMove(); + } + else + { + //rwwFIXMEFIXME I don't like randomness for this sort of thing, gives people reason to + //complain combat is unpredictable. Maybe do something more clever to determine + //if we should do a left or right? + /* + if (PM_irand_timesync(0, 1)) + { + newmove = LS_JUMPATTACK_STAFF_LEFT; + } + else + */ + { + return LS_JUMPATTACK_STAFF_RIGHT; + } + } + return LS_A_T2B; } saberMoveName_t PM_SaberJumpAttackMove( void ) { vec3_t fwdAngles, jumpFwd; - + saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 ); + saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 ); + //see if we have an overridden (or cancelled) lunge move + if ( saber1 + && saber1->jumpAtkFwdMove != LS_INVALID ) + { + if ( saber1->jumpAtkFwdMove != LS_NONE ) + { + return (saberMoveName_t)saber1->jumpAtkFwdMove; + } + } + if ( saber2 + && saber2->jumpAtkFwdMove != LS_INVALID ) + { + if ( saber2->jumpAtkFwdMove != LS_NONE ) + { + return (saberMoveName_t)saber2->jumpAtkFwdMove; + } + } + //no overrides, cancelled? + if ( saber1 + && saber1->jumpAtkFwdMove == LS_NONE ) + { + return LS_A_T2B;//LS_NONE; + } + if ( saber2 + && saber2->jumpAtkFwdMove == LS_NONE ) + { + return LS_A_T2B;//LS_NONE; + } + //just do it VectorCopy( pm->ps->viewangles, fwdAngles ); fwdAngles[PITCH] = fwdAngles[ROLL] = 0; AngleVectors( fwdAngles, jumpFwd, NULL, NULL ); @@ -1822,6 +2032,21 @@ float PM_WalkableGroundDistance(void) qboolean BG_SaberInTransitionAny( int move ); static qboolean PM_CanDoDualDoubleAttacks(void) { + if ( pm->ps->weapon == WP_SABER ) + { + saberInfo_t *saber = BG_MySaber( pm->ps->clientNum, 0 ); + if ( saber + && (saber->saberFlags&SFL_NO_MIRROR_ATTACKS) ) + { + return qfalse; + } + saber = BG_MySaber( pm->ps->clientNum, 1 ); + if ( saber + && (saber->saberFlags&SFL_NO_MIRROR_ATTACKS) ) + { + return qfalse; + } + } if (BG_SaberInSpecialAttack(pm->ps->torsoAnim) || BG_SaberInSpecialAttack(pm->ps->legsAnim)) { @@ -2017,45 +2242,118 @@ saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove) { saberMoveName_t newmove = LS_NONE; qboolean noSpecials = PM_InSecondaryStyle(); + qboolean allowCartwheels = qtrue; + saberMoveName_t overrideJumpRightAttackMove = LS_INVALID; + saberMoveName_t overrideJumpLeftAttackMove = LS_INVALID; + + if ( pm->ps->weapon == WP_SABER ) + { + saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 ); + saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 ); + + if ( saber1 + && saber1->jumpAtkRightMove != LS_INVALID ) + { + if ( saber1->jumpAtkRightMove != LS_NONE ) + {//actually overriding + overrideJumpRightAttackMove = (saberMoveName_t)saber1->jumpAtkRightMove; + } + else if ( saber2 + && saber2->jumpAtkRightMove > LS_NONE ) + {//would be cancelling it, but check the second saber, too + overrideJumpRightAttackMove = (saberMoveName_t)saber2->jumpAtkRightMove; + } + else + {//nope, just cancel it + overrideJumpRightAttackMove = LS_NONE; + } + } + else if ( saber2 + && saber2->jumpAtkRightMove != LS_INVALID ) + {//first saber not overridden, check second + overrideJumpRightAttackMove = (saberMoveName_t)saber2->jumpAtkRightMove; + } + + if ( saber1 + && saber1->jumpAtkLeftMove != LS_INVALID ) + { + if ( saber1->jumpAtkLeftMove != LS_NONE ) + {//actually overriding + overrideJumpLeftAttackMove = (saberMoveName_t)saber1->jumpAtkLeftMove; + } + else if ( saber2 + && saber2->jumpAtkLeftMove > LS_NONE ) + {//would be cancelling it, but check the second saber, too + overrideJumpLeftAttackMove = (saberMoveName_t)saber2->jumpAtkLeftMove; + } + else + {//nope, just cancel it + overrideJumpLeftAttackMove = LS_NONE; + } + } + else if ( saber2 + && saber2->jumpAtkLeftMove != LS_INVALID ) + {//first saber not overridden, check second + overrideJumpLeftAttackMove = (saberMoveName_t)saber1->jumpAtkLeftMove; + } + + if ( saber1 + && (saber1->saberFlags&SFL_NO_CARTWHEELS) ) + { + allowCartwheels = qfalse; + } + if ( saber2 + && (saber2->saberFlags&SFL_NO_CARTWHEELS) ) + { + allowCartwheels = qfalse; + } + } if ( pm->cmd.rightmove > 0 ) {//moving right if ( !noSpecials + && overrideJumpRightAttackMove != LS_NONE && pm->ps->velocity[2] > 20.0f //pm->ps->groundEntityNum != ENTITYNUM_NONE//on ground && (pm->cmd.buttons&BUTTON_ATTACK)//hitting attack && PM_GroundDistance() < 70.0f //not too high above ground && ( pm->cmd.upmove > 0 || (pm->ps->pm_flags & PMF_JUMP_HELD) )//focus-holding player && BG_EnoughForcePowerForMove( SABER_ALT_ATTACK_POWER_LR ) )//have enough power {//cartwheel right - vec3_t right, fwdAngles; - - VectorSet(fwdAngles, 0.0f, pm->ps->viewangles[YAW], 0.0f); - BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_LR); - - AngleVectors( fwdAngles, NULL, right, NULL ); - pm->ps->velocity[0] = pm->ps->velocity[1] = 0.0f; - VectorMA( pm->ps->velocity, 190.0f, right, pm->ps->velocity ); - if ( pm->ps->fd.saberAnimLevel == SS_STAFF ) - { - newmove = LS_BUTTERFLY_RIGHT; - pm->ps->velocity[2] = 350.0f; + if ( overrideJumpRightAttackMove != LS_INVALID ) + {//overridden with another move + return overrideJumpRightAttackMove; } else { - //PM_SetJumped( JUMP_VELOCITY, qtrue ); - PM_AddEvent( EV_JUMP ); - pm->ps->velocity[2] = 300.0f; + vec3_t right, fwdAngles; - //if ( !Q_irand( 0, 1 ) ) - //if (PM_GroundDistance() >= 25.0f) - if (1) + VectorSet(fwdAngles, 0.0f, pm->ps->viewangles[YAW], 0.0f); + + AngleVectors( fwdAngles, NULL, right, NULL ); + pm->ps->velocity[0] = pm->ps->velocity[1] = 0.0f; + VectorMA( pm->ps->velocity, 190.0f, right, pm->ps->velocity ); + if ( pm->ps->fd.saberAnimLevel == SS_STAFF ) { - newmove = LS_JUMPATTACK_ARIAL_RIGHT; + newmove = LS_BUTTERFLY_RIGHT; + pm->ps->velocity[2] = 350.0f; } - else + else if ( allowCartwheels ) { - newmove = LS_JUMPATTACK_CART_RIGHT; + //PM_SetJumped( JUMP_VELOCITY, qtrue ); + PM_AddEvent( EV_JUMP ); + pm->ps->velocity[2] = 300.0f; + + //if ( !Q_irand( 0, 1 ) ) + //if (PM_GroundDistance() >= 25.0f) + if (1) + { + newmove = LS_JUMPATTACK_ARIAL_RIGHT; + } + else + { + newmove = LS_JUMPATTACK_CART_RIGHT; + } } } } @@ -2075,41 +2373,48 @@ saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove) else if ( pm->cmd.rightmove < 0 ) {//moving left if ( !noSpecials + && overrideJumpLeftAttackMove != LS_NONE && pm->ps->velocity[2] > 20.0f //pm->ps->groundEntityNum != ENTITYNUM_NONE//on ground && (pm->cmd.buttons&BUTTON_ATTACK)//hitting attack && PM_GroundDistance() < 70.0f //not too high above ground && ( pm->cmd.upmove > 0 || (pm->ps->pm_flags & PMF_JUMP_HELD) )//focus-holding player && BG_EnoughForcePowerForMove( SABER_ALT_ATTACK_POWER_LR ) )//have enough power {//cartwheel left - vec3_t right, fwdAngles; - - VectorSet(fwdAngles, 0.0f, pm->ps->viewangles[YAW], 0.0f); - BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_LR); - AngleVectors( fwdAngles, NULL, right, NULL ); - pm->ps->velocity[0] = pm->ps->velocity[1] = 0.0f; - VectorMA( pm->ps->velocity, -190.0f, right, pm->ps->velocity ); - if ( pm->ps->fd.saberAnimLevel == SS_STAFF ) - { - newmove = LS_BUTTERFLY_LEFT; - pm->ps->velocity[2] = 250.0f; + if ( overrideJumpLeftAttackMove != LS_INVALID ) + {//overridden with another move + return overrideJumpLeftAttackMove; } else { - //PM_SetJumped( JUMP_VELOCITY, qtrue ); - PM_AddEvent( EV_JUMP ); - pm->ps->velocity[2] = 350.0f; + vec3_t right, fwdAngles; - //if ( !Q_irand( 0, 1 ) ) - //if (PM_GroundDistance() >= 25.0f) - if (1) + VectorSet(fwdAngles, 0.0f, pm->ps->viewangles[YAW], 0.0f); + AngleVectors( fwdAngles, NULL, right, NULL ); + pm->ps->velocity[0] = pm->ps->velocity[1] = 0.0f; + VectorMA( pm->ps->velocity, -190.0f, right, pm->ps->velocity ); + if ( pm->ps->fd.saberAnimLevel == SS_STAFF ) { - newmove = LS_JUMPATTACK_ARIAL_LEFT; + newmove = LS_BUTTERFLY_LEFT; + pm->ps->velocity[2] = 250.0f; } - else + else if ( allowCartwheels ) { - newmove = LS_JUMPATTACK_CART_LEFT; + //PM_SetJumped( JUMP_VELOCITY, qtrue ); + PM_AddEvent( EV_JUMP ); + pm->ps->velocity[2] = 350.0f; + + //if ( !Q_irand( 0, 1 ) ) + //if (PM_GroundDistance() >= 25.0f) + if (1) + { + newmove = LS_JUMPATTACK_ARIAL_LEFT; + } + else + { + newmove = LS_JUMPATTACK_CART_LEFT; + } } } } @@ -2144,26 +2449,11 @@ saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove) (pm->cmd.buttons & BUTTON_ATTACK)&& BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB) ) { //DUAL/STAFF JUMP ATTACK - BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); - if (pm->ps->fd.saberAnimLevel == SS_DUAL) + newmove = PM_SaberJumpAttackMove2(); + if ( newmove != LS_A_T2B + && newmove != LS_NONE ) { - newmove = PM_SaberDualJumpAttackMove(); - } - else - { - //rwwFIXMEFIXME I don't like randomness for this sort of thing, gives people reason to - //complain combat is unpredictable. Maybe do something more clever to determine - //if we should do a left or right? - /* - if (PM_irand_timesync(0, 1)) - { - newmove = LS_JUMPATTACK_STAFF_LEFT; - } - else - */ - { - newmove = LS_JUMPATTACK_STAFF_RIGHT; - } + BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); } } else if (!noSpecials&& @@ -2179,7 +2469,11 @@ saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove) //if (PM_SomeoneInFront(&tr)) { newmove = PM_SaberFlipOverAttackMove(); - BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); + if ( newmove != LS_A_T2B + && newmove != LS_NONE ) + { + BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); + } } } else if (!noSpecials&& @@ -2195,7 +2489,11 @@ saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove) //if (PM_SomeoneInFront(&tr)) { newmove = PM_SaberJumpAttackMove(); - BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); + if ( newmove != LS_A_T2B + && newmove != LS_NONE ) + { + BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); + } } } else if ((pm->ps->fd.saberAnimLevel == SS_FAST || pm->ps->fd.saberAnimLevel == SS_DUAL || pm->ps->fd.saberAnimLevel == SS_STAFF) && @@ -2205,25 +2503,18 @@ saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove) !BG_SaberInSpecialAttack(pm->ps->torsoAnim)&& BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB)) { //LUNGE (weak) - BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); - if (pm->ps->fd.saberAnimLevel == FORCE_LEVEL_1) + newmove = PM_SaberLungeAttackMove( noSpecials ); + if ( newmove != LS_A_T2B + && newmove != LS_NONE ) { - newmove = PM_SaberLungeAttackMove(); - } - else if ( !noSpecials && pm->ps->fd.saberAnimLevel == SS_STAFF) - { - newmove = LS_SPINATTACK; - } - else if ( !noSpecials ) - { - newmove = LS_SPINATTACK_DUAL; + BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); } } else if ( !noSpecials ) { saberMoveName_t stabDownMove = PM_CheckStabDown(); if (stabDownMove != LS_NONE - && BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB)) + && BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB) ) { newmove = stabDownMove; BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); @@ -2421,6 +2712,7 @@ qboolean PM_CanDoKata( void ) { return qfalse; } + if ( !pm->ps->saberInFlight//not throwing saber && PM_SaberMoveOkayForKata() && !BG_SaberInKata(pm->ps->saberMove) @@ -2438,6 +2730,18 @@ qboolean PM_CanDoKata( void ) && pm->cmd.upmove <= 0//not jumping...? && BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER) )// have enough power {//FIXME: check rage, etc... + saberInfo_t *saber = BG_MySaber( pm->ps->clientNum, 0 ); + if ( saber + && saber->kataMove == LS_NONE ) + {//kata move has been overridden in a way that should stop you from doing it at all + return qfalse; + } + saber = BG_MySaber( pm->ps->clientNum, 1 ); + if ( saber + && saber->kataMove == LS_NONE ) + {//kata move has been overridden in a way that should stop you from doing it at all + return qfalse; + } return qtrue; } return qfalse; @@ -2445,6 +2749,21 @@ qboolean PM_CanDoKata( void ) qboolean PM_CheckAltKickAttack( void ) { + if ( pm->ps->weapon == WP_SABER ) + { + saberInfo_t *saber = BG_MySaber( pm->ps->clientNum, 0 ); + if ( saber + && (saber->saberFlags&SFL_NO_KICKS) ) + { + return qfalse; + } + saber = BG_MySaber( pm->ps->clientNum, 1 ); + if ( saber + && (saber->saberFlags&SFL_NO_KICKS) ) + { + return qfalse; + } + } if ( (pm->cmd.buttons&BUTTON_ALT_ATTACK) //&& (!(pm->ps->pm_flags&PMF_ALT_ATTACK_HELD)||PM_SaberInReturn(pm->ps->saberMove)) && (!BG_FlippingAnim(pm->ps->legsAnim)||pm->ps->legsTimer<=250) @@ -2480,6 +2799,25 @@ qboolean PM_SaberPowerCheck(void) return qfalse; } +qboolean PM_CanDoRollStab( void ) +{ + if ( pm->ps->weapon == WP_SABER ) + { + saberInfo_t *saber = BG_MySaber( pm->ps->clientNum, 0 ); + if ( saber + && (saber->saberFlags&SFL_NO_ROLL_STAB) ) + { + return qfalse; + } + saber = BG_MySaber( pm->ps->clientNum, 1 ); + if ( saber + && (saber->saberFlags&SFL_NO_ROLL_STAB) ) + { + return qfalse; + } + } + return qtrue; +} /* ================= PM_WeaponLightsaber @@ -2520,14 +2858,17 @@ void PM_WeaponLightsaber(void) { if ( BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB) && !pm->ps->saberInFlight ) { - //make sure the saber is on for this move! - if ( pm->ps->saberHolstered == 2 ) - {//all the way off - pm->ps->saberHolstered = 0; - PM_AddEvent(EV_SABER_UNHOLSTER); + if ( PM_CanDoRollStab() ) + { + //make sure the saber is on for this move! + if ( pm->ps->saberHolstered == 2 ) + {//all the way off + pm->ps->saberHolstered = 0; + PM_AddEvent(EV_SABER_UNHOLSTER); + } + PM_SetSaberMove( LS_ROLL_STAB ); + BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); } - PM_SetSaberMove( LS_ROLL_STAB ); - BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB); } } } @@ -2999,31 +3340,79 @@ weapChecks: if ( PM_CanDoKata() ) { - //FIXME: make sure to turn on saber(s)! - switch ( pm->ps->fd.saberAnimLevel ) + saberMoveName_t overrideMove = LS_INVALID; + saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 ); + saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 ); + //see if we have an overridden (or cancelled) kata move + if ( saber1 && saber1->kataMove != LS_INVALID ) { - case SS_FAST: - case SS_TAVION: - PM_SetSaberMove( LS_A1_SPECIAL ); - break; - case SS_MEDIUM: - PM_SetSaberMove( LS_A2_SPECIAL ); - break; - case SS_STRONG: - case SS_DESANN: - PM_SetSaberMove( LS_A3_SPECIAL ); - break; - case SS_DUAL: - PM_SetSaberMove( LS_DUAL_SPIN_PROTECT );//PM_CheckDualSpinProtect(); - break; - case SS_STAFF: - PM_SetSaberMove( LS_STAFF_SOULCAL ); - break; + if ( saber1->kataMove != LS_NONE ) + { + overrideMove = (saberMoveName_t)saber1->kataMove; + } + } + if ( overrideMove == LS_INVALID ) + {//not overridden by first saber, check second + if ( saber2 + && saber2->kataMove != LS_INVALID ) + { + if ( saber2->kataMove != LS_NONE ) + { + overrideMove = (saberMoveName_t)saber2->kataMove; + } + } + } + //no overrides, cancelled? + if ( overrideMove == LS_INVALID ) + { + if ( saber2 + && saber2->kataMove == LS_NONE ) + { + overrideMove = LS_NONE; + } + else if ( saber2 + && saber2->kataMove == LS_NONE ) + { + overrideMove = LS_NONE; + } + } + if ( overrideMove == LS_INVALID ) + {//not overridden + //FIXME: make sure to turn on saber(s)! + switch ( pm->ps->fd.saberAnimLevel ) + { + case SS_FAST: + case SS_TAVION: + PM_SetSaberMove( LS_A1_SPECIAL ); + break; + case SS_MEDIUM: + PM_SetSaberMove( LS_A2_SPECIAL ); + break; + case SS_STRONG: + case SS_DESANN: + PM_SetSaberMove( LS_A3_SPECIAL ); + break; + case SS_DUAL: + PM_SetSaberMove( LS_DUAL_SPIN_PROTECT );//PM_CheckDualSpinProtect(); + break; + case SS_STAFF: + PM_SetSaberMove( LS_STAFF_SOULCAL ); + break; + } + pm->ps->weaponstate = WEAPON_FIRING; + //G_DrainPowerForSpecialMove( pm->gent, FP_SABER_OFFENSE, SABER_ALT_ATTACK_POWER );//FP_SPEED, SINGLE_SPECIAL_POWER ); + BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER); + } + else if ( overrideMove != LS_NONE ) + { + PM_SetSaberMove( overrideMove ); + pm->ps->weaponstate = WEAPON_FIRING; + BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER); + } + if ( overrideMove != LS_NONE ) + {//not cancelled + return; } - pm->ps->weaponstate = WEAPON_FIRING; - //G_DrainPowerForSpecialMove( pm->gent, FP_SABER_OFFENSE, SABER_ALT_ATTACK_POWER );//FP_SPEED, SINGLE_SPECIAL_POWER ); - BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER); - return; } if ( pm->ps->weaponTime > 0 ) @@ -3432,7 +3821,19 @@ void PM_SetSaberMove(short newMove) if ( newMove == LS_DRAW ) { - if ( pm->ps->fd.saberAnimLevel == SS_STAFF ) + saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 ); + saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 ); + if ( saber1 + && saber1->drawAnim != -1 ) + { + anim = saber1->drawAnim; + } + else if ( saber2 + && saber2->drawAnim != -1 ) + { + anim = saber2->drawAnim; + } + else if ( pm->ps->fd.saberAnimLevel == SS_STAFF ) { anim = BOTH_S1_S7; } @@ -3443,7 +3844,19 @@ void PM_SetSaberMove(short newMove) } else if ( newMove == LS_PUTAWAY ) { - if ( pm->ps->fd.saberAnimLevel == SS_STAFF ) + saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 ); + saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 ); + if ( saber1 + && saber1->putawayAnim != -1 ) + { + anim = saber1->putawayAnim; + } + else if ( saber2 + && saber2->putawayAnim != -1 ) + { + anim = saber2->putawayAnim; + } + else if ( pm->ps->fd.saberAnimLevel == SS_STAFF ) { anim = BOTH_S7_S1; } @@ -3684,4 +4097,47 @@ void PM_SetSaberMove(short newMove) } } +saberInfo_t *BG_MySaber( int clientNum, int saberNum ) +{ + //returns a pointer to the requested saberNum +#ifdef QAGAME + gentity_t *ent = &g_entities[clientNum]; + if ( ent->inuse && ent->client ) + { + if ( !ent->client->saber[saberNum].model + || !ent->client->saber[saberNum].model[0] ) + { //don't have saber anymore! + return NULL; + } + return &ent->client->saber[saberNum]; + } +#elif defined CGAME + clientInfo_t *ci = NULL; + if (clientNum < MAX_CLIENTS) + { + ci = &cgs.clientinfo[clientNum]; + } + else + { + centity_t *cent = &cg_entities[clientNum]; + if (cent->npcClient) + { + ci = cent->npcClient; + } + } + if ( ci + && ci->infoValid ) + { + if ( !ci->saber[saberNum].model + || !ci->saber[saberNum].model[0] ) + { //don't have sabers anymore! + return NULL; + } + return &ci->saber[saberNum]; + } +#endif + + return NULL; +} + #include "../namespace_end.h" diff --git a/codemp/game/bg_saberLoad.c b/codemp/game/bg_saberLoad.c index 1a42396..878c80e 100644 --- a/codemp/game/bg_saberLoad.c +++ b/codemp/game/bg_saberLoad.c @@ -4,6 +4,8 @@ #include "bg_local.h" #include "w_saber.h" +extern stringID_table_t animTable [MAX_ANIMATIONS+1]; + //Could use strap stuff but I don't particularly care at the moment anyway. #include "../namespace_begin.h" extern int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ); @@ -20,6 +22,8 @@ extern int G_SoundIndex( const char *name ); #elif defined CGAME #include "../namespace_begin.h" sfxHandle_t trap_S_RegisterSound( const char *sample); +qhandle_t trap_R_RegisterShader( const char *name ); // returns all white if not found +int trap_FX_RegisterEffect(const char *file); #include "../namespace_end.h" #endif @@ -36,7 +40,7 @@ int BG_SoundIndex(char *sound) extern stringID_table_t FPTable[]; -#define MAX_SABER_DATA_SIZE 0x10000 +#define MAX_SABER_DATA_SIZE 0x80000 static char SaberParms[MAX_SABER_DATA_SIZE]; stringID_table_t SaberTable[] = @@ -56,6 +60,71 @@ stringID_table_t SaberTable[] = "", -1 }; +stringID_table_t SaberMoveTable[] = +{ + ENUM2STRING(LS_NONE), + // Attacks + ENUM2STRING(LS_A_TL2BR), + ENUM2STRING(LS_A_L2R), + ENUM2STRING(LS_A_BL2TR), + ENUM2STRING(LS_A_BR2TL), + ENUM2STRING(LS_A_R2L), + ENUM2STRING(LS_A_TR2BL), + ENUM2STRING(LS_A_T2B), + ENUM2STRING(LS_A_BACKSTAB), + ENUM2STRING(LS_A_BACK), + ENUM2STRING(LS_A_BACK_CR), + ENUM2STRING(LS_ROLL_STAB), + ENUM2STRING(LS_A_LUNGE), + ENUM2STRING(LS_A_JUMP_T__B_), + ENUM2STRING(LS_A_FLIP_STAB), + ENUM2STRING(LS_A_FLIP_SLASH), + ENUM2STRING(LS_JUMPATTACK_DUAL), + ENUM2STRING(LS_JUMPATTACK_ARIAL_LEFT), + ENUM2STRING(LS_JUMPATTACK_ARIAL_RIGHT), + ENUM2STRING(LS_JUMPATTACK_CART_LEFT), + ENUM2STRING(LS_JUMPATTACK_CART_RIGHT), + ENUM2STRING(LS_JUMPATTACK_STAFF_LEFT), + ENUM2STRING(LS_JUMPATTACK_STAFF_RIGHT), + ENUM2STRING(LS_BUTTERFLY_LEFT), + ENUM2STRING(LS_BUTTERFLY_RIGHT), + ENUM2STRING(LS_A_BACKFLIP_ATK), + ENUM2STRING(LS_SPINATTACK_DUAL), + ENUM2STRING(LS_SPINATTACK), + ENUM2STRING(LS_LEAP_ATTACK), + ENUM2STRING(LS_SWOOP_ATTACK_RIGHT), + ENUM2STRING(LS_SWOOP_ATTACK_LEFT), + ENUM2STRING(LS_TAUNTAUN_ATTACK_RIGHT), + ENUM2STRING(LS_TAUNTAUN_ATTACK_LEFT), + ENUM2STRING(LS_KICK_F), + ENUM2STRING(LS_KICK_B), + ENUM2STRING(LS_KICK_R), + ENUM2STRING(LS_KICK_L), + ENUM2STRING(LS_KICK_S), + ENUM2STRING(LS_KICK_BF), + ENUM2STRING(LS_KICK_RL), + ENUM2STRING(LS_KICK_F_AIR), + ENUM2STRING(LS_KICK_B_AIR), + ENUM2STRING(LS_KICK_R_AIR), + ENUM2STRING(LS_KICK_L_AIR), + ENUM2STRING(LS_STABDOWN), + ENUM2STRING(LS_STABDOWN_STAFF), + ENUM2STRING(LS_STABDOWN_DUAL), + ENUM2STRING(LS_DUAL_SPIN_PROTECT), + ENUM2STRING(LS_STAFF_SOULCAL), + ENUM2STRING(LS_A1_SPECIAL), + ENUM2STRING(LS_A2_SPECIAL), + ENUM2STRING(LS_A3_SPECIAL), + ENUM2STRING(LS_UPSIDE_DOWN_ATTACK), + ENUM2STRING(LS_PULL_ATTACK_STAB), + ENUM2STRING(LS_PULL_ATTACK_SWING), + ENUM2STRING(LS_SPINATTACK_ALORA), + ENUM2STRING(LS_DUAL_FB), + ENUM2STRING(LS_DUAL_LR), + ENUM2STRING(LS_HILT_BASH), + "", -1 +}; + //Also used in npc code qboolean BG_ParseLiteral( const char **data, const char *string ) { @@ -143,6 +212,279 @@ saber_styles_t TranslateSaberStyle( const char *name ) return SS_NONE; } +qboolean WP_SaberBladeUseSecondBladeStyle( saberInfo_t *saber, int bladeNum ) +{ + if ( saber ) + { + if ( saber->bladeStyle2Start > 0 ) + { + if ( bladeNum >= saber->bladeStyle2Start ) + { + return qtrue; + } + } + } + return qfalse; +} + +qboolean WP_SaberBladeDoTransitionDamage( saberInfo_t *saber, int bladeNum ) +{ + if ( !WP_SaberBladeUseSecondBladeStyle( saber, bladeNum ) + && (saber->saberFlags2&SFL2_TRANSITION_DAMAGE) ) + {//use first blade style for this blade + return qtrue; + } + else if ( WP_SaberBladeUseSecondBladeStyle( saber, bladeNum ) + && (saber->saberFlags2&SFL2_TRANSITION_DAMAGE2) ) + {//use second blade style for this blade + return qtrue; + } + return qfalse; +} + +qboolean WP_UseFirstValidSaberStyle( saberInfo_t *saber1, saberInfo_t *saber2, int saberHolstered, int *saberAnimLevel ) +{ + qboolean styleInvalid = qfalse; + qboolean saber1Active; + qboolean saber2Active; + qboolean dualSabers = qfalse; + int validStyles = 0, styleNum; + + if ( saber2 && saber2->model && saber2->model[0] ) + { + dualSabers = qtrue; + } + + if ( dualSabers ) + {//dual + if ( saberHolstered > 1 ) + { + saber1Active = saber2Active = qfalse; + } + else if ( saberHolstered > 0 ) + { + saber1Active = qtrue; + saber2Active = qfalse; + } + else + { + saber1Active = saber2Active = qtrue; + } + } + else + { + saber2Active = qfalse; + if ( !saber1 + || !saber1->model + || !saber1->model[0] ) + { + saber1Active = qfalse; + } + else if ( saber1->numBlades > 1 ) + {//staff + if ( saberHolstered > 1 ) + { + saber1Active = qfalse; + } + else + { + saber1Active = qtrue; + } + } + else + {//single + if ( saberHolstered ) + { + saber1Active = qfalse; + } + else + { + saber1Active = qtrue; + } + } + } + + //initially, all styles are valid + for ( styleNum = SS_NONE+1; styleNum < SS_NUM_SABER_STYLES; styleNum++ ) + { + validStyles |= (1<model + && saber1->model[0] + && saber1->stylesForbidden ) + { + if ( (saber1->stylesForbidden&(1<<*saberAnimLevel)) ) + {//not a valid style for first saber! + styleInvalid = qtrue; + validStyles &= ~saber1->stylesForbidden; + } + } + if ( dualSabers ) + {//check second saber, too + if ( saber2Active + && saber2->stylesForbidden ) + { + if ( (saber2->stylesForbidden&(1<<*saberAnimLevel)) ) + {//not a valid style for second saber! + styleInvalid = qtrue; + //only the ones both sabers allow is valid + validStyles &= ~saber2->stylesForbidden; + } + } + } + if ( styleInvalid && validStyles ) + {//using an invalid style and have at least one valid style to use, so switch to it + int styleNum; + for ( styleNum = SS_FAST; styleNum < SS_NUM_SABER_STYLES; styleNum++ ) + { + if ( (validStyles&(1<model && saber2->model[0] ) + { + dualSabers = qtrue; + } + + if ( dualSabers ) + {//dual + if ( saberHolstered > 1 ) + { + saber1Active = saber2Active = qfalse; + } + else if ( saberHolstered > 0 ) + { + saber1Active = qtrue; + saber2Active = qfalse; + } + else + { + saber1Active = saber2Active = qtrue; + } + } + else + { + saber2Active = qfalse; + if ( !saber1 + || !saber1->model + || !saber1->model[0] ) + { + saber1Active = qfalse; + } + else if ( saber1->numBlades > 1 ) + {//staff + if ( saberHolstered > 1 ) + { + saber1Active = qfalse; + } + else + { + saber1Active = qtrue; + } + } + else + {//single + if ( saberHolstered ) + { + saber1Active = qfalse; + } + else + { + saber1Active = qtrue; + } + } + } + + if ( saber1Active + && saber1 + && saber1->model + && saber1->model[0] + && saber1->stylesForbidden ) + { + if ( (saber1->stylesForbidden&(1<model + && saber2->model[0] ) + { + if ( saber2->stylesForbidden ) + {//check second saber, too + if ( (saber2->stylesForbidden&(1<model + && saber1->model[0] + && (saber1->stylesLearned&(1<stylesLearned&(1<bladeStyle2Start > 0 + && saber->numBlades > saber->bladeStyle2Start ) + { + if ( (saber->saberFlags2&SFL2_NO_MANUAL_DEACTIVATE) + && (saber->saberFlags2&SFL2_NO_MANUAL_DEACTIVATE2) ) + {//all blades are always on + return qfalse; + } + } + else + { + if ( (saber->saberFlags2&SFL2_NO_MANUAL_DEACTIVATE) ) + {//all blades are always on + return qfalse; + } + } + //you can turn some off + return qtrue; +} + void WP_SaberSetDefaults( saberInfo_t *saber ) { int i; @@ -164,23 +506,110 @@ void WP_SaberSetDefaults( saberInfo_t *saber ) saber->soundOff = BG_SoundIndex( "sound/weapons/saber/enemy_saber_off.wav" ); saber->numBlades = 1; saber->type = SABER_SINGLE; - saber->style = SS_NONE; + saber->stylesLearned = 0; + saber->stylesForbidden = 0;//allow all styles saber->maxChain = 0;//0 = use default behavior - saber->lockable = qtrue; - saber->throwable = qtrue; - saber->disarmable = qtrue; - saber->activeBlocking = qtrue; - saber->twoHanded = qfalse; saber->forceRestrictions = 0; saber->lockBonus = 0; saber->parryBonus = 0; saber->breakParryBonus = 0; + saber->breakParryBonus2 = 0; saber->disarmBonus = 0; + saber->disarmBonus2 = 0; saber->singleBladeStyle = SS_NONE;//makes it so that you use a different style if you only have the first blade active - saber->singleBladeThrowable = qfalse;//makes it so that you can throw this saber if only the first blade is on // saber->brokenSaber1 = NULL;//if saber is actually hit by another saber, it can be cut in half/broken and will be replaced with this saber in your right hand // saber->brokenSaber2 = NULL;//if saber is actually hit by another saber, it can be cut in half/broken and will be replaced with this saber in your left hand - saber->returnDamage = qfalse;//when returning from a saber throw, it keeps spinning and doing damage +//===NEW======================================================================================== + //done in cgame (client-side code) + saber->saberFlags = 0; //see all the SFL_ flags + saber->saberFlags2 = 0; //see all the SFL2_ flags + + saber->spinSound = 0; //none - if set, plays this sound as it spins when thrown + saber->swingSound[0] = 0; //none - if set, plays one of these 3 sounds when swung during an attack - NOTE: must provide all 3!!! + saber->swingSound[1] = 0; //none - if set, plays one of these 3 sounds when swung during an attack - NOTE: must provide all 3!!! + saber->swingSound[2] = 0; //none - if set, plays one of these 3 sounds when swung during an attack - NOTE: must provide all 3!!! + + //done in game (server-side code) + saber->moveSpeedScale = 1.0f; //1.0 - you move faster/slower when using this saber + saber->animSpeedScale = 1.0f; //1.0 - plays normal attack animations faster/slower + + saber->kataMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they press both attack buttons at the same time + saber->lungeAtkMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they crouch+fwd+attack + saber->jumpAtkUpMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they jump+attack + saber->jumpAtkFwdMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they jump+fwd+attack + saber->jumpAtkBackMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they jump+back+attack + saber->jumpAtkRightMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they jump+rightattack + saber->jumpAtkLeftMove = LS_INVALID; //LS_INVALID - if set, player will execute this move when they jump+left+attack + saber->readyAnim = -1; //-1 - anim to use when standing idle + saber->drawAnim = -1; //-1 - anim to use when drawing weapon + saber->putawayAnim = -1; //-1 - anim to use when putting weapon away + saber->tauntAnim = -1; //-1 - anim to use when hit "taunt" + saber->bowAnim = -1; //-1 - anim to use when hit "bow" + saber->meditateAnim = -1; //-1 - anim to use when hit "meditate" + saber->flourishAnim = -1; //-1 - anim to use when hit "flourish" + saber->gloatAnim = -1; //-1 - anim to use when hit "gloat" + + //***NOTE: you can only have a maximum of 2 "styles" of blades, so this next value, "bladeStyle2Start" is the number of the first blade to use these value on... all blades before this use the normal values above, all blades at and after this number use the secondary values below*** + saber->bladeStyle2Start = 0; //0 - if set, blades from this number and higher use the following values (otherwise, they use the normal values already set) + + //***The following can be different for the extra blades - not setting them individually defaults them to the value for the whole saber (and first blade)*** + + //===PRIMARY BLADES===================== + //done in cgame (client-side code) + saber->trailStyle = 0; //0 - default (0) is normal, 1 is a motion blur and 2 is no trail at all (good for real-sword type mods) + saber->g2MarksShader = 0; //none - if set, the game will use this shader for marks on enemies instead of the default "gfx/damage/saberglowmark" + saber->g2WeaponMarkShader = 0; //none - if set, the game will use this shader for marks on enemies instead of the default "gfx/damage/saberglowmark" + //saber->bladeShader = 0; //none - if set, overrides the shader used for the saber blade? + //saber->trailShader = 0; //none - if set, overrides the shader used for the saber trail? + saber->hitSound[0] = 0; //none - if set, plays one of these 3 sounds when saber hits a person - NOTE: must provide all 3!!! + saber->hitSound[1] = 0; //none - if set, plays one of these 3 sounds when saber hits a person - NOTE: must provide all 3!!! + saber->hitSound[2] = 0; //none - if set, plays one of these 3 sounds when saber hits a person - NOTE: must provide all 3!!! + saber->blockSound[0] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits another saber/sword - NOTE: must provide all 3!!! + saber->blockSound[1] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits another saber/sword - NOTE: must provide all 3!!! + saber->blockSound[2] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits another saber/sword - NOTE: must provide all 3!!! + saber->bounceSound[0] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits a wall and bounces off (must set bounceOnWall to 1 to use these sounds) - NOTE: must provide all 3!!! + saber->bounceSound[1] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits a wall and bounces off (must set bounceOnWall to 1 to use these sounds) - NOTE: must provide all 3!!! + saber->bounceSound[2] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits a wall and bounces off (must set bounceOnWall to 1 to use these sounds) - NOTE: must provide all 3!!! + saber->blockEffect = 0; //none - if set, plays this effect when the saber/sword hits another saber/sword (instead of "saber/saber_block.efx") + saber->hitPersonEffect = 0; //none - if set, plays this effect when the saber/sword hits a person (instead of "saber/blood_sparks_mp.efx") + saber->hitOtherEffect = 0; //none - if set, plays this effect when the saber/sword hits something else damagable (instead of "saber/saber_cut.efx") + saber->bladeEffect = 0; //none - if set, plays this effect at the blade tag + + //done in game (server-side code) + saber->knockbackScale = 0; //0 - if non-zero, uses damage done to calculate an appropriate amount of knockback + saber->damageScale = 1.0f; //1 - scale up or down the damage done by the saber + saber->splashRadius = 0.0f; //0 - radius of splashDamage + saber->splashDamage = 0; //0 - amount of splashDamage, 100% at a distance of 0, 0% at a distance = splashRadius + saber->splashKnockback = 0.0f; //0 - amount of splashKnockback, 100% at a distance of 0, 0% at a distance = splashRadius + + //===SECONDARY BLADES=================== + //done in cgame (client-side code) + saber->trailStyle2 = 0; //0 - default (0) is normal, 1 is a motion blur and 2 is no trail at all (good for real-sword type mods) + saber->g2MarksShader2 = 0; //none - if set, the game will use this shader for marks on enemies instead of the default "gfx/damage/saberglowmark" + saber->g2WeaponMarkShader2 = 0; //none - if set, the game will use this shader for marks on enemies instead of the default "gfx/damage/saberglowmark" + //saber->bladeShader = 0; //none - if set, overrides the shader used for the saber blade? + //saber->trailShader = 0; //none - if set, overrides the shader used for the saber trail? + saber->hit2Sound[0] = 0; //none - if set, plays one of these 3 sounds when saber hits a person - NOTE: must provide all 3!!! + saber->hit2Sound[1] = 0; //none - if set, plays one of these 3 sounds when saber hits a person - NOTE: must provide all 3!!! + saber->hit2Sound[2] = 0; //none - if set, plays one of these 3 sounds when saber hits a person - NOTE: must provide all 3!!! + saber->block2Sound[0] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits another saber/sword - NOTE: must provide all 3!!! + saber->block2Sound[1] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits another saber/sword - NOTE: must provide all 3!!! + saber->block2Sound[2] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits another saber/sword - NOTE: must provide all 3!!! + saber->bounce2Sound[0] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits a wall and bounces off (must set bounceOnWall to 1 to use these sounds) - NOTE: must provide all 3!!! + saber->bounce2Sound[1] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits a wall and bounces off (must set bounceOnWall to 1 to use these sounds) - NOTE: must provide all 3!!! + saber->bounce2Sound[2] = 0; //none - if set, plays one of these 3 sounds when saber/sword hits a wall and bounces off (must set bounceOnWall to 1 to use these sounds) - NOTE: must provide all 3!!! + saber->blockEffect2 = 0; //none - if set, plays this effect when the saber/sword hits another saber/sword (instead of "saber/saber_block.efx") + saber->hitPersonEffect2 = 0; //none - if set, plays this effect when the saber/sword hits a person (instead of "saber/blood_sparks_mp.efx") + saber->hitOtherEffect2 = 0; //none - if set, plays this effect when the saber/sword hits something else damagable (instead of "saber/saber_cut.efx") + saber->bladeEffect2 = 0; //none - if set, plays this effect at the blade tag + + //done in game (server-side code) + saber->knockbackScale2 = 0; //0 - if non-zero, uses damage done to calculate an appropriate amount of knockback + saber->damageScale2 = 1.0f; //1 - scale up or down the damage done by the saber + saber->splashRadius2 = 0.0f; //0 - radius of splashDamage + saber->splashDamage2 = 0; //0 - amount of splashDamage, 100% at a distance of 0, 0% at a distance = splashRadius + saber->splashKnockback2 = 0.0f; //0 - amount of splashKnockback, 100% at a distance of 0, 0% at a distance = splashRadius +//========================================================================================================================================= } #define DEFAULT_SABER "Kyle" @@ -194,7 +623,9 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber ) float f; int n; qboolean triedDefault = qfalse; - + int saberMove = LS_INVALID; + int anim = -1; + if ( !saber ) { return qfalse; @@ -360,7 +791,7 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber ) SkipRestOfLine( &p ); continue; } - if ( n < 1 || n >= MAX_BLADES ) + if ( n < 1 || n > MAX_BLADES ) { Com_Error(ERR_DROP, "WP_SaberParseParms: saber %s has illegal number of blades (%d) max: %d", useSaber, n, MAX_BLADES ); continue; @@ -506,11 +937,46 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber ) //locked saber style if ( !Q_stricmp( token, "saberStyle" ) ) { + int style, styleNum; if ( COM_ParseString( &p, &value ) ) { continue; } - saber->style = TranslateSaberStyle( value ); + //OLD WAY: only allowed ONE style + style = TranslateSaberStyle( value ); + //learn only this style + saber->stylesLearned = (1<stylesForbidden = 0; + for ( styleNum = SS_NONE+1; styleNum < SS_NUM_SABER_STYLES; styleNum++ ) + { + if ( styleNum != style ) + { + saber->stylesForbidden |= (1<stylesLearned |= (1<stylesForbidden |= (1<lockable = ((qboolean)(n!=0)); + if ( n == 0 ) + { + saber->saberFlags |= SFL_NOT_LOCKABLE; + } continue; } @@ -546,7 +1015,10 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber ) SkipRestOfLine( &p ); continue; } - saber->throwable = ((qboolean)(n!=0)); + if ( n == 0 ) + { + saber->saberFlags |= SFL_NOT_THROWABLE; + } continue; } @@ -558,7 +1030,10 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber ) SkipRestOfLine( &p ); continue; } - saber->disarmable = ((qboolean)(n!=0)); + if ( n == 0 ) + { + saber->saberFlags |= SFL_NOT_DISARMABLE; + } continue; } @@ -570,7 +1045,10 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber ) SkipRestOfLine( &p ); continue; } - saber->activeBlocking = ((qboolean)(n!=0)); + if ( n == 0 ) + { + saber->saberFlags |= SFL_NOT_ACTIVE_BLOCKING; + } continue; } @@ -582,7 +1060,10 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber ) SkipRestOfLine( &p ); continue; } - saber->twoHanded = ((qboolean)(n!=0)); + if ( n ) + { + saber->saberFlags |= SFL_TWO_HANDED; + } continue; } @@ -639,6 +1120,18 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber ) continue; } + //breakParryBonus2 + if ( !Q_stricmp( token, "breakParryBonus2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->breakParryBonus2 = n; + continue; + } + //disarmBonus if ( !Q_stricmp( token, "disarmBonus" ) ) { @@ -651,6 +1144,18 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber ) continue; } + //disarmBonus2 + if ( !Q_stricmp( token, "disarmBonus2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->disarmBonus2 = n; + continue; + } + //single blade saber style if ( !Q_stricmp( token, "singleBladeStyle" ) ) { @@ -670,7 +1175,10 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber ) SkipRestOfLine( &p ); continue; } - saber->singleBladeThrowable = ((qboolean)(n!=0)); + if ( n ) + { + saber->saberFlags |= SFL_SINGLE_BLADE_THROWABLE; + } continue; } @@ -704,7 +1212,506 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber ) SkipRestOfLine( &p ); continue; } - saber->returnDamage = ((qboolean)(n!=0)); + if ( n ) + { + saber->saberFlags |= SFL_RETURN_DAMAGE; + } + continue; + } + + //spin sound (when thrown) + if ( !Q_stricmp( token, "spinSound" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->spinSound = BG_SoundIndex( (char *)value ); + continue; + } + + //swing sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "swingSound1" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->swingSound[0] = BG_SoundIndex( (char *)value ); + continue; + } + + //swing sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "swingSound2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->swingSound[1] = BG_SoundIndex( (char *)value ); + continue; + } + + //swing sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "swingSound3" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->swingSound[2] = BG_SoundIndex( (char *)value ); + continue; + } + + //you move faster/slower when using this saber + if ( !Q_stricmp( token, "moveSpeedScale" ) ) + { + if ( COM_ParseFloat( &p, &f ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->moveSpeedScale = f; + continue; + } + + //plays normal attack animations faster/slower + if ( !Q_stricmp( token, "animSpeedScale" ) ) + { + if ( COM_ParseFloat( &p, &f ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->animSpeedScale = f; + continue; + } + + //if non-zero, the saber will bounce back when it hits solid architecture (good for real-sword type mods) + if ( !Q_stricmp( token, "bounceOnWalls" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_BOUNCE_ON_WALLS; + } + continue; + } + + //if set, saber model is bolted to wrist, not in hand... useful for things like claws & shields, etc. + if ( !Q_stricmp( token, "boltToWrist" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_BOLT_TO_WRIST; + } + continue; + } + + //kata move + if ( !Q_stricmp( token, "kataMove" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saberMove = GetIDForString( SaberMoveTable, value ); + if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX ) + { + saber->kataMove = saberMove; //LS_INVALID - if set, player will execute this move when they press both attack buttons at the same time + } + continue; + } + //lungeAtkMove move + if ( !Q_stricmp( token, "lungeAtkMove" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saberMove = GetIDForString( SaberMoveTable, value ); + if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX ) + { + saber->lungeAtkMove = saberMove; + } + continue; + } + //jumpAtkUpMove move + if ( !Q_stricmp( token, "jumpAtkUpMove" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saberMove = GetIDForString( SaberMoveTable, value ); + if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX ) + { + saber->jumpAtkUpMove = saberMove; + } + continue; + } + //jumpAtkFwdMove move + if ( !Q_stricmp( token, "jumpAtkFwdMove" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saberMove = GetIDForString( SaberMoveTable, value ); + if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX ) + { + saber->jumpAtkFwdMove = saberMove; + } + continue; + } + //jumpAtkBackMove move + if ( !Q_stricmp( token, "jumpAtkBackMove" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saberMove = GetIDForString( SaberMoveTable, value ); + if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX ) + { + saber->jumpAtkBackMove = saberMove; + } + continue; + } + //jumpAtkRightMove move + if ( !Q_stricmp( token, "jumpAtkRightMove" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saberMove = GetIDForString( SaberMoveTable, value ); + if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX ) + { + saber->jumpAtkRightMove = saberMove; + } + continue; + } + //jumpAtkLeftMove move + if ( !Q_stricmp( token, "jumpAtkLeftMove" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saberMove = GetIDForString( SaberMoveTable, value ); + if ( saberMove >= LS_INVALID && saberMove < LS_MOVE_MAX ) + { + saber->jumpAtkLeftMove = saberMove; + } + continue; + } + //readyAnim + if ( !Q_stricmp( token, "readyAnim" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + anim = GetIDForString( animTable, value ); + if ( anim >= 0 && anim < MAX_ANIMATIONS ) + { + saber->readyAnim = anim; + } + continue; + } + //drawAnim + if ( !Q_stricmp( token, "drawAnim" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + anim = GetIDForString( animTable, value ); + if ( anim >= 0 && anim < MAX_ANIMATIONS ) + { + saber->drawAnim = anim; + } + continue; + } + //putawayAnim + if ( !Q_stricmp( token, "putawayAnim" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + anim = GetIDForString( animTable, value ); + if ( anim >= 0 && anim < MAX_ANIMATIONS ) + { + saber->putawayAnim = anim; + } + continue; + } + //tauntAnim + if ( !Q_stricmp( token, "tauntAnim" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + anim = GetIDForString( animTable, value ); + if ( anim >= 0 && anim < MAX_ANIMATIONS ) + { + saber->tauntAnim = anim; + } + continue; + } + //bowAnim + if ( !Q_stricmp( token, "bowAnim" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + anim = GetIDForString( animTable, value ); + if ( anim >= 0 && anim < MAX_ANIMATIONS ) + { + saber->bowAnim = anim; + } + continue; + } + //meditateAnim + if ( !Q_stricmp( token, "meditateAnim" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + anim = GetIDForString( animTable, value ); + if ( anim >= 0 && anim < MAX_ANIMATIONS ) + { + saber->meditateAnim = anim; + } + continue; + } + //flourishAnim + if ( !Q_stricmp( token, "flourishAnim" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + anim = GetIDForString( animTable, value ); + if ( anim >= 0 && anim < MAX_ANIMATIONS ) + { + saber->flourishAnim = anim; + } + continue; + } + //gloatAnim + if ( !Q_stricmp( token, "gloatAnim" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + anim = GetIDForString( animTable, value ); + if ( anim >= 0 && anim < MAX_ANIMATIONS ) + { + saber->gloatAnim = anim; + } + continue; + } + + //if set, cannot do roll-stab move at end of roll + if ( !Q_stricmp( token, "noRollStab" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_ROLL_STAB; + } + continue; + } + + //if set, cannot do pull+attack move (move not available in MP anyway) + if ( !Q_stricmp( token, "noPullAttack" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_PULL_ATTACK; + } + continue; + } + + //if set, cannot do back-stab moves + if ( !Q_stricmp( token, "noBackAttack" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_BACK_ATTACK; + } + continue; + } + + //if set, cannot do stabdown move (when enemy is on ground) + if ( !Q_stricmp( token, "noStabDown" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_STABDOWN; + } + continue; + } + + //if set, cannot side-run or forward-run on walls + if ( !Q_stricmp( token, "noWallRuns" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_WALL_RUNS; + } + continue; + } + + //if set, cannot do backflip off wall or side-flips off walls + if ( !Q_stricmp( token, "noWallFlips" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_WALL_FLIPS; + } + continue; + } + + //if set, cannot grab wall & jump off + if ( !Q_stricmp( token, "noWallGrab" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_WALL_GRAB; + } + continue; + } + + //if set, cannot roll + if ( !Q_stricmp( token, "noRolls" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_ROLLS; + } + continue; + } + + //if set, cannot do flips + if ( !Q_stricmp( token, "noFlips" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_FLIPS; + } + continue; + } + + //if set, cannot do cartwheels + if ( !Q_stricmp( token, "noCartwheels" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_CARTWHEELS; + } + continue; + } + + //if set, cannot do kicks (can't do kicks anyway if using a throwable saber/sword) + if ( !Q_stricmp( token, "noKicks" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_KICKS; + } + continue; + } + + //if set, cannot do the simultaneous attack left/right moves (only available in Dual Lightsaber Combat Style) + if ( !Q_stricmp( token, "noMirrorAttacks" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags |= SFL_NO_MIRROR_ATTACKS; + } + continue; + } + + //stays on in water + if ( !Q_stricmp( token, "onInWater" ) ) + {//ignore in MP + SkipRestOfLine( &p ); continue; } @@ -713,6 +1720,844 @@ qboolean WP_SaberParseParms( const char *SaberName, saberInfo_t *saber ) SkipRestOfLine( &p ); continue; } + +//===ABOVE THIS, ALL VALUES ARE GLOBAL TO THE SABER======================================================== + //bladeStyle2Start - where to start using the second set of blade data + if ( !Q_stricmp( token, "bladeStyle2Start" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->bladeStyle2Start = n; + continue; + } +//===BLADE-SPECIFIC FIELDS================================================================================= + + //===PRIMARY BLADE==================================== + //stops the saber from drawing marks on the world (good for real-sword type mods) + if ( !Q_stricmp( token, "noWallMarks" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_WALL_MARKS; + } + continue; + } + + //stops the saber from drawing a dynamic light (good for real-sword type mods) + if ( !Q_stricmp( token, "noDlight" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_DLIGHT; + } + continue; + } + + //stops the saber from drawing a blade (good for real-sword type mods) + if ( !Q_stricmp( token, "noBlade" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_BLADE; + } + continue; + } + + //default (0) is normal, 1 is a motion blur and 2 is no trail at all (good for real-sword type mods) + if ( !Q_stricmp( token, "trailStyle" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->trailStyle = n; + continue; + } + + //if set, the game will use this shader for marks on enemies instead of the default "gfx/damage/saberglowmark" + if ( !Q_stricmp( token, "g2MarksShader" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + SkipRestOfLine( &p ); + continue; + } +#ifdef QAGAME//cgame-only cares about this + SkipRestOfLine(&p); +#elif defined CGAME + saber->g2MarksShader = trap_R_RegisterShader( value ); +#else + SkipRestOfLine(&p); +#endif + continue; + } + + //if set, the game will use this shader for marks on enemies instead of the default "gfx/damage/saberglowmark" + if ( !Q_stricmp( token, "g2WeaponMarkShader" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + SkipRestOfLine( &p ); + continue; + } +#ifdef QAGAME//cgame-only cares about this + SkipRestOfLine(&p); +#elif defined CGAME + saber->g2WeaponMarkShader = trap_R_RegisterShader( value ); +#else + SkipRestOfLine(&p); +#endif + continue; + } + + //if non-zero, uses damage done to calculate an appropriate amount of knockback + if ( !Q_stricmp( token, "knockbackScale" ) ) + { + if ( COM_ParseFloat( &p, &f ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->knockbackScale = f; + continue; + } + + //scale up or down the damage done by the saber + if ( !Q_stricmp( token, "damageScale" ) ) + { + if ( COM_ParseFloat( &p, &f ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->damageScale = f; + continue; + } + + //if non-zero, the saber never does dismemberment (good for pointed/blunt melee weapons) + if ( !Q_stricmp( token, "noDismemberment" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_DISMEMBERMENT; + } + continue; + } + + //if non-zero, the saber will not do damage or any effects when it is idle (not in an attack anim). (good for real-sword type mods) + if ( !Q_stricmp( token, "noIdleEffect" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_IDLE_EFFECT; + } + continue; + } + + //if set, the blades will always be blocking (good for things like shields that should always block) + if ( !Q_stricmp( token, "alwaysBlock" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_ALWAYS_BLOCK; + } + continue; + } + + //if set, the blades cannot manually be toggled on and off + if ( !Q_stricmp( token, "noManualDeactivate" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_MANUAL_DEACTIVATE; + } + continue; + } + + //if set, the blade does damage in start, transition and return anims (like strong style does) + if ( !Q_stricmp( token, "transitionDamage" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_TRANSITION_DAMAGE; + } + continue; + } + + //splashRadius - radius of splashDamage + if ( !Q_stricmp( token, "splashRadius" ) ) + { + if ( COM_ParseFloat( &p, &f ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->splashRadius = f; + continue; + } + + //splashDamage - amount of splashDamage, 100% at a distance of 0, 0% at a distance = splashRadius + if ( !Q_stricmp( token, "splashDamage" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->splashDamage = n; + continue; + } + + //splashKnockback - amount of splashKnockback, 100% at a distance of 0, 0% at a distance = splashRadius + if ( !Q_stricmp( token, "splashKnockback" ) ) + { + if ( COM_ParseFloat( &p, &f ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->splashKnockback = f; + continue; + } + + //hit sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "hitSound1" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->hitSound[0] = BG_SoundIndex( (char *)value ); + continue; + } + + //hit sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "hitSound2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->hitSound[1] = BG_SoundIndex( (char *)value ); + continue; + } + + //hit sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "hitSound3" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->hitSound[2] = BG_SoundIndex( (char *)value ); + continue; + } + + //block sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "blockSound1" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->blockSound[0] = BG_SoundIndex( (char *)value ); + continue; + } + + //block sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "blockSound2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->blockSound[1] = BG_SoundIndex( (char *)value ); + continue; + } + + //block sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "blockSound3" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->blockSound[2] = BG_SoundIndex( (char *)value ); + continue; + } + + //bounce sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "bounceSound1" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->bounceSound[0] = BG_SoundIndex( (char *)value ); + continue; + } + + //bounce sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "bounceSound2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->bounceSound[1] = BG_SoundIndex( (char *)value ); + continue; + } + + //bounce sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "bounceSound3" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->bounceSound[2] = BG_SoundIndex( (char *)value ); + continue; + } + + //block effect - when saber/sword hits another saber/sword + if ( !Q_stricmp( token, "blockEffect" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } +#ifdef QAGAME//cgame-only cares about this + SkipRestOfLine(&p); +#elif defined CGAME + saber->blockEffect = trap_FX_RegisterEffect( (char *)value ); +#else + SkipRestOfLine(&p); +#endif + continue; + } + + //hit person effect - when saber/sword hits a person + if ( !Q_stricmp( token, "hitPersonEffect" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } +#ifdef QAGAME//cgame-only cares about this + SkipRestOfLine(&p); +#elif defined CGAME + saber->hitPersonEffect = trap_FX_RegisterEffect( (char *)value ); +#else + SkipRestOfLine(&p); +#endif + continue; + } + + //hit other effect - when saber/sword hits sopmething else damagable + if ( !Q_stricmp( token, "hitOtherEffect" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } +#ifdef QAGAME//cgame-only cares about this + SkipRestOfLine(&p); +#elif defined CGAME + saber->hitOtherEffect = trap_FX_RegisterEffect( (char *)value ); +#else + SkipRestOfLine(&p); +#endif + continue; + } + + //blade effect + if ( !Q_stricmp( token, "bladeEffect" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } +#ifdef QAGAME//cgame-only cares about this + SkipRestOfLine(&p); +#elif defined CGAME + saber->bladeEffect = trap_FX_RegisterEffect( (char *)value ); +#else + SkipRestOfLine(&p); +#endif + continue; + } + + //if non-zero, the saber will not do the big, white clash flare with other sabers + if ( !Q_stricmp( token, "noClashFlare" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_CLASH_FLARE; + } + continue; + } + + //===SECONDARY BLADE==================================== + //stops the saber from drawing marks on the world (good for real-sword type mods) + if ( !Q_stricmp( token, "noWallMarks2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_WALL_MARKS2; + } + continue; + } + + //stops the saber from drawing a dynamic light (good for real-sword type mods) + if ( !Q_stricmp( token, "noDlight2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_DLIGHT2; + } + continue; + } + + //stops the saber from drawing a blade (good for real-sword type mods) + if ( !Q_stricmp( token, "noBlade2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_BLADE2; + } + continue; + } + + //default (0) is normal, 1 is a motion blur and 2 is no trail at all (good for real-sword type mods) + if ( !Q_stricmp( token, "trailStyle2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->trailStyle2 = n; + continue; + } + + //if set, the game will use this shader for marks on enemies instead of the default "gfx/damage/saberglowmark" + if ( !Q_stricmp( token, "g2MarksShader2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + SkipRestOfLine( &p ); + continue; + } +#ifdef QAGAME//cgame-only cares about this + SkipRestOfLine(&p); +#elif defined CGAME + saber->g2MarksShader2 = trap_R_RegisterShader( value ); +#else + SkipRestOfLine(&p); +#endif + continue; + } + + //if set, the game will use this shader for marks on enemies instead of the default "gfx/damage/saberglowmark" + if ( !Q_stricmp( token, "g2WeaponMarkShader2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + SkipRestOfLine( &p ); + continue; + } +#ifdef QAGAME//cgame-only cares about this + SkipRestOfLine(&p); +#elif defined CGAME + saber->g2WeaponMarkShader2 = trap_R_RegisterShader( value ); +#else + SkipRestOfLine(&p); +#endif + continue; + } + + //if non-zero, uses damage done to calculate an appropriate amount of knockback + if ( !Q_stricmp( token, "knockbackScale2" ) ) + { + if ( COM_ParseFloat( &p, &f ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->knockbackScale2 = f; + continue; + } + + //scale up or down the damage done by the saber + if ( !Q_stricmp( token, "damageScale2" ) ) + { + if ( COM_ParseFloat( &p, &f ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->damageScale2 = f; + continue; + } + + //if non-zero, the saber never does dismemberment (good for pointed/blunt melee weapons) + if ( !Q_stricmp( token, "noDismemberment2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_DISMEMBERMENT2; + } + continue; + } + + //if non-zero, the saber will not do damage or any effects when it is idle (not in an attack anim). (good for real-sword type mods) + if ( !Q_stricmp( token, "noIdleEffect2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_IDLE_EFFECT2; + } + continue; + } + + //if set, the blades will always be blocking (good for things like shields that should always block) + if ( !Q_stricmp( token, "alwaysBlock2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_ALWAYS_BLOCK2; + } + continue; + } + + //if set, the blades cannot manually be toggled on and off + if ( !Q_stricmp( token, "noManualDeactivate2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_MANUAL_DEACTIVATE2; + } + continue; + } + + //if set, the blade does damage in start, transition and return anims (like strong style does) + if ( !Q_stricmp( token, "transitionDamage2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_TRANSITION_DAMAGE2; + } + continue; + } + + //splashRadius - radius of splashDamage + if ( !Q_stricmp( token, "splashRadius2" ) ) + { + if ( COM_ParseFloat( &p, &f ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->splashRadius2 = f; + continue; + } + + //splashDamage - amount of splashDamage, 100% at a distance of 0, 0% at a distance = splashRadius + if ( !Q_stricmp( token, "splashDamage2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->splashDamage2 = n; + continue; + } + + //splashKnockback - amount of splashKnockback, 100% at a distance of 0, 0% at a distance = splashRadius + if ( !Q_stricmp( token, "splashKnockback2" ) ) + { + if ( COM_ParseFloat( &p, &f ) ) + { + SkipRestOfLine( &p ); + continue; + } + saber->splashKnockback2 = f; + continue; + } + + //hit sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "hit2Sound1" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->hit2Sound[0] = BG_SoundIndex( (char *)value ); + continue; + } + + //hit sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "hit2Sound2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->hit2Sound[1] = BG_SoundIndex( (char *)value ); + continue; + } + + //hit sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "hit2Sound3" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->hit2Sound[2] = BG_SoundIndex( (char *)value ); + continue; + } + + //block sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "block2Sound1" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->block2Sound[0] = BG_SoundIndex( (char *)value ); + continue; + } + + //block sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "block2Sound2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->block2Sound[1] = BG_SoundIndex( (char *)value ); + continue; + } + + //block sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "block2Sound3" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->block2Sound[2] = BG_SoundIndex( (char *)value ); + continue; + } + + //bounce sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "bounce2Sound1" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->bounce2Sound[0] = BG_SoundIndex( (char *)value ); + continue; + } + + //bounce sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "bounce2Sound2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->bounce2Sound[1] = BG_SoundIndex( (char *)value ); + continue; + } + + //bounce sound - NOTE: must provide all 3!!! + if ( !Q_stricmp( token, "bounce2Sound3" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } + saber->bounce2Sound[2] = BG_SoundIndex( (char *)value ); + continue; + } + + //block effect - when saber/sword hits another saber/sword + if ( !Q_stricmp( token, "blockEffect2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } +#ifdef QAGAME//cgame-only cares about this + SkipRestOfLine(&p); +#elif defined CGAME + saber->blockEffect2 = trap_FX_RegisterEffect( (char *)value ); +#else + SkipRestOfLine(&p); +#endif + continue; + } + + //hit person effect - when saber/sword hits a person + if ( !Q_stricmp( token, "hitPersonEffect2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } +#ifdef QAGAME//cgame-only cares about this + SkipRestOfLine(&p); +#elif defined CGAME + saber->hitPersonEffect2 = trap_FX_RegisterEffect( (char *)value ); +#else + SkipRestOfLine(&p); +#endif + continue; + } + + //hit other effect - when saber/sword hits sopmething else damagable + if ( !Q_stricmp( token, "hitOtherEffect2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } +#ifdef QAGAME//cgame-only cares about this + SkipRestOfLine(&p); +#elif defined CGAME + saber->hitOtherEffect2 = trap_FX_RegisterEffect( (char *)value ); +#else + SkipRestOfLine(&p); +#endif + continue; + } + + //blade effect + if ( !Q_stricmp( token, "bladeEffect2" ) ) + { + if ( COM_ParseString( &p, &value ) ) + { + continue; + } +#ifdef QAGAME//cgame-only cares about this + SkipRestOfLine(&p); +#elif defined CGAME + saber->bladeEffect2 = trap_FX_RegisterEffect( (char *)value ); +#else + SkipRestOfLine(&p); +#endif + continue; + } + + //if non-zero, the saber will not do the big, white clash flare with other sabers + if ( !Q_stricmp( token, "noClashFlare2" ) ) + { + if ( COM_ParseInt( &p, &n ) ) + { + SkipRestOfLine( &p ); + continue; + } + if ( n ) + { + saber->saberFlags2 |= SFL2_NO_CLASH_FLARE2; + } + continue; + } +//===END BLADE-SPECIFIC FIELDS============================================================================= + //FIXME: saber sounds (on, off, loop) #ifdef _DEBUG @@ -866,12 +2711,12 @@ void WP_SetSaber( int entNum, saberInfo_t *sabers, int saberNum, const char *sab { WP_SaberParseParms( saberName, &sabers[saberNum] );//get saber info } - if (sabers[1].twoHanded) + if ((sabers[1].saberFlags&SFL_TWO_HANDED)) {//not allowed to use a 2-handed saber as second saber WP_RemoveSaber( sabers, 1 ); return; } - else if (sabers[0].twoHanded && + else if ((sabers[0].saberFlags&SFL_TWO_HANDED) && sabers[1].model[0]) { //you can't use a two-handed saber with a second saber, so remove saber 2 WP_RemoveSaber( sabers, 1 ); @@ -928,6 +2773,8 @@ void WP_SaberLoadParms( void ) trap_FS_Read(bgSaberParseTBuffer, len, f); bgSaberParseTBuffer[len] = 0; + len = COM_Compress( bgSaberParseTBuffer ); + Q_strcat( marker, MAX_SABER_DATA_SIZE-totallen, bgSaberParseTBuffer ); trap_FS_FCloseFile(f); diff --git a/codemp/game/bg_saga.c b/codemp/game/bg_saga.c index fa843a2..5a4aca5 100644 --- a/codemp/game/bg_saga.c +++ b/codemp/game/bg_saga.c @@ -73,6 +73,7 @@ stringID_table_t StanceTable[] = stringID_table_t WPTable[] = { "NULL",WP_NONE, + ENUM2STRING(WP_NONE), // Player weapons ENUM2STRING(WP_STUN_BATON), ENUM2STRING(WP_MELEE), @@ -933,7 +934,7 @@ void BG_SiegeParseClassFile(const char *filename, siegeClassDesc_t *descBuffer) } else { //It's alright, just default to 100 then. - bgSiegeClasses[bgNumSiegeClasses].starthealth = 100; + bgSiegeClasses[bgNumSiegeClasses].starthealth = bgSiegeClasses[bgNumSiegeClasses].maxhealth; } diff --git a/codemp/game/bg_slidemove.c b/codemp/game/bg_slidemove.c index ba49bdb..3970821 100644 --- a/codemp/game/bg_slidemove.c +++ b/codemp/game/bg_slidemove.c @@ -40,6 +40,7 @@ extern void trap_FX_PlayEffectID( int id, vec3_t org, vec3_t fwd, int vol, int r #ifdef QAGAME extern qboolean FighterIsLanded( Vehicle_t *pVeh, playerState_t *parentPS ); +extern void G_DamageFromKiller( gentity_t *pEnt, gentity_t *pVehEnt, gentity_t *attacker, vec3_t org, int damage, int dflags, int mod ); #endif extern void PM_SetPMViewAngle(playerState_t *ps, vec3_t angle, usercmd_t *ucmd); @@ -54,12 +55,12 @@ void PM_VehicleImpact(bgEntity_t *pEnt, trace_t *trace) #ifdef QAGAME gentity_t *hitEnt = trace!=NULL?&g_entities[trace->entityNum]:NULL; - if (!hitEnt || - (pSelfVeh && pSelfVeh->m_pPilot && - hitEnt && hitEnt->s.eType == ET_MISSILE && hitEnt->inuse && - hitEnt->r.ownerNum == pSelfVeh->m_pPilot->s.number) + if (!hitEnt || //nothing to hit + (pSelfVeh && pSelfVeh->m_pPilot &&//I'm a piloted vehicle + hitEnt && hitEnt->s.eType == ET_MISSILE && hitEnt->inuse &&//that hit a missile + hitEnt->r.ownerNum == pSelfVeh->m_pPilot->s.number)//and the missile is owned by my pilot ) - { + {//don't hit it return; } @@ -69,20 +70,7 @@ void PM_VehicleImpact(bgEntity_t *pEnt, trace_t *trace) if ( hitEnt->s.NPC_class == CLASS_VEHICLE ) {//hit another vehicle, explode! //Give credit to whoever got me into this death spiral state - gentity_t *parent = (gentity_t *)pSelfVeh->m_pParentEntity; - gentity_t *killer = NULL; - if (parent->client->ps.otherKiller < ENTITYNUM_WORLD && - parent->client->ps.otherKillerTime > level.time) - { - gentity_t *potentialKiller = &g_entities[parent->client->ps.otherKiller]; - - if (potentialKiller->inuse && potentialKiller->client) - { //he's valid I guess - killer = potentialKiller; - } - } - //FIXME: damage hitEnt, some, too? Our explosion should hurt them some, but... - G_Damage( (gentity_t *)pEnt, killer, killer, NULL, pm->ps->origin, 999999, DAMAGE_NO_ARMOR, MOD_FALLING );//FIXME: MOD_IMPACT + G_DamageFromKiller( (gentity_t *)pEnt, (gentity_t *)pSelfVeh->m_pParentEntity, (gentity_t *)hitEnt, pm->ps->origin, 999999, DAMAGE_NO_ARMOR, MOD_COLLISION ); return; } else if ( !VectorCompare( trace->plane.normal, vec3_origin ) @@ -96,19 +84,7 @@ void PM_VehicleImpact(bgEntity_t *pEnt, trace_t *trace) if ( impactDot <= -0.7f )//hit rather head-on and hard {// Just DIE now //Give credit to whoever got me into this death spiral state - gentity_t *parent = (gentity_t *)pSelfVeh->m_pParentEntity; - gentity_t *killer = NULL; - if (parent->client->ps.otherKiller < ENTITYNUM_WORLD && - parent->client->ps.otherKillerTime > level.time) - { - gentity_t *potentialKiller = &g_entities[parent->client->ps.otherKiller]; - - if (potentialKiller->inuse && potentialKiller->client) - { //he's valid I guess - killer = potentialKiller; - } - } - G_Damage( (gentity_t *)pEnt, killer, killer, NULL, pm->ps->origin, 999999, DAMAGE_NO_ARMOR, MOD_FALLING );//FIXME: MOD_IMPACT + G_DamageFromKiller( (gentity_t *)pEnt, (gentity_t *)pSelfVeh->m_pParentEntity, (gentity_t *)hitEnt, pm->ps->origin, 999999, DAMAGE_NO_ARMOR, MOD_FALLING ); return; } } @@ -169,7 +145,9 @@ void PM_VehicleImpact(bgEntity_t *pEnt, trace_t *trace) //FIXME: impact sound and effect should be gotten from g_vehicleInfo...? //FIXME: should pass in trace.endpos and trace.plane.normal vec3_t vehUp; -#ifndef QAGAME +#ifdef QAGAME + qboolean noDamage = qfalse; +#else bgEntity_t *hitEnt; #endif @@ -437,8 +415,10 @@ void PM_VehicleImpact(bgEntity_t *pEnt, trace_t *trace) pEnt->m_pVehicle->m_iHitDebounce = pm->cmd.serverTime + 200; magnitude /= pSelfVeh->m_pVehicleInfo->toughness * 50.0f; - if (hitEnt && (hitEnt->s.eType != ET_TERRAIN || !(hitEnt->spawnflags & 1) || pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)) + if (hitEnt + && (hitEnt->s.eType != ET_TERRAIN || !(hitEnt->spawnflags & 1) || pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER)) { //don't damage the vehicle from terrain that doesn't want to damage vehicles + gentity_t *killer = NULL; if (pSelfVeh->m_pVehicleInfo->type == VH_FIGHTER) { //increase the damage... float mult = (pSelfVeh->m_vOrientation[PITCH]*0.1f); @@ -466,7 +446,26 @@ void PM_VehicleImpact(bgEntity_t *pEnt, trace_t *trace) pSelfVeh->m_iLastImpactDmg = magnitude; //FIXME: what about proper death credit to the guy who shot you down? //FIXME: actually damage part of the ship that impacted? - G_Damage( (gentity_t *)pEnt, NULL, NULL, NULL, pm->ps->origin, magnitude*5, DAMAGE_NO_ARMOR, MOD_FALLING );//FIXME: MOD_IMPACT + if ( hitEnt->s.eType == ET_MISSILE )//missile + { + //FIX: NEVER do or take impact damage from a missile... + noDamage = qtrue; + if ( (hitEnt->s.eFlags&EF_JETPACK_ACTIVE)//vehicle missile + && ((gentity_t *)hitEnt)->r.ownerNum < MAX_CLIENTS )//valid client owner + {//I ran into a missile and died because of the impact, give credit to the missile's owner (PROBLEM: might this ever accidently give improper credit to client 0?) + /* + if ( ((gentity_t *)hitEnt)->r.ownerNum == pEnt->s.number ) + {//hit our own missile? Don't damage ourselves or it... (so we don't kill ourselves!) if it hits *us*, then fine, but not here + noDamage = qtrue; + } + */ + killer = &g_entities[((gentity_t *)hitEnt)->r.ownerNum]; + } + } + if ( !noDamage ) + { + G_Damage( (gentity_t *)pEnt, ((gentity_t*)hitEnt), killer!=NULL?killer:((gentity_t *)hitEnt), NULL, pm->ps->origin, magnitude*5, DAMAGE_NO_ARMOR, (hitEnt->s.NPC_class==CLASS_VEHICLE?MOD_COLLISION:MOD_FALLING) );//FIXME: MOD_IMPACT + } if (pSelfVeh->m_pVehicleInfo->surfDestruction) { @@ -510,6 +509,9 @@ void PM_VehicleImpact(bgEntity_t *pEnt, trace_t *trace) hitEnt->client->ps.otherKiller = pEnt->s.number; hitEnt->client->ps.otherKillerTime = pm->cmd.serverTime + 5000; hitEnt->client->ps.otherKillerDebounceTime = pm->cmd.serverTime + 100; + hitEnt->client->otherKillerMOD = MOD_COLLISION; + hitEnt->client->otherKillerVehWeapon = 0; + hitEnt->client->otherKillerWeaponType = WP_NONE; //add my velocity into his to force him along in the correct direction from impact VectorAdd(hitEnt->client->ps.velocity, pm->ps->velocity, hitEnt->client->ps.velocity); @@ -532,7 +534,10 @@ void PM_VehicleImpact(bgEntity_t *pEnt, trace_t *trace) { finalD = 1; } - G_Damage( hitEnt, attackEnt, attackEnt, NULL, pm->ps->origin, finalD, 0, MOD_MELEE );//FIXME: MOD_IMPACT + if ( !noDamage ) + { + G_Damage( hitEnt, attackEnt, attackEnt, NULL, pm->ps->origin, finalD, 0, (hitEnt->s.NPC_class==CLASS_VEHICLE?MOD_COLLISION:MOD_FALLING/*MOD_MELEE*/) );//FIXME: MOD_IMPACT + } } #else //this is gonna result in "double effects" for the client doing the prediction. //it doesn't look bad though. could just use predicted events, but I'm too lazy. diff --git a/codemp/game/bg_vehicleLoad.c b/codemp/game/bg_vehicleLoad.c index 865da19..6a83286 100644 --- a/codemp/game/bg_vehicleLoad.c +++ b/codemp/game/bg_vehicleLoad.c @@ -69,8 +69,8 @@ extern stringID_table_t animTable [MAX_ANIMATIONS+1]; // These buffers are filled in with the same contents and then just read from in // a few places. We only need one copy on Xbox. -#define MAX_VEH_WEAPON_DATA_SIZE 0x4000 -#define MAX_VEHICLE_DATA_SIZE 0x10000 +#define MAX_VEH_WEAPON_DATA_SIZE 0x20000 +#define MAX_VEHICLE_DATA_SIZE 0x80000 #if !defined(_XBOX) || defined(QAGAME) char VehWeaponParms[MAX_VEH_WEAPON_DATA_SIZE]; @@ -151,6 +151,7 @@ vehField_t vehWeaponFields[NUM_VWEAP_PARMS] = {"loopSound", VWFOFS(iLoopSound), VF_SOUND_CLIENT}, //index of loopSound {"speed", VWFOFS(fSpeed), VF_FLOAT}, //speed of projectile/range of traceline {"homing", VWFOFS(fHoming), VF_FLOAT}, //0.0 = not homing, 0.5 = half vel to targ, half cur vel, 1.0 = all vel to targ + {"homingFOV", VWFOFS(fHomingFOV), VF_FLOAT},//missile will lose lock on if DotProduct of missile direction and direction to target ever drops below this (-1 to 1, -1 = never lose target, 0 = lose if ship gets behind missile, 1 = pretty much will lose it's target right away) {"lockOnTime", VWFOFS(iLockOnTime), VF_INT}, //0 = no lock time needed, else # of ms needed to lock on {"damage", VWFOFS(iDamage), VF_INT}, //damage done when traceline or projectile directly hits target {"splashDamage", VWFOFS(iSplashDamage), VF_INT},//damage done to ents in splashRadius of end of traceline or projectile origin on impact @@ -1338,6 +1339,7 @@ int VEH_LoadVehicle( const char *vehicleName ) G_SoundIndex( "sound/vehicles/common/release.wav" ); #elif CGAME trap_R_RegisterShader( "gfx/menus/radar/bracket" ); + trap_R_RegisterShader( "gfx/menus/radar/lead" ); trap_R_RegisterShaderNoMip( "gfx/menus/radar/asteroid" ); trap_S_RegisterSound( "sound/vehicles/common/impactalarm.wav" ); trap_S_RegisterSound( "sound/vehicles/common/linkweaps.wav" ); diff --git a/codemp/game/bg_vehicles.h b/codemp/game/bg_vehicles.h index a2559f6..0030084 100644 --- a/codemp/game/bg_vehicles.h +++ b/codemp/game/bg_vehicles.h @@ -50,6 +50,7 @@ typedef struct int iLoopSound; //index of loopSound float fSpeed; //speed of projectile/range of traceline float fHoming; //0.0 = not homing, 0.5 = half vel to targ, half cur vel, 1.0 = all vel to targ + float fHomingFOV; //missile will lose lock on if DotProduct of missile direction and direction to target ever drops below this (-1 to 1, -1 = never lose target, 0 = lose if ship gets behind missile, 1 = pretty much will lose it's target right away) int iLockOnTime; //0 = no lock time needed, else # of ms needed to lock on int iDamage; //damage done when traceline or projectile directly hits target int iSplashDamage;//damage done to ents in splashRadius of end of traceline or projectile origin on impact @@ -62,7 +63,7 @@ typedef struct qboolean bExplodeOnExpire; //when iLifeTime is up, explodes rather than simply removing itself } vehWeaponInfo_t; //NOTE: this MUST stay up to date with the number of variables in the vehFields table!!! -#define NUM_VWEAP_PARMS 24 +#define NUM_VWEAP_PARMS 25 #define VWFOFS(x) ((int)&(((vehWeaponInfo_t *)0)->x)) diff --git a/codemp/game/g_ICARUScb.c b/codemp/game/g_ICARUScb.c index bbbf72c..d015c07 100644 --- a/codemp/game/g_ICARUScb.c +++ b/codemp/game/g_ICARUScb.c @@ -13,9 +13,10 @@ #include "../namespace_begin.h" qboolean BG_SabersOff( playerState_t *ps ); +extern stringID_table_t WPTable[]; +extern stringID_table_t BSTable[]; #include "../namespace_end.h" -extern stringID_table_t BSTable[]; //This is a hack I guess. It's because we can't include the file this enum is in //unless we're using cpp. But we need it for the interpreter stuff. @@ -2138,6 +2139,185 @@ static void Q3_SetOriginOffset( int entID, int axis, float offset ) Q3_Lerp2Origin( -1, entID, origin, duration ); } +/* +============= +Q3_SetEnemy + +Sets the enemy of an entity +============= +*/ +static void Q3_SetEnemy( int entID, const char *name ) +{ + gentity_t *ent = &g_entities[entID]; + + if ( !ent ) + { + G_DebugPrint( WL_WARNING, "Q3_SetEnemy: invalid entID %d\n", entID); + return; + } + + if( !Q_stricmp("NONE", name) || !Q_stricmp("NULL", name)) + { + if(ent->NPC) + { + G_ClearEnemy(ent); + } + else + { + ent->enemy = NULL; + } + } + else + { + gentity_t *enemy = G_Find( NULL, FOFS(targetname), (char *) name); + + if(enemy == NULL) + { + G_DebugPrint( WL_ERROR, "Q3_SetEnemy: no such enemy: '%s'\n", name ); + return; + } + /*else if(enemy->health <= 0) + { + //G_DebugPrint( WL_ERROR, "Q3_SetEnemy: ERROR - desired enemy has health %d\n", enemy->health ); + return; + }*/ + else + { + if(ent->NPC) + { + G_SetEnemy( ent, enemy ); + ent->cantHitEnemyCounter = 0; + } + else + { + G_SetEnemy(ent, enemy); + } + } + } +} + + +/* +============= +Q3_SetLeader + +Sets the leader of an NPC +============= +*/ +static void Q3_SetLeader( int entID, const char *name ) +{ + gentity_t *ent = &g_entities[entID]; + + if ( !ent ) + { + G_DebugPrint( WL_WARNING, "Q3_SetLeader: invalid entID %d\n", entID); + return; + } + + if ( !ent->client ) + { + G_DebugPrint( WL_ERROR, "Q3_SetLeader: ent %d is NOT a player or NPC!\n", entID); + return; + } + + if( !Q_stricmp("NONE", name) || !Q_stricmp("NULL", name)) + { + ent->client->leader = NULL; + } + else + { + gentity_t *leader = G_Find( NULL, FOFS(targetname), (char *) name); + + if(leader == NULL) + { + //G_DebugPrint( WL_ERROR,"Q3_SetEnemy: unable to locate enemy: '%s'\n", name ); + return; + } + else if(leader->health <= 0) + { + //G_DebugPrint( WL_ERROR,"Q3_SetEnemy: ERROR - desired enemy has health %d\n", enemy->health ); + return; + } + else + { + ent->client->leader = leader; + } + } +} + +/* +============= +Q3_SetNavGoal + +Sets the navigational goal of an entity +============= +*/ +static qboolean Q3_SetNavGoal( int entID, const char *name ) +{ + gentity_t *ent = &g_entities[ entID ]; + vec3_t goalPos; + + if ( !ent->health ) + { + G_DebugPrint( WL_ERROR, "Q3_SetNavGoal: tried to set a navgoal (\"%s\") on a corpse! \"%s\"\n", name, ent->script_targetname ); + return qfalse; + } + if ( !ent->NPC ) + { + G_DebugPrint( WL_ERROR, "Q3_SetNavGoal: tried to set a navgoal (\"%s\") on a non-NPC: \"%s\"\n", name, ent->script_targetname ); + return qfalse; + } + if ( !ent->NPC->tempGoal ) + { + G_DebugPrint( WL_ERROR, "Q3_SetNavGoal: tried to set a navgoal (\"%s\") on a dead NPC: \"%s\"\n", name, ent->script_targetname ); + return qfalse; + } + if ( !ent->NPC->tempGoal->inuse ) + { + G_DebugPrint( WL_ERROR, "Q3_SetNavGoal: NPC's (\"%s\") navgoal is freed: \"%s\"\n", name, ent->script_targetname ); + return qfalse; + } + if( Q_stricmp( "null", name) == 0 + || Q_stricmp( "NULL", name) == 0 ) + { + ent->NPC->goalEntity = NULL; + trap_ICARUS_TaskIDComplete( ent, TID_MOVE_NAV ); + return qfalse; + } + else + { + //Get the position of the goal + if ( TAG_GetOrigin2( NULL, name, goalPos ) == qfalse ) + { + gentity_t *targ = G_Find(NULL, FOFS(targetname), (char*)name); + if ( !targ ) + { + G_DebugPrint( WL_ERROR, "Q3_SetNavGoal: can't find NAVGOAL \"%s\"\n", name ); + return qfalse; + } + else + { + ent->NPC->goalEntity = targ; + ent->NPC->goalRadius = sqrt(ent->r.maxs[0]+ent->r.maxs[0]) + sqrt(targ->r.maxs[0]+targ->r.maxs[0]); + ent->NPC->aiFlags &= ~NPCAI_TOUCHED_GOAL; + } + } + else + { + int goalRadius = TAG_GetRadius( NULL, name ); + NPC_SetMoveGoal( ent, goalPos, goalRadius, qtrue, -1, NULL ); + //We know we want to clear the lastWaypoint here + ent->NPC->goalEntity->lastWaypoint = WAYPOINT_NONE; + ent->NPC->aiFlags &= ~NPCAI_TOUCHED_GOAL; + #ifdef _DEBUG + //this is *only* for debugging navigation + ent->NPC->tempGoal->target = G_NewString( name ); + #endif// _DEBUG + return qtrue; + } + } + return qfalse; +} /* ============ SetLowerAnim @@ -2920,9 +3100,14 @@ Q3_SetWeapon Argument : const char *wp_name ============ */ +extern void ChangeWeapon( gentity_t *ent, int newWeapon ); static void Q3_SetWeapon (int entID, const char *wp_name) { - G_DebugPrint( WL_WARNING, "Q3_SetWeapon currently unsupported in MP, ask if you need it.\n"); + gentity_t *ent = &g_entities[entID]; + int wp = GetIDForString( WPTable, wp_name ); + + ent->client->ps.stats[STAT_WEAPONS] = (1<NPC ) + { + G_DebugPrint( WL_ERROR, "Q3_SetWalkSpeed: '%s' is not an NPC!\n", self->targetname ); + return; + } + + if(int_data == 0) + { + self->NPC->stats.walkSpeed = self->client->ps.speed = 1; + } + + self->NPC->stats.walkSpeed = self->client->ps.speed = int_data; } @@ -2969,8 +3172,26 @@ Q3_SetRunSpeed */ static void Q3_SetRunSpeed (int entID, int int_data) { - G_DebugPrint( WL_WARNING, "Q3_SetRunSpeed: NOT SUPPORTED IN MP\n"); - return; + gentity_t *self = &g_entities[entID]; + + if ( !self ) + { + G_DebugPrint( WL_WARNING, "Q3_SetRunSpeed: invalid entID %d\n", entID); + return; + } + + if ( !self->NPC ) + { + G_DebugPrint( WL_ERROR, "Q3_SetRunSpeed: '%s' is not an NPC!\n", self->targetname ); + return; + } + + if(int_data == 0) + { + self->NPC->stats.runSpeed = self->client->ps.speed = 1; + } + + self->NPC->stats.runSpeed = self->client->ps.speed = int_data; } @@ -3152,11 +3373,25 @@ static void Q3_SetScale(int entID, float float_data) if (self->client) { - self->client->ps.iModelScale = float_data*100.0f; + if ( float_data < 0 ) + { + self->client->ps.iModelScale = float_data; + } + else + { + self->client->ps.iModelScale = float_data*100.0f; + } } else { - self->s.iModelScale = float_data*100.0f; + if ( float_data < 0 ) + { + self->s.iModelScale = float_data; + } + else + { + self->s.iModelScale = float_data*100.0f; + } } } @@ -3706,7 +3941,28 @@ Q3_SetWalking */ static void Q3_SetWalking( int entID, qboolean add) { - G_DebugPrint( WL_WARNING, "Q3_SetWalking: NOT SUPPORTED IN MP\n"); + gentity_t *ent = &g_entities[entID]; + + if ( !ent ) + { + G_DebugPrint( WL_WARNING, "Q3_SetWalking: invalid entID %d\n", entID); + return; + } + + if ( !ent->NPC ) + { + G_DebugPrint( WL_ERROR, "Q3_SetWalking: '%s' is not an NPC!\n", ent->targetname ); + return; + } + + if(add) + { + ent->NPC->scriptFlags |= SCF_WALKING; + } + else + { + ent->NPC->scriptFlags &= ~SCF_WALKING; + } return; } @@ -3980,8 +4236,28 @@ Q3_SetNoAvoid */ static void Q3_SetNoAvoid( int entID, qboolean noAvoid) { - G_DebugPrint( WL_WARNING, "Q3_SetNoAvoid: NOT SUPPORTED IN MP\n"); - return; + gentity_t *ent = &g_entities[entID]; + + if ( !ent ) + { + G_DebugPrint( WL_WARNING, "Q3_SetNoAvoid: invalid entID %d\n", entID); + return; + } + + if ( !ent->NPC ) + { + G_DebugPrint( WL_ERROR, "Q3_SetNoAvoid: '%s' is not an NPC!\n", ent->targetname ); + return; + } + + if(noAvoid) + { + ent->NPC->aiFlags |= NPCAI_NO_COLL_AVOID; + } + else + { + ent->NPC->aiFlags &= ~NPCAI_NO_COLL_AVOID; + } } /* @@ -4803,15 +5079,19 @@ qboolean Q3_Set( int taskID, int entID, const char *type_name, const char *data break; case SET_ENEMY: - G_DebugPrint( WL_WARNING, "Q3_SetEnemy: NOT SUPPORTED IN MP\n"); + Q3_SetEnemy( entID, (char *) data ); break; case SET_LEADER: - G_DebugPrint( WL_WARNING, "Q3_SetLeader: NOT SUPPORTED IN MP\n"); + Q3_SetLeader( entID, (char *) data ); break; case SET_NAVGOAL: - G_DebugPrint( WL_WARNING, "Q3_SetNavGoal: NOT SUPPORTED IN MP\n"); + if ( Q3_SetNavGoal( entID, (char *) data ) ) + { + trap_ICARUS_TaskIDSet( ent, TID_MOVE_NAV, taskID ); + return qfalse; //Don't call it back + } break; case SET_ANIM_UPPER: diff --git a/codemp/game/g_active.c b/codemp/game/g_active.c index 22e2c58..965614d 100644 --- a/codemp/game/g_active.c +++ b/codemp/game/g_active.c @@ -11,6 +11,7 @@ extern void Jedi_Decloak( gentity_t *self ); qboolean PM_SaberInTransition( int move ); qboolean PM_SaberInStart( int move ); qboolean PM_SaberInReturn( int move ); +qboolean WP_SaberStyleValidForSaber( saberInfo_t *saber1, saberInfo_t *saber2, int saberHolstered, int saberAnimLevel ); #include "../namespace_end.h" qboolean saberCheckKnockdown_DuelLoss(gentity_t *saberent, gentity_t *saberOwner, gentity_t *other); @@ -1688,6 +1689,16 @@ void G_SetTauntAnim( gentity_t *ent, int taunt ) { anim = BOTH_ENGAGETAUNT; } + else if ( ent->client->saber[0].tauntAnim != -1 ) + { + anim = ent->client->saber[0].tauntAnim; + } + else if ( ent->client->saber[1].model + && ent->client->saber[1].model[0] + && ent->client->saber[1].tauntAnim != -1 ) + { + anim = ent->client->saber[1].tauntAnim; + } else { switch ( ent->client->ps.fd.saberAnimLevel ) @@ -1738,7 +1749,20 @@ void G_SetTauntAnim( gentity_t *ent, int taunt ) } break; case TAUNT_BOW: - anim = BOTH_BOW; + if ( ent->client->saber[0].bowAnim != -1 ) + { + anim = ent->client->saber[0].bowAnim; + } + else if ( ent->client->saber[1].model + && ent->client->saber[1].model[0] + && ent->client->saber[1].bowAnim != -1 ) + { + anim = ent->client->saber[1].bowAnim; + } + else + { + anim = BOTH_BOW; + } if ( ent->client->ps.saberHolstered == 1 && ent->client->saber[1].model && ent->client->saber[1].model[0] ) @@ -1752,7 +1776,20 @@ void G_SetTauntAnim( gentity_t *ent, int taunt ) ent->client->ps.saberHolstered = 2; break; case TAUNT_MEDITATE: - anim = BOTH_MEDITATE; + if ( ent->client->saber[0].meditateAnim != -1 ) + { + anim = ent->client->saber[0].meditateAnim; + } + else if ( ent->client->saber[1].model + && ent->client->saber[1].model[0] + && ent->client->saber[1].meditateAnim != -1 ) + { + anim = ent->client->saber[1].meditateAnim; + } + else + { + anim = BOTH_MEDITATE; + } if ( ent->client->ps.saberHolstered == 1 && ent->client->saber[1].model && ent->client->saber[1].model[0] ) @@ -1779,69 +1816,95 @@ void G_SetTauntAnim( gentity_t *ent, int taunt ) G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOn ); } ent->client->ps.saberHolstered = 0; - switch ( ent->client->ps.fd.saberAnimLevel ) + if ( ent->client->saber[0].flourishAnim != -1 ) { - case SS_FAST: - case SS_TAVION: - anim = BOTH_SHOWOFF_FAST; - break; - case SS_MEDIUM: - anim = BOTH_SHOWOFF_MEDIUM; - break; - case SS_STRONG: - case SS_DESANN: - anim = BOTH_SHOWOFF_STRONG; - break; - case SS_DUAL: - anim = BOTH_SHOWOFF_DUAL; - break; - case SS_STAFF: - anim = BOTH_SHOWOFF_STAFF; - break; + anim = ent->client->saber[0].flourishAnim; + } + else if ( ent->client->saber[1].model + && ent->client->saber[1].model[0] + && ent->client->saber[1].flourishAnim != -1 ) + { + anim = ent->client->saber[1].flourishAnim; + } + else + { + switch ( ent->client->ps.fd.saberAnimLevel ) + { + case SS_FAST: + case SS_TAVION: + anim = BOTH_SHOWOFF_FAST; + break; + case SS_MEDIUM: + anim = BOTH_SHOWOFF_MEDIUM; + break; + case SS_STRONG: + case SS_DESANN: + anim = BOTH_SHOWOFF_STRONG; + break; + case SS_DUAL: + anim = BOTH_SHOWOFF_DUAL; + break; + case SS_STAFF: + anim = BOTH_SHOWOFF_STAFF; + break; + } } } break; case TAUNT_GLOAT: - switch ( ent->client->ps.fd.saberAnimLevel ) + if ( ent->client->saber[0].gloatAnim != -1 ) { - case SS_FAST: - case SS_TAVION: - anim = BOTH_VICTORY_FAST; - break; - case SS_MEDIUM: - anim = BOTH_VICTORY_MEDIUM; - break; - case SS_STRONG: - case SS_DESANN: - if ( ent->client->ps.saberHolstered ) - {//turn on first - G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOn ); + anim = ent->client->saber[0].gloatAnim; + } + else if ( ent->client->saber[1].model + && ent->client->saber[1].model[0] + && ent->client->saber[1].gloatAnim != -1 ) + { + anim = ent->client->saber[1].gloatAnim; + } + else + { + switch ( ent->client->ps.fd.saberAnimLevel ) + { + case SS_FAST: + case SS_TAVION: + anim = BOTH_VICTORY_FAST; + break; + case SS_MEDIUM: + anim = BOTH_VICTORY_MEDIUM; + break; + case SS_STRONG: + case SS_DESANN: + if ( ent->client->ps.saberHolstered ) + {//turn on first + G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOn ); + } + ent->client->ps.saberHolstered = 0; + anim = BOTH_VICTORY_STRONG; + break; + case SS_DUAL: + if ( ent->client->ps.saberHolstered == 1 + && ent->client->saber[1].model + && ent->client->saber[1].model[0] ) + {//turn on second saber + G_Sound( ent, CHAN_WEAPON, ent->client->saber[1].soundOn ); + } + else if ( ent->client->ps.saberHolstered == 2 ) + {//turn on first + G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOn ); + } + ent->client->ps.saberHolstered = 0; + anim = BOTH_VICTORY_DUAL; + break; + case SS_STAFF: + if ( ent->client->ps.saberHolstered ) + {//turn on first + G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOn ); + } + ent->client->ps.saberHolstered = 0; + anim = BOTH_VICTORY_STAFF; + break; } - ent->client->ps.saberHolstered = 0; - anim = BOTH_VICTORY_STRONG; - break; - case SS_DUAL: - if ( ent->client->ps.saberHolstered == 1 - && ent->client->saber[1].model - && ent->client->saber[1].model[0] ) - {//turn on second saber - G_Sound( ent, CHAN_WEAPON, ent->client->saber[1].soundOn ); - } - else if ( ent->client->ps.saberHolstered == 2 ) - {//turn on first - G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOn ); - } - ent->client->ps.saberHolstered = 0; - anim = BOTH_VICTORY_DUAL; - break; - case SS_STAFF: - if ( ent->client->ps.saberHolstered ) - {//turn on first - G_Sound( ent, CHAN_WEAPON, ent->client->saber[0].soundOn ); - } - ent->client->ps.saberHolstered = 0; - anim = BOTH_VICTORY_STAFF; - break; } break; } @@ -1962,31 +2025,40 @@ void ClientThink_real( gentity_t *ent ) { } else if (client->saber[0].model[0] && client->saber[1].model[0]) { //with two sabs always use akimbo style - client->ps.fd.saberAnimLevelBase = SS_DUAL; if ( client->ps.saberHolstered == 1 ) {//one saber should be off, adjust saberAnimLevel accordinly + client->ps.fd.saberAnimLevelBase = SS_DUAL; client->ps.fd.saberAnimLevel = SS_FAST; client->ps.fd.saberDrawAnimLevel = client->ps.fd.saberAnimLevel; } else { - client->ps.fd.saberAnimLevelBase = client->ps.fd.saberAnimLevel = SS_DUAL; + if ( !WP_SaberStyleValidForSaber( &client->saber[0], &client->saber[1], client->ps.saberHolstered, client->ps.fd.saberAnimLevel ) ) + {//only use dual style if the style we're trying to use isn't valid + client->ps.fd.saberAnimLevelBase = client->ps.fd.saberAnimLevel = SS_DUAL; + } client->ps.fd.saberDrawAnimLevel = client->ps.fd.saberAnimLevel; } } - else if (client->saber[0].style == SS_STAFF) - { //then always use the staff style - client->ps.fd.saberAnimLevelBase = SS_STAFF; - if ( client->ps.saberHolstered == 1 - && client->saber[0].singleBladeStyle != SS_NONE) - {//one blade should be off, adjust saberAnimLevel accordinly - client->ps.fd.saberAnimLevel = client->saber[0].singleBladeStyle; - client->ps.fd.saberDrawAnimLevel = client->ps.fd.saberAnimLevel; + else + { + if (client->saber[0].stylesLearned == (1<ps.fd.saberAnimLevelBase = SS_STAFF; } - else - { - client->ps.fd.saberAnimLevel = SS_STAFF; - client->ps.fd.saberDrawAnimLevel = client->ps.fd.saberAnimLevel; + if ( client->ps.fd.saberAnimLevelBase == SS_STAFF ) + {//using staff style + if ( client->ps.saberHolstered == 1 + && client->saber[0].singleBladeStyle != SS_NONE) + {//one blade should be off, adjust saberAnimLevel accordinly + client->ps.fd.saberAnimLevel = client->saber[0].singleBladeStyle; + client->ps.fd.saberDrawAnimLevel = client->ps.fd.saberAnimLevel; + } + else + { + client->ps.fd.saberAnimLevel = SS_STAFF; + client->ps.fd.saberDrawAnimLevel = client->ps.fd.saberAnimLevel; + } } } } @@ -2041,9 +2113,14 @@ void ClientThink_real( gentity_t *ent ) { // // check for exiting intermission // - if ( level.intermissiontime ) { - ClientIntermissionThink( client ); - return; + if ( level.intermissiontime ) + { + if ( ent->s.number < MAX_CLIENTS + || client->NPC_class == CLASS_VEHICLE ) + {//players and vehicles do nothing in intermissions + ClientIntermissionThink( client ); + return; + } } // spectators don't do much @@ -2313,30 +2390,32 @@ void ClientThink_real( gentity_t *ent ) { if (ucmd->buttons & BUTTON_WALKING) { //sort of a hack I guess since MP handles walking differently from SP (has some proxy cheat prevention methods) + /* if (ent->client->ps.speed > 64) { ent->client->ps.speed = 64; } + */ if (ucmd->forwardmove > 64) { - ucmd->forwardmove = ent->client->ps.speed; + ucmd->forwardmove = 64; } else if (ucmd->forwardmove < -64) { - ucmd->forwardmove = -ent->client->ps.speed; + ucmd->forwardmove = -64; } if (ucmd->rightmove > 64) { - ucmd->rightmove = ent->client->ps.speed; + ucmd->rightmove = 64; } else if ( ucmd->rightmove < -64) { - ucmd->rightmove = -ent->client->ps.speed; + ucmd->rightmove = -64; } - ent->client->ps.speed = ent->client->ps.basespeed = NPC_GetRunSpeed( ent ); + //ent->client->ps.speed = ent->client->ps.basespeed = NPC_GetRunSpeed( ent ); } client->ps.basespeed = client->ps.speed; } @@ -2662,6 +2741,9 @@ void ClientThink_real( gentity_t *ent ) { ent->client->ps.otherKiller = thrower->s.number; ent->client->ps.otherKillerTime = level.time + 8000; ent->client->ps.otherKillerDebounceTime = level.time + 100; + ent->client->otherKillerMOD = MOD_FALLING; + ent->client->otherKillerVehWeapon = 0; + ent->client->otherKillerWeaponType = WP_NONE; } else { //see if we can move to be next to the hand.. if it's not clear, break the throw. @@ -3097,6 +3179,27 @@ void ClientThink_real( gentity_t *ent ) { pm.checkDuelLoss = 0; } + if ( ent->client->ps.groundEntityNum < ENTITYNUM_WORLD ) + {//standing on an ent + gentity_t *groundEnt = &g_entities[ent->client->ps.groundEntityNum]; + if ( groundEnt + && groundEnt->s.eType == ET_NPC + && groundEnt->s.NPC_class == CLASS_VEHICLE + && groundEnt->inuse + && groundEnt->health > 0 + && groundEnt->m_pVehicle ) + {//standing on a valid, living vehicle + if ( !groundEnt->client->ps.speed + && groundEnt->m_pVehicle->m_ucmd.upmove > 0 ) + {//a vehicle that's trying to take off! + //just kill me + vec3_t up = {0,0,1}; + G_Damage( ent, NULL, NULL, up, ent->r.currentOrigin, 9999999, DAMAGE_NO_PROTECTION, MOD_CRUSH ); + return; + } + } + } + if (pm.cmd.generic_cmd && (pm.cmd.generic_cmd != ent->client->lastGenCmd || ent->client->lastGenCmdTime < level.time)) { @@ -3314,7 +3417,8 @@ void ClientThink_real( gentity_t *ent ) { if ( ent->client->ps.eventSequence != oldEventSequence ) { ent->eventTime = level.time; } - if (g_smoothClients.integer) { + if (g_smoothClients.integer) + { BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qfalse ); //rww - 12-03-02 - Don't snap the origin of players! It screws prediction all up. } @@ -3427,6 +3531,9 @@ void ClientThink_real( gentity_t *ent ) { faceKicked->client->ps.otherKiller = ent->s.number; faceKicked->client->ps.otherKillerTime = level.time + 5000; faceKicked->client->ps.otherKillerDebounceTime = level.time + 100; + faceKicked->client->otherKillerMOD = MOD_MELEE; + faceKicked->client->otherKillerVehWeapon = 0; + faceKicked->client->otherKillerWeaponType = WP_NONE; faceKicked->client->ps.velocity[0] = oppDir[0]*(strength*40); faceKicked->client->ps.velocity[1] = oppDir[1]*(strength*40); @@ -3721,7 +3828,11 @@ void ClientEndFrame( gentity_t *ent ) { // the player any normal movement attributes // if ( level.intermissiontime ) { - return; + if ( ent->s.number < MAX_CLIENTS + || ent->client->NPC_class == CLASS_VEHICLE ) + {//players and vehicles do nothing in intermissions + return; + } } // burn from lava, etc diff --git a/codemp/game/g_bot.c b/codemp/game/g_bot.c index c54e25d..b936023 100644 --- a/codemp/game/g_bot.c +++ b/codemp/game/g_bot.c @@ -135,6 +135,9 @@ int G_GetMapTypeBits(char *type) typeBits |= (1 << GT_FFA); typeBits |= (1 << GT_TEAM); } + if( strstr( type, "team" ) ) { + typeBits |= (1 << GT_TEAM); + } if( strstr( type, "holocron" ) ) { typeBits |= (1 << GT_HOLOCRON); } diff --git a/codemp/game/g_client.c b/codemp/game/g_client.c index 4b5cb31..5088205 100644 --- a/codemp/game/g_client.c +++ b/codemp/game/g_client.c @@ -13,6 +13,8 @@ extern int g_siegeRespawnCheck; void WP_SaberAddG2Model( gentity_t *saberent, const char *saberModel, qhandle_t saberSkin ); void WP_SaberRemoveG2Model( gentity_t *saberent ); +extern qboolean WP_SaberStyleValidForSaber( saberInfo_t *saber1, saberInfo_t *saber2, int saberHolstered, int saberAnimLevel ); +extern qboolean WP_UseFirstValidSaberStyle( saberInfo_t *saber1, saberInfo_t *saber2, int saberHolstered, int *saberAnimLevel ); forcedata_t Client_Force[MAX_CLIENTS]; @@ -105,6 +107,36 @@ void SP_info_player_start(gentity_t *ent) { SP_info_player_deathmatch( ent ); } +/*QUAKED info_player_start_red (1 0 0) (-16 -16 -24) (16 16 32) INITIAL +For Red Team DM starts + +Targets will be fired when someone spawns in on them. +equivalent to info_player_deathmatch + +INITIAL - The first time a player enters the game, they will be at an 'initial' spot. + +"nobots" will prevent bots from using this spot. +"nohumans" will prevent non-bots from using this spot. +*/ +void SP_info_player_start_red(gentity_t *ent) { + SP_info_player_deathmatch( ent ); +} + +/*QUAKED info_player_start_blue (1 0 0) (-16 -16 -24) (16 16 32) INITIAL +For Blue Team DM starts + +Targets will be fired when someone spawns in on them. +equivalent to info_player_deathmatch + +INITIAL - The first time a player enters the game, they will be at an 'initial' spot. + +"nobots" will prevent bots from using this spot. +"nohumans" will prevent non-bots from using this spot. +*/ +void SP_info_player_start_blue(gentity_t *ent) { + SP_info_player_deathmatch( ent ); +} + void SiegePointUse( gentity_t *self, gentity_t *other, gentity_t *activator ) { //Toggle the point on/off @@ -190,13 +222,37 @@ void SP_info_player_siegeteam2(gentity_t *ent) { ent->use = SiegePointUse; } -/*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32) +/*QUAKED info_player_intermission (1 0 1) (-16 -16 -24) (16 16 32) RED BLUE The intermission will be viewed from this point. Target an info_notnull for the view direction. +RED - In a Siege game, the intermission will happen here if the Red (attacking) team wins +BLUE - In a Siege game, the intermission will happen here if the Blue (defending) team wins */ void SP_info_player_intermission( gentity_t *ent ) { } +/*QUAKED info_player_intermission_red (1 0 1) (-16 -16 -24) (16 16 32) +The intermission will be viewed from this point. Target an info_notnull for the view direction. + +In a Siege game, the intermission will happen here if the Red (attacking) team wins +target - ent to look at +target2 - ents to use when this intermission point is chosen +*/ +void SP_info_player_intermission_red( gentity_t *ent ) { + +} + +/*QUAKED info_player_intermission_blue (1 0 1) (-16 -16 -24) (16 16 32) +The intermission will be viewed from this point. Target an info_notnull for the view direction. + +In a Siege game, the intermission will happen here if the Blue (defending) team wins +target - ent to look at +target2 - ents to use when this intermission point is chosen +*/ +void SP_info_player_intermission_blue( gentity_t *ent ) { + +} + #define JMSABER_RESPAWN_TIME 20000 //in case it gets stuck somewhere no one can reach void ThrowSaberToAttacker(gentity_t *self, gentity_t *attacker) @@ -595,7 +651,7 @@ SelectRandomFurthestSpawnPoint Chooses a player start, deathmatch start, etc ============ */ -gentity_t *SelectRandomFurthestSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles ) { +gentity_t *SelectRandomFurthestSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles, team_t team ) { gentity_t *spot; vec3_t delta; float dist; @@ -606,42 +662,89 @@ gentity_t *SelectRandomFurthestSpawnPoint ( vec3_t avoidPoint, vec3_t origin, ve numSpots = 0; spot = NULL; - while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) { - if ( SpotWouldTelefrag( spot ) ) { - continue; + //in Team DM, look for a team start spot first, if any + if ( g_gametype.integer == GT_TEAM + && team != TEAM_FREE + && team != TEAM_SPECTATOR ) + { + char *classname = NULL; + if ( team == TEAM_RED ) + { + classname = "info_player_start_red"; } - VectorSubtract( spot->s.origin, avoidPoint, delta ); - dist = VectorLength( delta ); - for (i = 0; i < numSpots; i++) { - if ( dist > list_dist[i] ) { - if ( numSpots >= 64 ) - numSpots = 64-1; - for (j = numSpots; j > i; j--) { - list_dist[j] = list_dist[j-1]; - list_spot[j] = list_spot[j-1]; + else + { + classname = "info_player_start_blue"; + } + while ((spot = G_Find (spot, FOFS(classname), classname)) != NULL) { + if ( SpotWouldTelefrag( spot ) ) { + continue; + } + VectorSubtract( spot->s.origin, avoidPoint, delta ); + dist = VectorLength( delta ); + for (i = 0; i < numSpots; i++) { + if ( dist > list_dist[i] ) { + if ( numSpots >= 64 ) + numSpots = 64-1; + for (j = numSpots; j > i; j--) { + list_dist[j] = list_dist[j-1]; + list_spot[j] = list_spot[j-1]; + } + list_dist[i] = dist; + list_spot[i] = spot; + numSpots++; + if (numSpots > 64) + numSpots = 64; + break; } - list_dist[i] = dist; - list_spot[i] = spot; + } + if (i >= numSpots && numSpots < 64) { + list_dist[numSpots] = dist; + list_spot[numSpots] = spot; numSpots++; - if (numSpots > 64) - numSpots = 64; - break; } } - if (i >= numSpots && numSpots < 64) { - list_dist[numSpots] = dist; - list_spot[numSpots] = spot; - numSpots++; - } } - if (!numSpots) { - spot = G_Find( NULL, FOFS(classname), "info_player_deathmatch"); - if (!spot) - G_Error( "Couldn't find a spawn point" ); - VectorCopy (spot->s.origin, origin); - origin[2] += 9; - VectorCopy (spot->s.angles, angles); - return spot; + + if ( !numSpots ) + {//couldn't find any of the above + while ((spot = G_Find (spot, FOFS(classname), "info_player_deathmatch")) != NULL) { + if ( SpotWouldTelefrag( spot ) ) { + continue; + } + VectorSubtract( spot->s.origin, avoidPoint, delta ); + dist = VectorLength( delta ); + for (i = 0; i < numSpots; i++) { + if ( dist > list_dist[i] ) { + if ( numSpots >= 64 ) + numSpots = 64-1; + for (j = numSpots; j > i; j--) { + list_dist[j] = list_dist[j-1]; + list_spot[j] = list_spot[j-1]; + } + list_dist[i] = dist; + list_spot[i] = spot; + numSpots++; + if (numSpots > 64) + numSpots = 64; + break; + } + } + if (i >= numSpots && numSpots < 64) { + list_dist[numSpots] = dist; + list_spot[numSpots] = spot; + numSpots++; + } + } + if (!numSpots) { + spot = G_Find( NULL, FOFS(classname), "info_player_deathmatch"); + if (!spot) + G_Error( "Couldn't find a spawn point" ); + VectorCopy (spot->s.origin, origin); + origin[2] += 9; + VectorCopy (spot->s.angles, angles); + return spot; + } } // select a random spot from the spawn points furthest away @@ -748,8 +851,8 @@ SelectSpawnPoint Chooses a player start, deathmatch start, etc ============ */ -gentity_t *SelectSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles ) { - return SelectRandomFurthestSpawnPoint( avoidPoint, origin, angles ); +gentity_t *SelectSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles, team_t team ) { + return SelectRandomFurthestSpawnPoint( avoidPoint, origin, angles, team ); /* gentity_t *spot; @@ -788,7 +891,7 @@ Try to find a spawn point marked 'initial', otherwise use normal spawn selection. ============ */ -gentity_t *SelectInitialSpawnPoint( vec3_t origin, vec3_t angles ) { +gentity_t *SelectInitialSpawnPoint( vec3_t origin, vec3_t angles, team_t team ) { gentity_t *spot; spot = NULL; @@ -799,7 +902,7 @@ gentity_t *SelectInitialSpawnPoint( vec3_t origin, vec3_t angles ) { } if ( !spot || SpotWouldTelefrag( spot ) ) { - return SelectSpawnPoint( vec3_origin, origin, angles ); + return SelectSpawnPoint( vec3_origin, origin, angles, team ); } VectorCopy (spot->s.origin, origin); @@ -1344,8 +1447,14 @@ qboolean G_SaberModelSetup(gentity_t *ent) trap_G2API_SetSkin(ent->client->weaponGhoul2[i], 0, ent->client->saber[i].skin, ent->client->saber[i].skin); } - // bolt to right hand for 0, or left hand for 1 - trap_G2API_SetBoltInfo(ent->client->weaponGhoul2[i], 0, i); + if (ent->client->saber[i].saberFlags & SFL_BOLT_TO_WRIST) + { + trap_G2API_SetBoltInfo(ent->client->weaponGhoul2[i], 0, 3+i); + } + else + { // bolt to right hand for 0, or left hand for 1 + trap_G2API_SetBoltInfo(ent->client->weaponGhoul2[i], 0, i); + } //Add all the bolt points while (j < ent->client->saber[i].numBlades) @@ -1721,6 +1830,10 @@ void SetupGameGhoul2Model(gentity_t *ent, char *modelname, char *skinName) //jetpack bolted to must always be third. trap_G2API_AddBolt(ent->ghoul2, 0, "*chestg"); + //claw bolts + trap_G2API_AddBolt(ent->ghoul2, 0, "*r_hand_cap_r_arm"); + trap_G2API_AddBolt(ent->ghoul2, 0, "*l_hand_cap_l_arm"); + trap_G2API_SetBoneAnim(ent->ghoul2, 0, "model_root", 0, 12, BONE_ANIM_OVERRIDE_LOOP, 1.0f, level.time, -1, -1); trap_G2API_SetBoneAngles(ent->ghoul2, 0, "upper_lumbar", tempVec, BONE_ANGLES_POSTMULT, POSITIVE_X, NEGATIVE_Y, NEGATIVE_Z, NULL, 0, level.time); trap_G2API_SetBoneAngles(ent->ghoul2, 0, "cranium", tempVec, BONE_ANGLES_POSTMULT, POSITIVE_Z, NEGATIVE_Y, POSITIVE_X, NULL, 0, level.time); @@ -1783,8 +1896,8 @@ void ClientUserinfoChanged( int clientNum ) { gclient_t *client; char c1[MAX_INFO_STRING]; char c2[MAX_INFO_STRING]; - char redTeam[MAX_INFO_STRING]; - char blueTeam[MAX_INFO_STRING]; +// char redTeam[MAX_INFO_STRING]; +// char blueTeam[MAX_INFO_STRING]; char userinfo[MAX_INFO_STRING]; char className[MAX_QPATH]; //name of class type to use in siege char saberName[MAX_QPATH]; @@ -2074,8 +2187,8 @@ void ClientUserinfoChanged( int clientNum ) { strcpy(c1, Info_ValueForKey( userinfo, "color1" )); strcpy(c2, Info_ValueForKey( userinfo, "color2" )); - strcpy(redTeam, Info_ValueForKey( userinfo, "g_redteam" )); - strcpy(blueTeam, Info_ValueForKey( userinfo, "g_blueteam" )); +// strcpy(redTeam, Info_ValueForKey( userinfo, "g_redteam" )); +// strcpy(blueTeam, Info_ValueForKey( userinfo, "g_blueteam" )); // send over a subset of the userinfo keys so other clients can // print scoreboards, display models, and play custom sounds @@ -2087,14 +2200,14 @@ void ClientUserinfoChanged( int clientNum ) { } else { if (g_gametype.integer == GT_SIEGE) { //more crap to send - s = va("n\\%s\\t\\%i\\model\\%s\\g_redteam\\%s\\g_blueteam\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\tl\\%d\\siegeclass\\%s\\st\\%s\\st2\\%s\\dt\\%i\\sdt\\%i", - client->pers.netname, client->sess.sessionTeam, model, redTeam, blueTeam, c1, c2, + s = va("n\\%s\\t\\%i\\model\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\tl\\%d\\siegeclass\\%s\\st\\%s\\st2\\%s\\dt\\%i\\sdt\\%i", + client->pers.netname, client->sess.sessionTeam, model, c1, c2, client->pers.maxHealth, client->sess.wins, client->sess.losses, teamTask, teamLeader, className, saberName, saber2Name, client->sess.duelTeam, client->sess.siegeDesiredTeam); } else { - s = va("n\\%s\\t\\%i\\model\\%s\\g_redteam\\%s\\g_blueteam\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\tl\\%d\\st\\%s\\st2\\%s\\dt\\%i", - client->pers.netname, client->sess.sessionTeam, model, redTeam, blueTeam, c1, c2, + s = va("n\\%s\\t\\%i\\model\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\tl\\%d\\st\\%s\\st2\\%s\\dt\\%i", + client->pers.netname, client->sess.sessionTeam, model, c1, c2, client->pers.maxHealth, client->sess.wins, client->sess.losses, teamTask, teamLeader, saberName, saber2Name, client->sess.duelTeam); } } @@ -2147,6 +2260,7 @@ char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ) { // char *areabits; gclient_t *client; char userinfo[MAX_INFO_STRING]; + char IPstring[32]={0}; gentity_t *ent; gentity_t *te; @@ -2156,6 +2270,9 @@ char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ) { // check to see if they are on the banned IP list value = Info_ValueForKey (userinfo, "ip"); + Q_strncpyz(IPstring, value, sizeof(IPstring) ); + + if ( G_FilterPacket( value ) ) { return "Banned."; } @@ -2190,6 +2307,9 @@ char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ) { } G_ReadSessionData( client ); + client->sess.IPstring[0] = 0; + Q_strncpyz(client->sess.IPstring, IPstring, sizeof(client->sess.IPstring) ); + if (g_gametype.integer == GT_SIEGE && (firstTime || level.newSession)) { //if this is the first time then auto-assign a desired siege team and show briefing for that team @@ -2225,6 +2345,7 @@ char *ClientConnect( int clientNum, qboolean firstTime, qboolean isBot ) { // get and distribute relevent paramters G_LogPrintf( "ClientConnect: %i\n", clientNum ); ClientUserinfoChanged( clientNum ); + G_LogPrintf( "%s connected with IP: %s\n", client->pers.netname, client->sess.IPstring ); // don't do the "xxx connected" messages if they were caried over from previous level if ( firstTime ) { @@ -2639,7 +2760,7 @@ tryTorso: f = torsoAnim; - BG_SaberStartTransAnim(self->client->ps.fd.saberAnimLevel, f, &animSpeedScale, self->client->ps.brokenLimbs); + BG_SaberStartTransAnim(self->s.number, self->client->ps.fd.saberAnimLevel, self->client->ps.weapon, f, &animSpeedScale, self->client->ps.brokenLimbs); animSpeed = 50.0f / bgAllAnims[self->localAnimIndex].anims[f].frameLerp; lAnimSpeedScale = (animSpeed *= animSpeedScale); @@ -2916,7 +3037,7 @@ void ClientSpawn(gentity_t *ent) { { //dual ent->client->ps.fd.saberAnimLevelBase = ent->client->ps.fd.saberAnimLevel = ent->client->ps.fd.saberDrawAnimLevel = SS_DUAL; } - else if (ent->client->saber[0].twoHanded) + else if ((ent->client->saber[0].saberFlags&SFL_TWO_HANDED)) { //staff ent->client->ps.fd.saberAnimLevel = ent->client->ps.fd.saberDrawAnimLevel = SS_STAFF; } @@ -2938,6 +3059,15 @@ void ClientSpawn(gentity_t *ent) { ent->client->ps.fd.saberAnimLevelBase = ent->client->ps.fd.saberAnimLevel = ent->client->ps.fd.saberDrawAnimLevel = ent->client->sess.saberLevel = ent->client->ps.fd.forcePowerLevel[FP_SABER_OFFENSE]; } } + if ( g_gametype.integer != GT_SIEGE ) + { + //let's just make sure the styles we chose are cool + if ( !WP_SaberStyleValidForSaber( &ent->client->saber[0], &ent->client->saber[1], ent->client->ps.saberHolstered, ent->client->ps.fd.saberAnimLevel ) ) + { + WP_UseFirstValidSaberStyle( &ent->client->saber[0], &ent->client->saber[1], ent->client->ps.saberHolstered, &ent->client->ps.fd.saberAnimLevel ); + ent->client->ps.fd.saberAnimLevelBase = ent->client->saberCycleQueue = ent->client->ps.fd.saberAnimLevel; + } + } } l = 0; @@ -3005,12 +3135,12 @@ void ClientSpawn(gentity_t *ent) { // the first spawn should be at a good looking spot if ( !client->pers.initialSpawn && client->pers.localClient ) { client->pers.initialSpawn = qtrue; - spawnPoint = SelectInitialSpawnPoint( spawn_origin, spawn_angles ); + spawnPoint = SelectInitialSpawnPoint( spawn_origin, spawn_angles, client->sess.sessionTeam ); } else { // don't spawn near existing origin if possible spawnPoint = SelectSpawnPoint ( client->ps.origin, - spawn_origin, spawn_angles); + spawn_origin, spawn_angles, client->sess.sessionTeam ); } } @@ -3755,6 +3885,7 @@ void ClientDisconnect( int clientNum ) { } G_LogPrintf( "ClientDisconnect: %i\n", clientNum ); + G_LogPrintf( "%s disconnected with IP: %s\n", ent->client->pers.netname, ent->client->sess.IPstring ); // if we are playing in tourney mode, give a win to the other player and clear his frags for this round if ( (g_gametype.integer == GT_DUEL ) diff --git a/codemp/game/g_cmds.c b/codemp/game/g_cmds.c index 2a7f2ee..ff6a5a3 100644 --- a/codemp/game/g_cmds.c +++ b/codemp/game/g_cmds.c @@ -521,6 +521,56 @@ void Cmd_TeamTask_f( gentity_t *ent ) { ClientUserinfoChanged(client); } +extern void AddIP( char *str ); +extern vmCvar_t g_autoKickTKSpammers; +extern vmCvar_t g_autoBanTKSpammers; +void G_CheckTKAutoKickBan( gentity_t *ent ) +{ + if ( !ent || !ent->client || ent->s.number >= MAX_CLIENTS ) + { + return; + } + + if ( g_autoKickTKSpammers.integer > 0 + || g_autoBanTKSpammers.integer > 0 ) + { + ent->client->sess.TKCount++; + if ( g_autoBanTKSpammers.integer > 0 + && ent->client->sess.TKCount >= g_autoBanTKSpammers.integer ) + { + if ( ent->client->sess.IPstring ) + {//ban their IP + AddIP( ent->client->sess.IPstring ); + } + + trap_SendServerCommand( -1, va("print \"%s %s\n\"", ent->client->pers.netname, G_GetStringEdString("MP_SVGAME_ADMIN", "TKBAN")) ); + //Com_sprintf ( level.voteString, sizeof(level.voteString ), "clientkick %d", ent->s.number ); + //Com_sprintf ( level.voteDisplayString, sizeof(level.voteDisplayString), "kick %s", ent->client->pers.netname ); + //trap_SendConsoleCommand( EXEC_INSERT, va( "banClient %d\n", ent->s.number ) ); + trap_SendConsoleCommand( EXEC_INSERT, va( "clientkick %d\n", ent->s.number ) ); + return; + } + if ( g_autoKickTKSpammers.integer > 0 + && ent->client->sess.TKCount >= g_autoKickTKSpammers.integer ) + { + trap_SendServerCommand( -1, va("print \"%s %s\n\"", ent->client->pers.netname, G_GetStringEdString("MP_SVGAME_ADMIN", "TKKICK")) ); + //Com_sprintf ( level.voteString, sizeof(level.voteString ), "clientkick %d", ent->s.number ); + //Com_sprintf ( level.voteDisplayString, sizeof(level.voteDisplayString), "kick \"%s\"\n", ent->client->pers.netname ); + trap_SendConsoleCommand( EXEC_INSERT, va( "clientkick %d\n", ent->s.number ) ); + return; + } + //okay, not gone (yet), but warn them... + if ( g_autoBanTKSpammers.integer > 0 + && (g_autoKickTKSpammers.integer <= 0 || g_autoBanTKSpammers.integer < g_autoKickTKSpammers.integer) ) + {//warn about ban + trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME_ADMIN", "WARNINGTKBAN")) ); + } + else if ( g_autoKickTKSpammers.integer > 0 ) + {//warn about kick + trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME_ADMIN", "WARNINGTKKICK")) ); + } + } +} /* @@ -528,6 +578,8 @@ void Cmd_TeamTask_f( gentity_t *ent ) { Cmd_Kill_f ================= */ +extern vmCvar_t g_autoKickKillSpammers; +extern vmCvar_t g_autoBanKillSpammers; void Cmd_Kill_f( gentity_t *ent ) { if ( ent->client->sess.sessionTeam == TEAM_SPECTATOR ) { return; @@ -546,6 +598,45 @@ void Cmd_Kill_f( gentity_t *ent ) { } } + if ( g_autoKickKillSpammers.integer > 0 + || g_autoBanKillSpammers.integer > 0 ) + { + ent->client->sess.killCount++; + if ( g_autoBanKillSpammers.integer > 0 + && ent->client->sess.killCount >= g_autoBanKillSpammers.integer ) + { + if ( ent->client->sess.IPstring ) + {//ban their IP + AddIP( ent->client->sess.IPstring ); + } + + trap_SendServerCommand( -1, va("print \"%s %s\n\"", ent->client->pers.netname, G_GetStringEdString("MP_SVGAME_ADMIN", "SUICIDEBAN")) ); + //Com_sprintf ( level.voteString, sizeof(level.voteString ), "clientkick %d", ent->s.number ); + //Com_sprintf ( level.voteDisplayString, sizeof(level.voteDisplayString), "kick %s", ent->client->pers.netname ); + //trap_SendConsoleCommand( EXEC_INSERT, va( "banClient %d\n", ent->s.number ) ); + trap_SendConsoleCommand( EXEC_INSERT, va( "clientkick %d\n", ent->s.number ) ); + return; + } + if ( g_autoKickKillSpammers.integer > 0 + && ent->client->sess.killCount >= g_autoKickKillSpammers.integer ) + { + trap_SendServerCommand( -1, va("print \"%s %s\n\"", ent->client->pers.netname, G_GetStringEdString("MP_SVGAME_ADMIN", "SUICIDEKICK")) ); + //Com_sprintf ( level.voteString, sizeof(level.voteString ), "clientkick %d", ent->s.number ); + //Com_sprintf ( level.voteDisplayString, sizeof(level.voteDisplayString), "kick %s", ent->client->pers.netname ); + trap_SendConsoleCommand( EXEC_INSERT, va( "clientkick %d\n", ent->s.number ) ); + return; + } + //okay, not gone (yet), but warn them... + if ( g_autoBanKillSpammers.integer > 0 + && (g_autoKickKillSpammers.integer <= 0 || g_autoBanKillSpammers.integer < g_autoKickKillSpammers.integer) ) + {//warn about ban + trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME_ADMIN", "WARNINGSUICIDEBAN")) ); + } + else if ( g_autoKickKillSpammers.integer > 0 ) + {//warn about kick + trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME_ADMIN", "WARNINGSUICIDEKICK")) ); + } + } ent->flags &= ~FL_GODMODE; ent->client->ps.stats[STAT_HEALTH] = ent->health = -999; player_die (ent, ent, ent, 100000, MOD_SUICIDE); @@ -1300,6 +1391,8 @@ argCheck: } } +extern qboolean WP_SaberStyleValidForSaber( saberInfo_t *saber1, saberInfo_t *saber2, int saberHolstered, int saberAnimLevel ); +extern qboolean WP_UseFirstValidSaberStyle( saberInfo_t *saber1, saberInfo_t *saber2, int saberHolstered, int *saberAnimLevel ); qboolean G_SetSaber(gentity_t *ent, int saberNum, char *saberName, qboolean siegeOverride) { char truncSaberName[64]; @@ -1352,6 +1445,12 @@ qboolean G_SetSaber(gentity_t *ent, int saberNum, char *saberName, qboolean sieg strcpy(ent->client->sess.saber2Type, ent->client->saber[1].name); } + if ( !WP_SaberStyleValidForSaber( &ent->client->saber[0], &ent->client->saber[1], ent->client->ps.saberHolstered, ent->client->ps.fd.saberAnimLevel ) ) + { + WP_UseFirstValidSaberStyle( &ent->client->saber[0], &ent->client->saber[1], ent->client->ps.saberHolstered, &ent->client->ps.fd.saberAnimLevel ); + ent->client->ps.fd.saberAnimLevelBase = ent->client->saberCycleQueue = ent->client->ps.fd.saberAnimLevel; + } + return qtrue; } @@ -2105,19 +2204,27 @@ Cmd_CallTeamVote_f ================== */ void Cmd_CallTeamVote_f( gentity_t *ent ) { - int i, team, cs_offset; + int i, targetClientNum=ENTITYNUM_NONE, team, cs_offset; char arg1[MAX_STRING_TOKENS]; char arg2[MAX_STRING_TOKENS]; + if ( g_gametype.integer < GT_TEAM ) + { + trap_SendServerCommand( ent-g_entities, "print \"Cannot call a team vote in a non-team gametype!\n\"" ); + return; + } team = ent->client->sess.sessionTeam; if ( team == TEAM_RED ) cs_offset = 0; else if ( team == TEAM_BLUE ) cs_offset = 1; else + { + trap_SendServerCommand( ent-g_entities, "print \"Cannot call a team vote if not on a team!\n\"" ); return; + } - if ( !g_allowVote.integer ) { + if ( !g_allowTeamVote.integer ) { trap_SendServerCommand( ent-g_entities, va("print \"%s\n\"", G_GetStringEdString("MP_SVGAME", "NOVOTE")) ); return; } @@ -2149,11 +2256,12 @@ void Cmd_CallTeamVote_f( gentity_t *ent ) { return; } - if ( !Q_stricmp( arg1, "leader" ) ) { - char netname[MAX_NETNAME], leader[MAX_NETNAME]; + if ( !Q_stricmp( arg1, "leader" ) + || !Q_stricmp( arg1, "kick" ) ) { + char netname[MAX_NETNAME], target[MAX_NETNAME]; if ( !arg2[0] ) { - i = ent->client->ps.clientNum; + targetClientNum = ent->client->ps.clientNum; } else { // numeric values are just slot numbers @@ -2162,20 +2270,20 @@ void Cmd_CallTeamVote_f( gentity_t *ent ) { break; } if ( i >= 3 || !arg2[i]) { - i = atoi( arg2 ); - if ( i < 0 || i >= level.maxclients ) { - trap_SendServerCommand( ent-g_entities, va("print \"Bad client slot: %i\n\"", i) ); + targetClientNum = atoi( arg2 ); + if ( targetClientNum < 0 || targetClientNum >= level.maxclients ) { + trap_SendServerCommand( ent-g_entities, va("print \"Bad client slot: %i\n\"", targetClientNum) ); return; } - if ( !g_entities[i].inuse ) { - trap_SendServerCommand( ent-g_entities, va("print \"Client %i is not active\n\"", i) ); + if ( !g_entities[targetClientNum].inuse ) { + trap_SendServerCommand( ent-g_entities, va("print \"Client %i is not active\n\"", targetClientNum) ); return; } } else { - Q_strncpyz(leader, arg2, sizeof(leader)); - Q_CleanStr(leader); + Q_strncpyz(target, arg2, sizeof(target)); + Q_CleanStr(target); for ( i = 0 ; i < level.maxclients ; i++ ) { if ( level.clients[i].pers.connected == CON_DISCONNECTED ) continue; @@ -2183,24 +2291,44 @@ void Cmd_CallTeamVote_f( gentity_t *ent ) { continue; Q_strncpyz(netname, level.clients[i].pers.netname, sizeof(netname)); Q_CleanStr(netname); - if ( !Q_stricmp(netname, leader) ) { + if ( !Q_stricmp(netname, target) ) + { + targetClientNum = i; break; } } - if ( i >= level.maxclients ) { + if ( targetClientNum >= level.maxclients ) { trap_SendServerCommand( ent-g_entities, va("print \"%s is not a valid player on your team.\n\"", arg2) ); return; } } } - Com_sprintf(arg2, sizeof(arg2), "%d", i); + if ( targetClientNum >= MAX_CLIENTS ) + {//wtf? + trap_SendServerCommand( ent-g_entities, va("print \"%s is not a valid player on your team.\n\"", arg2) ); + return; + } + if ( level.clients[targetClientNum].sess.sessionTeam != ent->client->sess.sessionTeam ) + {//can't call a team vote on someone not on your team! + trap_SendServerCommand( ent-g_entities, va("print \"Cannot call a team vote on someone not on your team (%s).\n\"", level.clients[targetClientNum].pers.netname) ); + return; + } + //just use the client number + Com_sprintf(arg2, sizeof(arg2), "%d", targetClientNum); } else { trap_SendServerCommand( ent-g_entities, "print \"Invalid vote string.\n\"" ); - trap_SendServerCommand( ent-g_entities, "print \"Team vote commands are: leader .\n\"" ); + trap_SendServerCommand( ent-g_entities, "print \"Team vote commands are: leader OR kick .\n\"" ); return; } - Com_sprintf( level.teamVoteString[cs_offset], sizeof( level.teamVoteString[cs_offset] ), "%s %s", arg1, arg2 ); + if ( !Q_stricmp( "kick", arg1 ) ) + {//use clientkick and number (so they can't change their name) + Com_sprintf( level.teamVoteString[cs_offset], sizeof( level.teamVoteString[cs_offset] ), "clientkick %s", arg2 ); + } + else + {//just a number + Com_sprintf( level.teamVoteString[cs_offset], sizeof( level.teamVoteString[cs_offset] ), "%s %s", arg1, arg2 ); + } for ( i = 0 ; i < level.maxclients ; i++ ) { if ( level.clients[i].pers.connected == CON_DISCONNECTED ) @@ -2220,6 +2348,14 @@ void Cmd_CallTeamVote_f( gentity_t *ent ) { } ent->client->mGameFlags |= PSG_TEAMVOTED; + /* + if ( !Q_stricmp( "kick", arg1 ) ) + {//if you're voting to kick somebody, make them auto-vote yes + level.clients[targetClientNum].mGameFlags |= PSG_TEAMVOTED; + level.teamVoteYes[cs_offset]++; + } + */ + trap_SetConfigstring( CS_TEAMVOTE_TIME + cs_offset, va("%i", level.teamVoteTime[cs_offset] ) ); trap_SetConfigstring( CS_TEAMVOTE_STRING + cs_offset, level.teamVoteString[cs_offset] ); trap_SetConfigstring( CS_TEAMVOTE_YES + cs_offset, va("%i", level.teamVoteYes[cs_offset] ) ); @@ -2535,10 +2671,12 @@ void Cmd_ToggleSaber_f(gentity_t *ent) extern vmCvar_t d_saberStanceDebug; +extern qboolean WP_SaberCanTurnOffSomeBlades( saberInfo_t *saber ); void Cmd_SaberAttackCycle_f(gentity_t *ent) { int selectLevel = 0; - + qboolean usingSiegeStyle = qfalse; + if ( !ent || !ent->client ) { return; @@ -2552,31 +2690,44 @@ void Cmd_SaberAttackCycle_f(gentity_t *ent) if (ent->client->saber[0].model[0] && ent->client->saber[1].model[0]) { //no cycling for akimbo - if ( ent->client->ps.saberHolstered == 1 ) - {//have one holstered - //unholster it - G_Sound(ent, CHAN_AUTO, ent->client->saber[1].soundOn); - ent->client->ps.saberHolstered = 0; - //g_active should take care of this, but... - ent->client->ps.fd.saberAnimLevel = SS_DUAL; - } - else if ( ent->client->ps.saberHolstered == 0 ) - {//have none holstered - //holster it - G_Sound(ent, CHAN_AUTO, ent->client->saber[1].soundOff); - ent->client->ps.saberHolstered = 1; - //g_active should take care of this, but... - ent->client->ps.fd.saberAnimLevel = SS_FAST; - } + if ( WP_SaberCanTurnOffSomeBlades( &ent->client->saber[1] ) ) + {//can turn second saber off + if ( ent->client->ps.saberHolstered == 1 ) + {//have one holstered + //unholster it + G_Sound(ent, CHAN_AUTO, ent->client->saber[1].soundOn); + ent->client->ps.saberHolstered = 0; + //g_active should take care of this, but... + ent->client->ps.fd.saberAnimLevel = SS_DUAL; + } + else if ( ent->client->ps.saberHolstered == 0 ) + {//have none holstered + if ( (ent->client->saber[1].saberFlags2&SFL2_NO_MANUAL_DEACTIVATE) ) + {//can't turn it off manually + } + else if ( ent->client->saber[1].bladeStyle2Start > 0 + && (ent->client->saber[1].saberFlags2&SFL2_NO_MANUAL_DEACTIVATE2) ) + {//can't turn it off manually + } + else + { + //turn it off + G_Sound(ent, CHAN_AUTO, ent->client->saber[1].soundOff); + ent->client->ps.saberHolstered = 1; + //g_active should take care of this, but... + ent->client->ps.fd.saberAnimLevel = SS_FAST; + } + } - if (d_saberStanceDebug.integer) - { - trap_SendServerCommand( ent-g_entities, va("print \"SABERSTANCEDEBUG: Attempted to toggle dual saber blade.\n\"") ); + if (d_saberStanceDebug.integer) + { + trap_SendServerCommand( ent-g_entities, va("print \"SABERSTANCEDEBUG: Attempted to toggle dual saber blade.\n\"") ); + } + return; } - return; } - - if (ent->client->saber[0].numBlades > 1 ) + else if (ent->client->saber[0].numBlades > 1 + && WP_SaberCanTurnOffSomeBlades( &ent->client->saber[0] ) ) { //use staff stance then. if ( ent->client->ps.saberHolstered == 1 ) {//second blade off @@ -2592,33 +2743,44 @@ void Cmd_SaberAttackCycle_f(gentity_t *ent) G_Sound(ent, CHAN_AUTO, ent->client->saber[0].soundOn); ent->client->ps.saberHolstered = 0; //g_active should take care of this, but... - if ( ent->client->saber[0].style != SS_NONE ) - { + if ( ent->client->saber[0].stylesForbidden ) + {//have a style we have to use + WP_UseFirstValidSaberStyle( &ent->client->saber[0], &ent->client->saber[1], ent->client->ps.saberHolstered, &selectLevel ); if ( ent->client->ps.weaponTime <= 0 ) { //not busy, set it now - ent->client->ps.fd.saberAnimLevel = ent->client->saber[0].style; + ent->client->ps.fd.saberAnimLevel = selectLevel; } else { //can't set it now or we might cause unexpected chaining, so queue it - ent->client->saberCycleQueue = ent->client->saber[0].style; + ent->client->saberCycleQueue = selectLevel; } } } else if ( ent->client->ps.saberHolstered == 0 ) {//both blades on - //turn second one off - G_Sound(ent, CHAN_AUTO, ent->client->saber[0].soundOff); - ent->client->ps.saberHolstered = 1; - //g_active should take care of this, but... - if ( ent->client->saber[0].singleBladeStyle != SS_NONE ) + if ( (ent->client->saber[0].saberFlags2&SFL2_NO_MANUAL_DEACTIVATE) ) + {//can't turn it off manually + } + else if ( ent->client->saber[0].bladeStyle2Start > 0 + && (ent->client->saber[0].saberFlags2&SFL2_NO_MANUAL_DEACTIVATE2) ) + {//can't turn it off manually + } + else { - if ( ent->client->ps.weaponTime <= 0 ) - { //not busy, set it now - ent->client->ps.fd.saberAnimLevel = ent->client->saber[0].singleBladeStyle; - } - else - { //can't set it now or we might cause unexpected chaining, so queue it - ent->client->saberCycleQueue = ent->client->saber[0].singleBladeStyle; + //turn second one off + G_Sound(ent, CHAN_AUTO, ent->client->saber[0].soundOff); + ent->client->ps.saberHolstered = 1; + //g_active should take care of this, but... + if ( ent->client->saber[0].singleBladeStyle != SS_NONE ) + { + if ( ent->client->ps.weaponTime <= 0 ) + { //not busy, set it now + ent->client->ps.fd.saberAnimLevel = ent->client->saber[0].singleBladeStyle; + } + else + { //can't set it now or we might cause unexpected chaining, so queue it + ent->client->saberCycleQueue = ent->client->saber[0].singleBladeStyle; + } } } } @@ -2644,6 +2806,8 @@ void Cmd_SaberAttackCycle_f(gentity_t *ent) { //we have a flag of useable stances so cycle through it instead int i = selectLevel+1; + usingSiegeStyle = qtrue; + while (i != selectLevel) { //cycle around upward til we hit the next style or end up back on this one if (i >= SS_NUM_SABER_STYLES) @@ -2692,6 +2856,12 @@ void Cmd_SaberAttackCycle_f(gentity_t *ent) } #endif */ + if ( !usingSiegeStyle ) + { + //make sure it's valid, change it if not + WP_UseFirstValidSaberStyle( &ent->client->saber[0], &ent->client->saber[1], ent->client->ps.saberHolstered, &selectLevel ); + } + if (ent->client->ps.weaponTime <= 0) { //not busy, set it now ent->client->ps.fd.saberAnimLevelBase = ent->client->ps.fd.saberAnimLevel = selectLevel; @@ -3068,6 +3238,8 @@ void ClientCommand( int clientNum ) { return; } + //note: these voice_cmds come from the ui/jamp/ingame_voicechat.menu menu file... + // the strings are in strings/English/menus.str and all start with "VC_" if (Q_stricmp(cmd, "voice_cmd") == 0) { Cmd_VoiceCommand_f(ent); diff --git a/codemp/game/g_combat.c b/codemp/game/g_combat.c index 306fcd4..ced984e 100644 --- a/codemp/game/g_combat.c +++ b/codemp/game/g_combat.c @@ -11,7 +11,8 @@ extern qboolean G_FlyVehicleDestroySurface( gentity_t *veh, int surface ); extern void G_VehicleSetDamageLocFlags( gentity_t *veh, int impactDir, int deathPoint ); extern void G_VehUpdateShields( gentity_t *targ ); extern void G_LetGoOfWall( gentity_t *ent ); - +extern void BG_ClearRocketLock( playerState_t *ps ); +extern void G_CheckTKAutoKickBan( gentity_t *ent ); //rww - pd void BotDamageNotification(gclient_t *bot, gentity_t *attacker); //end rww @@ -2053,6 +2054,56 @@ void G_AddPowerDuelLoserScore(int team, int score) } } + +extern qboolean g_noPDuelCheck; +void G_BroadcastObit( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int killer, int meansOfDeath, int wasInVehicle, qboolean wasJediMaster ) +{ + // broadcast the death event to everyone + if (self->s.eType != ET_NPC && !g_noPDuelCheck) + { + gentity_t *ent; + + ent = G_TempEntity( self->r.currentOrigin, EV_OBITUARY ); + ent->s.eventParm = meansOfDeath; + ent->s.otherEntityNum = self->s.number; + if ( attacker ) + { + ent->s.otherEntityNum2 = attacker->s.number; + } + else + {//??? + ent->s.otherEntityNum2 = killer; + } + if ( inflictor + && !Q_stricmp( "vehicle_proj", inflictor->classname ) ) + {//a vehicle missile + ent->s.eventParm = MOD_VEHICLE; + //store index into g_vehWeaponInfo + ent->s.weapon = inflictor->s.otherEntityNum2+1; + //store generic rocket or blaster type of missile + ent->s.generic1 = inflictor->s.weapon; + } + if ( wasInVehicle && self->s.number < MAX_CLIENTS ) + {//target is in a vehicle, store the entnum + ent->s.lookTarget = wasInVehicle; + } + if ( attacker ) + { + if ( attacker->s.m_iVehicleNum && attacker->s.number < MAX_CLIENTS ) + {//target is in a vehicle, store the entnum + ent->s.brokenLimbs = attacker->s.m_iVehicleNum; + } + else if ( ent->s.lookTarget + && !Q_stricmp( "func_rotating", attacker->classname ) ) + {//my vehicle was killed by a func_rotating, probably an asteroid, so... + ent->s.saberInFlight = qtrue; + } + } + ent->r.svFlags = SVF_BROADCAST; // send to everyone + ent->s.isJediMaster = wasJediMaster; + } +} + /* ================== player_die @@ -2069,9 +2120,7 @@ extern void Rancor_DropVictim( gentity_t *self ); extern qboolean g_dontFrickinCheck; extern qboolean g_endPDuel; -extern qboolean g_noPDuelCheck; void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int meansOfDeath ) { - gentity_t *ent; int anim; int contents; int killer; @@ -2079,6 +2128,10 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int char *killerName, *obit; qboolean wasJediMaster = qfalse; int sPMType = 0; + int wasInVehicle = 0; + gentity_t *tempInflictorEnt = inflictor; + qboolean tempInflictor = qfalse; + int actualMOD = meansOfDeath; if ( self->client->ps.pm_type == PM_DEAD ) { return; @@ -2130,6 +2183,18 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int if (murderPilot->inuse && murderPilot->client) { //give the pilot of the offending vehicle credit for the kill murderer = murderPilot; + actualMOD = self->client->otherKillerMOD; + if ( self->client->otherKillerVehWeapon > 0 ) + { + tempInflictorEnt = G_Spawn(); + if ( tempInflictorEnt ) + {//fake up the inflictor + tempInflictor = qtrue; + tempInflictorEnt->classname = "vehicle_proj"; + tempInflictorEnt->s.otherEntityNum2 = self->client->otherKillerVehWeapon-1; + tempInflictorEnt->s.weapon = self->client->otherKillerWeaponType; + } + } } } } @@ -2171,9 +2236,16 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int } //no valid murderer.. just use self I guess - if (!murderer) + if (!murderer) { - murderer = self; + if ( !attacker ) + { + murderer = self; + } + else + { + murderer = attacker; + } } if ( self->m_pVehicle->m_pVehicleInfo->hideRider ) @@ -2181,11 +2253,10 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int killEnt = (gentity_t *)self->m_pVehicle->m_pPilot; if (killEnt && killEnt->inuse && killEnt->client) { - G_Damage(killEnt, murderer, murderer, NULL, killEnt->client->ps.origin, 99999, DAMAGE_NO_PROTECTION, MOD_BLASTER); + G_Damage(killEnt, tempInflictorEnt, murderer, NULL, killEnt->client->ps.origin, 99999, DAMAGE_NO_PROTECTION, actualMOD); } if ( self->m_pVehicle->m_pVehicleInfo ) - {//FIXME: this wile got stuck in an endless loop, that's BAD!! This method SUCKS (not initting "i", not incrementing it or using it directly, all sorts of badness), so I'm rewriting it - //while (i < self->m_pVehicle->m_iNumPassengers) + { int numPass = self->m_pVehicle->m_iNumPassengers; for ( i = 0; i < numPass && self->m_pVehicle->m_iNumPassengers; i++ ) {//go through and eject the last passenger @@ -2195,7 +2266,7 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int self->m_pVehicle->m_pVehicleInfo->Eject(self->m_pVehicle, (bgEntity_t *)killEnt, qtrue); if ( killEnt->inuse && killEnt->client ) { - G_Damage(killEnt, murderer, murderer, NULL, killEnt->client->ps.origin, 99999, DAMAGE_NO_PROTECTION, MOD_BLASTER); + G_Damage(killEnt, tempInflictorEnt, murderer, NULL, killEnt->client->ps.origin, 99999, DAMAGE_NO_PROTECTION, actualMOD); } } } @@ -2205,8 +2276,15 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int if (killEnt && killEnt->inuse && killEnt->client) { killEnt->flags &= ~FL_UNDYING; - G_Damage(killEnt, murderer, murderer, NULL, killEnt->client->ps.origin, 99999, DAMAGE_NO_PROTECTION, MOD_BLASTER); + G_Damage(killEnt, tempInflictorEnt, murderer, NULL, killEnt->client->ps.origin, 99999, DAMAGE_NO_PROTECTION, actualMOD); } + if ( tempInflictor ) + { + G_FreeEntity( tempInflictorEnt ); + } + tempInflictorEnt = inflictor; + tempInflictor = qfalse; + actualMOD = meansOfDeath; } self->client->ps.emplacedIndex = 0; @@ -2241,6 +2319,8 @@ void player_die( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int if (veh->inuse && veh->client && veh->m_pVehicle) { + //remember it for obit + wasInVehicle = (veh->m_pVehicle->m_pVehicleInfo-&g_vehicleInfo[0]); veh->m_pVehicle->m_pVehicleInfo->Eject(veh->m_pVehicle, (bgEntity_t *)self, qtrue); if (veh->m_pVehicle->m_pVehicleInfo->type == VH_FIGHTER) @@ -2376,6 +2456,9 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); self->client->ps.heldByClient = 0; self->client->beingThrown = 0; self->client->doingThrow = 0; + BG_ClearRocketLock( &self->client->ps ); + self->client->isHacking = 0; + self->client->ps.hackingTime = 0; if (inflictor && inflictor->activator && !inflictor->client && !attacker->client && inflictor->activator->client && inflictor->activator->inuse && @@ -2397,10 +2480,25 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); self->client->ps.fd.forceDeactivateAll = 1; if ((self == attacker || !attacker->client) && - (meansOfDeath == MOD_CRUSH || meansOfDeath == MOD_FALLING || meansOfDeath == MOD_TRIGGER_HURT || meansOfDeath == MOD_UNKNOWN) && + (meansOfDeath == MOD_CRUSH || meansOfDeath == MOD_FALLING || meansOfDeath == MOD_TRIGGER_HURT || meansOfDeath == MOD_UNKNOWN || meansOfDeath == MOD_SUICIDE) && self->client->ps.otherKillerTime > level.time) - { + {//remember who last attacked us attacker = &g_entities[self->client->ps.otherKiller]; + if ( self->client->otherKillerMOD != MOD_UNKNOWN ) + { + actualMOD = self->client->otherKillerMOD; + } + if ( self->client->otherKillerVehWeapon > 0 ) + { + tempInflictorEnt = G_Spawn(); + if ( tempInflictorEnt ) + {//fake up the inflictor + tempInflictor = qtrue; + tempInflictorEnt->classname = "vehicle_proj"; + tempInflictorEnt->s.otherEntityNum2 = self->client->otherKillerVehWeapon-1; + tempInflictorEnt->s.weapon = self->client->otherKillerWeaponType; + } + } } // check for an almost capture @@ -2462,15 +2560,10 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); G_LogWeaponFrag(killer, self->s.number); } - // broadcast the death event to everyone - if (self->s.eType != ET_NPC && !g_noPDuelCheck) + G_BroadcastObit( self, inflictor, attacker, killer, actualMOD, wasInVehicle, wasJediMaster ); + if ( tempInflictor ) { - ent = G_TempEntity( self->r.currentOrigin, EV_OBITUARY ); - ent->s.eventParm = meansOfDeath; - ent->s.otherEntityNum = self->s.number; - ent->s.otherEntityNum2 = killer; - ent->r.svFlags = SVF_BROADCAST; // send to everyone - ent->s.isJediMaster = wasJediMaster; + G_FreeEntity( tempInflictorEnt ); } self->enemy = attacker; @@ -2482,13 +2575,34 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); self->client->ps.fd.suicides++; } - if (attacker && attacker->client) { - attacker->client->lastkilled_client = self->s.number; + if (attacker && attacker->client) + {//killed by a client of some kind (player, NPC or vehicle) + if ( self->s.number < MAX_CLIENTS ) + {//only remember real clients + attacker->client->lastkilled_client = self->s.number; + } G_CheckVictoryScript(attacker); - if ( attacker == self || OnSameTeam (self, attacker ) ) { - if (g_gametype.integer == GT_DUEL) + if ( self->s.number >= MAX_CLIENTS//not a player client + && self->client //an NPC client + && self->client->NPC_class != CLASS_VEHICLE //not a vehicle + && self->s.m_iVehicleNum )//a droid in a vehicle + {//no credit for droid, you do get credit for the vehicle kill and the pilot (2 points) + } + else if ( meansOfDeath == MOD_COLLISION + || meansOfDeath == MOD_VEH_EXPLOSION ) + {//no credit for veh-veh collisions? + } + else if ( attacker == self || OnSameTeam (self, attacker ) ) + {//killed self or teammate + if ( meansOfDeath == MOD_FALLING + && attacker != self + && attacker->s.number < MAX_CLIENTS + && attacker->s.m_iVehicleNum ) + {//crushed by a teammate in a vehicle, no penalty + } + else if (g_gametype.integer == GT_DUEL) { //in duel, if you kill yourself, the person you are dueling against gets a kill for it int otherClNum = -1; if (level.sortedClients[0] == self->s.number) @@ -2514,6 +2628,12 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); else { AddScore( attacker, self->r.currentOrigin, -1 ); + if ( attacker != self + && attacker->s.number < MAX_CLIENTS + && self->s.number < MAX_CLIENTS ) + { + G_CheckTKAutoKickBan( attacker ); + } } if (g_gametype.integer == GT_JEDIMASTER) { @@ -2525,7 +2645,9 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); self->client->ps.isJediMaster = qfalse; } } - } else { + } + else + { if (g_gametype.integer == GT_JEDIMASTER) { if ((attacker->client && attacker->client->ps.isJediMaster) || @@ -2576,7 +2698,13 @@ extern void RunEmplacedWeapon( gentity_t *ent, usercmd_t **ucmd ); attacker->client->lastKillTime = level.time; } - } else { + } + else if ( meansOfDeath == MOD_COLLISION + || meansOfDeath == MOD_VEH_EXPLOSION ) + {//no credit for veh-veh collisions? + } + else + { if (self->client && self->client->ps.isJediMaster) { //killed ourself so return the saber to the original position //(to avoid people jumping off ledges and making the saber @@ -3239,8 +3367,10 @@ void G_GetDismemberBolt(gentity_t *self, vec3_t boltPoint, int limbType) boltAngles[2] = -boltMatrix.matrix[2][1]; te = G_TempEntity( boltPoint, EV_SABER_HIT ); - te->s.otherEntityNum = ENTITYNUM_NONE; - te->s.otherEntityNum2 = self->s.number; + te->s.otherEntityNum = self->s.number; + te->s.otherEntityNum2 = ENTITYNUM_NONE; + te->s.weapon = 0;//saberNum + te->s.legsAnim = 0;//bladeNum VectorCopy(boltPoint, te->s.origin); VectorCopy(boltAngles, te->s.angles); @@ -4237,6 +4367,11 @@ void G_LocationBasedDamageModifier(gentity_t *ent, vec3_t point, int mod, int df return; } + if ( ent->client && ent->client->NPC_class == CLASS_VEHICLE ) + {//no location-based damage on vehicles + return; + } + if ((d_saberGhoul2Collision.integer && ent->client && ent->client->g2LastSurfaceTime == level.time && mod == MOD_SABER) || //using ghoul2 collision? Then if the mod is a saber we should have surface data from the last hit (unless thrown). (d_projectileGhoul2Collision.integer && ent->client && ent->client->g2LastSurfaceTime == level.time)) //It's safe to assume we died from the projectile that just set our surface index. So, go ahead and use that as the surf I guess. { @@ -4325,6 +4460,89 @@ void G_Knockdown( gentity_t *victim ) } } +void G_ApplyVehicleOtherKiller( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, int mod, qboolean vehicleDying ) +{ + if ( targ && targ->client && attacker ) + { + if ( targ->client->ps.otherKillerDebounceTime > level.time ) + {//wait a minute, I already have a last damager + if ( targ->health < 0 + || (targ->m_pVehicle && targ->m_pVehicle->m_iRemovedSurfaces) ) + {//already dying? don't let credit transfer to anyone else + return; + } + //otherwise, still alive, so, fine, use this damager... + } + + targ->client->ps.otherKiller = attacker->s.number; + targ->client->ps.otherKillerTime = level.time + 25000; + targ->client->ps.otherKillerDebounceTime = level.time + 25000; + targ->client->otherKillerMOD = mod; + if ( inflictor && !Q_stricmp( "vehicle_proj", inflictor->classname ) ) + { + targ->client->otherKillerVehWeapon = inflictor->s.otherEntityNum2+1; + targ->client->otherKillerWeaponType = inflictor->s.weapon; + } + else + { + targ->client->otherKillerVehWeapon = 0; + targ->client->otherKillerWeaponType = WP_NONE; + } + if ( vehicleDying ) + { + //propogate otherkiller down to pilot and passengers so that proper credit is given if they suicide or eject... + if ( targ->m_pVehicle ) + { + int passNum; + if ( targ->m_pVehicle->m_pPilot ) + { + gentity_t *pilot = &g_entities[targ->m_pVehicle->m_pPilot->s.number]; + if ( pilot->client ) + { + pilot->client->ps.otherKiller = targ->client->ps.otherKiller; + pilot->client->ps.otherKillerTime = targ->client->ps.otherKillerTime; + pilot->client->ps.otherKillerDebounceTime = targ->client->ps.otherKillerDebounceTime; + pilot->client->otherKillerMOD = targ->client->otherKillerMOD; + pilot->client->otherKillerVehWeapon = targ->client->otherKillerVehWeapon; + pilot->client->otherKillerWeaponType = targ->client->otherKillerWeaponType; + } + } + for ( passNum = 0; passNum < targ->m_pVehicle->m_iNumPassengers; passNum++ ) + { + gentity_t *pass = &g_entities[targ->m_pVehicle->m_ppPassengers[passNum]->s.number]; + if ( pass->client ) + { + pass->client->ps.otherKiller = targ->client->ps.otherKiller; + pass->client->ps.otherKillerTime = targ->client->ps.otherKillerTime; + pass->client->ps.otherKillerDebounceTime = targ->client->ps.otherKillerDebounceTime; + pass->client->otherKillerMOD = targ->client->otherKillerMOD; + pass->client->otherKillerVehWeapon = targ->client->otherKillerVehWeapon; + pass->client->otherKillerWeaponType = targ->client->otherKillerWeaponType; + } + } + } + } + } +} + +qboolean G_CheckVehicleNPCTeamDamage( gentity_t *ent ) +{ + //NOTE: this covers both the vehicle and NPCs riding vehicles (droids) + if ( !ent || ent->s.number < MAX_CLIENTS || ent->s.eType != ET_NPC ) + {//not valid or a real client or not an NPC + return qfalse; + } + + if ( ent->s.NPC_class != CLASS_VEHICLE ) + {//regualar NPC + if ( ent->s.m_iVehicleNum ) + {//an NPC in a vehicle, check for team damage + return qtrue; + } + } + return qfalse; +} + /* ============ T_Damage @@ -4448,10 +4666,13 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, mod != MOD_CONC_ALT && mod != MOD_SABER && mod != MOD_TURBLAST && + mod != MOD_TARGET_LASER && mod != MOD_SUICIDE && mod != MOD_FALLING && mod != MOD_CRUSH && mod != MOD_TELEFRAG && + mod != MOD_COLLISION && + mod != MOD_VEH_EXPLOSION && mod != MOD_TRIGGER_HURT) { if ( mod != MOD_MELEE || !G_HeavyMelee( attacker ) ) @@ -4499,9 +4720,12 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, } } - if (targ && targ->client && (targ->client->ps.fd.forcePowersActive & (1 << FP_RAGE))) - { - damage *= 0.5; + if ( !(dflags & DAMAGE_NO_PROTECTION) ) + {//rage overridden by no_protection + if (targ && targ->client && (targ->client->ps.fd.forcePowersActive & (1 << FP_RAGE))) + { + damage *= 0.5; + } } // the intermission has allready been qualified for, so don't @@ -4527,7 +4751,11 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, } // reduce damage by the attacker's handicap value // unless they are rocket jumping - if ( attacker->client && attacker != targ && attacker->s.eType == ET_PLAYER ) { + if ( attacker->client + && attacker != targ + && attacker->s.eType == ET_PLAYER + && g_gametype.integer != GT_SIEGE ) + { max = attacker->client->ps.stats[STAT_MAX_HEALTH]; damage = damage * max / 100; } @@ -4590,7 +4818,48 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, if (mod == MOD_SABER) { - VectorScale (dir, (g_knockback.value * (float)knockback / mass)*g_saberDmgVelocityScale.integer, kvel); + float saberKnockbackScale = g_saberDmgVelocityScale.value; + if ( (dflags&DAMAGE_SABER_KNOCKBACK1) + || (dflags&DAMAGE_SABER_KNOCKBACK2) ) + {//saber does knockback, scale it by the right number + if ( !saberKnockbackScale ) + { + saberKnockbackScale = 1.0f; + } + if ( attacker + && attacker->client ) + { + if ( (dflags&DAMAGE_SABER_KNOCKBACK1) ) + { + if ( attacker && attacker->client ) + { + saberKnockbackScale *= attacker->client->saber[0].knockbackScale; + } + } + if ( (dflags&DAMAGE_SABER_KNOCKBACK1_B2) ) + { + if ( attacker && attacker->client ) + { + saberKnockbackScale *= attacker->client->saber[0].knockbackScale2; + } + } + if ( (dflags&DAMAGE_SABER_KNOCKBACK2) ) + { + if ( attacker && attacker->client ) + { + saberKnockbackScale *= attacker->client->saber[1].knockbackScale; + } + } + if ( (dflags&DAMAGE_SABER_KNOCKBACK2_B2) ) + { + if ( attacker && attacker->client ) + { + saberKnockbackScale *= attacker->client->saber[1].knockbackScale2; + } + } + } + } + VectorScale (dir, (g_knockback.value * (float)knockback / mass)*saberKnockbackScale, kvel); } else { @@ -4598,22 +4867,9 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, } VectorAdd (targ->client->ps.velocity, kvel, targ->client->ps.velocity); - if (attacker && attacker->client && attacker != targ) - { - float dur = 5000; - float dur2 = 100; - if (targ->client && targ->s.eType == ET_NPC && targ->s.NPC_class == CLASS_VEHICLE) - { - dur = 25000; - dur2 = 25000; - } - targ->client->ps.otherKiller = attacker->s.number; - targ->client->ps.otherKillerTime = level.time + dur; - targ->client->ps.otherKillerDebounceTime = level.time + dur2; - } // set the timer so that the other client can't cancel // out the movement immediately - if ( !targ->client->ps.pm_time && (g_saberDmgVelocityScale.integer || mod != MOD_SABER) ) { + if ( !targ->client->ps.pm_time && (g_saberDmgVelocityScale.integer || mod != MOD_SABER || (dflags&DAMAGE_SABER_KNOCKBACK1) || (dflags&DAMAGE_SABER_KNOCKBACK2) || (dflags&DAMAGE_SABER_KNOCKBACK1_B2) || (dflags&DAMAGE_SABER_KNOCKBACK2_B2) ) ) { int t; t = knockback * 2; @@ -4627,13 +4883,6 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, targ->client->ps.pm_flags |= PMF_TIME_KNOCKBACK; } } - else if (targ->client && targ->s.eType == ET_NPC && targ->s.NPC_class == CLASS_VEHICLE && attacker != targ) - { - targ->client->ps.otherKiller = attacker->s.number; - targ->client->ps.otherKillerTime = level.time + 25000; - targ->client->ps.otherKillerDebounceTime = level.time + 25000; - } - if ( (g_trueJedi.integer || g_gametype.integer == GT_SIEGE) && client ) @@ -4838,6 +5087,25 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, if ( damage < 1 ) { damage = 1; } + + //store the attacker as the potential killer in case we die by other means + if ( targ->client && attacker && attacker != targ ) + { + if ( targ->s.eType == ET_NPC && targ->s.NPC_class == CLASS_VEHICLE) + {//vehicle + G_ApplyVehicleOtherKiller( targ, inflictor, attacker, mod, qfalse ); + } + else + {//other client + targ->client->ps.otherKiller = attacker->s.number; + targ->client->ps.otherKillerTime = level.time + 5000; + targ->client->ps.otherKillerDebounceTime = level.time + 100; + targ->client->otherKillerMOD = mod; + targ->client->otherKillerVehWeapon = 0; + targ->client->otherKillerWeaponType = WP_NONE; + } + } + take = damage; save = 0; @@ -4916,9 +5184,15 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, { if ( targ->locationDamage[surface] >= deathPoint) { //this area of the ship is now dead + qboolean wasDying = (targ->m_pVehicle->m_iRemovedSurfaces!=0); if ( G_FlyVehicleDestroySurface( targ, surface ) ) {//actually took off a surface G_VehicleSetDamageLocFlags( targ, surface, deathPoint ); + if ( !wasDying ) + {//always take credit for kill if they were healthy before + targ->client->ps.otherKillerDebounceTime = 0; + } + G_ApplyVehicleOtherKiller( targ, inflictor, attacker, mod, qtrue ); } } else @@ -5136,71 +5410,74 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, targ->client->lasthurt_mod = mod; } - if (take && targ->client && (targ->client->ps.fd.forcePowersActive & (1 << FP_PROTECT))) - { - if (targ->client->ps.fd.forcePower) + if ( !(dflags & DAMAGE_NO_PROTECTION) ) + {//protect overridden by no_protection + if (take && targ->client && (targ->client->ps.fd.forcePowersActive & (1 << FP_PROTECT))) { - int maxtake = take; - - //G_Sound(targ, CHAN_AUTO, protectHitSound); - if (targ->client->forcePowerSoundDebounce < level.time) + if (targ->client->ps.fd.forcePower) { - G_PreDefSound(targ->client->ps.origin, PDSOUND_PROTECTHIT); - targ->client->forcePowerSoundDebounce = level.time + 400; - } + int maxtake = take; - if (targ->client->ps.fd.forcePowerLevel[FP_PROTECT] == FORCE_LEVEL_1) - { - famt = 1; - hamt = 0.40; - - if (maxtake > 100) + //G_Sound(targ, CHAN_AUTO, protectHitSound); + if (targ->client->forcePowerSoundDebounce < level.time) { - maxtake = 100; + G_PreDefSound(targ->client->ps.origin, PDSOUND_PROTECTHIT); + targ->client->forcePowerSoundDebounce = level.time + 400; } - } - else if (targ->client->ps.fd.forcePowerLevel[FP_PROTECT] == FORCE_LEVEL_2) - { - famt = 0.5; - hamt = 0.60; - if (maxtake > 200) + if (targ->client->ps.fd.forcePowerLevel[FP_PROTECT] == FORCE_LEVEL_1) { - maxtake = 200; + famt = 1; + hamt = 0.40; + + if (maxtake > 100) + { + maxtake = 100; + } } - } - else if (targ->client->ps.fd.forcePowerLevel[FP_PROTECT] == FORCE_LEVEL_3) - { - famt = 0.25; - hamt = 0.80; - - if (maxtake > 400) + else if (targ->client->ps.fd.forcePowerLevel[FP_PROTECT] == FORCE_LEVEL_2) { - maxtake = 400; + famt = 0.5; + hamt = 0.60; + + if (maxtake > 200) + { + maxtake = 200; + } } - } - - if (!targ->client->ps.powerups[PW_FORCE_BOON]) - { - targ->client->ps.fd.forcePower -= maxtake*famt; - } - else - { - targ->client->ps.fd.forcePower -= (maxtake*famt)/2; - } - subamt = (maxtake*hamt)+(take-maxtake); - if (targ->client->ps.fd.forcePower < 0) - { - subamt += targ->client->ps.fd.forcePower; - targ->client->ps.fd.forcePower = 0; - } - if (subamt) - { - take -= subamt; - - if (take < 0) + else if (targ->client->ps.fd.forcePowerLevel[FP_PROTECT] == FORCE_LEVEL_3) { - take = 0; + famt = 0.25; + hamt = 0.80; + + if (maxtake > 400) + { + maxtake = 400; + } + } + + if (!targ->client->ps.powerups[PW_FORCE_BOON]) + { + targ->client->ps.fd.forcePower -= maxtake*famt; + } + else + { + targ->client->ps.fd.forcePower -= (maxtake*famt)/2; + } + subamt = (maxtake*hamt)+(take-maxtake); + if (targ->client->ps.fd.forcePower < 0) + { + subamt += targ->client->ps.fd.forcePower; + targ->client->ps.fd.forcePower = 0; + } + if (subamt) + { + take -= subamt; + + if (take < 0) + { + take = 0; + } } } } @@ -5269,9 +5546,12 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, } } - if (targ->client && (targ->client->ps.fd.forcePowersActive & (1 << FP_RAGE)) && (inflictor->client || attacker->client)) - { - take /= (targ->client->ps.fd.forcePowerLevel[FP_RAGE]+1); + if ( !(dflags & DAMAGE_NO_PROTECTION) ) + {//rage overridden by no_protection + if (targ->client && (targ->client->ps.fd.forcePowersActive & (1 << FP_RAGE)) && (inflictor->client || attacker->client)) + { + take /= (targ->client->ps.fd.forcePowerLevel[FP_RAGE]+1); + } } targ->health = targ->health - take; @@ -5287,15 +5567,18 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, targ->client->ps.stats[STAT_HEALTH] = targ->health; } - if (targ->client && (targ->client->ps.fd.forcePowersActive & (1 << FP_RAGE)) && (inflictor->client || attacker->client)) - { - if (targ->health <= 0) + if ( !(dflags & DAMAGE_NO_PROTECTION) ) + {//rage overridden by no_protection + if (targ->client && (targ->client->ps.fd.forcePowersActive & (1 << FP_RAGE)) && (inflictor->client || attacker->client)) { - targ->health = 1; - } - if (targ->client->ps.stats[STAT_HEALTH] <= 0) - { - targ->client->ps.stats[STAT_HEALTH] = 1; + if (targ->health <= 0) + { + targ->health = 1; + } + if (targ->client->ps.stats[STAT_HEALTH] <= 0) + { + targ->client->ps.stats[STAT_HEALTH] = 1; + } } } @@ -5387,7 +5670,8 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, (targ->s.eFlags & EF_DEAD)) { //an NPC that's already dead. Maybe we can cut some more limbs off! if ( (mod == MOD_SABER || (mod == MOD_MELEE && G_HeavyMelee( attacker )) )//saber or heavy melee (claws) - && take > 2) + && take > 2 + && !(dflags&DAMAGE_NO_DISMEMBER) ) { G_CheckForDismemberment(targ, attacker, targ->pos1, take, targ->client->ps.torsoAnim, qtrue); } @@ -5430,6 +5714,48 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, } +void G_DamageFromKiller( gentity_t *pEnt, gentity_t *pVehEnt, gentity_t *attacker, vec3_t org, int damage, int dflags, int mod ) +{ + gentity_t *killer = attacker, *inflictor = attacker; + qboolean tempInflictor = qfalse; + if ( !pEnt || !pVehEnt || !pVehEnt->client ) + { + return; + } + if (pVehEnt->client->ps.otherKiller < ENTITYNUM_WORLD && + pVehEnt->client->ps.otherKillerTime > level.time) + { + gentity_t *potentialKiller = &g_entities[pVehEnt->client->ps.otherKiller]; + + if ( potentialKiller->inuse )//&& potentialKiller->client) + { //he's valid I guess + killer = potentialKiller; + mod = pVehEnt->client->otherKillerMOD; + inflictor = killer; + if ( pVehEnt->client->otherKillerVehWeapon > 0 ) + { + inflictor = G_Spawn(); + if ( inflictor ) + {//fake up the inflictor + tempInflictor = qtrue; + inflictor->classname = "vehicle_proj"; + inflictor->s.otherEntityNum2 = pVehEnt->client->otherKillerVehWeapon-1; + inflictor->s.weapon = pVehEnt->client->otherKillerWeaponType; + } + } + } + } + //FIXME: damage hitEnt, some, too? Our explosion should hurt them some, but... + if ( killer && killer->s.eType == ET_NPC && killer->s.NPC_class == CLASS_VEHICLE && killer->m_pVehicle && killer->m_pVehicle->m_pPilot ) + { + killer = (gentity_t *)killer->m_pVehicle->m_pPilot; + } + G_Damage( pEnt, inflictor, killer, NULL, org, damage, dflags, mod ); + if ( tempInflictor ) + { + G_FreeEntity( inflictor ); + } +} /* ============ @@ -5577,11 +5903,11 @@ qboolean G_RadiusDamage ( vec3_t origin, gentity_t *attacker, float damage, floa attacker->s.eType == ET_NPC && attacker->s.NPC_class == CLASS_VEHICLE && attacker->m_pVehicle && attacker->m_pVehicle->m_pPilot) { //say my pilot did it. - G_Damage (ent, NULL, (gentity_t *)attacker->m_pVehicle->m_pPilot, dir, origin, (int)points, DAMAGE_RADIUS, mod); + G_Damage (ent, missile, (gentity_t *)attacker->m_pVehicle->m_pPilot, dir, origin, (int)points, DAMAGE_RADIUS, mod); } else { - G_Damage (ent, NULL, attacker, dir, origin, (int)points, DAMAGE_RADIUS, mod); + G_Damage (ent, missile, attacker, dir, origin, (int)points, DAMAGE_RADIUS, mod); } if (ent && ent->client && roastPeople && missile && diff --git a/codemp/game/g_local.h b/codemp/game/g_local.h index fdf7c7e..8c1023c 100644 --- a/codemp/game/g_local.h +++ b/codemp/game/g_local.h @@ -26,7 +26,7 @@ extern vec3_t gPainPoint; //================================================================== // the "gameversion" client command will print this plus compile date -#define GAMEVERSION "basejk" +#define GAMEVERSION "basejka" #define BODY_QUEUE_SIZE 8 @@ -425,6 +425,9 @@ typedef struct { char saber2Type[64]; int duelTeam; int siegeDesiredTeam; + int killCount; + int TKCount; + char IPstring[32]; // yeah, I know, could be 16, but, just in case... } clientSession_t; // playerstate mGameFlags @@ -737,6 +740,11 @@ struct gclient_s { int lastGenCmd; int lastGenCmdTime; + + //can't put these in playerstate, crashes game (need to change exe?) + int otherKillerMOD; + int otherKillerVehWeapon; + int otherKillerWeaponType; }; //Interest points @@ -1095,6 +1103,8 @@ qboolean trap_G2API_RemoveGhoul2Models(void *ghlInfo); void trap_G2API_CleanGhoul2Models(void **ghoul2Ptr); void trap_G2API_CollisionDetect ( CollisionRecord_t *collRecMap, void* ghoul2, const vec3_t angles, const vec3_t position, int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, int traceFlags, int useLod, float fRadius ); +void trap_G2API_CollisionDetectCache ( CollisionRecord_t *collRecMap, void* ghoul2, const vec3_t angles, const vec3_t position, + int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, int traceFlags, int useLod, float fRadius ); qboolean trap_G2API_SetBoneAngles(void *ghoul2, int modelIndex, const char *boneName, const vec3_t angles, const int flags, const int up, const int right, const int forward, qhandle_t *modelList, @@ -1173,6 +1183,11 @@ extern int gGAvoidDismember; #define DAMAGE_HEAVY_WEAP_CLASS 0x00001000 // Heavy damage #define DAMAGE_NO_HIT_LOC 0x00002000 // No hit location #define DAMAGE_NO_SELF_PROTECTION 0x00004000 // Dont apply half damage to self attacks +#define DAMAGE_NO_DISMEMBER 0x00008000 // Dont do dismemberment +#define DAMAGE_SABER_KNOCKBACK1 0x00010000 // Check the attacker's first saber for a knockbackScale +#define DAMAGE_SABER_KNOCKBACK2 0x00020000 // Check the attacker's second saber for a knockbackScale +#define DAMAGE_SABER_KNOCKBACK1_B2 0x00040000 // Check the attacker's first saber for a knockbackScale2 +#define DAMAGE_SABER_KNOCKBACK2_B2 0x00080000 // Check the attacker's second saber for a knockbackScale2 // // g_exphysics.c // @@ -1261,7 +1276,7 @@ team_t TeamCount( int ignoreClientNum, int team ); int TeamLeader( int team ); team_t PickTeam( int ignoreClientNum ); void SetClientViewAngle( gentity_t *ent, vec3_t angle ); -gentity_t *SelectSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles ); +gentity_t *SelectSpawnPoint ( vec3_t avoidPoint, vec3_t origin, vec3_t angles, team_t team ); void MaintainBodyQueue(gentity_t *ent); void respawn (gentity_t *ent); void BeginIntermission (void); @@ -1545,6 +1560,8 @@ extern vmCvar_t d_projectileGhoul2Collision; extern vmCvar_t g_g2TraceLod; +extern vmCvar_t g_optvehtrace; + extern vmCvar_t g_locationBasedDamage; extern vmCvar_t g_allowHighPingDuelist; @@ -1601,6 +1618,7 @@ extern vmCvar_t g_warmup; extern vmCvar_t g_doWarmup; extern vmCvar_t g_blood; extern vmCvar_t g_allowVote; +extern vmCvar_t g_allowTeamVote; extern vmCvar_t g_teamAutoJoin; extern vmCvar_t g_teamForceBalance; extern vmCvar_t g_banIPs; @@ -1608,8 +1626,8 @@ extern vmCvar_t g_filterBan; extern vmCvar_t g_debugForward; extern vmCvar_t g_debugRight; extern vmCvar_t g_debugUp; -extern vmCvar_t g_redteam; -extern vmCvar_t g_blueteam; +//extern vmCvar_t g_redteam; +//extern vmCvar_t g_blueteam; extern vmCvar_t g_smoothClients; #include "../namespace_begin.h" @@ -1617,8 +1635,6 @@ extern vmCvar_t pmove_fixed; extern vmCvar_t pmove_msec; #include "../namespace_end.h" -extern vmCvar_t g_rankings; -extern vmCvar_t g_enableDust; extern vmCvar_t g_enableBreath; extern vmCvar_t g_singlePlayer; extern vmCvar_t g_dismember; diff --git a/codemp/game/g_log.c b/codemp/game/g_log.c index 9c29e21..8237856 100644 --- a/codemp/game/g_log.c +++ b/codemp/game/g_log.c @@ -70,6 +70,7 @@ int weaponFromMOD[MOD_MAX] = WP_NONE, //MOD_CRUSH, WP_NONE, //MOD_TELEFRAG, WP_NONE, //MOD_FALLING, + WP_NONE, //MOD_COLLISION, WP_NONE, //MOD_SUICIDE, WP_NONE, //MOD_TARGET_LASER, WP_NONE, //MOD_TRIGGER_HURT, diff --git a/codemp/game/g_main.c b/codemp/game/g_main.c index cd5181d..c796bf3 100644 --- a/codemp/game/g_main.c +++ b/codemp/game/g_main.c @@ -74,6 +74,8 @@ vmCvar_t d_projectileGhoul2Collision; vmCvar_t g_g2TraceLod; +vmCvar_t g_optvehtrace; + vmCvar_t g_locationBasedDamage; vmCvar_t g_allowHighPingDuelist; @@ -140,6 +142,7 @@ vmCvar_t g_blood; vmCvar_t g_podiumDist; vmCvar_t g_podiumDrop; vmCvar_t g_allowVote; +vmCvar_t g_allowTeamVote; vmCvar_t g_teamAutoJoin; vmCvar_t g_teamForceBalance; vmCvar_t g_banIPs; @@ -154,12 +157,10 @@ vmCvar_t pmove_fixed; vmCvar_t pmove_msec; #include "../namespace_end.h" -vmCvar_t g_rankings; vmCvar_t g_listEntity; -vmCvar_t g_redteam; -vmCvar_t g_blueteam; +//vmCvar_t g_redteam; +//vmCvar_t g_blueteam; vmCvar_t g_singlePlayer; -vmCvar_t g_enableDust; vmCvar_t g_enableBreath; vmCvar_t g_dismember; vmCvar_t g_forceDodge; @@ -174,6 +175,11 @@ vmCvar_t g_saberDebugPrint; vmCvar_t g_siegeTeamSwitch; vmCvar_t bg_fighterAltControl; +vmCvar_t g_vehAutoAimLead; +vmCvar_t g_autoKickKillSpammers; +vmCvar_t g_autoBanKillSpammers; +vmCvar_t g_autoKickTKSpammers; +vmCvar_t g_autoBanTKSpammers; #ifdef DEBUG_SABER_BOX vmCvar_t g_saberDebugBox; @@ -237,22 +243,22 @@ static cvarTable_t gameCvarTable[] = { { NULL, "sv_mapname", "", CVAR_SERVERINFO | CVAR_ROM, 0, qfalse }, // latched vars - { &g_gametype, "g_gametype", "0", CVAR_SERVERINFO | CVAR_USERINFO | CVAR_LATCH, 0, qfalse }, - { &g_MaxHolocronCarry, "g_MaxHolocronCarry", "3", CVAR_SERVERINFO | CVAR_USERINFO | CVAR_LATCH, 0, qfalse }, + { &g_gametype, "g_gametype", "0", CVAR_SERVERINFO | CVAR_LATCH, 0, qfalse }, + { &g_MaxHolocronCarry, "g_MaxHolocronCarry", "3", CVAR_SERVERINFO | CVAR_LATCH, 0, qfalse }, { &g_maxclients, "sv_maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse }, { &g_maxGameClients, "g_maxGameClients", "0", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qfalse }, + { &g_trueJedi, "g_jediVmerc", "0", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qtrue }, + // change anytime vars { &g_ff_objectives, "g_ff_objectives", "0", /*CVAR_SERVERINFO |*/ CVAR_CHEAT | CVAR_NORESTART, 0, qtrue }, - { &g_trueJedi, "g_jediVmerc", "0", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE, 0, qtrue }, - { &g_autoMapCycle, "g_autoMapCycle", "0", CVAR_ARCHIVE | CVAR_NORESTART, 0, qtrue }, { &g_dmflags, "dmflags", "0", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue }, - { &g_maxForceRank, "g_maxForceRank", "6", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_USERINFO | CVAR_LATCH, 0, qfalse }, - { &g_forceBasedTeams, "g_forceBasedTeams", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_USERINFO | CVAR_LATCH, 0, qfalse }, + { &g_maxForceRank, "g_maxForceRank", "6", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_LATCH, 0, qfalse }, + { &g_forceBasedTeams, "g_forceBasedTeams", "0", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_LATCH, 0, qfalse }, { &g_privateDuel, "g_privateDuel", "1", CVAR_SERVERINFO | CVAR_ARCHIVE, 0, qtrue }, { &g_allowNPC, "g_allowNPC", "1", CVAR_SERVERINFO | CVAR_CHEAT, 0, qtrue }, @@ -285,6 +291,8 @@ static cvarTable_t gameCvarTable[] = { { &g_g2TraceLod, "g_g2TraceLod", "3", 0, 0, qtrue }, + { &g_optvehtrace, "com_optvehtrace", "0", 0, 0, qtrue }, + { &g_locationBasedDamage, "g_locationBasedDamage", "1", 0, 0, qtrue }, { &g_allowHighPingDuelist, "g_allowHighPingDuelist", "1", 0, 0, qtrue }, @@ -370,6 +378,7 @@ static cvarTable_t gameCvarTable[] = { { &g_podiumDrop, "g_podiumDrop", "70", 0, 0, qfalse }, { &g_allowVote, "g_allowVote", "1", CVAR_ARCHIVE, 0, qfalse }, + { &g_allowTeamVote, "g_allowTeamVote", "1", CVAR_ARCHIVE, 0, qfalse }, { &g_listEntity, "g_listEntity", "0", 0, 0, qfalse }, #if 0 @@ -378,18 +387,15 @@ static cvarTable_t gameCvarTable[] = { { &g_debugUp, "g_debugUp", "0", 0, 0, qfalse }, #endif - { &g_redteam, "g_redteam", "Empire", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO , 0, qtrue, qtrue }, - { &g_blueteam, "g_blueteam", "Rebellion", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO , 0, qtrue, qtrue }, +// { &g_redteam, "g_redteam", "Empire", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO , 0, qtrue, qtrue }, +// { &g_blueteam, "g_blueteam", "Rebellion", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_USERINFO , 0, qtrue, qtrue }, { &g_singlePlayer, "ui_singlePlayerActive", "", 0, 0, qfalse, qfalse }, - { &g_enableDust, "g_enableDust", "0", 0, 0, qtrue, qfalse }, { &g_enableBreath, "g_enableBreath", "0", 0, 0, qtrue, qfalse }, { &g_smoothClients, "g_smoothClients", "1", 0, 0, qfalse}, { &pmove_fixed, "pmove_fixed", "0", CVAR_SYSTEMINFO, 0, qfalse}, { &pmove_msec, "pmove_msec", "8", CVAR_SYSTEMINFO, 0, qfalse}, - { &g_rankings, "g_rankings", "0", 0, 0, qfalse}, - { &g_dismember, "g_dismember", "0", CVAR_ARCHIVE, 0, qtrue }, { &g_forceDodge, "g_forceDodge", "1", 0, 0, qtrue }, @@ -412,6 +418,11 @@ static cvarTable_t gameCvarTable[] = { { &g_siegeTeamSwitch, "g_siegeTeamSwitch", "1", CVAR_SERVERINFO|CVAR_ARCHIVE, qfalse }, { &bg_fighterAltControl, "bg_fighterAltControl", "0", CVAR_SERVERINFO, 0, qtrue }, + { &g_vehAutoAimLead, "g_vehAutoAimLead", "0", CVAR_ARCHIVE }, + { &g_autoKickKillSpammers, "g_autoKickKillSpammers", "0", CVAR_ARCHIVE, 0, qtrue }, + { &g_autoBanKillSpammers, "g_autoBanKillSpammers", "0", CVAR_ARCHIVE, 0, qtrue }, + { &g_autoKickTKSpammers, "g_autoKickTKSpammers", "0", CVAR_ARCHIVE, 0, qtrue }, + { &g_autoBanTKSpammers, "g_autoBanTKSpammers", "0", CVAR_ARCHIVE, 0, qtrue }, #ifdef DEBUG_SABER_BOX { &g_saberDebugBox, "g_saberDebugBox", "0", CVAR_CHEAT, 0, qfalse }, @@ -445,7 +456,7 @@ static cvarTable_t gameCvarTable[] = { { &d_saberCombat, "d_saberCombat", "0", CVAR_CHEAT }, - { &g_spskill, "g_npcspskill", "0", CVAR_ARCHIVE | CVAR_USERINFO }, + { &g_spskill, "g_npcspskill", "0", CVAR_ARCHIVE | CVAR_INTERNAL }, //for overriding the level defaults { &g_siegeTeam1, "g_siegeTeam1", "none", CVAR_ARCHIVE|CVAR_SERVERINFO, 0, qfalse }, @@ -498,6 +509,9 @@ This must be the very first function compiled into the .q3vm file ================ */ #include "../namespace_begin.h" +#ifdef __linux__ +extern "C" { +#endif int vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) { switch ( command ) { case GAME_INIT: @@ -680,6 +694,9 @@ int vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int a return -1; } +#ifdef __linux__ +} +#endif #include "../namespace_end.h" @@ -876,6 +893,7 @@ G_InitGame */ extern void RemoveAllWP(void); extern void BG_ClearVehicleParseParms(void); +extern void G_LoadIPBans(void); void G_InitGame( int levelTime, int randomSeed, int restart ) { int i; vmCvar_t mapname; @@ -912,7 +930,8 @@ void G_InitGame( int levelTime, int randomSeed, int restart ) { G_RegisterCvars(); - G_ProcessIPBans(); + //G_ProcessIPBans(); + G_LoadIPBans(); G_InitMemory(); @@ -1105,12 +1124,14 @@ void G_InitGame( int levelTime, int randomSeed, int restart ) { G_ShutdownGame ================= */ +extern void G_SaveBanIP( void ); void G_ShutdownGame( int restart ) { int i = 0; gentity_t *ent; // G_Printf ("==== ShutdownGame ====\n"); + G_SaveBanIP(); G_CleanAllFakeClients(); //get rid of dynamically allocated fake client structs. BG_ClearAnimsets(); //free all dynamic allocations made through the engine @@ -1952,14 +1973,43 @@ FindIntermissionPoint This is also used for spectator spawns ================== */ +extern qboolean gSiegeRoundBegun; +extern qboolean gSiegeRoundEnded; +extern qboolean gSiegeRoundWinningTeam; void FindIntermissionPoint( void ) { - gentity_t *ent, *target; + gentity_t *ent = NULL; + gentity_t *target; vec3_t dir; // find the intermission spot - ent = G_Find (NULL, FOFS(classname), "info_player_intermission"); + if ( g_gametype.integer == GT_SIEGE + && level.intermissiontime + && level.intermissiontime <= level.time + && gSiegeRoundEnded ) + { + if (gSiegeRoundWinningTeam == SIEGETEAM_TEAM1) + { + ent = G_Find (NULL, FOFS(classname), "info_player_intermission_red"); + if ( ent && ent->target2 ) + { + G_UseTargets2( ent, ent, ent->target2 ); + } + } + else if (gSiegeRoundWinningTeam == SIEGETEAM_TEAM2) + { + ent = G_Find (NULL, FOFS(classname), "info_player_intermission_blue"); + if ( ent && ent->target2 ) + { + G_UseTargets2( ent, ent, ent->target2 ); + } + } + } + if ( !ent ) + { + ent = G_Find (NULL, FOFS(classname), "info_player_intermission"); + } if ( !ent ) { // the map creator forgot to put in an intermission point... - SelectSpawnPoint ( vec3_origin, level.intermission_origin, level.intermission_angle ); + SelectSpawnPoint ( vec3_origin, level.intermission_origin, level.intermission_angle, TEAM_SPECTATOR ); } else { VectorCopy (ent->s.origin, level.intermission_origin); VectorCopy (ent->s.angles, level.intermission_angle); @@ -3223,8 +3273,9 @@ void CheckVote( void ) { if (g_fraglimitVoteCorrection.integer) { //This means to auto-correct fraglimit when voting to and from duel. - int currentGT = trap_Cvar_VariableIntegerValue("g_gametype"); - int currentFL = trap_Cvar_VariableIntegerValue("fraglimit"); + const int currentGT = trap_Cvar_VariableIntegerValue("g_gametype"); + const int currentFL = trap_Cvar_VariableIntegerValue("fraglimit"); + const int currentTL = trap_Cvar_VariableIntegerValue("timelimit"); if ((level.votingGametypeTo == GT_DUEL || level.votingGametypeTo == GT_POWERDUEL) && currentGT != GT_DUEL && currentGT != GT_POWERDUEL) { @@ -3232,6 +3283,10 @@ void CheckVote( void ) { { //if voting to duel, and fraglimit is more than 3 (or unlimited), then set it down to 3 trap_SendConsoleCommand(EXEC_APPEND, "fraglimit 3\n"); } + if (currentTL) + { //if voting to duel, and timelimit is set, make it unlimited + trap_SendConsoleCommand(EXEC_APPEND, "timelimit 0\n"); + } } else if ((level.votingGametypeTo != GT_DUEL && level.votingGametypeTo != GT_POWERDUEL) && (currentGT == GT_DUEL || currentGT == GT_POWERDUEL)) diff --git a/codemp/game/g_missile.c b/codemp/game/g_missile.c index b22f6aa..a409b49 100644 --- a/codemp/game/g_missile.c +++ b/codemp/game/g_missile.c @@ -232,6 +232,13 @@ void G_ExplodeMissile( gentity_t *ent ) { ent->takedamage = qfalse; // splash damage if ( ent->splashDamage ) { + //NOTE: vehicle missiles don't have an ent->parent set, so check that here and set it + if ( ent->s.eType == ET_MISSILE//missile + && (ent->s.eFlags&EF_JETPACK_ACTIVE)//vehicle missile + && ent->r.ownerNum < MAX_CLIENTS )//valid client owner + {//set my parent to my owner for purposes of damage credit... + ent->parent = &g_entities[ent->r.ownerNum]; + } if( G_RadiusDamage( ent->r.currentOrigin, ent->parent, ent->splashDamage, ent->splashRadius, ent, ent, ent->splashMethodOfDeath ) ) { @@ -339,6 +346,8 @@ void G_MissileBounceEffect( gentity_t *ent, vec3_t org, vec3_t dir ) VectorCopy(org, te->s.origin); VectorCopy(dir, te->s.angles); te->s.eventParm = 0; + te->s.weapon = 0;//saberNum + te->s.legsAnim = 0;//bladeNum } break; } @@ -436,7 +445,9 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace ) { ent->methodOfDeath != MOD_CONC && ent->methodOfDeath != MOD_CONC_ALT && ent->methodOfDeath != MOD_SABER && - ent->methodOfDeath != MOD_TURBLAST) + ent->methodOfDeath != MOD_TURBLAST && + ent->methodOfDeath != MOD_TARGET_LASER)// && + //ent->methodOfDeath != MOD_COLLISION) { vec3_t fwd; @@ -465,6 +476,7 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace ) { ent->methodOfDeath != MOD_REPEATER_ALT && ent->methodOfDeath != MOD_FLECHETTE_ALT_SPLASH && ent->methodOfDeath != MOD_TURBLAST && + ent->methodOfDeath != MOD_TARGET_LASER && ent->methodOfDeath != MOD_VEHICLE && ent->methodOfDeath != MOD_CONC && ent->methodOfDeath != MOD_CONC_ALT && @@ -508,6 +520,8 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace ) { VectorCopy(ent->r.currentOrigin, te->s.origin); VectorCopy(trace->plane.normal, te->s.angles); te->s.eventParm = 0; + te->s.weapon = 0;//saberNum + te->s.legsAnim = 0;//bladeNum /*if (other->client->ps.velocity[2] > 0 || other->client->pers.cmd.forwardmove || @@ -583,6 +597,8 @@ void G_MissileImpact( gentity_t *ent, trace_t *trace ) { VectorCopy(ent->r.currentOrigin, te->s.origin); VectorCopy(trace->plane.normal, te->s.angles); te->s.eventParm = 0; + te->s.weapon = 0;//saberNum + te->s.legsAnim = 0;//bladeNum /*if (otherOwner->client->ps.velocity[2] > 0 || otherOwner->client->pers.cmd.forwardmove || diff --git a/codemp/game/g_mover.c b/codemp/game/g_mover.c index d1ea0fe..3bb9644 100644 --- a/codemp/game/g_mover.c +++ b/codemp/game/g_mover.c @@ -155,6 +155,7 @@ G_TryPushingEntity Returns qfalse if the move is blocked ================== */ +extern void G_DamageFromKiller( gentity_t *pEnt, gentity_t *pVehEnt, gentity_t *attacker, vec3_t org, int damage, int dflags, int mod ); qboolean G_TryPushingEntity( gentity_t *check, gentity_t *pusher, vec3_t move, vec3_t amove ) { vec3_t matrix[3], transpose[3]; vec3_t org, org2, move2; @@ -173,7 +174,16 @@ qboolean G_TryPushingEntity( gentity_t *check, gentity_t *pusher, vec3_t move, v && (pusher->spawnflags&16) //IMPACT && Q_stricmp( "func_rotating", pusher->classname ) == 0 ) {//just blow the fuck out of them - G_Damage( check, pusher, pusher, NULL, NULL, pusher->damage, DAMAGE_NO_KNOCKBACK, MOD_CRUSH ); + /* + if ( check->m_pVehicle ) + { + G_DamageFromKiller( check, check, pusher, NULL, pusher->damage, DAMAGE_NO_KNOCKBACK, MOD_CRUSH ); + } + else + */ + { + G_Damage( check, pusher, pusher, NULL, NULL, pusher->damage, DAMAGE_NO_KNOCKBACK, MOD_CRUSH ); + } return qtrue; } @@ -1984,7 +1994,9 @@ void SP_func_static( gentity_t *ent ) #endif if (ent->s.iModelScale < 0) { - ent->s.iModelScale = 0; + //NOTE: -1 scale is x -100% (so -3 is 300%) + ent->s.legsFlip = qtrue;//treat it as a scalar + ent->s.iModelScale = -ent->s.iModelScale; } else if (ent->s.iModelScale > 1023) { @@ -2062,7 +2074,7 @@ the point around which it is rotated. It will rotate around the Z axis by defaul check either the X_AXIS or Y_AXIS box to change that. "model2" .md3 model to also draw -"model2scale" percent of normal scale (on all x y and z axii) to scale the model2 if there is one. 100 is normal scale, min is 1 (100 times smaller than normal), max is 1000 (ten times normal). +"model2scale" percent of normal scale (on all x y and z axes) to scale the model2 if there is one. 100 is normal scale, min is 1 (100 times smaller than normal), max is 1000 (ten times normal). "speed" determines how fast it moves; default value is 100. "dmg" damage to inflict when blocked (2 default) "color" constantLight color @@ -2148,7 +2160,9 @@ void SP_func_rotating (gentity_t *ent) { #endif if (ent->s.iModelScale < 0) { - ent->s.iModelScale = 0; + //NOTE: -1 scale is x -100% (so -3 is 300%) + ent->s.legsFlip = qtrue;//treat it as a scalar + ent->s.iModelScale = -ent->s.iModelScale; } else if (ent->s.iModelScale > 1023) { diff --git a/codemp/game/g_nav.c b/codemp/game/g_nav.c index a78ae83..ed7457b 100644 --- a/codemp/game/g_nav.c +++ b/codemp/game/g_nav.c @@ -917,6 +917,10 @@ qboolean NAV_AvoidCollision( gentity_t *self, gentity_t *goal, navInfo_t *info ) VectorMA( self->r.currentOrigin, info->distance, info->direction, movepos ); VectorCopy( info->direction, movedir ); + if ( self && self->NPC && (self->NPC->aiFlags&NPCAI_NO_COLL_AVOID) ) + {//pretend there's no-one in the way + return qtrue; + } //Now test against entities if ( NAV_CheckAhead( self, movepos, &info->trace, CONTENTS_BODY ) == qfalse ) { diff --git a/codemp/game/g_public.h b/codemp/game/g_public.h index 07abab6..1dcf025 100644 --- a/codemp/game/g_public.h +++ b/codemp/game/g_public.h @@ -36,6 +36,10 @@ #define SVF_GLASS_BRUSH 0x08000000 // Ent is a glass brush +#define SVF_NO_BASIC_SOUNDS 0x10000000 // No basic sounds +#define SVF_NO_COMBAT_SOUNDS 0x20000000 // No combat sounds +#define SVF_NO_EXTRA_SOUNDS 0x40000000 // No extra or jedi sounds + //rww - ghoul2 trace flags #define G2TRFLAG_DOGHOULTRACE 0x00000001 //do the ghoul2 trace #define G2TRFLAG_HITCORPSES 0x00000002 //will try g2 collision on the ent even if it's EF_DEAD @@ -524,6 +528,7 @@ Ghoul2 Insert Start G_G2_REMOVEGHOUL2MODELS, G_G2_CLEANMODELS, G_G2_COLLISIONDETECT, + G_G2_COLLISIONDETECTCACHE, G_G2_SETROOTSURFACE, G_G2_SETSURFACEONOFF, diff --git a/codemp/game/g_saga.c b/codemp/game/g_saga.c index 3de8101..faa3629 100644 --- a/codemp/game/g_saga.c +++ b/codemp/game/g_saga.c @@ -35,6 +35,7 @@ int imperial_attackers = 0; qboolean gSiegeRoundBegun = qfalse; qboolean gSiegeRoundEnded = qfalse; +qboolean gSiegeRoundWinningTeam = 0; int gSiegeBeginTime = Q3_INFINITE; int g_preroundState = 0; //default to starting as spec (1 is starting ingame) @@ -684,6 +685,7 @@ void SiegeRoundComplete(int winningteam, int winningclient) trap_SetConfigstring(CS_SIEGE_STATE, va("3|%i", level.time)); //ended gSiegeRoundBegun = qfalse; gSiegeRoundEnded = qtrue; + gSiegeRoundWinningTeam = winningteam; if (BG_SiegeGetValueGroup(siege_info, teamstr, gParseObjectives)) { diff --git a/codemp/game/g_spawn.c b/codemp/game/g_spawn.c index bf89820..4280cb0 100644 --- a/codemp/game/g_spawn.c +++ b/codemp/game/g_spawn.c @@ -163,7 +163,11 @@ void SP_info_player_deathmatch (gentity_t *ent); void SP_info_player_siegeteam1 (gentity_t *ent); void SP_info_player_siegeteam2 (gentity_t *ent); void SP_info_player_intermission (gentity_t *ent); +void SP_info_player_intermission_red (gentity_t *ent); +void SP_info_player_intermission_blue (gentity_t *ent); void SP_info_jedimaster_start (gentity_t *ent); +void SP_info_player_start_red (gentity_t *ent); +void SP_info_player_start_blue (gentity_t *ent); void SP_info_firstplace(gentity_t *ent); void SP_info_secondplace(gentity_t *ent); void SP_info_thirdplace(gentity_t *ent); @@ -200,6 +204,7 @@ void SP_trigger_hurt (gentity_t *ent); void SP_trigger_space(gentity_t *self); void SP_trigger_shipboundary(gentity_t *self); void SP_trigger_hyperspace(gentity_t *self); +void SP_trigger_asteroid_field(gentity_t *self); void SP_target_remove_powerups( gentity_t *ent ); void SP_target_give (gentity_t *ent); @@ -438,7 +443,11 @@ spawn_t spawns[] = { {"info_player_siegeteam1", SP_info_player_siegeteam1}, {"info_player_siegeteam2", SP_info_player_siegeteam2}, {"info_player_intermission", SP_info_player_intermission}, + {"info_player_intermission_red", SP_info_player_intermission_red}, + {"info_player_intermission_blue", SP_info_player_intermission_blue}, {"info_jedimaster_start", SP_info_jedimaster_start}, + {"info_player_start_red", SP_info_player_start_red}, + {"info_player_start_blue", SP_info_player_start_blue}, {"info_null", SP_info_null}, {"info_notnull", SP_info_notnull}, // use target_position instead {"info_camp", SP_info_camp}, @@ -480,6 +489,7 @@ spawn_t spawns[] = { {"trigger_space", SP_trigger_space}, {"trigger_shipboundary", SP_trigger_shipboundary}, {"trigger_hyperspace", SP_trigger_hyperspace}, + {"trigger_asteroid_field", SP_trigger_asteroid_field}, // targets perform no action by themselves, but must be triggered // by another entity @@ -1323,9 +1333,6 @@ void SP_worldspawn( void ) G_SpawnString( "gravity", "800", &text ); trap_Cvar_Set( "g_gravity", text ); - G_SpawnString( "enableDust", "0", &text ); - trap_Cvar_Set( "g_enableDust", text ); - G_SpawnString( "enableBreath", "0", &text ); trap_Cvar_Set( "g_enableBreath", text ); diff --git a/codemp/game/g_svcmds.c b/codemp/game/g_svcmds.c index bcea59f..6e59c7f 100644 --- a/codemp/game/g_svcmds.c +++ b/codemp/game/g_svcmds.c @@ -170,7 +170,7 @@ qboolean G_FilterPacket (char *from) AddIP ================= */ -static void AddIP( char *str ) +void AddIP( char *str ) { int i; @@ -273,6 +273,111 @@ void Svcmd_RemoveIP_f (void) G_Printf ( "Didn't find %s.\n", str ); } +void Svcmd_ListIPs_f( void ) +{ + int i; + char *str; + byte b[4]; + + G_Printf ( "%d IP slots used.\n", numIPFilters ); + for ( i = 0 ; i < numIPFilters ; i++ ) + { + G_Printf ( "%d: ", i ); + if (ipFilters[i].compare == 0xffffffff) + { + G_Printf ( "unused\n" ); + } + else + { + *(unsigned *)b = ipFilters[i].compare; + str = va("%i.%i.%i.%i \n", b[0], b[1], b[2], b[3]); + G_Printf ( "%s\n", str ); + } + } +} + +void G_SaveBanIP( void ) +{//save out all the banned IPs + int i; + char *str; + fileHandle_t fh; + byte b[4]; + + trap_FS_FOpenFile("banip.txt", &fh, FS_WRITE); + if ( !fh ) + { + G_Printf ( "G_SaveBanIP - ERROR: can't open banip.txt\n" ); + return; + } + + str = va("%d \n", numIPFilters); + trap_FS_Write(str, strlen(str), fh); + for ( i = 0 ; i < numIPFilters ; i++ ) + { + if (ipFilters[i].compare == 0xffffffff) + { + str = "unused \n"; + trap_FS_Write(str, strlen(str), fh); + } + else + { + *(unsigned *)b = ipFilters[i].compare; + str = va("%i.%i.%i.%i \n", b[0], b[1], b[2], b[3]); + trap_FS_Write(str, strlen(str), fh); + } + } + + trap_FS_FCloseFile(fh); +} + +void G_LoadIPBans( void ) +{//load in all the banned IPs + int i, len; + char *p, *token; + fileHandle_t fh; + char banIPBuffer[MAX_IPFILTERS*32]; // The list of file names read in + char banIPFile[MAX_QPATH]; + + len = trap_FS_FOpenFile("banip.txt", &fh, FS_READ); + if ( !fh ) + { + G_Printf ( "G_LoadBanIP - ERROR: can't open banip.txt\n" ); + return; + } + + trap_FS_Read(banIPBuffer, len, fh); + banIPBuffer[len] = 0; + trap_FS_FCloseFile(fh); + p = banIPBuffer; + COM_BeginParseSession(banIPFile); + + token = COM_ParseExt( &p, qtrue ); + if ( token ) + { + numIPFilters = atoi(token); + + for ( i = 0 ; i < numIPFilters ; i++ ) + { + token = COM_ParseExt( &p, qtrue ); + if ( token ) + {//have an ip + if ( !Q_stricmp("unused",token) ) + { + ipFilters[i].compare = 0xffffffffu; + } + else + { + StringToFilter(token,&ipFilters[i]); + } + } + else + { + break; + } + } + } +} + /* =================== Svcmd_EntityList_f @@ -451,7 +556,8 @@ qboolean ConsoleCommand( void ) { } if (Q_stricmp (cmd, "listip") == 0) { - trap_SendConsoleCommand( EXEC_NOW, "g_banIPs\n" ); + Svcmd_ListIPs_f(); + //trap_SendConsoleCommand( EXEC_NOW, "g_banIPs\n" ); return qtrue; } diff --git a/codemp/game/g_syscalls.c b/codemp/game/g_syscalls.c index 61b87f1..5fc18db 100644 --- a/codemp/game/g_syscalls.c +++ b/codemp/game/g_syscalls.c @@ -8,9 +8,15 @@ static int (QDECL *syscall)( int arg, ... ) = (int (QDECL *)( int, ...))-1; #include "../namespace_begin.h" +#ifdef __linux__ +extern "C" { +#endif void dllEntry( int (QDECL *syscallptr)( int arg,... ) ) { syscall = syscallptr; } +#ifdef __linux__ +} +#endif int PASSFLOAT( float x ) { float floatTemp; @@ -1317,6 +1323,24 @@ void trap_G2API_CollisionDetect ( syscall ( G_G2_COLLISIONDETECT, collRecMap, ghoul2, angles, position, frameNumber, entNum, rayStart, rayEnd, scale, traceFlags, useLod, PASSFLOAT(fRadius) ); } +void trap_G2API_CollisionDetectCache ( + CollisionRecord_t *collRecMap, + void* ghoul2, + const vec3_t angles, + const vec3_t position, + int frameNumber, + int entNum, + vec3_t rayStart, + vec3_t rayEnd, + vec3_t scale, + int traceFlags, + int useLod, + float fRadius + ) +{ + syscall ( G_G2_COLLISIONDETECTCACHE, collRecMap, ghoul2, angles, position, frameNumber, entNum, rayStart, rayEnd, scale, traceFlags, useLod, PASSFLOAT(fRadius) ); +} + void trap_G2API_GetSurfaceName(void *ghoul2, int surfNumber, int modelIndex, char *fillBuf) { syscall(G_G2_GETSURFACENAME, ghoul2, surfNumber, modelIndex, fillBuf); diff --git a/codemp/game/g_target.c b/codemp/game/g_target.c index 94ba33a..ac4c4f9 100644 --- a/codemp/game/g_target.c +++ b/codemp/game/g_target.c @@ -133,11 +133,8 @@ void Use_Target_Print (gentity_t *ent, gentity_t *other, gentity_t *activator) { if (!ent || !ent->inuse) { - Com_Error(ERR_DROP, "Bad ent in Use_Target_Print"); - } - else if (!activator || !activator->inuse) - { - Com_Error(ERR_DROP, "Bad activator in Use_Target_Print"); + Com_Printf("ERROR: Bad ent in Use_Target_Print"); + return; } if (ent->wait) @@ -150,6 +147,15 @@ void Use_Target_Print (gentity_t *ent, gentity_t *other, gentity_t *activator) } #ifndef FINAL_BUILD + if (!ent || !ent->inuse) + { + Com_Error(ERR_DROP, "Bad ent in Use_Target_Print"); + } + else if (!activator || !activator->inuse) + { + Com_Error(ERR_DROP, "Bad activator in Use_Target_Print"); + } + if (ent->genericValue15 > level.time) { Com_Printf("TARGET PRINT ERRORS:\n"); @@ -175,15 +181,24 @@ void Use_Target_Print (gentity_t *ent, gentity_t *other, gentity_t *activator) #endif G_ActivateBehavior(ent,BSET_USE); - if ( activator->client && ( ent->spawnflags & 4 ) ) { - if (ent->message[0] == '@' && ent->message[1] != '@') + if ( ( ent->spawnflags & 4 ) ) + {//private, to one client only + if (!activator || !activator->inuse) { - trap_SendServerCommand( activator-g_entities, va("cps \"%s\"", ent->message )); + Com_Printf("ERROR: Bad activator in Use_Target_Print"); } - else - { - trap_SendServerCommand( activator-g_entities, va("cp \"%s\"", ent->message )); + if ( activator && activator->client ) + {//make sure there's a valid client ent to send it to + if (ent->message[0] == '@' && ent->message[1] != '@') + { + trap_SendServerCommand( activator-g_entities, va("cps \"%s\"", ent->message )); + } + else + { + trap_SendServerCommand( activator-g_entities, va("cp \"%s\"", ent->message )); + } } + //NOTE: change in functionality - if there *is* no valid client ent, it won't send it to anyone at all return; } diff --git a/codemp/game/g_team.c b/codemp/game/g_team.c index d9eaec6..48c75a8 100644 --- a/codemp/game/g_team.c +++ b/codemp/game/g_team.c @@ -183,6 +183,7 @@ void AddTeamScore(vec3_t origin, int team, int score) { OnSameTeam ============== */ +extern qboolean G_CheckVehicleNPCTeamDamage( gentity_t *ent ); qboolean OnSameTeam( gentity_t *ent1, gentity_t *ent2 ) { if ( !ent1->client || !ent2->client ) { return qfalse; @@ -252,6 +253,14 @@ qboolean OnSameTeam( gentity_t *ent1, gentity_t *ent2 ) { if (ent1->s.eType == ET_NPC && ent2->s.eType == ET_PLAYER) { + if ( G_CheckVehicleNPCTeamDamage( ent1 ) ) + {//hit an NPC that is in a vehicle - a droid? + if ( ent1->client->sess.sessionTeam == ent2->client->sess.sessionTeam + || ent1->teamnodmg == ent2->client->sess.sessionTeam ) + { + return qtrue; + } + } return qfalse; } else if (ent1->s.eType == ET_PLAYER && ent2->s.eType == ET_NPC) @@ -1043,7 +1052,7 @@ gentity_t *SelectCTFSpawnPoint ( team_t team, int teamstate, vec3_t origin, vec3 spot = SelectRandomTeamSpawnPoint ( teamstate, team, -1 ); if (!spot) { - return SelectSpawnPoint( vec3_origin, origin, angles ); + return SelectSpawnPoint( vec3_origin, origin, angles, team ); } VectorCopy (spot->s.origin, origin); @@ -1065,7 +1074,7 @@ gentity_t *SelectSiegeSpawnPoint ( int siegeClass, team_t team, int teamstate, v spot = SelectRandomTeamSpawnPoint ( teamstate, team, siegeClass ); if (!spot) { - return SelectSpawnPoint( vec3_origin, origin, angles ); + return SelectSpawnPoint( vec3_origin, origin, angles, team ); } VectorCopy (spot->s.origin, origin); diff --git a/codemp/game/g_trigger.c b/codemp/game/g_trigger.c index 34adc5f..68a3c91 100644 --- a/codemp/game/g_trigger.c +++ b/codemp/game/g_trigger.c @@ -1364,6 +1364,9 @@ void hurt_touch( gentity_t *self, gentity_t *other, trace_t *trace ) { { //we're as good as dead, so if someone pushed us into this then remember them other->client->ps.otherKillerTime = level.time + 20000; other->client->ps.otherKillerDebounceTime = level.time + 10000; + other->client->otherKillerMOD = MOD_FALLING; + other->client->otherKillerVehWeapon = 0; + other->client->otherKillerWeaponType = WP_NONE; } other->client->ps.fallingToDeath = level.time; @@ -1625,6 +1628,7 @@ void hyperspace_touch( gentity_t *self, gentity_t *other, trace_t *trace ) fDiff = DotProduct( fwd, diff ); rDiff = DotProduct( right, diff ); uDiff = DotProduct( up, diff ); + //Now get the base position of the destination ent = G_Find (NULL, FOFS(targetname), self->target2); if (!ent || !ent->inuse) @@ -1635,9 +1639,9 @@ void hyperspace_touch( gentity_t *self, gentity_t *other, trace_t *trace ) VectorCopy( ent->s.origin, newOrg ); //finally, add the offset into the new origin AngleVectors( ent->s.angles, fwd, right, up ); - VectorMA( newOrg, fDiff, fwd, newOrg ); - VectorMA( newOrg, rDiff, right, newOrg ); - VectorMA( newOrg, uDiff, up, newOrg ); + VectorMA( newOrg, fDiff*self->radius, fwd, newOrg ); + VectorMA( newOrg, rDiff*self->radius, right, newOrg ); + VectorMA( newOrg, uDiff*self->radius, up, newOrg ); //G_Printf("hyperspace from %s to %s\n", vtos(other->client->ps.origin), vtos(newOrg) ); //now put them in the offset position, facing the angles that position wants them to be facing TeleportPlayer( other, newOrg, ent->s.angles ); @@ -1700,9 +1704,12 @@ Ship will turn to face the angles of the first target_position then fly forward, "target" whatever position the ship teleports from in relation to the target_position specified here, that's the relative position the ship will spawn at around the target2 target_position "target2" name of target_position to teleport the ship to (will be relative to it's origin) +"exitscale" Can use this to make the vehicle appear farther from the exit position than they were from the entry position at the time of teleporting (scales the relative position - default is "1" - normal, no scale) */ void SP_trigger_hyperspace(gentity_t *self) { + G_SpawnFloat( "exitscale", "1", &self->radius); + //register the hyperspace end sound (start sounds are customized) G_SoundIndex( "sound/vehicles/common/hyperend.wav" ); @@ -1788,4 +1795,213 @@ void SP_func_timer( gentity_t *self ) { self->r.svFlags = SVF_NOCLIENT; } +gentity_t *asteroid_pick_random_asteroid( gentity_t *self ) +{ + int t_count = 0, pick; + gentity_t *t = NULL; + while ( (t = G_Find (t, FOFS(targetname), self->target)) != NULL ) + { + if (t != self) + { + t_count++; + } + } + + if(!t_count) + { + return NULL; + } + + if(t_count == 1) + { + return (G_Find (NULL, FOFS(targetname), self->target)); + } + + //FIXME: need a seed + pick = Q_irand(1, t_count); + t_count = 0; + while ( (t = G_Find (t, FOFS(targetname), self->target)) != NULL ) + { + if (t != self) + { + t_count++; + } + else + { + continue; + } + + if(t_count == pick) + { + return t; + } + } + return NULL; +} + +int asteroid_count_num_asteroids( gentity_t *self ) +{ + int i, count = 0; + + for ( i = MAX_CLIENTS; i < ENTITYNUM_WORLD; i++ ) + { + if ( !g_entities[i].inuse ) + { + continue; + } + if ( g_entities[i].r.ownerNum == self->s.number ) + { + count++; + } + } + return count; +} + +extern void SP_func_rotating (gentity_t *ent); +extern void Q3_Lerp2Origin( int taskID, int entID, vec3_t origin, float duration ); +void asteroid_move_to_start(gentity_t *self); +void asteroid_move_to_start2(gentity_t *self, gentity_t *ownerTrigger) +{//move asteroid to a new start position + if ( ownerTrigger ) + {//move it + vec3_t startSpot, endSpot, startAngles; + float dist, speed = flrand( self->speed * 0.25f, self->speed * 2.0f ); + int capAxis, axis, time = 0; + + capAxis = Q_irand( 0, 2 ); + for ( axis = 0; axis < 3; axis++ ) + { + if ( axis == capAxis ) + { + if ( Q_irand( 0, 1 ) ) + { + startSpot[axis] = ownerTrigger->r.mins[axis]; + endSpot[axis] = ownerTrigger->r.maxs[axis]; + } + else + { + startSpot[axis] = ownerTrigger->r.maxs[axis]; + endSpot[axis] = ownerTrigger->r.mins[axis]; + } + } + else + { + startSpot[axis] = ownerTrigger->r.mins[axis]+(flrand(0,1.0f)*(ownerTrigger->r.maxs[axis]-ownerTrigger->r.mins[axis])); + endSpot[axis] = ownerTrigger->r.mins[axis]+(flrand(0,1.0f)*(ownerTrigger->r.maxs[axis]-ownerTrigger->r.mins[axis])); + } + } + //FIXME: maybe trace from start to end to make sure nothing is in the way? How big of a trace? + + G_SetOrigin( self, startSpot ); + dist = Distance( endSpot, startSpot ); + time = ceil(dist/speed)*1000; + Q3_Lerp2Origin( -1, self->s.number, endSpot, time ); + + //spin it + startAngles[0] = flrand( -360, 360 ); + startAngles[1] = flrand( -360, 360 ); + startAngles[2] = flrand( -360, 360 ); + G_SetAngles( self, startAngles ); + self->s.apos.trDelta[0] = flrand( -100, 100 ); + self->s.apos.trDelta[1] = flrand( -100, 100 ); + self->s.apos.trDelta[2] = flrand( -100, 100 ); + self->s.apos.trTime = level.time; + self->s.apos.trType = TR_LINEAR; + //move itownerTrigger back to a new start when done + self->think = asteroid_move_to_start; + self->nextthink = level.time+time; + } + else + {//crap, go bye-bye + self->think = G_FreeEntity; + self->nextthink = level.time+FRAMETIME; + } +} + +void asteroid_move_to_start(gentity_t *self) +{//move asteroid to a new start position + asteroid_move_to_start2( self, &g_entities[self->r.ownerNum] ); +} + +void asteroid_field_think(gentity_t *self) +{ + int numAsteroids = asteroid_count_num_asteroids( self ); + + self->nextthink = level.time + 500; + + if ( numAsteroids < self->count ) + { + //need to spawn a new asteroid + gentity_t *newAsteroid = G_Spawn(); + if ( newAsteroid ) + { + gentity_t *copyAsteroid = asteroid_pick_random_asteroid( self ); + if ( copyAsteroid ) + { + newAsteroid->model = copyAsteroid->model; + newAsteroid->model2 = copyAsteroid->model2; + newAsteroid->health = copyAsteroid->health; + newAsteroid->spawnflags = copyAsteroid->spawnflags; + newAsteroid->mass = copyAsteroid->mass; + newAsteroid->damage = copyAsteroid->damage; + newAsteroid->speed = copyAsteroid->speed; + + G_SetOrigin( newAsteroid, copyAsteroid->s.origin ); + G_SetAngles( newAsteroid, copyAsteroid->s.angles ); + newAsteroid->classname = "func_rotating"; + + SP_func_rotating( newAsteroid ); + + newAsteroid->genericValue15 = copyAsteroid->genericValue15; + newAsteroid->s.iModelScale = copyAsteroid->s.iModelScale; + newAsteroid->maxHealth = newAsteroid->health; + G_ScaleNetHealth(newAsteroid); + newAsteroid->radius = copyAsteroid->radius; + newAsteroid->material = copyAsteroid->material; + //CacheChunkEffects( self->material ); + + //keep track of it + newAsteroid->r.ownerNum = self->s.number; + + //position it + asteroid_move_to_start2( newAsteroid, self ); + + //think again sooner if need even more + if ( numAsteroids+1 < self->count ) + {//still need at least one more + //spawn it in 100ms + self->nextthink = level.time + 100; + } + } + } + } +} + +/*QUAKED trigger_asteroid_field (.5 .5 .5) ? +speed - how fast, on average, the asteroid moves +count - how many asteroids, max, to have at one time +target - target this at func_rotating asteroids +*/ +void SP_trigger_asteroid_field(gentity_t *self) +{ + trap_SetBrushModel( self, self->model ); +// self->r.contents = CONTENTS_TRIGGER; // replaces the -1 from trap_SetBrushModel + self->r.contents = 0; + self->r.svFlags = SVF_NOCLIENT; + + if ( !self->count ) + { + self->health = 20; + } + + if ( !self->speed ) + { + self->speed = 10000; + } + + self->think = asteroid_field_think; + self->nextthink = level.time + 100; + + trap_LinkEntity(self); +} \ No newline at end of file diff --git a/codemp/game/g_turret.c b/codemp/game/g_turret.c index 8a30494..6633b02 100644 --- a/codemp/game/g_turret.c +++ b/codemp/game/g_turret.c @@ -656,11 +656,15 @@ Large 2-piece turbolaser turret 0 - none 1 - red 2 - blue + +"icon" - icon that represents the objective on the radar */ //----------------------------------------------------- void SP_misc_turret( gentity_t *base ) //----------------------------------------------------- { + char* s; + base->s.modelindex2 = G_ModelIndex( "models/map_objects/hoth/turret_bottom.md3" ); base->s.modelindex = G_ModelIndex( "models/map_objects/hoth/turret_base.md3" ); //base->playerModel = gi.G2API_InitGhoul2Model( base->ghoul2, "models/map_objects/imp_mine/turret_canon.glm", base->s.modelindex ); @@ -669,6 +673,14 @@ void SP_misc_turret( gentity_t *base ) //gi.G2API_SetBoneAngles( &base->ghoul2[base->playerModel], "Bone_body", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, NULL ); //base->torsoBolt = gi.G2API_AddBolt( &base->ghoul2[base->playerModel], "*flash03" ); + G_SpawnString( "icon", "", &s ); + if (s && s[0]) + { + // We have an icon, so index it now. We are reusing the genericenemyindex + // variable rather than adding a new one to the entity state. + base->s.genericenemyindex = G_IconIndex(s); + } + G_SetAngles( base, base->s.angles ); G_SetOrigin( base, base->s.origin ); diff --git a/codemp/game/g_turret_G2.c b/codemp/game/g_turret_G2.c index afe6573..b38eaca 100644 --- a/codemp/game/g_turret_G2.c +++ b/codemp/game/g_turret_G2.c @@ -251,6 +251,14 @@ void turretG2_die ( gentity_t *self, gentity_t *inflictor, gentity_t *attacker, self->s.shouldtarget = qfalse; //self->s.owner = MAX_CLIENTS; //not owned by any client + if ( attacker + && attacker->s.number < MAX_CLIENTS + && !OnSameTeam( attacker, self ) ) + {//give them a point for the kill + AddScore( attacker, self->r.currentOrigin, 1 ); + //should we send an obit? nah... + } + // hack the effect angle so that explode death can orient the effect properly if ( self->spawnflags & 2 ) { @@ -1014,12 +1022,16 @@ Turret that hangs from the ceiling, will aim and shoot at enemies 2 - blue customscale - custom scaling size. 100 is normal size, 1024 is the max scaling. this will change the bounding box size, so be careful of starting in solid! + +"icon" - icon that represents the objective on the radar */ //----------------------------------------------------- void SP_misc_turretG2( gentity_t *base ) //----------------------------------------------------- { int customscaleVal; + char* s; + turretG2_set_models( base, qfalse ); G_SpawnInt("painwait", "0", &base->genericValue4); @@ -1036,6 +1048,14 @@ void SP_misc_turretG2( gentity_t *base ) base->modelScale[0] = base->modelScale[1] = base->modelScale[2] = base->s.iModelScale/100.0f; } + G_SpawnString( "icon", "", &s ); + if (s && s[0]) + { + // We have an icon, so index it now. We are reusing the genericenemyindex + // variable rather than adding a new one to the entity state. + base->s.genericenemyindex = G_IconIndex(s); + } + finish_spawning_turretG2( base ); if (( base->spawnflags & 1 )) // Start_Off diff --git a/codemp/game/g_utils.c b/codemp/game/g_utils.c index ca84b3a..1e5cdde 100644 --- a/codemp/game/g_utils.c +++ b/codemp/game/g_utils.c @@ -744,7 +744,7 @@ static void G_SpewEntList(void) numTempEntST++; } - str = va("TEMPENT %4i: EV %i\n", ent->s.number, (ent->s.event&~EV_EVENT_BITS)); + str = va("TEMPENT %4i: EV %i\n", ent->s.number, ent->s.eType-ET_EVENTS); Com_Printf(str); #ifndef VM_OR_FINAL_BUILD if (fh) @@ -1065,6 +1065,10 @@ gentity_t *G_TempEntity( vec3_t origin, int event ) { VectorCopy( origin, snapped ); SnapVector( snapped ); // save network bandwidth G_SetOrigin( e, snapped ); + //WTF? Why aren't we setting the s.origin? (like below) + //cg_events.c code checks origin all over the place!!! + //Trying to save bandwidth...? + //VectorCopy( snapped, e->s.origin ); // find cluster for PVS trap_LinkEntity( e ); diff --git a/codemp/game/g_vehicleTurret.c b/codemp/game/g_vehicleTurret.c index 41a8a04..0a34ffc 100644 --- a/codemp/game/g_vehicleTurret.c +++ b/codemp/game/g_vehicleTurret.c @@ -348,6 +348,11 @@ void VEH_TurretThink( Vehicle_t *pVeh, gentity_t *parent, int turretNum ) {//this turret does not think on its own. return; } + //okay, so it has AI, but still don't think if there's no pilot! + if ( !pVeh->m_pPilot ) + { + return; + } vehWeapon = &g_vehWeaponInfo[turretStats->iWeapon]; rangeSq = (turretStats->fAIRange*turretStats->fAIRange); @@ -377,8 +382,12 @@ void VEH_TurretThink( Vehicle_t *pVeh, gentity_t *parent, int turretNum ) } else if ( parent->enemy && parent->enemy->s.number < ENTITYNUM_WORLD ) { - turretEnemy = parent->enemy; - doAim = qtrue; + if ( g_gametype.integer < GT_TEAM + || !OnSameTeam( parent->enemy, parent ) ) + {//either not in a team game or the enemy isn't on the same team + turretEnemy = parent->enemy; + doAim = qtrue; + } } if ( turretEnemy ) {//found one diff --git a/codemp/game/g_vehicles.c b/codemp/game/g_vehicles.c index 88ac841..56fad48 100644 --- a/codemp/game/g_vehicles.c +++ b/codemp/game/g_vehicles.c @@ -44,7 +44,10 @@ #ifdef _JK2MP extern gentity_t *NPC_Spawn_Do( gentity_t *ent ); extern void NPC_SetAnim(gentity_t *ent,int setAnimParts,int anim,int setAnimFlags); +extern void G_DamageFromKiller( gentity_t *pEnt, gentity_t *pVehEnt, gentity_t *attacker, vec3_t org, int damage, int dflags, int mod ); + #else + extern gentity_t *NPC_Spawn_Do( gentity_t *pEnt, qboolean fullSpawnNow ); extern qboolean G_ClearLineOfSight(const vec3_t point1, const vec3_t point2, int ignore, int clipmask); @@ -590,6 +593,7 @@ bool ValidateBoard( Vehicle_t *pVeh, bgEntity_t *pEnt ) return true; } +#ifdef VEH_CONTROL_SCHEME_4 void FighterStorePilotViewAngles( Vehicle_t *pVeh, bgEntity_t *parent ) { playerState_t *riderPS; @@ -620,6 +624,7 @@ void FighterStorePilotViewAngles( Vehicle_t *pVeh, bgEntity_t *parent ) VectorClear( pVeh->m_vPrevRiderViewAngles ); pVeh->m_vPrevRiderViewAngles[YAW] = AngleNormalize180(riderPS->viewangles[YAW]); } +#endif// VEH_CONTROL_SCHEME_4 // Board this Vehicle (get on). The first entity to board an empty vehicle becomes the Pilot. bool Board( Vehicle_t *pVeh, bgEntity_t *pEnt ) @@ -852,10 +857,13 @@ bool Board( Vehicle_t *pVeh, bgEntity_t *pEnt ) #endif } +#ifdef VEH_CONTROL_SCHEME_4 if ( pVeh->m_pVehicleInfo->type == VH_FIGHTER ) {//clear their angles FighterStorePilotViewAngles( pVeh, (bgEntity_t *)parent ); } +#endif //VEH_CONTROL_SCHEME_4 + VectorCopy( pVeh->m_vOrientation, vPlayerDir ); vPlayerDir[ROLL] = 0; SetClientViewAngle( ent, vPlayerDir ); @@ -1581,7 +1589,7 @@ static void DeathUpdate( Vehicle_t *pVeh ) bottom[2] += parent->mins[2] - 32; G_VehicleTrace( &trace, parent->currentOrigin, lMins, lMaxs, bottom, parent->s.number, CONTENTS_SOLID ); #ifdef _JK2MP - G_RadiusDamage( trace.endpos, NULL, pVeh->m_pVehicleInfo->explosionDamage, pVeh->m_pVehicleInfo->explosionRadius, NULL, NULL, MOD_EXPLOSIVE );//FIXME: extern damage and radius or base on fuel + G_RadiusDamage( trace.endpos, parent, pVeh->m_pVehicleInfo->explosionDamage, pVeh->m_pVehicleInfo->explosionRadius, NULL, NULL, MOD_VEH_EXPLOSION );//FIXME: extern damage and radius or base on fuel #else G_RadiusDamage( trace.endpos, NULL, pVeh->m_pVehicleInfo->explosionDamage, pVeh->m_pVehicleInfo->explosionRadius, NULL, MOD_EXPLOSIVE );//FIXME: extern damage and radius or base on fuel #endif @@ -2285,26 +2293,15 @@ maintainSelfDuringBoarding: { if (pVeh->m_iRemovedSurfaces) { - gentity_t *killer = parent; float dmg; G_VehicleDamageBoxSizing(pVeh); //damage him constantly if any chunks are currently taken off - if (parent->client->ps.otherKiller < ENTITYNUM_WORLD && - parent->client->ps.otherKillerTime > level.time) - { - gentity_t *potentialKiller = &g_entities[parent->client->ps.otherKiller]; - - if (potentialKiller->inuse && potentialKiller->client) - { //he's valid I guess - killer = potentialKiller; - } - } - //FIXME: aside from bypassing shields, maybe set m_iShields to 0, too... ? // 3 seconds max on death. dmg = (float)parent->client->ps.stats[STAT_MAX_HEALTH] * pVeh->m_fTimeModifier / 180.0f; - G_Damage(parent, killer, killer, NULL, parent->client->ps.origin, dmg, DAMAGE_NO_SELF_PROTECTION|DAMAGE_NO_HIT_LOC|DAMAGE_NO_PROTECTION|DAMAGE_NO_ARMOR, MOD_SUICIDE); + //FIXME: aside from bypassing shields, maybe set m_iShields to 0, too... ? + G_DamageFromKiller( parent, parent, parent, parent->client->ps.origin, dmg, DAMAGE_NO_SELF_PROTECTION|DAMAGE_NO_HIT_LOC|DAMAGE_NO_PROTECTION|DAMAGE_NO_ARMOR, MOD_SUICIDE ); } //make sure playerstate value stays in sync @@ -3078,8 +3075,8 @@ void G_VehicleSetDamageLocFlags( gentity_t *veh, int impactDir, int deathPoint ) { perc = 0.99f; } - heavyDamagePoint = ceil( deathPoint*perc*0.25f ); - lightDamagePoint = ceil( deathPoint*perc ); + lightDamagePoint = ceil( deathPoint*perc*0.25f ); + heavyDamagePoint = ceil( deathPoint*perc ); } else { @@ -3091,14 +3088,14 @@ void G_VehicleSetDamageLocFlags( gentity_t *veh, int impactDir, int deathPoint ) {//destroyed G_SetVehDamageFlags( veh, impactDir, 3 ); } - else if ( veh->locationDamage[impactDir] <= heavyDamagePoint ) - {//heavy only - G_SetVehDamageFlags( veh, impactDir, 2 ); - } else if ( veh->locationDamage[impactDir] <= lightDamagePoint ) {//light only G_SetVehDamageFlags( veh, impactDir, 1 ); } + else if ( veh->locationDamage[impactDir] <= heavyDamagePoint ) + {//heavy only + G_SetVehDamageFlags( veh, impactDir, 2 ); + } } } @@ -3182,7 +3179,7 @@ qboolean G_FlyVehicleDestroySurface( gentity_t *veh, int surface ) veh->m_pVehicle->m_iRemovedSurfaces |= smashedBits; //do some explosive damage, but don't damage this ship with it - G_RadiusDamage(veh->client->ps.origin, veh, 100, 500, veh, NULL, MOD_SUICIDE); + G_RadiusDamage(veh->client->ps.origin, veh, 100, 500, veh, NULL, MOD_VEH_EXPLOSION); //when spiraling to your death, do the electical shader veh->client->ps.electrifyTime = level.time + 10000; diff --git a/codemp/game/g_weapon.c b/codemp/game/g_weapon.c index ac5fbad..ebfe0ec 100644 --- a/codemp/game/g_weapon.c +++ b/codemp/game/g_weapon.c @@ -170,6 +170,8 @@ void touch_NULL( gentity_t *ent, gentity_t *other, trace_t *trace ) void laserTrapExplode( gentity_t *self ); void RocketDie(gentity_t *self, gentity_t *inflictor, gentity_t *attacker, int damage, int mod); +extern vmCvar_t g_vehAutoAimLead; + //We should really organize weapon data into tables or parse from the ext data so we have accurate info for this, float WP_SpeedOfMissileForWeapon( int wp, qboolean alt_fire ) { @@ -401,8 +403,8 @@ void WP_FireTurboLaserMissile( gentity_t *ent, vec3_t start, vec3_t dir ) missile->splashDamage = ent->splashDamage; //FIXME: externalize missile->splashRadius = ent->splashRadius; //FIXME: externalize missile->dflags = DAMAGE_DEATH_KNOCKBACK; - missile->methodOfDeath = MOD_TURBLAST; //count as a heavy weap - missile->splashMethodOfDeath = MOD_TURBLAST;// ?SPLASH; + missile->methodOfDeath = MOD_TARGET_LASER;//MOD_TURBLAST; //count as a heavy weap + missile->splashMethodOfDeath = MOD_TARGET_LASER;//MOD_TURBLAST;// ?SPLASH; missile->clipmask = MASK_SHOT; // we don't want it to bounce forever @@ -564,6 +566,8 @@ static void WP_DisruptorMainFire( gentity_t *ent ) te->s.angles[1] = 1; } te->s.eventParm = 0; + te->s.weapon = 0;//saberNum + te->s.legsAnim = 0;//bladeNum return; } @@ -767,6 +771,8 @@ void WP_DisruptorAltFire( gentity_t *ent ) te->s.angles[1] = 1; } te->s.eventParm = 0; + te->s.weapon = 0;//saberNum + te->s.legsAnim = 0;//bladeNum return; } @@ -1701,6 +1707,38 @@ void rocketThink( gentity_t *ent ) // Now the rocket can't do a 180 in space, so we'll limit the turn to about 45 degrees. dot = DotProduct( targetdir, ent->movedir ); + if ( (ent->spawnflags&1) ) + {//vehicle rocket + if ( ent->radius > -1.0f ) + {//can lose the lock if DotProduct drops below this number + if ( dot < ent->radius ) + {//lost the lock!!! + //HMM... maybe can re-lock on if they come in front again? + /* + //OR: should it stop trying to lock altogether? + if ( ent->genericValue1 ) + {//have a timelimit, set next think to that + ent->nextthink = ent->genericValue1; + if ( ent->genericValue2 ) + {//explode when die + ent->think = G_ExplodeMissile; + } + else + { + ent->think = G_FreeEntity; + } + } + else + { + ent->think = NULL; + ent->nextthink = -1; + } + */ + return; + } + } + } + // a dot of 1.0 means right-on-target. if ( dot < 0.0f ) @@ -3107,6 +3145,9 @@ static void WP_FireConcussionAlt( gentity_t *ent ) traceEnt->client->ps.otherKiller = ent->s.number; traceEnt->client->ps.otherKillerTime = level.time + 5000; traceEnt->client->ps.otherKillerDebounceTime = level.time + 100; + traceEnt->client->otherKillerMOD = MOD_UNKNOWN; + traceEnt->client->otherKillerVehWeapon = 0; + traceEnt->client->otherKillerWeaponType = WP_NONE; traceEnt->client->ps.velocity[0] += pushDir[0]*pStr; traceEnt->client->ps.velocity[1] += pushDir[1]*pStr; @@ -3669,10 +3710,13 @@ gentity_t *WP_FireVehicleWeapon( gentity_t *ent, vec3_t start, vec3_t dir, vehWe if ( vehWeapon->iHealth ) {//the missile can take damage + /* + //don't do this - ships hit them first and have no trace.plane.normal to bounce off it at and end up in the middle of the asteroid... missile->health = vehWeapon->iHealth; missile->takedamage = qtrue; missile->r.contents = MASK_SHOT; missile->die = RocketDie; + */ } //pilot should own this projectile on server if we have a pilot @@ -3748,6 +3792,7 @@ gentity_t *WP_FireVehicleWeapon( gentity_t *ent, vec3_t start, vec3_t dir, vehWe missile->spawnflags |= 1;//just to let it know it should be faster... missile->speed = vehWeapon->fSpeed; missile->angle = vehWeapon->fHoming; + missile->radius = vehWeapon->fHomingFOV; //crap, if we have a lifetime, need to store that somewhere else on ent and have rocketThink func check it every frame... if ( vehWeapon->iLifeTime ) {//expire after a time @@ -3771,6 +3816,13 @@ gentity_t *WP_FireVehicleWeapon( gentity_t *ent, vec3_t start, vec3_t dir, vehWe } if ( !vehWeapon->fSpeed ) {//a mine or something? + if ( vehWeapon->iHealth ) + {//the missile can take damage + missile->health = vehWeapon->iHealth; + missile->takedamage = qtrue; + missile->r.contents = MASK_SHOT; + missile->die = RocketDie; + } //only do damage when someone touches us missile->s.weapon = WP_THERMAL;//does this really matter? G_SetOrigin( missile, start ); @@ -3851,6 +3903,7 @@ void G_EstimateCamPos( vec3_t viewAngles, vec3_t cameraFocusLoc, float viewheigh cameraFocusAngles[PITCH] += pitchOffset; if ( !bg_fighterAltControl.integer ) {//clamp view pitch + cameraFocusAngles[PITCH] = AngleNormalize180( cameraFocusAngles[PITCH] ); if (cameraFocusAngles[PITCH] > 80.0) { cameraFocusAngles[PITCH] = 80.0; @@ -3954,13 +4007,48 @@ void WP_GetVehicleCamPos( gentity_t *ent, gentity_t *pilot, vec3_t camPos ) } } + //Control Scheme 3 Method: + G_EstimateCamPos( ent->client->ps.viewangles, pilot->client->ps.origin, pilot->client->ps.viewheight, thirdPersonRange, + thirdPersonHorzOffset, vertOffset, pitchOffset, + pilot->s.number, camPos ); + /* + //Control Scheme 2 Method: G_EstimateCamPos( ent->m_pVehicle->m_vOrientation, ent->r.currentOrigin, pilot->client->ps.viewheight, thirdPersonRange, thirdPersonHorzOffset, vertOffset, pitchOffset, pilot->s.number, camPos ); + */ +} + +void WP_VehLeadCrosshairVeh( gentity_t *camTraceEnt, vec3_t newEnd, const vec3_t dir, const vec3_t shotStart, vec3_t shotDir ) +{ + if ( g_vehAutoAimLead.integer ) + { + if ( camTraceEnt + && camTraceEnt->client + && camTraceEnt->client->NPC_class == CLASS_VEHICLE ) + {//if the crosshair is on a vehicle, lead it + float dot, distAdjust = DotProduct( camTraceEnt->client->ps.velocity, dir ); + vec3_t predPos, predShotDir; + if ( distAdjust > 500 || DistanceSquared( camTraceEnt->client->ps.origin, shotStart ) > 7000000 ) + {//moving away from me at a decent speed and/or more than @2600 units away from me + VectorMA( newEnd, distAdjust, dir, predPos ); + VectorSubtract( predPos, shotStart, predShotDir ); + VectorNormalize( predShotDir ); + dot = DotProduct( predShotDir, shotDir ); + if ( dot >= 0.75f ) + {//if the new aim vector is no more than 23 degrees off the original one, go ahead and adjust the aim + VectorCopy( predPos, newEnd ); + } + } + } + } + VectorSubtract( newEnd, shotStart, shotDir ); + VectorNormalize( shotDir ); } #define MAX_XHAIR_DIST_ACCURACY 20000.0f extern float g_cullDistance; +extern int BG_VehTraceFromCamPos( trace_t *camTrace, bgEntity_t *bgEnt, const vec3_t entOrg, const vec3_t shotStart, const vec3_t end, vec3_t newEnd, vec3_t shotDir, float bestDist ); qboolean WP_VehCheckTraceFromCamPos( gentity_t *ent, const vec3_t shotStart, vec3_t shotDir ) { //FIXME: only if dynamicCrosshair and dynamicCrosshairPrecision is on! @@ -4011,28 +4099,12 @@ qboolean WP_VehCheckTraceFromCamPos( gentity_t *ent, const vec3_t shotStart, vec } else {//NOW do the trace from the camPos and compare with above trace - //NOTE: this MUST stay up to date with the method used in CG_ScanForCrosshairEntity (where it checks the doExtraVehTraceFromViewPos bool) trace_t extraTrace; - vec3_t viewDir2End, extraEnd, camPos; - float minAutoAimDist; - - WP_GetVehicleCamPos( ent, (gentity_t *)ent->m_pVehicle->m_pPilot, camPos ); - - minAutoAimDist = Distance( ent->r.currentOrigin, camPos ) + (ent->m_pVehicle->m_pVehicleInfo->length/2.0f) + 200.0f; - - VectorSubtract( end, camPos, viewDir2End ); - VectorNormalize( viewDir2End ); - VectorMA( camPos, MAX_XHAIR_DIST_ACCURACY, viewDir2End, extraEnd ); - trap_Trace( &extraTrace, camPos, vec3_origin, vec3_origin, extraEnd, - ent->s.number, CONTENTS_SOLID|CONTENTS_BODY ); - if ( !extraTrace.allsolid - && !extraTrace.startsolid - && extraTrace.fraction < 1.0f - && (extraTrace.fraction*MAX_XHAIR_DIST_ACCURACY) > minAutoAimDist - && ((extraTrace.fraction*MAX_XHAIR_DIST_ACCURACY)-Distance( ent->r.currentOrigin, camPos )) < (trace.fraction*g_cullDistance) ) - {//this trace hit *something* that's closer than the thing the main trace hit, so use this result instead - VectorSubtract( extraTrace.endpos, shotStart, shotDir ); - VectorNormalize( shotDir ); + vec3_t newEnd; + int camTraceEntNum = BG_VehTraceFromCamPos( &extraTrace, (bgEntity_t *)ent, ent->r.currentOrigin, shotStart, end, newEnd, shotDir, (trace.fraction*g_cullDistance) ); + if ( camTraceEntNum ) + { + WP_VehLeadCrosshairVeh( &g_entities[camTraceEntNum-1], newEnd, dir, shotStart, shotDir ); return qtrue; } } @@ -4225,6 +4297,7 @@ void FireVehicleWeapon( gentity_t *ent, qboolean alt_fire ) trace_t trace; vec3_t end; vec3_t ang; + vec3_t fixedDir; if (pVeh->m_pVehicleInfo->type == VH_SPEEDER) { @@ -4234,14 +4307,15 @@ void FireVehicleWeapon( gentity_t *ent, qboolean alt_fire ) { VectorCopy(pVeh->m_vOrientation, ang); } - AngleVectors( ang, dir, NULL, NULL ); - VectorMA( ent->r.currentOrigin, 32768, dir, end ); + AngleVectors( ang, fixedDir, NULL, NULL ); + VectorMA( ent->r.currentOrigin, 32768, fixedDir, end ); //VectorMA( ent->r.currentOrigin, 8192, dir, end ); trap_Trace( &trace, ent->r.currentOrigin, vec3_origin, vec3_origin, end, ent->s.number, MASK_SHOT ); if ( trace.fraction < 1.0f && !trace.allsolid && !trace.startsolid ) { - VectorSubtract( trace.endpos, start, dir ); - VectorNormalize( dir ); + vec3_t newEnd; + VectorCopy( trace.endpos, newEnd ); + WP_VehLeadCrosshairVeh( &g_entities[trace.entityNum], newEnd, fixedDir, start, dir ); } } diff --git a/codemp/game/mssccprj.scc b/codemp/game/mssccprj.scc index da4c818..38c4259 100644 --- a/codemp/game/mssccprj.scc +++ b/codemp/game/mssccprj.scc @@ -1,5 +1,5 @@ SCC = This is a Source Code Control file [JK2_game.vcproj] -SCC_Aux_Path = "\\ravendata1\vss\central_code" +SCC_Aux_Path = "\\ravendata1\VSS\central_code" SCC_Project_Name = "$/jedi/codemp/game", EGAAAAAA diff --git a/codemp/game/q_math.c b/codemp/game/q_math.c index aab7f34..6f61016 100644 --- a/codemp/game/q_math.c +++ b/codemp/game/q_math.c @@ -1442,14 +1442,16 @@ float flrand(float min, float max) { float result; - assert((max - min) < 32768); - holdrand = (holdrand * 214013L) + 2531011L; result = (float)(holdrand >> 17); // 0 - 32767 range result = ((result * (max - min)) / 32768.0F) + min; return(result); } +float Q_flrand(float min, float max) +{ + return flrand(min,max); +} // Returns an integer min <= x <= max (ie inclusive) @@ -1466,6 +1468,11 @@ int irand(int min, int max) return(result); } +int Q_irand(int value1, int value2) +{ + return irand(value1, value2); +} + float powf ( float x, int y ) { float r = x; diff --git a/codemp/game/q_shared.c b/codemp/game/q_shared.c index e026398..c495668 100644 --- a/codemp/game/q_shared.c +++ b/codemp/game/q_shared.c @@ -1365,14 +1365,6 @@ void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) { strcat (s, newi); } - -//rww - convience function.. -int Q_irand(int value1, int value2) -{ - value2++; //so it can round down - return ((rand() * (value2 - value1)) >> 15) + value1; -} - //==================================================================== diff --git a/codemp/game/q_shared.h b/codemp/game/q_shared.h index 8926d97..26ae173 100644 --- a/codemp/game/q_shared.h +++ b/codemp/game/q_shared.h @@ -682,6 +682,56 @@ typedef enum SS_NUM_SABER_STYLES } saber_styles_t; +//SABER FLAGS +//Old bools converted to a flag now +#define SFL_NOT_LOCKABLE (1<<0)//can't get into a saberlock +#define SFL_NOT_THROWABLE (1<<1)//can't be thrown - FIXME: maybe make this a max level of force saber throw that can be used with this saber? +#define SFL_NOT_DISARMABLE (1<<2)//can't be dropped +#define SFL_NOT_ACTIVE_BLOCKING (1<<3)//don't to try to block incoming shots with this saber +#define SFL_TWO_HANDED (1<<4)//uses both hands +#define SFL_SINGLE_BLADE_THROWABLE (1<<5)//can throw this saber if only the first blade is on +#define SFL_RETURN_DAMAGE (1<<6)//when returning from a saber throw, it keeps spinning and doing damage +//NEW FLAGS +#define SFL_ON_IN_WATER (1<<7)//if set, weapon stays active even in water +#define SFL_BOUNCE_ON_WALLS (1<<8)//if set, the saber will bounce back when it hits solid architecture (good for real-sword type mods) +#define SFL_BOLT_TO_WRIST (1<<9)//if set, saber model is bolted to wrist, not in hand... useful for things like claws & shields, etc. +//#define SFL_STICK_ON_IMPACT (1<= NUM_FORCE_MASTERY_LEVELS) + {//ack, prevent user from being dumb + maxRank = FORCE_MASTERY_JEDI_MASTER; + trap_Cvar_Set( "g_maxForceRank", va("%i", maxRank) ); + } /* if (g_forcePowerDisable.integer) @@ -462,7 +467,7 @@ void WP_InitForcePowers( gentity_t *ent ) { if (warnClient || !ent->client->sess.setForce) { //the client's rank is too high for the server and has been autocapped, so tell them - if (g_gametype.integer != GT_HOLOCRON && g_gametype.integer != GT_JEDIMASTER) + if (g_gametype.integer != GT_HOLOCRON && g_gametype.integer != GT_JEDIMASTER ) { #ifdef EVENT_FORCE_RANK gentity_t *te = G_TempEntity( vec3_origin, EV_GIVE_NEW_RANK ); @@ -501,7 +506,7 @@ void WP_InitForcePowers( gentity_t *ent ) ent->client->sess.setForce = qtrue; } - if (!didEvent) + if (!didEvent ) { #ifdef EVENT_FORCE_RANK gentity_t *te = G_TempEntity( vec3_origin, EV_GIVE_NEW_RANK ); @@ -879,7 +884,7 @@ qboolean WP_ForcePowerUsable( gentity_t *self, forcePowers_t forcePower ) if ( !self->client->ps.saberHolstered ) { - if ( self->client->saber[0].twoHanded ) + if ( (self->client->saber[0].saberFlags&SFL_TWO_HANDED) ) { if ( g_saberRestrictForce.integer ) { @@ -897,7 +902,7 @@ qboolean WP_ForcePowerUsable( gentity_t *self, forcePowers_t forcePower ) } } - if ( self->client->saber[0].twoHanded + if ( (self->client->saber[0].saberFlags&SFL_TWO_HANDED) || (self->client->saber[0].model && self->client->saber[0].model[0]) ) {//this saber requires the use of two hands OR our other hand is using an active saber too if ( (self->client->saber[0].forceRestrictions&(1<client->ps.otherKiller = self->s.number; push_list[x]->client->ps.otherKillerTime = level.time + 5000; push_list[x]->client->ps.otherKillerDebounceTime = level.time + 100; + push_list[x]->client->otherKillerMOD = MOD_UNKNOWN; + push_list[x]->client->otherKillerVehWeapon = 0; + push_list[x]->client->otherKillerWeaponType = WP_NONE; pushPowerMod -= (dirLen*0.7); if (pushPowerMod < 16) @@ -4034,6 +4042,9 @@ void DoGripAction(gentity_t *self, forcePowers_t forcePower) gripEnt->client->ps.otherKiller = self->s.number; gripEnt->client->ps.otherKillerTime = level.time + 5000; gripEnt->client->ps.otherKillerDebounceTime = level.time + 100; + gripEnt->client->otherKillerMOD = MOD_UNKNOWN; + gripEnt->client->otherKillerVehWeapon = 0; + gripEnt->client->otherKillerWeaponType = WP_NONE; gripEnt->client->ps.forceGripChangeMovetype = PM_FLOAT; @@ -4067,6 +4078,9 @@ void DoGripAction(gentity_t *self, forcePowers_t forcePower) gripEnt->client->ps.otherKiller = self->s.number; gripEnt->client->ps.otherKillerTime = level.time + 5000; gripEnt->client->ps.otherKillerDebounceTime = level.time + 100; + gripEnt->client->otherKillerMOD = MOD_UNKNOWN; + gripEnt->client->otherKillerVehWeapon = 0; + gripEnt->client->otherKillerWeaponType = WP_NONE; gripEnt->client->ps.forceGripChangeMovetype = PM_FLOAT; diff --git a/codemp/game/w_saber.c b/codemp/game/w_saber.c index ab3e1c7..41fcfd1 100644 --- a/codemp/game/w_saber.c +++ b/codemp/game/w_saber.c @@ -27,13 +27,19 @@ qboolean BG_SaberInReturn( int move ); qboolean BG_InKnockDownOnGround( playerState_t *ps ); qboolean BG_StabDownAnim( int anim ); qboolean BG_SabersOff( playerState_t *ps ); +qboolean BG_SaberInTransitionAny( int move ); +qboolean BG_SaberInAttackPure( int move ); +qboolean WP_SaberBladeUseSecondBladeStyle( saberInfo_t *saber, int bladeNum ); +qboolean WP_SaberBladeDoTransitionDamage( saberInfo_t *saber, int bladeNum ); #include "../namespace_end.h" void WP_SaberAddG2Model( gentity_t *saberent, const char *saberModel, qhandle_t saberSkin ); void WP_SaberRemoveG2Model( gentity_t *saberent ); float RandFloat(float min, float max) { - return ((rand() * (max - min)) / 32768.0F) + min; +// return ((rand() * (max - min)) / 32768.0F) + min; +//for linux: + return ((rand() * (max - min)) / (float)RAND_MAX) + min; } #ifdef DEBUG_SABER_BOX @@ -374,6 +380,9 @@ static GAME_INLINE void SetSaberBoxSize(gentity_t *saberent) int i; int j = 0; int k = 0; + qboolean dualSabers = qfalse; + qboolean alwaysBlock[MAX_SABERS][MAX_BLADES]; + qboolean forceBlock = qfalse; assert(saberent && saberent->inuse); @@ -393,18 +402,63 @@ static GAME_INLINE void SetSaberBoxSize(gentity_t *saberent) return; } + if ( owner->client->saber[1].model + && owner->client->saber[1].model[0] ) + { + dualSabers = qtrue; + } + if ( PM_SaberInBrokenParry(owner->client->ps.saberMove) || BG_SuperBreakLoseAnim( owner->client->ps.torsoAnim ) ) { //let swings go right through when we're in this state - VectorSet( saberent->r.mins, 0, 0, 0 ); - VectorSet( saberent->r.maxs, 0, 0, 0 ); -#ifndef FINAL_BUILD - if (g_saberDebugPrint.integer > 1) + for ( i = 0; i < MAX_SABERS; i++ ) { - Com_Printf("Client %i in broken parry, saber box 0\n", owner->s.number); + if ( i > 0 && !dualSabers ) + {//not using a second saber, set it to not blocking + for ( j = 0; j < MAX_BLADES; j++ ) + { + alwaysBlock[i][j] = qfalse; + } + } + else + { + if ( (owner->client->saber[i].saberFlags2&SFL2_ALWAYS_BLOCK) ) + { + for ( j = 0; j < owner->client->saber[i].numBlades; j++ ) + { + alwaysBlock[i][j] = qtrue; + forceBlock = qtrue; + } + } + if ( owner->client->saber[i].bladeStyle2Start > 0 ) + { + for ( j = owner->client->saber[i].bladeStyle2Start; j < owner->client->saber[i].numBlades; j++ ) + { + if ( (owner->client->saber[i].saberFlags2&SFL2_ALWAYS_BLOCK2) ) + { + alwaysBlock[i][j] = qtrue; + forceBlock = qtrue; + } + else + { + alwaysBlock[i][j] = qfalse; + } + } + } + } } + if ( !forceBlock ) + {//no sabers/blades to FORCE to be on, so turn off blocking altogether + VectorSet( saberent->r.mins, 0, 0, 0 ); + VectorSet( saberent->r.maxs, 0, 0, 0 ); +#ifndef FINAL_BUILD + if (g_saberDebugPrint.integer > 1) + { + Com_Printf("Client %i in broken parry, saber box 0\n", owner->s.number); + } #endif - return; + return; + } } if ((level.time - owner->client->lastSaberStorageTime) > 200 || @@ -415,6 +469,27 @@ static GAME_INLINE void SetSaberBoxSize(gentity_t *saberent) return; } + if ( dualSabers + || owner->client->saber[0].numBlades > 1 ) + {//dual sabers or multi-blade saber + if ( owner->client->ps.saberHolstered > 1 ) + {//entirely off + //no blocking at all + VectorSet( saberent->r.mins, 0, 0, 0 ); + VectorSet( saberent->r.maxs, 0, 0, 0 ); + return; + } + } + else + {//single saber + if ( owner->client->ps.saberHolstered ) + {//off + //no blocking at all + VectorSet( saberent->r.mins, 0, 0, 0 ); + VectorSet( saberent->r.maxs, 0, 0, 0 ); + return; + } + } //Start out at the saber origin, then go through all the blades and push out the extents //for each blade, then set the box relative to the origin. VectorCopy(saberent->r.currentOrigin, saberent->r.mins); @@ -428,9 +503,35 @@ static GAME_INLINE void SetSaberBoxSize(gentity_t *saberent) { break; } - + if ( dualSabers + && owner->client->ps.saberHolstered == 1 + && j == 1 ) + { //this mother is holstered, get outta here. + j++; + continue; + } for (k = 0; k < owner->client->saber[j].numBlades; k++) { + if ( k > 0 ) + {//not the first blade + if ( !dualSabers ) + {//using a single saber + if ( owner->client->saber[j].numBlades > 1 ) + {//with multiple blades + if( owner->client->ps.saberHolstered == 1 ) + {//all blades after the first one are off + break; + } + } + } + } + if ( forceBlock ) + {//only do blocking with blades that are marked to block + if ( !alwaysBlock[j][k] ) + {//this blade shouldn't be blocking + continue; + } + } //VectorMA(owner->client->saber[j].blade[k].muzzlePoint, owner->client->saber[j].blade[k].lengthMax*0.5f, owner->client->saber[j].blade[k].muzzleDir, saberOrg); VectorCopy(owner->client->saber[j].blade[k].muzzlePoint, saberOrg); VectorMA(owner->client->saber[j].blade[k].muzzlePoint, owner->client->saber[j].blade[k].lengthMax, owner->client->saber[j].blade[k].muzzleDir, saberTip); @@ -1462,22 +1563,22 @@ qboolean WP_SabersCheckLock( gentity_t *ent1, gentity_t *ent2 ) return qfalse; } - if ( !ent1->client->saber[0].lockable - || !ent2->client->saber[0].lockable ) + if ( (ent1->client->saber[0].saberFlags&SFL_NOT_LOCKABLE) + || (ent2->client->saber[0].saberFlags&SFL_NOT_LOCKABLE) ) { return qfalse; } if ( ent1->client->saber[1].model && ent1->client->saber[1].model[0] && !ent1->client->ps.saberHolstered - && !ent1->client->saber[1].lockable ) + && (ent1->client->saber[1].saberFlags&SFL_NOT_LOCKABLE) ) { return qfalse; } if ( ent2->client->saber[1].model && ent2->client->saber[1].model[0] && !ent2->client->ps.saberHolstered - && !ent2->client->saber[1].lockable ) + && (ent2->client->saber[1].saberFlags&SFL_NOT_LOCKABLE) ) { return qfalse; } @@ -2146,7 +2247,7 @@ static GAME_INLINE int G_GetAttackDamage(gentity_t *self, int minDmg, int maxDmg float animSpeedFactor = 1.0f; //Be sure to scale by the proper anim speed just as if we were going to play the animation - BG_SaberStartTransAnim(self->client->ps.fd.saberAnimLevel, self->client->ps.torsoAnim, &animSpeedFactor, self->client->ps.brokenLimbs); + BG_SaberStartTransAnim(self->s.number, self->client->ps.fd.saberAnimLevel, self->client->ps.weapon, self->client->ps.torsoAnim, &animSpeedFactor, self->client->ps.brokenLimbs); speedDif = attackAnimLength - (attackAnimLength * animSpeedFactor); attackAnimLength += speedDif; peakPoint = attackAnimLength; @@ -2195,7 +2296,7 @@ static GAME_INLINE float G_GetAnimPoint(gentity_t *self) float animPercentage = 0; //Be sure to scale by the proper anim speed just as if we were going to play the animation - BG_SaberStartTransAnim(self->client->ps.fd.saberAnimLevel, self->client->ps.torsoAnim, &animSpeedFactor, self->client->ps.brokenLimbs); + BG_SaberStartTransAnim(self->s.number, self->client->ps.fd.saberAnimLevel, self->client->ps.weapon, self->client->ps.torsoAnim, &animSpeedFactor, self->client->ps.brokenLimbs); speedDif = attackAnimLength - (attackAnimLength * animSpeedFactor); attackAnimLength += speedDif; @@ -2287,7 +2388,17 @@ static GAME_INLINE qboolean G_G2TraceCollide(trace_t *tr, vec3_t lastValidStart, angles[YAW] = g2Hit->r.currentAngles[YAW]; } - trap_G2API_CollisionDetect ( G2Trace, g2Hit->ghoul2, angles, g2HitOrigin, level.time, g2Hit->s.number, lastValidStart, lastValidEnd, g2Hit->modelScale, 0, g_g2TraceLod.integer, fRadius ); + if (g_optvehtrace.integer && + g2Hit->s.eType == ET_NPC && + g2Hit->s.NPC_class == CLASS_VEHICLE && + g2Hit->m_pVehicle) + { + trap_G2API_CollisionDetectCache ( G2Trace, g2Hit->ghoul2, angles, g2HitOrigin, level.time, g2Hit->s.number, lastValidStart, lastValidEnd, g2Hit->modelScale, 0, g_g2TraceLod.integer, fRadius ); + } + else + { + trap_G2API_CollisionDetect ( G2Trace, g2Hit->ghoul2, angles, g2HitOrigin, level.time, g2Hit->s.number, lastValidStart, lastValidEnd, g2Hit->modelScale, 0, g_g2TraceLod.integer, fRadius ); + } if (G2Trace[0].mEntityNum != g2Hit->s.number) { @@ -3391,9 +3502,12 @@ static GAME_INLINE int G_PowerLevelForSaberAnim( gentity_t *ent, int saberNum, q #define MAX_SABER_VICTIMS 16 static int victimEntityNum[MAX_SABER_VICTIMS]; +static qboolean victimHitEffectDone[MAX_SABER_VICTIMS]; static float totalDmg[MAX_SABER_VICTIMS]; static vec3_t dmgDir[MAX_SABER_VICTIMS]; static vec3_t dmgSpot[MAX_SABER_VICTIMS]; +static qboolean dismemberDmg[MAX_SABER_VICTIMS]; +static int saberKnockbackFlags[MAX_SABER_VICTIMS]; static int numVictims = 0; void WP_SaberClearDamage( void ) { @@ -3402,13 +3516,17 @@ void WP_SaberClearDamage( void ) { victimEntityNum[ven] = ENTITYNUM_NONE; } - memset( totalDmg, 0, sizeof( totalDmg) ); + memset( victimHitEffectDone, 0, sizeof( victimHitEffectDone ) ); + memset( totalDmg, 0, sizeof( totalDmg ) ); memset( dmgDir, 0, sizeof( dmgDir ) ); memset( dmgSpot, 0, sizeof( dmgSpot ) ); + memset( dismemberDmg, 0, sizeof( dismemberDmg ) ); + memset( saberKnockbackFlags, 0, sizeof( saberKnockbackFlags ) ); numVictims = 0; } -void WP_SaberDamageAdd( int trVictimEntityNum, vec3_t trDmgDir, vec3_t trDmgSpot, int trDmg ) +void WP_SaberDamageAdd( int trVictimEntityNum, vec3_t trDmgDir, vec3_t trDmgSpot, + int trDmg, qboolean doDismemberment, int knockBackFlags ) { if ( trVictimEntityNum < 0 || trVictimEntityNum >= ENTITYNUM_WORLD ) { @@ -3448,6 +3566,11 @@ void WP_SaberDamageAdd( int trVictimEntityNum, vec3_t trDmgDir, vec3_t trDmgSpot { VectorCopy( trDmgSpot, dmgSpot[curVictim] ); } + if ( doDismemberment ) + { + dismemberDmg[curVictim] = qtrue; + } + saberKnockbackFlags[curVictim] |= knockBackFlags; } } @@ -3460,8 +3583,8 @@ void WP_SaberApplyDamage( gentity_t *self ) } for ( i = 0; i < numVictims; i++ ) { - gentity_t *te = NULL, *victim = NULL; - qboolean isDroid = qfalse; + gentity_t *victim = NULL; + int dflags = 0; victim = &g_entities[victimEntityNum[i]]; @@ -3471,7 +3594,37 @@ void WP_SaberApplyDamage( gentity_t *self ) totalDmg[i] *= g_saberWallDamageScale.value; } - G_Damage( victim, self, self, dmgDir[i], dmgSpot[i], totalDmg[i], 0, MOD_SABER ); + if ( !dismemberDmg[i] ) + {//don't do dismemberment! + dflags |= DAMAGE_NO_DISMEMBER; + } + dflags |= saberKnockbackFlags[i]; + + G_Damage( victim, self, self, dmgDir[i], dmgSpot[i], totalDmg[i], dflags, MOD_SABER ); + } +} + + +void WP_SaberDoHit( gentity_t *self, int saberNum, int bladeNum ) +{ + int i; + if ( !numVictims ) + { + return; + } + for ( i = 0; i < numVictims; i++ ) + { + gentity_t *te = NULL, *victim = NULL; + qboolean isDroid = qfalse; + + if ( victimHitEffectDone[i] ) + { + continue; + } + + victimHitEffectDone[i] = qtrue; + + victim = &g_entities[victimEntityNum[i]]; if ( victim->client ) { @@ -3491,6 +3644,8 @@ void WP_SaberApplyDamage( gentity_t *self ) { te->s.otherEntityNum = victimEntityNum[i]; te->s.otherEntityNum2 = self->s.number; + te->s.weapon = saberNum; + te->s.legsAnim = bladeNum; VectorCopy(dmgSpot[i], te->s.origin); //VectorCopy(tr.plane.normal, te->s.angles); @@ -3519,12 +3674,118 @@ void WP_SaberApplyDamage( gentity_t *self ) } else { - if (totalDmg[i] > SABER_NONATTACK_DAMAGE) - { //I suppose I could tie this into the saberblock event, but I'm tired of adding flags to that thing. - gentity_t *teS = G_TempEntity( te->s.origin, EV_SABER_CLASHFLARE ); - VectorCopy(te->s.origin, teS->s.origin); + if ( !WP_SaberBladeUseSecondBladeStyle( &self->client->saber[saberNum], bladeNum ) + && (self->client->saber[saberNum].saberFlags2&SFL2_NO_CLASH_FLARE) ) + {//don't do clash flare + } + else if ( WP_SaberBladeUseSecondBladeStyle( &self->client->saber[saberNum], bladeNum ) + && (self->client->saber[saberNum].saberFlags2&SFL2_NO_CLASH_FLARE2) ) + {//don't do clash flare + } + else + { + if (totalDmg[i] > SABER_NONATTACK_DAMAGE) + { //I suppose I could tie this into the saberblock event, but I'm tired of adding flags to that thing. + gentity_t *teS = G_TempEntity( te->s.origin, EV_SABER_CLASHFLARE ); + VectorCopy(te->s.origin, teS->s.origin); + } + te->s.eventParm = 0; + } + } + } + } +} + +extern qboolean G_EntIsBreakable( int entityNum ); +extern void G_Knockdown( gentity_t *victim ); +void WP_SaberRadiusDamage( gentity_t *ent, vec3_t point, float radius, int damage, float knockBack ) +{ + if ( !ent || !ent->client ) + { + return; + } + else if ( radius <= 0.0f || (damage <= 0 && knockBack <= 0) ) + { + return; + } + else + { + vec3_t mins, maxs, entDir; + int radiusEnts[128]; + gentity_t *radiusEnt = NULL; + int numEnts, i; + float dist; + + //Setup the bbox to search in + for ( i = 0; i < 3; i++ ) + { + mins[i] = point[i] - radius; + maxs[i] = point[i] + radius; + } + + //Get the number of entities in a given space + numEnts = trap_EntitiesInBox( mins, maxs, radiusEnts, 128 ); + + for ( i = 0; i < numEnts; i++ ) + { + radiusEnt = &g_entities[radiusEnts[i]]; + if ( !radiusEnt->inuse ) + { + continue; + } + + if ( radiusEnt == ent ) + {//Skip myself + continue; + } + + if ( radiusEnt->client == NULL ) + {//must be a client + if ( G_EntIsBreakable( radiusEnt->s.number ) ) + {//damage breakables within range, but not as much + G_Damage( radiusEnt, ent, ent, vec3_origin, radiusEnt->r.currentOrigin, 10, 0, MOD_MELEE ); + } + continue; + } + + if ( (radiusEnt->client->ps.eFlags2&EF2_HELD_BY_MONSTER) ) + {//can't be one being held + continue; + } + + VectorSubtract( radiusEnt->r.currentOrigin, point, entDir ); + dist = VectorNormalize( entDir ); + if ( dist <= radius ) + {//in range + if ( damage > 0 ) + {//do damage + int points = ceil((float)damage*dist/radius); + G_Damage( radiusEnt, ent, ent, vec3_origin, radiusEnt->r.currentOrigin, points, DAMAGE_NO_KNOCKBACK, MOD_MELEE ); + } + if ( knockBack > 0 ) + {//do knockback + if ( radiusEnt->client + && radiusEnt->client->NPC_class != CLASS_RANCOR + && radiusEnt->client->NPC_class != CLASS_ATST + && !(radiusEnt->flags&FL_NO_KNOCKBACK) )//don't throw them back + { + float knockbackStr = knockBack*dist/radius; + entDir[2] += 0.1f; + VectorNormalize( entDir ); + G_Throw( radiusEnt, entDir, knockbackStr ); + if ( radiusEnt->health > 0 ) + {//still alive + if ( knockbackStr > 50 ) + {//close enough and knockback high enough to possibly knock down + if ( dist < (radius*0.5f) + || radiusEnt->client->ps.groundEntityNum != ENTITYNUM_NONE ) + {//within range of my fist or within ground-shaking range and not in the air + G_Knockdown( radiusEnt );//, ent, entDir, 500, qtrue ); + } + } + } + } } - te->s.eventParm = 0; } } } @@ -3534,7 +3795,7 @@ static qboolean saberDoClashEffect = qfalse; static vec3_t saberClashPos = {0}; static vec3_t saberClashNorm = {0}; static int saberClashEventParm = 1; -void WP_SaberDoClash( void ) +void WP_SaberDoClash( gentity_t *self, int saberNum, int bladeNum ) { if ( saberDoClashEffect ) { @@ -3542,6 +3803,43 @@ void WP_SaberDoClash( void ) VectorCopy(saberClashPos, te->s.origin); VectorCopy(saberClashNorm, te->s.angles); te->s.eventParm = saberClashEventParm; + te->s.otherEntityNum2 = self->s.number; + te->s.weapon = saberNum; + te->s.legsAnim = bladeNum; + } +} + +void WP_SaberBounceSound( gentity_t *ent, int saberNum, int bladeNum ) +{ + int index = 1; + if ( !ent || !ent->client ) + { + return; + } + index = Q_irand( 1, 9 ); + if ( !WP_SaberBladeUseSecondBladeStyle( &ent->client->saber[saberNum], bladeNum ) + && ent->client->saber[saberNum].bounceSound[0] ) + { + G_Sound( ent, CHAN_AUTO, ent->client->saber[saberNum].bounceSound[Q_irand( 0, 2 )] ); + } + else if ( WP_SaberBladeUseSecondBladeStyle( &ent->client->saber[saberNum], bladeNum ) + && ent->client->saber[saberNum].bounce2Sound[0] ) + { + G_Sound( ent, CHAN_AUTO, ent->client->saber[saberNum].bounce2Sound[Q_irand( 0, 2 )] ); + } + else if ( !WP_SaberBladeUseSecondBladeStyle( &ent->client->saber[saberNum], bladeNum ) + && ent->client->saber[saberNum].blockSound[0] ) + { + G_Sound( ent, CHAN_AUTO, ent->client->saber[saberNum].blockSound[Q_irand( 0, 2 )] ); + } + else if ( WP_SaberBladeUseSecondBladeStyle( &ent->client->saber[saberNum], bladeNum ) + && ent->client->saber[saberNum].block2Sound[0] ) + { + G_Sound( ent, CHAN_AUTO, ent->client->saber[saberNum].block2Sound[Q_irand( 0, 2 )] ); + } + else + { + G_Sound( ent, CHAN_AUTO, G_SoundIndex( va( "sound/weapons/saber/saberblock%d.wav", index ) ) ); } } @@ -3635,8 +3933,16 @@ static GAME_INLINE qboolean CheckSaberDamage(gentity_t *self, int rSaberNum, int int traceTests = 0; float trDif = 8; - VectorCopy(self->client->saber[rSaberNum].blade[rBladeNum].trail.base, oldSaberStart); - VectorCopy(self->client->saber[rSaberNum].blade[rBladeNum].trail.tip, oldSaberEnd); + if ( (level.time-self->client->saber[rSaberNum].blade[rBladeNum].trail.lastTime) > 100 ) + {//no valid last pos, use current + VectorCopy(saberStart, oldSaberStart); + VectorCopy(saberEnd, oldSaberEnd); + } + else + {//trace from last pos + VectorCopy(self->client->saber[rSaberNum].blade[rBladeNum].trail.base, oldSaberStart); + VectorCopy(self->client->saber[rSaberNum].blade[rBladeNum].trail.tip, oldSaberEnd); + } VectorSubtract(saberStart, saberEnd, saberDif); VectorSubtract(oldSaberStart, oldSaberEnd, oldSaberDif); @@ -3674,8 +3980,16 @@ static GAME_INLINE qboolean CheckSaberDamage(gentity_t *self, int rSaberNum, int while (tr.fraction == 1.0 && traceTests < 4 && tr.entityNum >= ENTITYNUM_NONE) { - VectorCopy(self->client->saber[rSaberNum].blade[rBladeNum].trail.base, oldSaberStart); - VectorCopy(self->client->saber[rSaberNum].blade[rBladeNum].trail.tip, oldSaberEnd); + if ( (level.time-self->client->saber[rSaberNum].blade[rBladeNum].trail.lastTime) > 100 ) + {//no valid last pos, use current + VectorCopy(saberStart, oldSaberStart); + VectorCopy(saberEnd, oldSaberEnd); + } + else + {//trace from last pos + VectorCopy(self->client->saber[rSaberNum].blade[rBladeNum].trail.base, oldSaberStart); + VectorCopy(self->client->saber[rSaberNum].blade[rBladeNum].trail.tip, oldSaberEnd); + } VectorSubtract(saberStart, saberEnd, saberDif); VectorSubtract(oldSaberStart, oldSaberEnd, oldSaberDif); @@ -3759,11 +4073,13 @@ static GAME_INLINE qboolean CheckSaberDamage(gentity_t *self, int rSaberNum, int saberTraceDone = qtrue; } - if ( (SaberAttacking(self) + if ( self->client->ps.saberAttackWound < level.time + && (SaberAttacking(self) || BG_SuperBreakWinAnim(self->client->ps.torsoAnim) || (d_saberSPStyleDamage.integer&&self->client->ps.saberInFlight&&rSaberNum==0) - || (self->client->ps.m_iVehicleNum && self->client->ps.saberMove > LS_READY) ) && - self->client->ps.saberAttackWound < level.time ) + || (WP_SaberBladeDoTransitionDamage( &self->client->saber[rSaberNum], rBladeNum )&&BG_SaberInTransitionAny(self->client->ps.saberMove)) + || (self->client->ps.m_iVehicleNum && self->client->ps.saberMove > LS_READY) ) + ) { //this animation is that of the last attack movement, and so it should do full damage qboolean saberInSpecial = BG_SaberInSpecial(self->client->ps.saberMove); qboolean inBackAttack = G_SaberInBackAttack(self->client->ps.saberMove); @@ -3991,6 +4307,10 @@ static GAME_INLINE qboolean CheckSaberDamage(gentity_t *self, int rSaberNum, int else if (self->client->ps.saberAttackWound < level.time && self->client->ps.saberIdleWound < level.time) { //just touching, do minimal damage and only check for it every 200ms (mainly to cut down on network traffic for hit events) + if ( (self->client->saber[0].saberFlags2&SFL2_NO_IDLE_EFFECT) ) + {//no idle damage or effects + return qtrue;//true cause even though we didn't get a hit, we don't want to do those extra traces because the debounce time says not to. + } trMask &= ~CONTENTS_LIGHTSABER; if ( d_saberSPStyleDamage.integer ) { @@ -4089,6 +4409,18 @@ static GAME_INLINE qboolean CheckSaberDamage(gentity_t *self, int rSaberNum, int { dmg *= g_saberDamageScale.value; + //see if this specific saber has a damagescale + if ( !WP_SaberBladeUseSecondBladeStyle( &self->client->saber[rSaberNum], rBladeNum ) + && self->client->saber[rSaberNum].damageScale != 1.0f ) + { + dmg = ceil( (float)dmg*self->client->saber[rSaberNum].damageScale ); + } + else if ( WP_SaberBladeUseSecondBladeStyle( &self->client->saber[rSaberNum], rBladeNum ) + && self->client->saber[rSaberNum].damageScale2 != 1.0f ) + { + dmg = ceil( (float)dmg*self->client->saber[rSaberNum].damageScale2 ); + } + if ((self->client->ps.brokenLimbs & (1 << BROKENLIMB_RARM)) || (self->client->ps.brokenLimbs & (1 << BROKENLIMB_LARM))) { //weaken it if an arm is broken @@ -4139,6 +4471,81 @@ static GAME_INLINE qboolean CheckSaberDamage(gentity_t *self, int rSaberNum, int saberHitWall = qtrue; } + if (saberHitWall + && (self->client->saber[rSaberNum].saberFlags & SFL_BOUNCE_ON_WALLS) + && (BG_SaberInAttackPure( self->client->ps.saberMove ) //only in a normal attack anim + || self->client->ps.saberMove == LS_A_JUMP_T__B_ ) //or in the strong jump-fwd-attack "death from above" move + ) + { //then bounce off + /* + qboolean onlyIfNotSpecial = qfalse; + qboolean skipIt = qfalse; + if (tr.plane.normal[2] >= 0.8f || + tr.plane.normal[2] <= -0.8f || + VectorCompare(tr.plane.normal, vec3_origin)) + { + if ((tr.plane.normal[2] >= 0.8f || VectorCompare(tr.plane.normal, vec3_origin)) && + self->client->ps.viewangles[PITCH] <= 30.0f && + self->client->pers.cmd.upmove >= 0) + { //don't hit the ground if we are not looking down a lot/crouched + skipIt = qtrue; + } + else + { + onlyIfNotSpecial = qtrue; + } + } + if (!skipIt && (!onlyIfNotSpecial || !BG_SaberInSpecial(self->client->ps.saberMove))) + */ + { + gentity_t *te = NULL; + /* + qboolean pre = saberDoClashEffect; + + VectorCopy( tr.endpos, saberClashPos ); + VectorCopy( tr.plane.normal, saberClashNorm ); + saberClashEventParm = 1; + saberDoClashEffect = qtrue; + WP_SaberDoClash( self, rSaberNum, rBladeNum ); + saberDoClashEffect = pre; + */ + + self->client->ps.saberMove = BG_BrokenParryForAttack(self->client->ps.saberMove); + self->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN; + if (self->client->ps.torsoAnim == self->client->ps.legsAnim) + { //set anim now on both parts + int anim = saberMoveData[self->client->ps.saberMove].animToUse; + G_SetAnim(self, &self->client->pers.cmd, SETANIM_BOTH, anim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0); + } + + //do bounce sound & force feedback + WP_SaberBounceSound( self, rSaberNum, rBladeNum ); + //do hit effect + te = G_TempEntity( tr.endpos, EV_SABER_HIT ); + te->s.otherEntityNum = ENTITYNUM_NONE;//we didn't hit anyone in particular + te->s.otherEntityNum2 = self->s.number;//send this so it knows who we are + te->s.weapon = rSaberNum; + te->s.legsAnim = rBladeNum; + VectorCopy(tr.endpos, te->s.origin); + VectorCopy(tr.plane.normal, te->s.angles); + if (!te->s.angles[0] && !te->s.angles[1] && !te->s.angles[2]) + { //don't let it play with no direction + te->s.angles[1] = 1; + } + //do radius damage/knockback, if any + if ( !WP_SaberBladeUseSecondBladeStyle( &self->client->saber[rSaberNum], rBladeNum ) ) + { + WP_SaberRadiusDamage( self, tr.endpos, self->client->saber[rSaberNum].splashRadius, self->client->saber[rSaberNum].splashDamage, self->client->saber[rSaberNum].splashKnockback ); + } + else + { + WP_SaberRadiusDamage( self, tr.endpos, self->client->saber[rSaberNum].splashRadius2, self->client->saber[rSaberNum].splashDamage2, self->client->saber[rSaberNum].splashKnockback2 ); + } + + return qtrue; + } + } + //rww - I'm saying || tr.startsolid here, because otherwise your saber tends to skip positions and go through //people, and the compensation traces start in their bbox too. Which results in the saber passing through people //when you visually cut right through them. Which sucks. @@ -4192,7 +4599,7 @@ static GAME_INLINE qboolean CheckSaberDamage(gentity_t *self, int rSaberNum, int } saberDoClashEffect = qtrue; VectorCopy( tr.endpos, saberClashPos ); - VectorCopy( tr.endpos, saberClashNorm ); + VectorCopy( tr.plane.normal, saberClashNorm ); saberClashEventParm = 1; if (dmg > SABER_NONATTACK_DAMAGE) @@ -4232,14 +4639,26 @@ static GAME_INLINE qboolean CheckSaberDamage(gentity_t *self, int rSaberNum, int } else {//damage the thing we hit - if (g_entities[tr.entityNum].client - && !g_entities[tr.entityNum].client->ps.weapon != WP_SABER )//fd.forcePowerLevel[FP_SABER_OFFENSE]) + qboolean doDismemberment = qfalse; + int knockbackFlags = 0; + + if (g_entities[tr.entityNum].client) { //not a "jedi", so make them suffer more if ( dmg > SABER_NONATTACK_DAMAGE ) { //don't bother increasing just for idle touch damage dmg *= 1.5; } } + /* + if (g_entities[tr.entityNum].client + && g_entities[tr.entityNum].client->ps.weapon != WP_SABER )//fd.forcePowerLevel[FP_SABER_OFFENSE]) + { //not a "jedi", so make them suffer more + if ( dmg > SABER_NONATTACK_DAMAGE ) + { //don't bother increasing just for idle touch damage + dmg *= 1.5; + } + } + */ if ( !d_saberSPStyleDamage.integer ) { @@ -4270,7 +4689,44 @@ static GAME_INLINE qboolean CheckSaberDamage(gentity_t *self, int rSaberNum, int } //store the damage, we'll apply it later - WP_SaberDamageAdd( tr.entityNum, dir, tr.endpos, dmg ); + if ( !WP_SaberBladeUseSecondBladeStyle( &self->client->saber[rSaberNum], rBladeNum ) + && !(self->client->saber[rSaberNum].saberFlags2&SFL2_NO_DISMEMBERMENT) ) + { + doDismemberment = qtrue; + } + if ( WP_SaberBladeUseSecondBladeStyle( &self->client->saber[rSaberNum], rBladeNum ) + && !(self->client->saber[rSaberNum].saberFlags2&SFL2_NO_DISMEMBERMENT) ) + { + doDismemberment = qtrue; + } + + if ( !WP_SaberBladeUseSecondBladeStyle( &self->client->saber[rSaberNum], rBladeNum ) + && self->client->saber[rSaberNum].knockbackScale > 0.0f ) + { + if ( rSaberNum < 1 ) + { + knockbackFlags = DAMAGE_SABER_KNOCKBACK1; + } + else + { + knockbackFlags = DAMAGE_SABER_KNOCKBACK2; + } + } + + if ( WP_SaberBladeUseSecondBladeStyle( &self->client->saber[rSaberNum], rBladeNum ) + && self->client->saber[rSaberNum].knockbackScale > 0.0f ) + { + if ( rSaberNum < 1 ) + { + knockbackFlags = DAMAGE_SABER_KNOCKBACK1_B2; + } + else + { + knockbackFlags = DAMAGE_SABER_KNOCKBACK2_B2; + } + } + + WP_SaberDamageAdd( tr.entityNum, dir, tr.endpos, dmg, doDismemberment, knockbackFlags ); if (g_entities[tr.entityNum].client) { @@ -4370,7 +4826,7 @@ static GAME_INLINE qboolean CheckSaberDamage(gentity_t *self, int rSaberNum, int saberDoClashEffect = qtrue; VectorCopy( tr.endpos, saberClashPos ); - VectorCopy( tr.endpos, saberClashNorm ); + VectorCopy( tr.plane.normal, saberClashNorm ); saberClashEventParm = 1; sabersClashed = qtrue; @@ -4832,8 +5288,16 @@ void G_SPSaberDamageTraceLerped( gentity_t *self, int saberNum, int bladeNum, ve vec3_t mp1, mp2; vec3_t md1, md2; - VectorCopy( self->client->saber[saberNum].blade[bladeNum].trail.base, baseOld ); - VectorCopy( self->client->saber[saberNum].blade[bladeNum].trail.tip, endOld ); + if ( (level.time-self->client->saber[saberNum].blade[bladeNum].trail.lastTime) > 100 ) + {//no valid last pos, use current + VectorCopy(baseNew, baseOld); + VectorCopy(endNew, endOld); + } + else + {//trace from last pos + VectorCopy( self->client->saber[saberNum].blade[bladeNum].trail.base, baseOld ); + VectorCopy( self->client->saber[saberNum].blade[bladeNum].trail.tip, endOld ); + } VectorCopy( baseOld, mp1 ); VectorCopy( baseNew, mp2 ); @@ -5078,7 +5542,7 @@ void WP_SaberStartMissileBlockCheck( gentity_t *self, usercmd_t *ucmd ) return; } - if ( !self->client->saber[0].activeBlocking ) + if ( (self->client->saber[0].saberFlags&SFL_NOT_ACTIVE_BLOCKING) ) {//can't actively block with this saber type return; } @@ -5481,6 +5945,8 @@ static GAME_INLINE qboolean CheckThrownSaberDamaged(gentity_t *saberent, gentity te->s.angles[1] = 1; } te->s.eventParm = 1; + te->s.weapon = 0;//saberNum + te->s.legsAnim = 0;//bladeNum if (saberCheckKnockdown_Thrown(saberent, saberOwner, &g_entities[tr.entityNum])) { //it was knocked out of the air @@ -5498,6 +5964,7 @@ static GAME_INLINE qboolean CheckThrownSaberDamaged(gentity_t *saberent, gentity else { //a good hit vec3_t dir; + int dflags = 0; VectorSubtract(tr.endpos, saberent->r.currentOrigin, dir); VectorNormalize(dir); @@ -5507,18 +5974,30 @@ static GAME_INLINE qboolean CheckThrownSaberDamaged(gentity_t *saberent, gentity dir[1] = 1; } + if ( (saberOwner->client->saber[0].saberFlags2&SFL2_NO_DISMEMBERMENT) ) + { + dflags |= DAMAGE_NO_DISMEMBER; + } + + if ( saberOwner->client->saber[0].knockbackScale > 0.0f ) + { + dflags |= DAMAGE_SABER_KNOCKBACK1; + } + if (saberOwner->client->ps.isJediMaster) { //2x damage for the Jedi Master - G_Damage(ent, saberOwner, saberOwner, dir, tr.endpos, saberent->damage*2, 0, MOD_SABER); + G_Damage(ent, saberOwner, saberOwner, dir, tr.endpos, saberent->damage*2, dflags, MOD_SABER); } else { - G_Damage(ent, saberOwner, saberOwner, dir, tr.endpos, saberent->damage, 0, MOD_SABER); + G_Damage(ent, saberOwner, saberOwner, dir, tr.endpos, saberent->damage, dflags, MOD_SABER); } te = G_TempEntity( tr.endpos, EV_SABER_HIT ); te->s.otherEntityNum = ent->s.number; te->s.otherEntityNum2 = saberOwner->s.number; + te->s.weapon = 0;//saberNum + te->s.legsAnim = 0;//bladeNum VectorCopy(tr.endpos, te->s.origin); VectorCopy(tr.plane.normal, te->s.angles); if (!te->s.angles[0] && !te->s.angles[1] && !te->s.angles[2]) @@ -5574,23 +6053,35 @@ static GAME_INLINE qboolean CheckThrownSaberDamaged(gentity_t *saberent, gentity if (tr.fraction == 1 || tr.entityNum == ent->s.number) { vec3_t dir; + int dflags = 0; VectorSubtract(tr.endpos, entOrigin, dir); VectorNormalize(dir); + if ( (saberOwner->client->saber[0].saberFlags2&SFL2_NO_DISMEMBERMENT) ) + { + dflags |= DAMAGE_NO_DISMEMBER; + } + if ( saberOwner->client->saber[0].knockbackScale > 0.0f ) + { + dflags |= DAMAGE_SABER_KNOCKBACK1; + } + if (ent->s.eType == ET_NPC) { //an animent - G_Damage(ent, saberOwner, saberOwner, dir, tr.endpos, 40, 0, MOD_SABER); + G_Damage(ent, saberOwner, saberOwner, dir, tr.endpos, 40, dflags, MOD_SABER); } else { - G_Damage(ent, saberOwner, saberOwner, dir, tr.endpos, 5, 0, MOD_SABER); + G_Damage(ent, saberOwner, saberOwner, dir, tr.endpos, 5, dflags, MOD_SABER); } te = G_TempEntity( tr.endpos, EV_SABER_HIT ); te->s.otherEntityNum = ENTITYNUM_NONE; //don't do this for throw damage //te->s.otherEntityNum = ent->s.number; - //te->s.otherEntityNum2 = saberOwner->s.number; + te->s.otherEntityNum2 = saberOwner->s.number;//actually, do send this, though - for the overridden per-saber hit effects/sounds + te->s.weapon = 0;//saberNum + te->s.legsAnim = 0;//bladeNum VectorCopy(tr.endpos, te->s.origin); VectorCopy(tr.plane.normal, te->s.angles); if (!te->s.angles[0] && !te->s.angles[1] && !te->s.angles[2]) @@ -5598,13 +6089,22 @@ static GAME_INLINE qboolean CheckThrownSaberDamaged(gentity_t *saberent, gentity te->s.angles[1] = 1; } - if (ent->s.eType == ET_MOVER) + if ( ent->s.eType == ET_MOVER ) { - //I suppose I could tie this into the saberblock event, but I'm tired of adding flags to that thing. - gentity_t *teS = G_TempEntity( te->s.origin, EV_SABER_CLASHFLARE ); - VectorCopy(te->s.origin, teS->s.origin); + if ( saberOwner + && saberOwner->client + && (saberOwner->client->saber[0].saberFlags2&SFL2_NO_CLASH_FLARE) ) + {//don't do clash flare - NOTE: assumes same is true for both sabers if using dual sabers! + G_FreeEntity( te );//kind of a waste, but... + } + else + { + //I suppose I could tie this into the saberblock event, but I'm tired of adding flags to that thing. + gentity_t *teS = G_TempEntity( te->s.origin, EV_SABER_CLASHFLARE ); + VectorCopy(te->s.origin, teS->s.origin); - te->s.eventParm = 0; + te->s.eventParm = 0; + } } else { @@ -6133,7 +6633,7 @@ qboolean saberKnockOutOfHand(gentity_t *saberent, gentity_t *saberOwner, vec3_t { return qfalse; } - if ( !saberOwner->client->saber[0].disarmable ) + if ( (saberOwner->client->saber[0].saberFlags&SFL_NOT_DISARMABLE) ) { return qfalse; } @@ -6533,7 +7033,7 @@ void saberBackToOwner(gentity_t *saberent) //I'm just doing this now. I don't really like the spin on the way back. And it does weird stuff with the new saber-knocked-away code. if (saberOwner->client->ps.saberEntityNum == saberent->s.number) { - if ( !saberOwner->client->saber[0].returnDamage + if ( !(saberOwner->client->saber[0].saberFlags&SFL_RETURN_DAMAGE) || saberOwner->client->ps.saberHolstered ) { saberent->s.saberInFlight = qfalse; @@ -7087,6 +7587,9 @@ static gentity_t *G_KickTrace( gentity_t *ent, vec3_t kickDir, float kickDist, v hitEnt->client->ps.otherKiller = ent->s.number; hitEnt->client->ps.otherKillerDebounceTime = level.time + 10000; hitEnt->client->ps.otherKillerTime = level.time + 10000; + hitEnt->client->otherKillerMOD = MOD_MELEE; + hitEnt->client->otherKillerVehWeapon = 0; + hitEnt->client->otherKillerWeaponType = WP_NONE; } if (d_saberKickTweak.integer) @@ -7927,9 +8430,9 @@ void WP_SaberPositionUpdate( gentity_t *self, usercmd_t *ucmd ) if (self->client->ps.saberThrowDelay < level.time) { - if ( !self->client->saber[0].throwable ) + if ( (self->client->saber[0].saberFlags&SFL_NOT_THROWABLE) ) {//cant throw it normally! - if ( self->client->saber[0].singleBladeThrowable ) + if ( (self->client->saber[0].saberFlags&SFL_SINGLE_BLADE_THROWABLE) ) {//but can throw it if only have 1 blade on if ( self->client->saber[0].numBlades > 1 && self->client->ps.saberHolstered == 1 ) @@ -8175,7 +8678,14 @@ nextStep: VectorScale(dir, 400, saberent->s.pos.trDelta ); saberent->s.pos.trTime = level.time; - saberent->s.loopSound = saberSpinSound; + if ( self->client->saber[0].spinSound ) + { + saberent->s.loopSound = self->client->saber[0].spinSound; + } + else + { + saberent->s.loopSound = saberSpinSound; + } saberent->s.loopIsSoundset = qfalse; self->client->ps.saberDidThrowTime = level.time; @@ -8238,6 +8748,8 @@ nextStep: VectorCopy(g_entities[saberNum].r.currentOrigin, te->s.origin); VectorCopy(dir, te->s.angles); te->s.eventParm = 1; + te->s.weapon = 0;//saberNum + te->s.legsAnim = 0;//bladeNum self->client->ps.saberIdleWound = level.time + Q_irand(400, 600); } @@ -8249,6 +8761,7 @@ nextStep: { //Don't bother updating the bolt for each blade for this, it's just a very rough fallback method for during saberlocks VectorCopy(boltOrigin, self->client->saber[saberNum].blade[rBladeNum].trail.base); VectorCopy(end, self->client->saber[saberNum].blade[rBladeNum].trail.tip); + self->client->saber[saberNum].blade[rBladeNum].trail.lastTime = level.time; rBladeNum++; } @@ -8443,8 +8956,16 @@ nextStep: vec3_t saberSubBase; float deltaX, deltaY, deltaZ; - VectorCopy(self->client->saber[rSaberNum].blade[rBladeNum].trail.base, oldSaberStart); - VectorCopy(self->client->saber[rSaberNum].blade[rBladeNum].trail.tip, oldSaberEnd); + if ( (level.time-self->client->saber[rSaberNum].blade[rBladeNum].trail.lastTime) > 100 ) + {//no valid last pos, use current + VectorCopy(boltOrigin, oldSaberStart); + VectorCopy(end, oldSaberEnd); + } + else + {//trace from last pos + VectorCopy(self->client->saber[rSaberNum].blade[rBladeNum].trail.base, oldSaberStart); + VectorCopy(self->client->saber[rSaberNum].blade[rBladeNum].trail.tip, oldSaberEnd); + } VectorSubtract(oldSaberEnd, oldSaberStart, saberAngleBefore); vectoangles(saberAngleBefore, saberAngleBefore); @@ -8540,19 +9061,26 @@ nextStep: VectorCopy(boltOrigin, self->client->saber[rSaberNum].blade[rBladeNum].trail.base); VectorCopy(end, self->client->saber[rSaberNum].blade[rBladeNum].trail.tip); + self->client->saber[rSaberNum].blade[rBladeNum].trail.lastTime = level.time; //VectorCopy(boltOrigin, self->client->lastSaberBase); //VectorCopy(end, self->client->lastSaberTip); self->client->hasCurrentPosition = qtrue; + //do hit effects + WP_SaberDoHit( self, rSaberNum, rBladeNum ); + WP_SaberDoClash( self, rSaberNum, rBladeNum ); + rBladeNum++; } rSaberNum++; } - - //now actually go through and apply all the damage we did + WP_SaberApplyDamage( self ); - WP_SaberDoClash(); + //NOTE: doing one call like this after the 2 loops above is a bit cheaper, tempentity-wise... but won't use the correct saber and blade numbers... + //now actually go through and apply all the damage we did + //WP_SaberDoHit( self, 0, 0 ); + //WP_SaberDoClash( self, 0, 0 ); if (mySaber && mySaber->inuse) { diff --git a/codemp/ghoul2/G2.h b/codemp/ghoul2/G2.h index 69bf6d2..f74d40f 100644 --- a/codemp/ghoul2/G2.h +++ b/codemp/ghoul2/G2.h @@ -9,6 +9,10 @@ #define BONE_ANGLES_POSTMULT 0x0002 #define BONE_ANGLES_REPLACE 0x0004 +//added for a trace optimization. set in routines where a bone is +//set to be transformed in any way. -rww +#define BONE_NEED_TRANSFORM 0x8000 + //rww - RAGDOLL_BEGIN #define BONE_ANGLES_RAGDOLL 0x2000 // the rag flags give more details //rww - RAGDOLL_END diff --git a/codemp/ghoul2/G2_API.cpp b/codemp/ghoul2/G2_API.cpp index b24719c..44d71f3 100644 --- a/codemp/ghoul2/G2_API.cpp +++ b/codemp/ghoul2/G2_API.cpp @@ -2000,10 +2000,139 @@ static int QDECL QsortDistance( const void *a, const void *b ) { return 1; } +static inline bool G2_NeedRetransform(CGhoul2Info *g2, int frameNum) +{ //see if we need to do another transform + int i = 0; + bool needTrans = false; + while (i < g2->mBlist.size()) + { + float time; + boneInfo_t &bone = g2->mBlist[i]; + + if (bone.pauseTime) + { + time = (bone.pauseTime - bone.startTime) / 50.0f; + } + else + { + time = (frameNum - bone.startTime) / 50.0f; + } + int newFrame = bone.startFrame + (time * bone.animSpeed); + + if (newFrame < bone.endFrame || + (bone.flags & BONE_ANIM_OVERRIDE_LOOP) || + (bone.flags & BONE_NEED_TRANSFORM)) + { //ok, we're gonna have to do it. bone is apparently animating. + bone.flags &= ~BONE_NEED_TRANSFORM; + needTrans = true; + } + i++; + } + + return needTrans; +} + +void G2API_CollisionDetectCache(CollisionRecord_t *collRecMap, CGhoul2Info_v &ghoul2, const vec3_t angles, const vec3_t position, + int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, CMiniHeap *G2VertSpace, int traceFlags, int useLod, float fRadius) +{ //this will store off the transformed verts for the next trace - this is slower, but for models that do not animate + //frequently it is much much faster. -rww + int *test = ghoul2[0].mTransformedVertsArray; + if (G2_SetupModelPointers(ghoul2)) + { + vec3_t transRayStart, transRayEnd; + + int tframeNum=G2API_GetTime(frameNumber); + // make sure we have transformed the whole skeletons for each model + if (G2_NeedRetransform(&ghoul2[0], tframeNum) || !ghoul2[0].mTransformedVertsArray) + { //optimization, only create new transform space if we need to, otherwise + //store it off! + int i = 0; + while (i < ghoul2.size()) + { + CGhoul2Info &g2 = ghoul2[i]; + + /* + if ((g2.mFlags & GHOUL2_ZONETRANSALLOC) && g2.mTransformedVertsArray) + { //clear it out, yo. + Z_Free(g2.mTransformedVertsArray); + g2.mTransformedVertsArray = 0; + } + */ + if (!g2.mTransformedVertsArray || !(g2.mFlags & GHOUL2_ZONETRANSALLOC)) + { //reworked so we only alloc once! + //if we have a pointer, but not a ghoul2_zonetransalloc flag, then that means + //it is a miniheap pointer. Just stomp over it. + int iSize = g2.currentModel->mdxm->numSurfaces * 4; + g2.mTransformedVertsArray = (int *)Z_Malloc(iSize, TAG_GHOUL2, qtrue); + } + + g2.mFlags |= GHOUL2_ZONETRANSALLOC; + + i++; + } + G2_ConstructGhoulSkeleton(ghoul2, frameNumber, true, scale); + G2VertSpace->ResetHeap(); + + // now having done that, time to build the model +#ifdef _G2_GORE + G2_TransformModel(ghoul2, frameNumber, scale, G2VertSpace, useLod, false); +#else + G2_TransformModel(ghoul2, frameNumber, scale, G2VertSpace, useLod); +#endif + + //don't need to do this anymore now that I am using a flag for zone alloc. + /* + i = 0; + while (i < ghoul2.size()) + { + CGhoul2Info &g2 = ghoul2[i]; + int iSize = g2.currentModel->mdxm->numSurfaces * 4; + + int *zoneMem = (int *)Z_Malloc(iSize, TAG_GHOUL2, qtrue); + memcpy(zoneMem, g2.mTransformedVertsArray, iSize); + g2.mTransformedVertsArray = zoneMem; + g2.mFlags |= GHOUL2_ZONETRANSALLOC; + i++; + } + */ + } + + // pre generate the world matrix - used to transform the incoming ray + G2_GenerateWorldMatrix(angles, position); + + // model is built. Lets check to see if any triangles are actually hit. + // first up, translate the ray to model space + TransformAndTranslatePoint(rayStart, transRayStart, &worldMatrixInv); + TransformAndTranslatePoint(rayEnd, transRayEnd, &worldMatrixInv); + + // now walk each model and check the ray against each poly - sigh, this is SO expensive. I wish there was a better way to do this. +#ifdef _G2_GORE + G2_TraceModels(ghoul2, transRayStart, transRayEnd, collRecMap, entNum, traceFlags, useLod, fRadius,0,0,0,0,0,qfalse); +#else + G2_TraceModels(ghoul2, transRayStart, transRayEnd, collRecMap, entNum, traceFlags, useLod, fRadius); +#endif + int i; + for ( i = 0; i < MAX_G2_COLLISIONS && collRecMap[i].mEntityNum != -1; i ++ ); + + // now sort the resulting array of collision records so they are distance ordered + qsort( collRecMap, i, + sizeof( CollisionRecord_t ), QsortDistance ); + } +} + void G2API_CollisionDetect(CollisionRecord_t *collRecMap, CGhoul2Info_v &ghoul2, const vec3_t angles, const vec3_t position, int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, CMiniHeap *G2VertSpace, int traceFlags, int useLod, float fRadius) { + /* + if (1) + { + G2API_CollisionDetectCache(collRecMap, ghoul2, angles, position, frameNumber, entNum, + rayStart, rayEnd, scale, G2VertSpace, traceFlags, useLod, fRadius); + return; + } + */ + if (G2_SetupModelPointers(ghoul2)) { vec3_t transRayStart, transRayEnd; @@ -2030,7 +2159,7 @@ void G2API_CollisionDetect(CollisionRecord_t *collRecMap, CGhoul2Info_v &ghoul2, // now walk each model and check the ray against each poly - sigh, this is SO expensive. I wish there was a better way to do this. #ifdef _G2_GORE - G2_TraceModels(ghoul2, transRayStart, transRayEnd, collRecMap, entNum, traceFlags, useLod, fRadius,0,0,0,0,0); + G2_TraceModels(ghoul2, transRayStart, transRayEnd, collRecMap, entNum, traceFlags, useLod, fRadius,0,0,0,0,0,qfalse); #else G2_TraceModels(ghoul2, transRayStart, transRayEnd, collRecMap, entNum, traceFlags, useLod, fRadius); #endif @@ -2469,7 +2598,7 @@ void G2API_AddSkinGore(CGhoul2Info_v &ghoul2,SSkinGoreData &gore) G2_TransformModel(ghoul2, gore.currentTime, gore.scale,G2VertSpaceServer,lod,true); // now walk each model and compute new texture coordinates - G2_TraceModels(ghoul2, transHitLocation, transRayDirection, 0, gore.entNum, 0,lod,0.0f,gore.SSize,gore.TSize,gore.theta,gore.shader,&gore); + G2_TraceModels(ghoul2, transHitLocation, transRayDirection, 0, gore.entNum, 0,lod,0.0f,gore.SSize,gore.TSize,gore.theta,gore.shader,&gore,qtrue); } } #endif diff --git a/codemp/ghoul2/G2_bones.cpp b/codemp/ghoul2/G2_bones.cpp index ccf1269..11493a2 100644 --- a/codemp/ghoul2/G2_bones.cpp +++ b/codemp/ghoul2/G2_bones.cpp @@ -649,6 +649,9 @@ qboolean G2_Set_Bone_Anim_Index( { return qtrue; // don't accept any calls on ragdoll bones } + + //mark it for needing a transform for the cached trace transform stuff + blist[index].flags |= BONE_NEED_TRANSFORM; } if (setFrame != -1) diff --git a/codemp/ghoul2/G2_local.h b/codemp/ghoul2/G2_local.h index 949b468..051bd6d 100644 --- a/codemp/ghoul2/G2_local.h +++ b/codemp/ghoul2/G2_local.h @@ -66,7 +66,7 @@ void G2_List_Model_Surfaces(const char *fileName); void G2_List_Model_Bones(const char *fileName, int frame); qboolean G2_GetAnimFileName(const char *fileName, char **filename); #ifdef _G2_GORE -void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CollisionRecord_t *collRecMap, int entNum, int traceFlags, int useLod, float fRadius, float ssize,float tsize,float theta,int shader, SSkinGoreData *gore); +void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CollisionRecord_t *collRecMap, int entNum, int traceFlags, int useLod, float fRadius, float ssize,float tsize,float theta,int shader, SSkinGoreData *gore, qboolean skipIfLODNotMatch); #else void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CollisionRecord_t *collRecMap, int entNum, int traceFlags, int useLod, float fRadius); #endif @@ -151,6 +151,8 @@ int G2API_GetGhoul2ModelFlags(CGhoul2Info *ghlInfo); qboolean G2API_GetAnimFileName(CGhoul2Info *ghlInfo, char **filename); void G2API_CollisionDetect(CollisionRecord_t *collRecMap, CGhoul2Info_v &ghoul2, const vec3_t angles, const vec3_t position, int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, CMiniHeap *G2VertSpace, int traceFlags, int useLod, float fRadius); +void G2API_CollisionDetectCache(CollisionRecord_t *collRecMap, CGhoul2Info_v &ghoul2, const vec3_t angles, const vec3_t position, + int frameNumber, int entNum, vec3_t rayStart, vec3_t rayEnd, vec3_t scale, CMiniHeap *G2VertSpace, int traceFlags, int useLod, float fRadius); void G2API_GiveMeVectorFromMatrix(mdxaBone_t *boltMatrix, Eorientations flags, vec3_t vec); int G2API_CopyGhoul2Instance(CGhoul2Info_v &g2From, CGhoul2Info_v &g2To, int modelIndex); diff --git a/codemp/ghoul2/G2_misc.cpp b/codemp/ghoul2/G2_misc.cpp index 032e2d3..1dadcf9 100644 --- a/codemp/ghoul2/G2_misc.cpp +++ b/codemp/ghoul2/G2_misc.cpp @@ -37,7 +37,7 @@ static map,int> GoreTagsTemp; // this is a surface index to gore t // temporarily during the generation phase so we reuse gore tags per LOD int goreModelIndex; -bool AddGoreToAllModels=false; +static cvar_t *cg_g2MarksAllModels=NULL; GoreTextureCoordinates *FindGoreRecord(int tag); static inline void DestroyGoreTexCoordinates(int tag) @@ -564,6 +564,18 @@ void G2_TransformModel(CGhoul2Info_v &ghoul2, const int frameNum, vec3_t scale, { int i, lod; vec3_t correctScale; + qboolean firstModelOnly = qfalse; + + if ( cg_g2MarksAllModels == NULL ) + { + cg_g2MarksAllModels = Cvar_Get( "cg_g2MarksAllModels", "0", 0 ); + } + + if (cg_g2MarksAllModels == NULL + || !cg_g2MarksAllModels->integer ) + { + firstModelOnly = qtrue; + } VectorCopy(scale, correctScale); @@ -604,7 +616,13 @@ void G2_TransformModel(CGhoul2Info_v &ghoul2, const int frameNum, vec3_t scale, if (lod>=g.currentModel->numLods) { g.mTransformedVertsArray = 0; - return; + if ( firstModelOnly ) + { + // we don't really need to do multiple models for gore. + return; + } + //do the rest + continue; } } else @@ -616,10 +634,13 @@ void G2_TransformModel(CGhoul2Info_v &ghoul2, const int frameNum, vec3_t scale, #endif // give us space for the transformed vertex array to be put in - g.mTransformedVertsArray = (int*)G2VertSpace->MiniHeapAlloc(g.currentModel->mdxm->numSurfaces * 4); - if (!g.mTransformedVertsArray) - { - Com_Error(ERR_DROP, "Ran out of transform space for Ghoul2 Models. Adjust MiniHeapSize in SV_SpawnServer.\n"); + if (!(g.mFlags & GHOUL2_ZONETRANSALLOC)) + { //do not stomp if we're using zone space + g.mTransformedVertsArray = (int*)G2VertSpace->MiniHeapAlloc(g.currentModel->mdxm->numSurfaces * 4); + if (!g.mTransformedVertsArray) + { + Com_Error(ERR_DROP, "Ran out of transform space for Ghoul2 Models. Adjust MiniHeapSize in SV_SpawnServer.\n"); + } } memset(g.mTransformedVertsArray, 0,(g.currentModel->mdxm->numSurfaces * 4)); @@ -630,7 +651,7 @@ void G2_TransformModel(CGhoul2Info_v &ghoul2, const int frameNum, vec3_t scale, G2_TransformSurfaces(g.mSurfaceRoot, g.mSlist, g.mBoneCache, g.currentModel, lod, correctScale, G2VertSpace, g.mTransformedVertsArray, false); #ifdef _G2_GORE - if (ApplyGore&&!AddGoreToAllModels) + if (ApplyGore && firstModelOnly) { // we don't really need to do multiple models for gore. break; @@ -1490,7 +1511,7 @@ static void G2_TraceSurfaces(CTraceSurface &TS) } #ifdef _G2_GORE -void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CollisionRecord_t *collRecMap, int entNum, int eG2TraceType, int useLod, float fRadius, float ssize,float tsize,float theta,int shader, SSkinGoreData *gore) +void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CollisionRecord_t *collRecMap, int entNum, int eG2TraceType, int useLod, float fRadius, float ssize,float tsize,float theta,int shader, SSkinGoreData *gore, qboolean skipIfLODNotMatch) #else void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, CollisionRecord_t *collRecMap, int entNum, int eG2TraceType, int useLod, float fRadius) #endif @@ -1498,6 +1519,18 @@ void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, Colli int i, lod; skin_t *skin; shader_t *cust_shader; + qboolean firstModelOnly = qfalse; + + if ( cg_g2MarksAllModels == NULL ) + { + cg_g2MarksAllModels = Cvar_Get( "cg_g2MarksAllModels", "0", 0 ); + } + + if (cg_g2MarksAllModels == NULL + || !cg_g2MarksAllModels->integer ) + { + firstModelOnly = qtrue; + } // walk each possible model for this entity and try tracing against it for (i=0; i=ghoul2[i].currentModel->numLods) - { - return; + lod = G2_DecideTraceLod(ghoul2[i],useLod); + if ( skipIfLODNotMatch ) + {//we only want to hit this SPECIFIC LOD... + if ( lod != useLod ) + {//doesn't match, skip this model + continue; } } -#else - lod = G2_DecideTraceLod(ghoul2[i],useLod); -#endif //reset the quick surface override lookup G2_FindOverrideSurface(-1, ghoul2[i].mSlist); @@ -1577,7 +1601,7 @@ void G2_TraceModels(CGhoul2Info_v &ghoul2, vec3_t rayStart, vec3_t rayEnd, Colli break; } #ifdef _G2_GORE - if (!collRecMap&&!AddGoreToAllModels) + if (!collRecMap&&firstModelOnly) { // we don't really need to do multiple models for gore. break; diff --git a/codemp/ghoul2/ghoul2_shared.h b/codemp/ghoul2/ghoul2_shared.h index f193fb2..9b67cc8 100644 --- a/codemp/ghoul2/ghoul2_shared.h +++ b/codemp/ghoul2/ghoul2_shared.h @@ -231,6 +231,9 @@ typedef vector > mdxaBone_v; #define GHOUL2_NOMODEL 0x004 #define GHOUL2_NEWORIGIN 0x008 +//for transform optimization -rww +#define GHOUL2_ZONETRANSALLOC 0x2000 + class CBoneCache; // NOTE order in here matters. We save out from mModelindex to mFlags, but not the STL vectors that are at the top or the bottom. diff --git a/codemp/ghoul2/vssver.scc b/codemp/ghoul2/vssver.scc index ad42de0..d293ab0 100644 Binary files a/codemp/ghoul2/vssver.scc and b/codemp/ghoul2/vssver.scc differ diff --git a/codemp/goblib/mssccprj.scc b/codemp/goblib/mssccprj.scc index 65afff4..3c6070f 100644 --- a/codemp/goblib/mssccprj.scc +++ b/codemp/goblib/mssccprj.scc @@ -1,5 +1,5 @@ SCC = This is a Source Code Control file [goblib.vcproj] -SCC_Aux_Path = "\\ravendata1\vss\central_code" +SCC_Aux_Path = "\\ravendata1\VSS\central_code" SCC_Project_Name = "$/jedi/codemp/goblib", FBIAAAAA diff --git a/codemp/goblib/vssver.scc b/codemp/goblib/vssver.scc index 41e0b88..5331d4a 100644 Binary files a/codemp/goblib/vssver.scc and b/codemp/goblib/vssver.scc differ diff --git a/codemp/icarus/Q3_Interface.cpp b/codemp/icarus/Q3_Interface.cpp index afa2798..08fc225 100644 --- a/codemp/icarus/Q3_Interface.cpp +++ b/codemp/icarus/Q3_Interface.cpp @@ -24,12 +24,8 @@ stringID_table_t tagsTable [] = } */ -//rwwFIXEFIXME: Put somewhere else -inline float Q_flrand(float min, float max) { - return ((rand() * (max - min)) / 32768.0F) + min; -} - -qboolean COM_ParseString( char **data, char **s ); +extern float Q_flrand(float min, float max); +extern qboolean COM_ParseString( char **data, char **s ); //======================================================================= diff --git a/codemp/icarus/vssver.scc b/codemp/icarus/vssver.scc index ee3406d..2e2c94b 100644 Binary files a/codemp/icarus/vssver.scc and b/codemp/icarus/vssver.scc differ diff --git a/codemp/jpeg-6/vssver.scc b/codemp/jpeg-6/vssver.scc index 7cd142b..6ae5f44 100644 Binary files a/codemp/jpeg-6/vssver.scc and b/codemp/jpeg-6/vssver.scc differ diff --git a/codemp/mp3code/vssver.scc b/codemp/mp3code/vssver.scc index 8a610cc..088367c 100644 Binary files a/codemp/mp3code/vssver.scc and b/codemp/mp3code/vssver.scc differ diff --git a/codemp/mssccprj.scc b/codemp/mssccprj.scc index 34e1057..25b0737 100644 --- a/codemp/mssccprj.scc +++ b/codemp/mssccprj.scc @@ -1,17 +1,17 @@ SCC = This is a Source Code Control file [jk2mp.vcproj] -SCC_Aux_Path = "\\ravendata1\vss\central_code" +SCC_Aux_Path = "\\ravendata1\VSS\central_code" SCC_Project_Name = "$/jedi/codemp", CAAAAAAA [JKA_mp.sln] -SCC_Aux_Path = "\\ravendata1\vss\central_code" +SCC_Aux_Path = "\\ravendata1\VSS\central_code" SCC_Project_Name = "$/jedi/codemp", CAAAAAAA [WinDed.dsp] -SCC_Aux_Path = "\\ravendata1\vss\central_code" +SCC_Aux_Path = "\\ravendata1\VSS\central_code" SCC_Project_Name = "$/jedi/codemp", CAAAAAAA [WinDed.vcproj] -SCC_Aux_Path = "\\ravendata1\vss\central_code" +SCC_Aux_Path = "\\ravendata1\VSS\central_code" SCC_Project_Name = "$/jedi/codemp", CAAAAAAA diff --git a/codemp/null/vssver.scc b/codemp/null/vssver.scc index 7a02421..596f1aa 100644 Binary files a/codemp/null/vssver.scc and b/codemp/null/vssver.scc differ diff --git a/codemp/null/win_main.cpp b/codemp/null/win_main.cpp index 21f1cc1..af56f06 100644 --- a/codemp/null/win_main.cpp +++ b/codemp/null/win_main.cpp @@ -728,6 +728,49 @@ void Sys_UnloadDll( void *dllHandle ) { Com_Error (ERR_FATAL, "Sys_UnloadDll FreeLibrary failed"); } } +//make sure the dll can be opened by the file system, then write the +//file back out again so it can be loaded is a library. If the read +//fails then the dll is probably not in the pk3 and we are running +//a pure server -rww +bool Sys_UnpackDLL(const char *name) +{ + void *data; + fileHandle_t f; + int len = FS_ReadFile(name, &data); + int ck; + + if (len < 1) + { //failed to read the file (out of the pk3 if pure) + return false; + } + + if (FS_FileIsInPAK(name, &ck) == -1) + { //alright, it isn't in a pk3 anyway, so we don't need to write it. + //this is allowable when running non-pure. + FS_FreeFile(data); + return true; + } + + f = FS_FOpenFileWrite( name ); + if ( !f ) + { //can't open for writing? Might be in use. + //This is possibly a malicious user attempt to circumvent dll + //replacement so we won't allow it. + FS_FreeFile(data); + return false; + } + + if (FS_Write( data, len, f ) < len) + { //Failed to write the full length. Full disk maybe? + FS_FreeFile(data); + return false; + } + + FS_FCloseFile( f ); + FS_FreeFile(data); + + return true; +} /* ================= @@ -747,35 +790,14 @@ void * QDECL Sys_LoadDll( const char *name, int (QDECL **entryPoint)(int, ...), char *cdpath; char *gamedir; char *fn; -#ifdef NDEBUG - int timestamp; - int ret; -#endif char filename[MAX_QPATH]; Com_sprintf( filename, sizeof( filename ), "%sx86.dll", name ); -#ifdef NDEBUG - timestamp = Sys_Milliseconds(); -// if( ((timestamp - lastWarning) > (5 * 60000)) && !Cvar_VariableIntegerValue( "dedicated" ) -// && !Cvar_VariableIntegerValue( "com_blindlyLoadDLLs" ) ) { - if (0) { - if (FS_FileExists(filename)) { - lastWarning = timestamp; - ret = MessageBoxEx( NULL, "You are about to load a .DLL executable that\n" - "has not been verified for use with Quake III Arena.\n" - "This type of file can compromise the security of\n" - "your computer.\n\n" - "Select 'OK' if you choose to load it anyway.", - "Security Warning", MB_OKCANCEL | MB_ICONEXCLAMATION | MB_DEFBUTTON2 | MB_TOPMOST | MB_SETFOREGROUND, - MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ) ); - if( ret != IDOK ) { - return NULL; - } - } + if (!Sys_UnpackDLL(filename)) + { + return NULL; } -#endif - // rjr disable for final release #ifndef NDEBUG libHandle = LoadLibrary( filename ); diff --git a/codemp/png/vssver.scc b/codemp/png/vssver.scc index 5b6ff21..11cc4f9 100644 Binary files a/codemp/png/vssver.scc and b/codemp/png/vssver.scc differ diff --git a/codemp/qcommon/common.cpp b/codemp/qcommon/common.cpp index 60c57e9..eae5eda 100644 --- a/codemp/qcommon/common.cpp +++ b/codemp/qcommon/common.cpp @@ -50,6 +50,8 @@ cvar_t *com_cl_running; cvar_t *com_logfile; // 1 = buffer log, 2 = flush after each print cvar_t *com_showtrace; +cvar_t *com_optvehtrace; + #ifdef G2_PERFORMANCE_ANALYSIS cvar_t *com_G2Report; #endif @@ -1318,6 +1320,8 @@ void Com_Init( char *commandLine ) { com_timedemo = Cvar_Get ("timedemo", "0", 0); com_cameraMode = Cvar_Get ("com_cameraMode", "0", CVAR_CHEAT); + com_optvehtrace = Cvar_Get("com_optvehtrace", "0", 0); + cl_paused = Cvar_Get ("cl_paused", "0", CVAR_ROM); sv_paused = Cvar_Get ("sv_paused", "0", CVAR_ROM); com_sv_running = Cvar_Get ("sv_running", "0", CVAR_ROM); diff --git a/codemp/qcommon/files_pc.cpp b/codemp/qcommon/files_pc.cpp index be51e16..3ee6165 100644 --- a/codemp/qcommon/files_pc.cpp +++ b/codemp/qcommon/files_pc.cpp @@ -563,6 +563,8 @@ fileHandle_t FS_FOpenFileAppend( const char *filename ) { return f; } +#ifndef __linux__ + bool Sys_GetFileTime(LPCSTR psFileName, FILETIME &ft) { bool bSuccess = false; @@ -627,6 +629,8 @@ bool Sys_FileOutOfDate( LPCSTR psFinalFileName /* dest */, LPCSTR psDataFileName return false; } +#endif // !__linux__ + bool FS_FileCacheable(const char* const filename) { extern cvar_t *com_buildScript; @@ -890,7 +894,7 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF && Q_stricmp( filename + l - 4, ".dat" ) ) { // for journal files fs_fakeChkSum = random(); } - +#ifndef __linux__ // if running with fs_copyfiles 2, and search path == local, then we need to fail to open // if the time/date stamp != the network version (so it'll loop round again and use the network path, // which comes later in the search order) @@ -905,7 +909,7 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF continue; //carry on to find the cdpath version. } } - +#endif Q_strncpyz( fsh[*file].name, filename, sizeof( fsh[*file].name ) ); fsh[*file].zipFile = qfalse; if ( fs_debug->integer ) { @@ -913,6 +917,7 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF dir->path, dir->gamedir ); } +#ifndef __linux__ // if we are getting it from the cdpath, optionally copy it // to the basepath if ( fs_copyfiles->integer && !Q_stricmp( dir->path, fs_cdpath->string ) ) { @@ -960,7 +965,7 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueF break; } } - +#endif if (bFasterToReOpenUsingNewLocalFile) { break; // and re-read the local copy, not the net version diff --git a/codemp/qcommon/qcommon.h b/codemp/qcommon/qcommon.h index d53b858..48be0e8 100644 --- a/codemp/qcommon/qcommon.h +++ b/codemp/qcommon/qcommon.h @@ -202,7 +202,7 @@ PROTOCOL ============================================================== */ -#define PROTOCOL_VERSION 25 +#define PROTOCOL_VERSION 26 #ifndef _XBOX // No gethostbyname(), and can't really use this stuff #define UPDATE_SERVER_NAME "updatejk3.ravensoft.com" @@ -699,6 +699,8 @@ extern cvar_t *com_buildScript; // for building release pak files extern cvar_t *com_journal; extern cvar_t *com_cameraMode; +extern cvar_t *com_optvehtrace; + #ifdef G2_PERFORMANCE_ANALYSIS extern cvar_t *com_G2Report; #endif diff --git a/codemp/qcommon/vssver.scc b/codemp/qcommon/vssver.scc index 3f48578..ff8e5be 100644 Binary files a/codemp/qcommon/vssver.scc and b/codemp/qcommon/vssver.scc differ diff --git a/codemp/renderer/tr_WorldEffects.cpp b/codemp/renderer/tr_WorldEffects.cpp index 637a42c..d622a18 100644 --- a/codemp/renderer/tr_WorldEffects.cpp +++ b/codemp/renderer/tr_WorldEffects.cpp @@ -9,8 +9,9 @@ #include "../qcommon/exe_headers.h" #pragma warning( disable : 4512 ) +// Returns a float min <= x < max (exclusive; will get max - 0.00001; but never max) inline float WE_flrand(float min, float max) { - return ((rand() * (max - min)) / 32768.0F) + min; + return ((rand() * (max - min)) / (RAND_MAX+1)) + min; } //////////////////////////////////////////////////////////////////////////////////////// @@ -98,12 +99,6 @@ inline float FloatRand(void) return ((float)rand() / (float)RAND_MAX); } -inline float fast_flrand(float min, float max) -{ - //return min + (max - min) * flrand; - return WE_flrand(min, max); //fixme? -} - inline void SnapFloatToGrid(float& f, int GridSize) { f = (int)(f); diff --git a/codemp/renderer/tr_image.cpp b/codemp/renderer/tr_image.cpp index 88be3b3..87ec9ef 100644 --- a/codemp/renderer/tr_image.cpp +++ b/codemp/renderer/tr_image.cpp @@ -2996,6 +2996,10 @@ bool RE_SplitSkins(const char *INname, char *skinhead, char *skintorso, char *sk //advance to second char *p2 = strchr(p, '|'); assert(p2); + if (!p2) + { + return false; + } *p2=0; p2++; strcat (skinhead, p); @@ -3005,6 +3009,10 @@ bool RE_SplitSkins(const char *INname, char *skinhead, char *skintorso, char *sk //advance to third p = strchr(p2, '|'); assert(p); + if (!p) + { + return false; + } *p=0; p++; strcat (skintorso,p2); diff --git a/codemp/renderer/tr_init.cpp b/codemp/renderer/tr_init.cpp index 0559da6..8d519ec 100644 --- a/codemp/renderer/tr_init.cpp +++ b/codemp/renderer/tr_init.cpp @@ -870,6 +870,8 @@ void GL_SetDefaultState( void ) GfxInfo_f ================ */ +extern bool g_bTextureRectangleHack; + void GfxInfo_f( void ) { cvar_t *sys_cpustring = Cvar_Get( "sys_cpustring", "", CVAR_ROM ); @@ -955,6 +957,7 @@ void GfxInfo_f( void ) Com_Printf ("anisotropic filtering: %s ", enablestrings[(r_ext_texture_filter_anisotropic->integer != 0) && glConfig.maxTextureFilterAnisotropy] ); Com_Printf ("(%f of %f)\n", r_ext_texture_filter_anisotropic->value, glConfig.maxTextureFilterAnisotropy ); Com_Printf ("Dynamic Glow: %s\n", enablestrings[r_DynamicGlow->integer] ); + if (g_bTextureRectangleHack) Com_Printf ("Dynamic Glow ATI BAD DRIVER HACK %s\n", enablestrings[g_bTextureRectangleHack] ); if ( r_finish->integer ) { Com_Printf ("Forcing glFinish\n" ); @@ -968,6 +971,11 @@ void GfxInfo_f( void ) } } +void R_AtiHackToggle_f(void) +{ + g_bTextureRectangleHack = !g_bTextureRectangleHack; +} + #endif // !DEDICATED /* =============== @@ -993,7 +1001,7 @@ void R_Register( void ) #endif r_ext_texture_filter_anisotropic = Cvar_Get( "r_ext_texture_filter_anisotropic", "16", CVAR_ARCHIVE ); - r_DynamicGlow = Cvar_Get( "r_DynamicGlow", "1", CVAR_ARCHIVE ); + r_DynamicGlow = Cvar_Get( "r_DynamicGlow", "0", CVAR_ARCHIVE ); r_DynamicGlowPasses = Cvar_Get( "r_DynamicGlowPasses", "5", CVAR_CHEAT ); r_DynamicGlowDelta = Cvar_Get( "r_DynamicGlowDelta", "0.8f", CVAR_CHEAT ); r_DynamicGlowIntensity = Cvar_Get( "r_DynamicGlowIntensity", "1.13f", CVAR_CHEAT ); @@ -1184,6 +1192,7 @@ extern qboolean Sys_LowPhysicalMemory(); Cmd_AddCommand( "screenshot", R_ScreenShot_f ); Cmd_AddCommand( "screenshot_tga", R_ScreenShotTGA_f ); Cmd_AddCommand( "gfxinfo", GfxInfo_f ); + Cmd_AddCommand( "r_atihack", R_AtiHackToggle_f ); Cmd_AddCommand( "r_we", R_WorldEffect_f); Cmd_AddCommand( "imagecacheinfo", RE_RegisterImages_Info_f); #endif @@ -1331,6 +1340,7 @@ void RE_Shutdown( qboolean destroyWindow ) { Cmd_RemoveCommand ("screenshot"); Cmd_RemoveCommand ("screenshot_tga"); Cmd_RemoveCommand ("gfxinfo"); + Cmd_RemoveCommand ("r_atihack"); Cmd_RemoveCommand ("r_we"); Cmd_RemoveCommand ("imagecacheinfo"); Cmd_RemoveCommand ("modellist"); diff --git a/codemp/renderer/vssver.scc b/codemp/renderer/vssver.scc index 6f5404c..ab4a3ed 100644 Binary files a/codemp/renderer/vssver.scc and b/codemp/renderer/vssver.scc differ diff --git a/codemp/server/NPCNav/vssver.scc b/codemp/server/NPCNav/vssver.scc index 1e3f995..75921e4 100644 Binary files a/codemp/server/NPCNav/vssver.scc and b/codemp/server/NPCNav/vssver.scc differ diff --git a/codemp/server/server.h b/codemp/server/server.h index 86341ef..118573d 100644 --- a/codemp/server/server.h +++ b/codemp/server/server.h @@ -259,9 +259,10 @@ extern cvar_t *sv_maxPing; extern cvar_t *sv_gametype; extern cvar_t *sv_pure; extern cvar_t *sv_floodProtect; -extern cvar_t *sv_allowAnonymous; extern cvar_t *sv_needpass; - +#ifdef USE_CD_KEY +extern cvar_t *sv_allowAnonymous; +#endif //=========================================================== diff --git a/codemp/server/sv_ccmds.cpp b/codemp/server/sv_ccmds.cpp index 599ce07..7167a96 100644 --- a/codemp/server/sv_ccmds.cpp +++ b/codemp/server/sv_ccmds.cpp @@ -163,7 +163,7 @@ static void SV_Map_f( void ) { #endif // force latched values to get set - Cvar_Get ("g_gametype", "0", CVAR_SERVERINFO | CVAR_USERINFO | CVAR_LATCH ); + Cvar_Get ("g_gametype", "0", CVAR_SERVERINFO | CVAR_LATCH ); cmd = Cmd_Argv(0); if( Q_stricmpn( cmd, "sp", 2 ) == 0 ) { diff --git a/codemp/server/sv_game.cpp b/codemp/server/sv_game.cpp index 28af282..46b2a2e 100644 --- a/codemp/server/sv_game.cpp +++ b/codemp/server/sv_game.cpp @@ -1452,7 +1452,22 @@ int SV_GameSystemCalls( int *args ) { args[11], VMF(12) ); return 0; - + + case G_G2_COLLISIONDETECTCACHE: + G2API_CollisionDetectCache ( (CollisionRecord_t*)VMA(1), *((CGhoul2Info_v *)args[2]), + (const float*)VMA(3), + (const float*)VMA(4), + args[5], + args[6], + (float*)VMA(7), + (float*)VMA(8), + (float*)VMA(9), + G2VertSpaceServer, + args[10], + args[11], + VMF(12) ); + return 0; + case G_G2_SETROOTSURFACE: return G2API_SetRootSurface(*((CGhoul2Info_v *)args[1]), args[2], (const char *)VMA(3)); diff --git a/codemp/server/sv_init.cpp b/codemp/server/sv_init.cpp index 647666d..e69cbfa 100644 --- a/codemp/server/sv_init.cpp +++ b/codemp/server/sv_init.cpp @@ -807,6 +807,7 @@ void SV_Init (void) { Cvar_Get ("dmflags", "0", CVAR_SERVERINFO); Cvar_Get ("fraglimit", "20", CVAR_SERVERINFO); Cvar_Get ("timelimit", "0", CVAR_SERVERINFO); + Cvar_Get ("capturelimit", "0", CVAR_SERVERINFO); // Get these to establish them and to make sure they have a default before the menus decide to stomp them. Cvar_Get ("g_maxHolocronCarry", "3", CVAR_SERVERINFO); @@ -829,8 +830,9 @@ void SV_Init (void) { sv_minPing = Cvar_Get ("sv_minPing", "0", CVAR_ARCHIVE | CVAR_SERVERINFO ); sv_maxPing = Cvar_Get ("sv_maxPing", "0", CVAR_ARCHIVE | CVAR_SERVERINFO ); sv_floodProtect = Cvar_Get ("sv_floodProtect", "1", CVAR_ARCHIVE | CVAR_SERVERINFO ); +#ifdef USE_CD_KEY sv_allowAnonymous = Cvar_Get ("sv_allowAnonymous", "0", CVAR_SERVERINFO); - +#endif // systeminfo Cvar_Get ("sv_cheats", "0", CVAR_SYSTEMINFO | CVAR_ROM ); sv_serverid = Cvar_Get ("sv_serverid", "0", CVAR_SYSTEMINFO | CVAR_ROM ); diff --git a/codemp/server/sv_main.cpp b/codemp/server/sv_main.cpp index 16507a2..ce2dca7 100644 --- a/codemp/server/sv_main.cpp +++ b/codemp/server/sv_main.cpp @@ -37,9 +37,10 @@ cvar_t *sv_maxPing; cvar_t *sv_gametype; cvar_t *sv_pure; cvar_t *sv_floodProtect; -cvar_t *sv_allowAnonymous; cvar_t *sv_needpass; - +#ifdef USE_CD_KEY +cvar_t *sv_allowAnonymous; +#endif /* ============================================================================= @@ -445,7 +446,9 @@ void SVC_Info( netadr_t from ) { if( *gamedir ) { Info_SetValueForKey( infostring, "game", gamedir ); } +#ifdef USE_CD_KEY Info_SetValueForKey( infostring, "sv_allowAnonymous", va("%i", sv_allowAnonymous->integer) ); +#endif #ifdef _XBOX // Include Xbox specific networking info diff --git a/codemp/server/sv_world.cpp b/codemp/server/sv_world.cpp index f05fb1f..4fb55b6 100644 --- a/codemp/server/sv_world.cpp +++ b/codemp/server/sv_world.cpp @@ -734,8 +734,19 @@ Ghoul2 Insert Start Com_Printf( "Ghoul2 trace lod=%1d length=%6.0f to %s\n",clip->useLod,VectorDistance(clip->start, clip->end),(*((CGhoul2Info_v *)touch->ghoul2))[0].mFileName); } #endif - G2API_CollisionDetect(G2Trace, *((CGhoul2Info_v *)touch->ghoul2), angles, touch->r.currentOrigin, svs.time, touch->s.number, clip->start, clip->end, touch->modelScale, G2VertSpaceServer, 0, clip->useLod, fRadius); + if (com_optvehtrace && + com_optvehtrace->integer && + touch->s.eType == ET_NPC && + touch->s.NPC_class == CLASS_VEHICLE && + touch->m_pVehicle) + { //for vehicles cache the transform data. + G2API_CollisionDetectCache(G2Trace, *((CGhoul2Info_v *)touch->ghoul2), angles, touch->r.currentOrigin, svs.time, touch->s.number, clip->start, clip->end, touch->modelScale, G2VertSpaceServer, 0, clip->useLod, fRadius); + } + else + { + G2API_CollisionDetect(G2Trace, *((CGhoul2Info_v *)touch->ghoul2), angles, touch->r.currentOrigin, svs.time, touch->s.number, clip->start, clip->end, touch->modelScale, G2VertSpaceServer, 0, clip->useLod, fRadius); + } tN = 0; while (tN < MAX_G2_COLLISIONS) diff --git a/codemp/server/vssver.scc b/codemp/server/vssver.scc index a124f85..033553e 100644 Binary files a/codemp/server/vssver.scc and b/codemp/server/vssver.scc differ diff --git a/codemp/smartheap/vssver.scc b/codemp/smartheap/vssver.scc index 2d62d88..5b34795 100644 Binary files a/codemp/smartheap/vssver.scc and b/codemp/smartheap/vssver.scc differ diff --git a/codemp/strings/vssver.scc b/codemp/strings/vssver.scc index 725fcc8..b6291c1 100644 Binary files a/codemp/strings/vssver.scc and b/codemp/strings/vssver.scc differ diff --git a/codemp/ui/mssccprj.scc b/codemp/ui/mssccprj.scc index 468ec41..2cc4590 100644 --- a/codemp/ui/mssccprj.scc +++ b/codemp/ui/mssccprj.scc @@ -1,5 +1,5 @@ SCC = This is a Source Code Control file [ui.vcproj] -SCC_Aux_Path = "\\ravendata1\vss\central_code" +SCC_Aux_Path = "\\ravendata1\VSS\central_code" SCC_Project_Name = "$/jedi/codemp/ui", YSAAAAAA diff --git a/codemp/ui/ui_gameinfo.c b/codemp/ui/ui_gameinfo.c index bfcc625..b418bf8 100644 --- a/codemp/ui/ui_gameinfo.c +++ b/codemp/ui/ui_gameinfo.c @@ -164,6 +164,9 @@ void UI_LoadArenas( void ) { if( strstr( type, "ffa" ) ) { uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_FFA); } + if( strstr( type, "team" ) ) { + uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_TEAM); + } if( strstr( type, "holocron" ) ) { uiInfo.mapList[uiInfo.mapCount].typeBits |= (1 << GT_HOLOCRON); } diff --git a/codemp/ui/ui_local.h b/codemp/ui/ui_local.h index f72aa20..8e990c4 100644 --- a/codemp/ui/ui_local.h +++ b/codemp/ui/ui_local.h @@ -15,9 +15,6 @@ extern vmCvar_t ui_ffa_fraglimit; extern vmCvar_t ui_ffa_timelimit; -extern vmCvar_t ui_tourney_fraglimit; -extern vmCvar_t ui_tourney_timelimit; - extern vmCvar_t ui_selectedModelIndex; extern vmCvar_t ui_team_fraglimit; @@ -41,23 +38,6 @@ extern vmCvar_t ui_drawCrosshair; extern vmCvar_t ui_drawCrosshairNames; extern vmCvar_t ui_marks; -extern vmCvar_t ui_server1; -extern vmCvar_t ui_server2; -extern vmCvar_t ui_server3; -extern vmCvar_t ui_server4; -extern vmCvar_t ui_server5; -extern vmCvar_t ui_server6; -extern vmCvar_t ui_server7; -extern vmCvar_t ui_server8; -extern vmCvar_t ui_server9; -extern vmCvar_t ui_server10; -extern vmCvar_t ui_server11; -extern vmCvar_t ui_server12; -extern vmCvar_t ui_server13; -extern vmCvar_t ui_server14; -extern vmCvar_t ui_server15; -extern vmCvar_t ui_server16; - extern vmCvar_t ui_captureLimit; extern vmCvar_t ui_fragLimit; extern vmCvar_t ui_gameType; diff --git a/codemp/ui/ui_main.c b/codemp/ui/ui_main.c index 19401d1..1dc0a3e 100644 --- a/codemp/ui/ui_main.c +++ b/codemp/ui/ui_main.c @@ -2112,27 +2112,24 @@ static void UI_DrawForceMastery(rectDef_t *rect, float scale, vec4_t color, int char *s; i = val; - if (i < min || i > max) + if (i < min) { i = min; } + if (i > max) + { + i = max; + } - s = (char *)UI_GetStringEdString("MP_INGAME", forceMasteryLevels[val]); + s = (char *)UI_GetStringEdString("MP_INGAME", forceMasteryLevels[i]); Text_Paint(rect->x, rect->y, scale, color, s, 0, 0, textStyle, iMenuFont); } static void UI_DrawSkinColor(rectDef_t *rect, float scale, vec4_t color, int textStyle, int val, int min, int max, int iMenuFont) { - int i; char s[256]; - i = val; - if (i < min || i > max) - { - i = min; - } - switch(val) { case TEAM_RED: @@ -2154,18 +2151,11 @@ static void UI_DrawSkinColor(rectDef_t *rect, float scale, vec4_t color, int tex static void UI_DrawForceSide(rectDef_t *rect, float scale, vec4_t color, int textStyle, int val, int min, int max, int iMenuFont) { - int i; char s[256]; menuDef_t *menu; char info[MAX_INFO_VALUE]; - i = val; - if (i < min || i > max) - { - i = min; - } - info[0] = '\0'; trap_GetConfigString(CS_SERVERINFO, info, sizeof(info)); @@ -5213,8 +5203,8 @@ static void UI_StartSkirmish(qboolean next) { trap_Cvar_Set("g_warmup", "15"); trap_Cvar_Set("sv_pure", "0"); trap_Cvar_Set("g_friendlyFire", "0"); - trap_Cvar_Set("g_redTeam", UI_Cvar_VariableString("ui_teamName")); - trap_Cvar_Set("g_blueTeam", UI_Cvar_VariableString("ui_opponentName")); +// trap_Cvar_Set("g_redTeam", UI_Cvar_VariableString("ui_teamName")); +// trap_Cvar_Set("g_blueTeam", UI_Cvar_VariableString("ui_opponentName")); if (trap_Cvar_VariableValue("ui_recordSPDemo")) { Com_sprintf(buff, MAX_STRING_CHARS, "%s_%i", uiInfo.mapList[ui_currentMap.integer].mapLoadName, g); @@ -6227,8 +6217,8 @@ static void UI_RunMenuScript(char **args) trap_Cvar_SetValue( "dedicated", Com_Clamp( 0, 2, ui_dedicated.integer ) ); } trap_Cvar_SetValue( "g_gametype", Com_Clamp( 0, 8, uiInfo.gameTypes[ui_netGameType.integer].gtEnum ) ); - trap_Cvar_Set("g_redTeam", UI_Cvar_VariableString("ui_teamName")); - trap_Cvar_Set("g_blueTeam", UI_Cvar_VariableString("ui_opponentName")); + //trap_Cvar_Set("g_redTeam", UI_Cvar_VariableString("ui_teamName")); + //trap_Cvar_Set("g_blueTeam", UI_Cvar_VariableString("ui_opponentName")); trap_Cmd_ExecuteText( EXEC_APPEND, va( "wait ; wait ; map %s\n", uiInfo.mapList[ui_currentNetMap.integer].mapLoadName ) ); skill = trap_Cvar_VariableValue( "g_spSkill" ); @@ -6253,6 +6243,7 @@ static void UI_RunMenuScript(char **args) trap_Cvar_VariableValue( "g_gametype" ) == GT_POWERDUEL) { //always set fraglimit 1 when starting a duel game trap_Cvar_Set("fraglimit", "1"); + trap_Cvar_Set("timelimit", "0"); } for (i = 0; i < PLAYERS_PER_TEAM; i++) @@ -6525,6 +6516,10 @@ static void UI_RunMenuScript(char **args) if (uiInfo.teamIndex >= 0 && uiInfo.teamIndex < uiInfo.myTeamCount) { trap_Cmd_ExecuteText( EXEC_APPEND, va("callteamvote leader \"%s\"\n",uiInfo.teamNames[uiInfo.teamIndex]) ); } + } else if (Q_stricmp(name, "voteTeamKick") == 0) { + if (uiInfo.teamIndex >= 0 && uiInfo.teamIndex < uiInfo.myTeamCount) { + trap_Cmd_ExecuteText( EXEC_APPEND, va("callteamvote kick \"%s\"\n",uiInfo.teamNames[uiInfo.teamIndex]) ); + } } else if (Q_stricmp(name, "addBot") == 0) { if (trap_Cvar_VariableValue("g_gametype") >= GT_TEAM) { trap_Cmd_ExecuteText( EXEC_APPEND, va("addbot \"%s\" %i %s\n", UI_GetBotNameByNumber(uiInfo.botIndex), uiInfo.skillIndex+1, (uiInfo.redBlue == 0) ? "Red" : "Blue") ); @@ -7869,11 +7864,6 @@ static void UI_BuildServerDisplayList(qboolean force) { numinvisible++; } } - else - { - trap_LAN_MarkServerVisible(ui_netSource.integer, i, qfalse); -// visible = qfalse; - } } uiInfo.serverStatus.refreshtime = uiInfo.uiDC.realTime; @@ -9663,7 +9653,10 @@ qboolean UI_FeederSelection(float feederFloat, int index, itemDef_t *item) index = actual; if (index >= 0 && index < uiInfo.q3HeadCount) { - trap_Cvar_Set( "model", uiInfo.q3HeadNames[index]); + trap_Cvar_Set( "model", uiInfo.q3HeadNames[index]); //standard model + trap_Cvar_Set ( "char_color_red", "255" ); //standard colors + trap_Cvar_Set ( "char_color_green", "255" ); + trap_Cvar_Set ( "char_color_blue", "255" ); } } else if (feederID == FEEDER_MOVES) @@ -11293,9 +11286,6 @@ typedef struct { vmCvar_t ui_ffa_fraglimit; vmCvar_t ui_ffa_timelimit; -vmCvar_t ui_tourney_fraglimit; -vmCvar_t ui_tourney_timelimit; - vmCvar_t ui_selectedModelIndex; vmCvar_t ui_char_model; vmCvar_t ui_char_skin_head; @@ -11330,23 +11320,6 @@ vmCvar_t ui_drawCrosshair; vmCvar_t ui_drawCrosshairNames; vmCvar_t ui_marks; -vmCvar_t ui_server1; -vmCvar_t ui_server2; -vmCvar_t ui_server3; -vmCvar_t ui_server4; -vmCvar_t ui_server5; -vmCvar_t ui_server6; -vmCvar_t ui_server7; -vmCvar_t ui_server8; -vmCvar_t ui_server9; -vmCvar_t ui_server10; -vmCvar_t ui_server11; -vmCvar_t ui_server12; -vmCvar_t ui_server13; -vmCvar_t ui_server14; -vmCvar_t ui_server15; -vmCvar_t ui_server16; - vmCvar_t ui_redteam; vmCvar_t ui_redteam1; vmCvar_t ui_redteam2; @@ -11427,9 +11400,6 @@ static cvarTable_t cvarTable[] = { { &ui_ffa_fraglimit, "ui_ffa_fraglimit", "20", CVAR_ARCHIVE|CVAR_INTERNAL }, { &ui_ffa_timelimit, "ui_ffa_timelimit", "0", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_tourney_fraglimit, "ui_tourney_fraglimit", "0", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_tourney_timelimit, "ui_tourney_timelimit", "15", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_selectedModelIndex, "ui_selectedModelIndex", "16", CVAR_ARCHIVE|CVAR_INTERNAL }, { &ui_char_model, "ui_char_model", "jedi_tf",CVAR_ROM|CVAR_INTERNAL}, @@ -11468,29 +11438,13 @@ static cvarTable_t cvarTable[] = { { &ui_browserShowFull, "ui_browserShowFull", "1", CVAR_ARCHIVE|CVAR_INTERNAL }, { &ui_browserShowEmpty, "ui_browserShowEmpty", "1", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_drawCrosshair, "cg_drawCrosshair", "1", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_marks, "cg_marks", "1", CVAR_ARCHIVE|CVAR_INTERNAL }, + { &ui_drawCrosshair, "cg_drawCrosshair", "1", CVAR_ARCHIVE }, + { &ui_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE }, + { &ui_marks, "cg_marks", "1", CVAR_ARCHIVE }, - { &ui_server1, "server1", "", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_server2, "server2", "", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_server3, "server3", "", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_server4, "server4", "", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_server5, "server5", "", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_server6, "server6", "", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_server7, "server7", "", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_server8, "server8", "", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_server9, "server9", "", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_server10, "server10", "", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_server11, "server11", "", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_server12, "server12", "", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_server13, "server13", "", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_server14, "server14", "", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_server15, "server15", "", CVAR_ARCHIVE|CVAR_INTERNAL }, - { &ui_server16, "server16", "", CVAR_ARCHIVE|CVAR_INTERNAL }, { &ui_debug, "ui_debug", "0", CVAR_TEMP|CVAR_INTERNAL }, { &ui_initialized, "ui_initialized", "0", CVAR_TEMP|CVAR_INTERNAL }, - { &ui_teamName, "ui_teamName", "Empire", CVAR_ARCHIVE|CVAR_INTERNAL }, + //{ &ui_teamName, "ui_teamName", "Empire", CVAR_ARCHIVE|CVAR_INTERNAL }, { &ui_opponentName, "ui_opponentName", "Rebellion", CVAR_ARCHIVE|CVAR_INTERNAL }, { &ui_rankChange, "ui_rankChange", "0", CVAR_ARCHIVE|CVAR_INTERNAL }, { &ui_freeSaber, "ui_freeSaber", "0", CVAR_ARCHIVE|CVAR_INTERNAL }, @@ -11559,8 +11513,8 @@ static cvarTable_t cvarTable[] = { { &ui_captureLimit, "ui_captureLimit", "5", CVAR_INTERNAL}, { &ui_findPlayer, "ui_findPlayer", "Kyle", CVAR_ARCHIVE|CVAR_INTERNAL}, { &ui_recordSPDemo, "ui_recordSPDemo", "0", CVAR_ARCHIVE|CVAR_INTERNAL}, - { &ui_realWarmUp, "g_warmup", "20", CVAR_ARCHIVE|CVAR_INTERNAL}, - { &ui_realCaptureLimit, "capturelimit", "8", CVAR_SERVERINFO | CVAR_ARCHIVE| CVAR_INTERNAL | CVAR_NORESTART}, + { &ui_realWarmUp, "g_warmup", "20", CVAR_ARCHIVE}, + { &ui_realCaptureLimit, "capturelimit", "0", CVAR_SERVERINFO | CVAR_ARCHIVE| CVAR_NORESTART}, { &ui_serverStatusTimeOut, "ui_serverStatusTimeOut", "7000", CVAR_ARCHIVE|CVAR_INTERNAL}, { &se_language, "se_language","english", CVAR_ARCHIVE | CVAR_NORESTART}, //text (string ed) @@ -11626,7 +11580,7 @@ static void UI_StopServerRefresh( void ) uiInfo.serverStatus.numPlayersOnServers); count = trap_LAN_GetServerCount(ui_netSource.integer); if (count - uiInfo.serverStatus.numDisplayServers > 0) { - Com_Printf("%d servers not listed due to packet loss or pings higher than %d\n", + Com_Printf("%d servers not listed due to filters, packet loss, or pings higher than %d\n", count - uiInfo.serverStatus.numDisplayServers, (int) trap_Cvar_VariableValue("cl_maxPing")); } diff --git a/codemp/ui/ui_public.h b/codemp/ui/ui_public.h index 5c9ae58..25b9655 100644 --- a/codemp/ui/ui_public.h +++ b/codemp/ui/ui_public.h @@ -148,6 +148,7 @@ Ghoul2 Insert Start UI_G2_GETBOLT_NOREC_NOROT, UI_G2_INITGHOUL2MODEL, UI_G2_COLLISIONDETECT, + UI_G2_COLLISIONDETECTCACHE, UI_G2_CLEANMODELS, UI_G2_ANGLEOVERRIDE, UI_G2_PLAYANIM, diff --git a/codemp/ui/ui_saber.c b/codemp/ui/ui_saber.c index ce230b8..a63812c 100644 --- a/codemp/ui/ui_saber.c +++ b/codemp/ui/ui_saber.c @@ -14,7 +14,7 @@ USER INTERFACE SABER LOADING & DISPLAY CODE #include "ui_shared.h" //#define MAX_SABER_DATA_SIZE 0x8000 -#define MAX_SABER_DATA_SIZE 0x9000 +#define MAX_SABER_DATA_SIZE 0x80000 // On Xbox, static linking lets us steal the buffer from wp_saberLoad // Just make sure that the saber data size is the same @@ -196,6 +196,39 @@ int UI_SaberNumBladesForSaber( const char *saberName ) return numBlades; } +qboolean UI_SaberShouldDrawBlade( const char *saberName, int bladeNum ) +{ + int bladeStyle2Start = 0, noBlade = 0; + char bladeStyle2StartString[8]={0}; + char noBladeString[8]={0}; + UI_SaberParseParm( saberName, "bladeStyle2Start", bladeStyle2StartString ); + if ( bladeStyle2StartString + && bladeStyle2StartString[0] ) + { + bladeStyle2Start = atoi( bladeStyle2StartString ); + } + if ( bladeStyle2Start + && bladeNum >= bladeStyle2Start ) + {//use second blade style + UI_SaberParseParm( saberName, "noBlade2", noBladeString ); + if ( noBladeString + && noBladeString[0] ) + { + noBlade = atoi( noBladeString ); + } + } + else + {//use first blade style + UI_SaberParseParm( saberName, "noBlade", noBladeString ); + if ( noBladeString + && noBladeString[0] ) + { + noBlade = atoi( noBladeString ); + } + } + return ((qboolean)(noBlade==0)); +} + qboolean UI_IsSaberTwoHanded( const char *saberName ) { @@ -973,7 +1006,10 @@ void UI_SaberDrawBlades( itemDef_t *item, vec3_t origin, vec3_t angles ) saberType = TranslateSaberType( saberTypeString ); for ( curBlade = 0; curBlade < numBlades; curBlade++ ) { - UI_SaberDrawBlade( item, saber, saberModel, saberType, origin, angles, curBlade ); + if ( UI_SaberShouldDrawBlade( saber, curBlade ) ) + { + UI_SaberDrawBlade( item, saber, saberModel, saberType, origin, angles, curBlade ); + } } } } diff --git a/codemp/ui/ui_shared.c b/codemp/ui/ui_shared.c index 55fe8de..549431b 100644 --- a/codemp/ui/ui_shared.c +++ b/codemp/ui/ui_shared.c @@ -5838,7 +5838,18 @@ void Item_Model_Paint(itemDef_t *item) memset( &ent, 0, sizeof(ent) ); // use item storage to track - if (modelPtr->rotationSpeed) + if ( (item->flags&ITF_ISANYSABER) && !(item->flags&ITF_ISCHARACTER) ) + {//hack to put saber on it's side + if (modelPtr->rotationSpeed) + { + VectorSet( angles, modelPtr->angle+(float)refdef.time/modelPtr->rotationSpeed, 0, 90 ); + } + else + { + VectorSet( angles, modelPtr->angle, 0, 90 ); + } + } + else if (modelPtr->rotationSpeed) { VectorSet( angles, 0, modelPtr->angle + (float)refdef.time/modelPtr->rotationSpeed, 0 ); } @@ -5847,11 +5858,6 @@ void Item_Model_Paint(itemDef_t *item) VectorSet( angles, 0, modelPtr->angle, 0 ); } - if ( (item->flags&ITF_ISANYSABER) && !(item->flags&ITF_ISCHARACTER) ) - {//hack to put saber on it's side - VectorSet( angles, modelPtr->angle, 0, 90 ); - } - AnglesToAxis( angles, ent.axis ); if (item->ghoul2) diff --git a/codemp/ui/ui_shared.h b/codemp/ui/ui_shared.h index e631e45..84c94fe 100644 --- a/codemp/ui/ui_shared.h +++ b/codemp/ui/ui_shared.h @@ -562,6 +562,8 @@ Ghoul2 Insert Start */ // UI specific API access void trap_G2API_CollisionDetect ( CollisionRecord_t *collRecMap, void* ghoul2, const vec3_t angles, const vec3_t position,int frameNumber, int entNum, const vec3_t rayStart, const vec3_t rayEnd, const vec3_t scale, int traceFlags, int useLod, float fRadius ); +void trap_G2API_CollisionDetectCache ( CollisionRecord_t *collRecMap, void* ghoul2, const vec3_t angles, const vec3_t position,int frameNumber, int entNum, const vec3_t rayStart, const vec3_t rayEnd, const vec3_t scale, int traceFlags, int useLod, float fRadius ); + void trap_G2_ListModelSurfaces(void *ghlInfo); void trap_G2_ListModelBones(void *ghlInfo, int frame); diff --git a/codemp/ui/ui_syscalls.c b/codemp/ui/ui_syscalls.c index cbbda6c..1c3f106 100644 --- a/codemp/ui/ui_syscalls.c +++ b/codemp/ui/ui_syscalls.c @@ -519,6 +519,24 @@ void trap_G2API_CollisionDetect ( syscall ( UI_G2_COLLISIONDETECT, collRecMap, ghoul2, angles, position, frameNumber, entNum, rayStart, rayEnd, scale, traceFlags, useLod, PASSFLOAT(fRadius) ); } +void trap_G2API_CollisionDetectCache ( + CollisionRecord_t *collRecMap, + void* ghoul2, + const vec3_t angles, + const vec3_t position, + int frameNumber, + int entNum, + const vec3_t rayStart, + const vec3_t rayEnd, + const vec3_t scale, + int traceFlags, + int useLod, + float fRadius + ) +{ + syscall ( UI_G2_COLLISIONDETECTCACHE, collRecMap, ghoul2, angles, position, frameNumber, entNum, rayStart, rayEnd, scale, traceFlags, useLod, PASSFLOAT(fRadius) ); +} + void trap_G2API_CleanGhoul2Models(void **ghoul2Ptr) { syscall(UI_G2_CLEANMODELS, ghoul2Ptr); diff --git a/codemp/ui/vssver.scc b/codemp/ui/vssver.scc index 6a3ff90..868844b 100644 Binary files a/codemp/ui/vssver.scc and b/codemp/ui/vssver.scc differ diff --git a/codemp/unix/makefile b/codemp/unix/makefile index 4b12a1a..455dca5 100644 --- a/codemp/unix/makefile +++ b/codemp/unix/makefile @@ -77,7 +77,7 @@ DLL_ONLY=false # bk001205: no mo' -Dstricmp=strcasecmp, see q_shared.h #BASE_CFLAGS = -pipe -fsigned-char -x c++ -D_JK2 -D_M_IX86 -I/home/drews/STLport-4.5.3/stlport -I/opt/intel/compiler50/ia32/include #BASE_CFLAGS = -pipe -fsigned-char -Kc++ -D_JK2 -D_M_IX86 -I/opt/intel/compiler50/ia32/include - BASE_CFLAGS = -Kc++ -D_JK2 -D_M_IX86 -w -I/opt/intel/compiler50/ia32/include + BASE_CFLAGS = -D_JK2 -D_M_IX86 -Kc++ -w -I/opt/intel/compiler50/ia32/include # rcg010216: DLL_ONLY for PPC ifeq ($(strip $(DLL_ONLY)),true) BASE_CFLAGS += -DDLL_ONLY @@ -112,7 +112,8 @@ DLL_ONLY=false # TTimo: legacy RELEASE_CFLAGS # NOTE: the -fomit-frame-pointer option leads to an unstable binary on my test box if it was built on the main box # but building on the Mdk 7.2 baseline seems to work - RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O2 -unroll -tpp6 +# -O2 -unroll + RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O2 -unroll # TTimo: use this for building on P3 gcc 2.95.3 libc2.2 for all targets (experimental! -fomit-fram-pointer removed) # RELEASE_CFLAGS=$(BASE_CFLAGS) -DNDEBUG -O6 -mcpu=pentiumpro -march=pentium -pipe -ffast-math -malign-loops=2 -malign-jumps=2 -malign-functions=2 -fno-strict-aliasing -fstrength-reduce endif @@ -121,7 +122,7 @@ DLL_ONLY=false LIBEXT=a SHLIBEXT=so - SHLIBCFLAGS=-fPIC + SHLIBCFLAGS=-D_JK2 -DJK2AWARDS -DQAGAME -DMISSIONPACK SHLIBLDFLAGS=-shared $(LDFLAGS) ARFLAGS=ar rv @@ -134,19 +135,19 @@ DLL_ONLY=false TARGETS=\ $(B)/$(PLATFORM)jampded \ - $(B)/$(BUILD_NAME)game$(ARCH)-debug.so + $(B)/baseq3/jampgame$(ARCH).$(SHLIBEXT) DO_CC=$(CC) $(CFLAGS) -o $@ -c $< DO_CXX=$(CXX) $(CFLAGS) -o $@ -c $< DO_SMP_CC=$(CC) $(CFLAGS) -DSMP -o $@ -c $< -DO_BOT_CC=$(CC) $(CFLAGS) -DBOTLIB -o $@ -c $< # $(SHLIBCFLAGS) # bk001212 +DO_BOT_CC=$(CC) $(CFLAGS) -use_msasm -DBOTLIB -o $@ -c $< # $(SHLIBCFLAGS) # bk001212 DO_DEBUG_CC=$(CC) $(DEBUG_CFLAGS) -o $@ -c $< -DO_SHLIB_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) -o $@ -c $< +DO_SHLIB_CC=$(CC) $(CFLAGS) $(SHLIBCFLAGS) -use_msasm -o $@ -c $< DO_SHLIB_DEBUG_CC=$(CC) $(DEBUG_CFLAGS) $(SHLIBCFLAGS) -o $@ -c $< DO_AS=$(CC) $(CFLAGS) -DELF -x assembler-with-cpp -o $@ -c $< DO_NASM=nasm -f elf -o $@ $< DO_DED_CC=$(CC) -DDEDICATED -DC_ONLY $(CFLAGS) -use_msasm -o $@ -c $< -DO_DED_CC2=$(CC) -DDEDICATED -DC_ONLY $(CFLAGS) -o $@ -c $< +DO_DED_CC2=$(CC) -D__linux2__ -DDEDICATED -DC_ONLY $(CFLAGS) -o $@ -c $< DO_DED_CPP=$(CXX) -DDEDICATED -DC_ONLY $(CFLAGS) -o $@ -c $< #DO_LCC=$(LCC) -o $@ -S -Wf-target=bytecode -Wf-g -DQ3_VM -I$(CGDIR) -I$(GDIR) -I$(UIDIR) $< @@ -166,6 +167,7 @@ build_release: #Build both debug and release builds all:build_debug build_release + targets:makedirs $(TARGETS) @@ -302,7 +304,7 @@ Q3DOBJ = \ $(B)/ded/gameCallbacks.o \ $(B)/ded/files_common.o \ $(B)/ded/cmd_common.o \ - $(B)/ded/files_linux.o \ + $(B)/ded/files_pc.o \ $(B)/ded/RM_Manager.o \ $(B)/ded/RM_Mission.o \ $(B)/ded/RM_Instance.o \ @@ -360,9 +362,6 @@ endif $(B)/$(PLATFORM)jampded : $(Q3DOBJ) $(CC) -o $@ $(Q3DOBJ) $(LDFLAGS) -$(B)/$(BUILD_NAME)game$(ARCH)-debug.so : $(Q3GOBJ) - $(CC) -o $@ $(Q3GOBJ) $(LDFLAGS) -shared - $(B)/ded/sv_bot.o : $(SDIR)/sv_bot.cpp; $(DO_DED_CC) $(B)/ded/sv_client.o : $(SDIR)/sv_client.cpp; $(DO_DED_CC) $(B)/ded/sv_ccmds.o : $(SDIR)/sv_ccmds.cpp; $(DO_DED_CC) @@ -396,7 +395,7 @@ $(B)/ded/q_math.o : $(GDIR)/q_math.c; $(DO_DED_CC) $(B)/ded/z_memman_pc.o : $(CMDIR)/z_memman_pc.cpp; $(DO_DED_CC) $(B)/ded/files_common.o : $(CMDIR)/files_common.cpp; $(DO_DED_CC) $(B)/ded/cmd_common.o : $(CMDIR)/cmd_common.cpp; $(DO_DED_CC) -$(B)/ded/files_linux.o : $(UDIR)/files_linux.cpp; $(DO_DED_CC) +$(B)/ded/files_pc.o : $(CMDIR)/files_pc.cpp; $(DO_DED_CC) $(B)/ded/RM_Manager.o : $(RMGDIR)/RM_Manager.cpp; $(DO_DED_CC) $(B)/ded/RM_Mission.o : $(RMGDIR)/RM_Mission.cpp; $(DO_DED_CC) @@ -487,7 +486,7 @@ $(B)/ded/l_struct.o : $(BLIBDIR)/l_struct.cpp; $(DO_BOT_CC) $(B)/ded/linux_common.o : $(UDIR)/linux_common.c; $(DO_CC) $(B)/ded/linux_glimp.o : $(UDIR)/linux_glimp.c; $(DO_DED_CC) -$(B)/ded/unix_main.o : $(UDIR)/unix_main.c; $(DO_DED_CC2) +$(B)/ded/unix_main.o : $(UDIR)/unix_main.c; $(DO_DED_CC) $(B)/ded/unix_net.o : $(UDIR)/unix_net.c; $(DO_DED_CC) $(B)/ded/unix_shared.o : $(UDIR)/unix_shared.cpp; $(DO_DED_CC) $(B)/ded/linux_qgl.o : $(UDIR)/linux_qgl.c; $(DO_DED_CC) @@ -620,75 +619,187 @@ $(B)/baseq3/cgame/q_shared.o : $(GDIR)/q_shared.c; $(DO_SHLIB_CC) ############################################################################# Q3GOBJ = \ - $(B)/baseq3/game/ai_chat.o \ - $(B)/baseq3/game/ai_cmd.o \ - $(B)/baseq3/game/ai_dmnet.o \ - $(B)/baseq3/game/ai_dmq3.o \ + $(B)/baseq3/game/g_main.o \ + $(B)/baseq3/game/AnimalNPC.o \ + $(B)/baseq3/game/FighterNPC.o \ + $(B)/baseq3/game/NPC.o \ + $(B)/baseq3/game/NPC_AI_Atst.o \ + $(B)/baseq3/game/NPC_AI_Default.o \ + $(B)/baseq3/game/NPC_AI_Droid.o \ + $(B)/baseq3/game/NPC_AI_GalakMech.o \ + $(B)/baseq3/game/NPC_AI_Grenadier.o \ + $(B)/baseq3/game/NPC_AI_Howler.o \ + $(B)/baseq3/game/NPC_AI_ImperialProbe.o \ + $(B)/baseq3/game/NPC_AI_Interrogator.o \ + $(B)/baseq3/game/NPC_AI_Jedi.o \ + $(B)/baseq3/game/NPC_AI_Mark1.o \ + $(B)/baseq3/game/NPC_AI_Mark2.o \ + $(B)/baseq3/game/NPC_AI_MineMonster.o \ + $(B)/baseq3/game/NPC_AI_Rancor.o \ + $(B)/baseq3/game/NPC_AI_Remote.o \ + $(B)/baseq3/game/NPC_AI_Seeker.o \ + $(B)/baseq3/game/NPC_AI_Sentry.o \ + $(B)/baseq3/game/NPC_AI_Sniper.o \ + $(B)/baseq3/game/NPC_AI_Stormtrooper.o \ + $(B)/baseq3/game/NPC_AI_Utils.o \ + $(B)/baseq3/game/NPC_AI_Wampa.o \ + $(B)/baseq3/game/NPC_behavior.o \ + $(B)/baseq3/game/NPC_combat.o \ + $(B)/baseq3/game/NPC_goal.o \ + $(B)/baseq3/game/NPC_misc.o \ + $(B)/baseq3/game/NPC_move.o \ + $(B)/baseq3/game/NPC_reactions.o \ + $(B)/baseq3/game/NPC_senses.o \ + $(B)/baseq3/game/NPC_sounds.o \ + $(B)/baseq3/game/NPC_spawn.o \ + $(B)/baseq3/game/NPC_stats.o \ + $(B)/baseq3/game/NPC_utils.o \ + $(B)/baseq3/game/SpeederNPC.o \ + $(B)/baseq3/game/WalkerNPC.o \ $(B)/baseq3/game/ai_main.o \ - $(B)/baseq3/game/ai_team.o \ - $(B)/baseq3/game/ai_vcmd.o \ + $(B)/baseq3/game/ai_util.o \ + $(B)/baseq3/game/ai_wpnav.o \ + $(B)/baseq3/game/bg_g2_utils.o \ + $(B)/baseq3/game/bg_lib.o \ $(B)/baseq3/game/bg_misc.o \ + $(B)/baseq3/game/bg_panimate.o \ $(B)/baseq3/game/bg_pmove.o \ + $(B)/baseq3/game/bg_saber.o \ + $(B)/baseq3/game/bg_saberLoad.o \ + $(B)/baseq3/game/bg_saga.o \ $(B)/baseq3/game/bg_slidemove.o \ + $(B)/baseq3/game/bg_vehicleLoad.o \ + $(B)/baseq3/game/bg_weapons.o \ + $(B)/baseq3/game/g_ICARUScb.o \ $(B)/baseq3/game/g_active.o \ $(B)/baseq3/game/g_arenas.o \ $(B)/baseq3/game/g_bot.o \ $(B)/baseq3/game/g_client.o \ $(B)/baseq3/game/g_cmds.o \ $(B)/baseq3/game/g_combat.o \ + $(B)/baseq3/game/g_exphysics.o \ $(B)/baseq3/game/g_items.o \ - $(B)/baseq3/game/g_main.o \ + $(B)/baseq3/game/g_log.o \ $(B)/baseq3/game/g_mem.o \ $(B)/baseq3/game/g_misc.o \ $(B)/baseq3/game/g_missile.o \ $(B)/baseq3/game/g_mover.o \ + $(B)/baseq3/game/g_nav.o \ + $(B)/baseq3/game/g_navnew.o \ + $(B)/baseq3/game/g_object.o \ + $(B)/baseq3/game/g_saga.o \ $(B)/baseq3/game/g_session.o \ $(B)/baseq3/game/g_spawn.o \ + $(B)/baseq3/game/g_strap.o \ $(B)/baseq3/game/g_svcmds.o \ $(B)/baseq3/game/g_syscalls.o \ $(B)/baseq3/game/g_target.o \ $(B)/baseq3/game/g_team.o \ + $(B)/baseq3/game/g_timer.o \ $(B)/baseq3/game/g_trigger.o \ + $(B)/baseq3/game/g_turret.o \ + $(B)/baseq3/game/g_turret_G2.o \ $(B)/baseq3/game/g_utils.o \ + $(B)/baseq3/game/g_vehicleTurret.o \ + $(B)/baseq3/game/g_vehicles.o \ $(B)/baseq3/game/g_weapon.o \ + $(B)/baseq3/game/tri_coll_test.o \ + $(B)/baseq3/game/w_force.o \ + $(B)/baseq3/game/w_saber.o \ \ $(B)/baseq3/game/q_math.o \ $(B)/baseq3/game/q_shared.o -$(B)/baseq3/qagame$(ARCH).$(SHLIBEXT) : $(Q3GOBJ) +$(B)/baseq3/jampgame$(ARCH).$(SHLIBEXT) : $(Q3GOBJ) $(CC) $(SHLIBLDFLAGS) -o $@ $(Q3GOBJ) -$(B)/baseq3/game/ai_chat.o : $(GDIR)/ai_chat.c; $(DO_SHLIB_CC) -$(B)/baseq3/game/ai_cmd.o : $(GDIR)/ai_cmd.c; $(DO_SHLIB_CC) -$(B)/baseq3/game/ai_dmnet.o : $(GDIR)/ai_dmnet.c; $(DO_SHLIB_CC) -$(B)/baseq3/game/ai_dmq3.o : $(GDIR)/ai_dmq3.c; $(DO_SHLIB_CC) -$(B)/baseq3/game/ai_main.o : $(GDIR)/ai_main.c; $(DO_SHLIB_CC) -$(B)/baseq3/game/ai_team.o : $(GDIR)/ai_team.c; $(DO_SHLIB_CC) -$(B)/baseq3/game/ai_vcmd.o : $(GDIR)/ai_vcmd.c; $(DO_SHLIB_CC) -$(B)/baseq3/game/bg_misc.o : $(GDIR)/bg_misc.c; $(DO_SHLIB_CC) -$(B)/baseq3/game/bg_pmove.o : $(GDIR)/bg_pmove.c; $(DO_SHLIB_CC) -$(B)/baseq3/game/bg_slidemove.o : $(GDIR)/bg_slidemove.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/ai_main.o : $(GDIR)/ai_main.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/ai_util.o : $(GDIR)/ai_util.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/ai_wpnav.o : $(GDIR)/ai_wpnav.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/AnimalNPC.o : $(GDIR)/AnimalNPC.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/FighterNPC.o : $(GDIR)/FighterNPC.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC.o : $(GDIR)/NPC.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_AI_Atst.o : $(GDIR)/NPC_AI_Atst.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_AI_Default.o : $(GDIR)/NPC_AI_Default.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_AI_Droid.o : $(GDIR)/NPC_AI_Droid.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_AI_GalakMech.o : $(GDIR)/NPC_AI_GalakMech.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_AI_Grenadier.o : $(GDIR)/NPC_AI_Grenadier.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_AI_Howler.o : $(GDIR)/NPC_AI_Howler.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_AI_ImperialProbe.o : $(GDIR)/NPC_AI_ImperialProbe.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_AI_Interrogator.o : $(GDIR)/NPC_AI_Interrogator.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_AI_Jedi.o : $(GDIR)/NPC_AI_Jedi.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_AI_Mark1.o : $(GDIR)/NPC_AI_Mark1.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_AI_Mark2.o : $(GDIR)/NPC_AI_Mark2.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_AI_MineMonster.o : $(GDIR)/NPC_AI_MineMonster.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_AI_Rancor.o : $(GDIR)/NPC_AI_Rancor.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_AI_Remote.o : $(GDIR)/NPC_AI_Remote.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_AI_Seeker.o : $(GDIR)/NPC_AI_Seeker.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_AI_Sentry.o : $(GDIR)/NPC_AI_Sentry.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_AI_Sniper.o : $(GDIR)/NPC_AI_Sniper.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_AI_Stormtrooper.o : $(GDIR)/NPC_AI_Stormtrooper.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_AI_Utils.o : $(GDIR)/NPC_AI_Utils.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_AI_Wampa.o : $(GDIR)/NPC_AI_Wampa.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_behavior.o : $(GDIR)/NPC_behavior.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_combat.o : $(GDIR)/NPC_combat.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_goal.o : $(GDIR)/NPC_goal.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_misc.o : $(GDIR)/NPC_misc.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_reactions.o : $(GDIR)/NPC_reactions.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_senses.o : $(GDIR)/NPC_senses.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_sounds.o : $(GDIR)/NPC_sounds.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_spawn.o : $(GDIR)/NPC_spawn.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_stats.o : $(GDIR)/NPC_stats.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_utils.o : $(GDIR)/NPC_utils.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/SpeederNPC.o : $(GDIR)/SpeederNPC.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/WalkerNPC.o : $(GDIR)/WalkerNPC.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/NPC_move.o : $(GDIR)/NPC_move.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/bg_g2_utils.o : $(GDIR)/bg_g2_utils.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/bg_lib.o : $(GDIR)/bg_lib.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/bg_misc.o : $(GDIR)/bg_misc.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/bg_panimate.o : $(GDIR)/bg_panimate.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/bg_pmove.o : $(GDIR)/bg_pmove.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/bg_saber.o : $(GDIR)/bg_saber.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/bg_saberLoad.o : $(GDIR)/bg_saberLoad.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/bg_saga.o : $(GDIR)/bg_saga.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/bg_slidemove.o : $(GDIR)/bg_slidemove.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/bg_vehicleLoad.o : $(GDIR)/bg_vehicleLoad.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/bg_weapons.o : $(GDIR)/bg_weapons.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_ICARUScb.o : $(GDIR)/g_ICARUScb.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_active.o : $(GDIR)/g_active.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_arenas.o : $(GDIR)/g_arenas.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_bot.o : $(GDIR)/g_bot.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_client.o : $(GDIR)/g_client.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_cmds.o : $(GDIR)/g_cmds.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_combat.o : $(GDIR)/g_combat.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_exphysics.o : $(GDIR)/g_exphysics.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_items.o : $(GDIR)/g_items.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_log.o : $(GDIR)/g_log.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_main.o : $(GDIR)/g_main.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_mem.o : $(GDIR)/g_mem.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_misc.o : $(GDIR)/g_misc.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_missile.o : $(GDIR)/g_missile.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_mover.o : $(GDIR)/g_mover.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_nav.o : $(GDIR)/g_nav.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_navnew.o : $(GDIR)/g_navnew.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_object.o : $(GDIR)/g_object.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_saga.o : $(GDIR)/g_saga.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_session.o : $(GDIR)/g_session.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_spawn.o : $(GDIR)/g_spawn.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_strap.o : $(GDIR)/g_strap.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_svcmds.o : $(GDIR)/g_svcmds.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_syscalls.o : $(GDIR)/g_syscalls.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_target.o : $(GDIR)/g_target.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_team.o : $(GDIR)/g_team.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_timer.o : $(GDIR)/g_timer.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_trigger.o : $(GDIR)/g_trigger.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_turret.o : $(GDIR)/g_turret.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_turret_G2.o : $(GDIR)/g_turret_G2.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_utils.o : $(GDIR)/g_utils.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_vehicleTurret.o : $(GDIR)/g_vehicleTurret.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/g_vehicles.o : $(GDIR)/g_vehicles.c; $(DO_SHLIB_CC) $(B)/baseq3/game/g_weapon.o : $(GDIR)/g_weapon.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/tri_coll_test.o : $(GDIR)/tri_coll_test.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/w_force.o : $(GDIR)/w_force.c; $(DO_SHLIB_CC) +$(B)/baseq3/game/w_saber.o : $(GDIR)/w_saber.c; $(DO_SHLIB_CC) $(B)/baseq3/game/q_math.o : $(GDIR)/q_math.c; $(DO_SHLIB_CC) $(B)/baseq3/game/q_shared.o : $(GDIR)/q_shared.c; $(DO_SHLIB_CC) diff --git a/codemp/unix/unix_main.c b/codemp/unix/unix_main.c index 8d58b9b..789aafe 100644 --- a/codemp/unix/unix_main.c +++ b/codemp/unix/unix_main.c @@ -382,7 +382,11 @@ void *Sys_LoadDll( const char *name, // bk001129 - from cvs1.17 (mkv), was fname not fn libHandle = dlopen( fn, Q_RTLD ); - + +#ifndef NDEBUG + if (libHandle == NULL) Com_Printf("Failed to open DLL\n"); +#endif + if ( !libHandle ) { if( cdpath[0] ) { // bk001206 - report any problem @@ -415,9 +419,16 @@ void *Sys_LoadDll( const char *name, //#endif dllEntry = (void (*)(int (*)(int,...))) dlsym( libHandle, "dllEntry" ); + if (!dllEntry) + { + err = dlerror(); + Com_Printf("Sys_LoadDLL(%s) failed dlsym(dllEntry): \"%s\" ! \n",name,err); + } + //int vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 ) *entryPoint = (int(*)(int,...))dlsym( libHandle, "vmMain" ); + if (!*entryPoint) + err = dlerror(); if ( !*entryPoint || !dllEntry ) { - err = dlerror(); #ifdef NDEBUG // bk001206 - in debug abort on failure Com_Error ( ERR_FATAL, "Sys_LoadDll(%s) failed dlsym(vmMain): \"%s\" !\n", name, err ); #else @@ -1062,7 +1073,7 @@ void Sys_Print( const char *msg ) void Sys_ConfigureFPU() { // bk001213 - divide by zero -#ifdef __linux__ +#ifdef __linux2__ #ifdef __i386 #ifndef NDEBUG // bk0101022 - enable FPE's in debug mode diff --git a/codemp/unix/unix_shared.cpp b/codemp/unix/unix_shared.cpp index fb6beed..ff26e18 100644 --- a/codemp/unix/unix_shared.cpp +++ b/codemp/unix/unix_shared.cpp @@ -317,7 +317,7 @@ char *Sys_DefaultHomePath(void) #ifdef MACOS_X Q_strcat(homePath, sizeof(homePath), "/Library/Application Support/Quake3"); #else - Q_strcat(homePath, sizeof(homePath), "/.jkii"); + Q_strcat(homePath, sizeof(homePath), "/.ja"); #endif if (mkdir(homePath, 0777)) { if (errno != EEXIST) diff --git a/codemp/unix/vssver.scc b/codemp/unix/vssver.scc index 9ad194a..c2e3447 100644 Binary files a/codemp/unix/vssver.scc and b/codemp/unix/vssver.scc differ diff --git a/codemp/vssver.scc b/codemp/vssver.scc index 09af422..0ae558e 100644 Binary files a/codemp/vssver.scc and b/codemp/vssver.scc differ diff --git a/codemp/win32/AutoVersion.h b/codemp/win32/AutoVersion.h index 650373e..6e08b62 100644 --- a/codemp/win32/AutoVersion.h +++ b/codemp/win32/AutoVersion.h @@ -3,15 +3,18 @@ #define VERSION_MAJOR_RELEASE 1 #define VERSION_MINOR_RELEASE 0 -#define VERSION_EXTERNAL_BUILD 0 +#define VERSION_EXTERNAL_BUILD 1 #define VERSION_INTERNAL_BUILD 0 -#define VERSION_STRING "1, 0, 0, 0" -#define VERSION_STRING_DOTTED "1.0.0.0" +#define VERSION_STRING "1, 0, 1, 0" +#define VERSION_STRING_DOTTED "1.0.1.0" -#define VERSION_BUILD_NUMBER 86 +#define VERSION_BUILD_NUMBER 91 // BEGIN COMMENTS +// 1.0.1.0 10/24/2003 16:22:44 jmonroe patch rc1 +// 1.0.0.3 10/17/2003 17:51:58 jmonroe fix ati rect hack, fix NET_OpenIP bug preventing multiple servers, inc protocol +// 1.0.0.0 09/15/2003 15:21:18 mgummelt Final code changes for siege_destroyer/flying vehicles // 1.0.0.0 07/21/2003 16:05:31 jmonroe going gold // 0.0.12.0 07/20/2003 19:05:02 jmonroe build 0.12 for qa // 0.0.11.0 07/18/2003 12:08:44 jmonroe dlight fix, ui name fix, jk2 -> ja diff --git a/codemp/win32/vssver.scc b/codemp/win32/vssver.scc index bd69e45..9eacd37 100644 Binary files a/codemp/win32/vssver.scc and b/codemp/win32/vssver.scc differ diff --git a/codemp/win32/win_glimp.cpp b/codemp/win32/win_glimp.cpp index 9c367ff..8c273eb 100644 --- a/codemp/win32/win_glimp.cpp +++ b/codemp/win32/win_glimp.cpp @@ -1360,17 +1360,17 @@ static void GLW_InitExtensions( void ) } // Figure out which texture rectangle extension to use. - // TOTAL HACK!!! This will need to be fixed. - // FIXMEFIXMEFIXME! bool bTexRectSupported = false; - if ( strstr( glConfig.extensions_string, "GL_EXT_texture_rectangle" ) ) + if ( strnicmp( glConfig.vendor_string, "ATI Technologies",16 )==0 + && strnicmp( glConfig.version_string, "1.3.3",5 )==0 + && glConfig.version_string[5] < '9' ) //1.3.34 and 1.3.37 and 1.3.38 are broken for sure, 1.3.39 is not { g_bTextureRectangleHack = true; - bTexRectSupported = true; } - else if ( strstr( glConfig.extensions_string, "GL_NV_texture_rectangle" ) ) + + if ( strstr( glConfig.extensions_string, "GL_NV_texture_rectangle" ) + || strstr( glConfig.extensions_string, "GL_EXT_texture_rectangle" ) ) { - g_bTextureRectangleHack = false; bTexRectSupported = true; } diff --git a/codemp/win32/win_main.cpp b/codemp/win32/win_main.cpp index 29f8ad4..f36b6b1 100644 --- a/codemp/win32/win_main.cpp +++ b/codemp/win32/win_main.cpp @@ -1304,10 +1304,10 @@ void Sys_Net_Restart_f( void ) { static bool Sys_IsExpired() { #if 0 -// sec min Hr Day Mon Yr - struct tm t_valid_start = { 0, 0, 8, 5, 8, 103 }; //zero based months! -// sec min Hr Day Mon Yr - struct tm t_valid_end = { 0, 0, 20, 13, 8, 103 }; +// sec min Hr Day Mon Yr + struct tm t_valid_start = { 0, 0, 8, 23, 6, 103 }; //zero based months! +// sec min Hr Day Mon Yr + struct tm t_valid_end = { 0, 0, 20, 30, 6, 103 }; // struct tm t_valid_end = t_valid_start; // t_valid_end.tm_mday += 8; time_t startTime = mktime( &t_valid_start); diff --git a/codemp/win32/win_net.cpp b/codemp/win32/win_net.cpp index 03a45d5..5c1959e 100644 --- a/codemp/win32/win_net.cpp +++ b/codemp/win32/win_net.cpp @@ -585,7 +585,7 @@ void Sys_ShowIP(void) { NET_IPSocket ==================== */ -int NET_IPSocket( char *net_interface, int port ) { +SOCKET NET_IPSocket( char *net_interface, int port ) { SOCKET newsocket; struct sockaddr_in address; qboolean _true = qtrue; @@ -925,7 +925,7 @@ void NET_OpenIP( void ) // a different net_port for each one for( i = 0 ; i < 10 ; i++ ) { ip_socket = NET_IPSocket( ip->string, port + i ); - if ( ip_socket ) { + if ( ip_socket != INVALID_SOCKET ) { Cvar_SetValue( "net_port", port + i ); if ( net_socksEnabled->integer ) { NET_OpenSocks( port + i ); diff --git a/codemp/x_botlib/mssccprj.scc b/codemp/x_botlib/mssccprj.scc index e91b3f3..34b5181 100644 --- a/codemp/x_botlib/mssccprj.scc +++ b/codemp/x_botlib/mssccprj.scc @@ -1,5 +1,5 @@ SCC = This is a Source Code Control file [x_botlib.vcproj] -SCC_Aux_Path = "\\ravendata1\vss\central_code" +SCC_Aux_Path = "\\ravendata1\VSS\central_code" SCC_Project_Name = "$/jedi/codemp/x_botlib", SUHAAAAA diff --git a/codemp/x_botlib/vssver.scc b/codemp/x_botlib/vssver.scc index e36998b..4690e62 100644 Binary files a/codemp/x_botlib/vssver.scc and b/codemp/x_botlib/vssver.scc differ diff --git a/codemp/x_exe/mssccprj.scc b/codemp/x_exe/mssccprj.scc index 66fedab..14c842c 100644 --- a/codemp/x_exe/mssccprj.scc +++ b/codemp/x_exe/mssccprj.scc @@ -1,5 +1,5 @@ SCC = This is a Source Code Control file [x_exe.vcproj] -SCC_Aux_Path = "\\ravendata1\vss\central_code" +SCC_Aux_Path = "\\ravendata1\VSS\central_code" SCC_Project_Name = "$/jedi/codemp/x_exe", TUHAAAAA diff --git a/codemp/x_exe/vssver.scc b/codemp/x_exe/vssver.scc index 4afeb9c..eac3b81 100644 Binary files a/codemp/x_exe/vssver.scc and b/codemp/x_exe/vssver.scc differ diff --git a/codemp/x_jk2cgame/mssccprj.scc b/codemp/x_jk2cgame/mssccprj.scc index 3bcec23..b9149cc 100644 --- a/codemp/x_jk2cgame/mssccprj.scc +++ b/codemp/x_jk2cgame/mssccprj.scc @@ -1,5 +1,5 @@ SCC = This is a Source Code Control file [x_jk2cgame.vcproj] -SCC_Aux_Path = "\\ravendata1\vss\central_code" +SCC_Aux_Path = "\\ravendata1\VSS\central_code" SCC_Project_Name = "$/jedi/codemp/x_jk2cgame", UUHAAAAA diff --git a/codemp/x_jk2cgame/vssver.scc b/codemp/x_jk2cgame/vssver.scc index ccaae48..74fed8e 100644 Binary files a/codemp/x_jk2cgame/vssver.scc and b/codemp/x_jk2cgame/vssver.scc differ diff --git a/codemp/x_jk2game/mssccprj.scc b/codemp/x_jk2game/mssccprj.scc index eb9c743..4c8defe 100644 --- a/codemp/x_jk2game/mssccprj.scc +++ b/codemp/x_jk2game/mssccprj.scc @@ -1,5 +1,5 @@ SCC = This is a Source Code Control file [x_jk2game.vcproj] -SCC_Aux_Path = "\\ravendata1\vss\central_code" +SCC_Aux_Path = "\\ravendata1\VSS\central_code" SCC_Project_Name = "$/jedi/codemp/x_jk2game", VUHAAAAA diff --git a/codemp/x_jk2game/vssver.scc b/codemp/x_jk2game/vssver.scc index dc6db29..ca360eb 100644 Binary files a/codemp/x_jk2game/vssver.scc and b/codemp/x_jk2game/vssver.scc differ diff --git a/codemp/x_ui/mssccprj.scc b/codemp/x_ui/mssccprj.scc index 8757bf4..8c3cd6f 100644 --- a/codemp/x_ui/mssccprj.scc +++ b/codemp/x_ui/mssccprj.scc @@ -1,5 +1,5 @@ SCC = This is a Source Code Control file [x_ui.vcproj] -SCC_Aux_Path = "\\ravendata1\vss\central_code" +SCC_Aux_Path = "\\ravendata1\VSS\central_code" SCC_Project_Name = "$/jedi/codemp/x_ui", WUHAAAAA diff --git a/codemp/x_ui/vssver.scc b/codemp/x_ui/vssver.scc index 2864a40..6689187 100644 Binary files a/codemp/x_ui/vssver.scc and b/codemp/x_ui/vssver.scc differ diff --git a/codemp/zlib32/vssver.scc b/codemp/zlib32/vssver.scc index 2a04f56..acfabc1 100644 Binary files a/codemp/zlib32/vssver.scc and b/codemp/zlib32/vssver.scc differ