diff --git a/Classic/evoClassicTaco.vl2 b/Classic/evoClassicTaco.vl2 index 6c9257b..22f278f 100644 Binary files a/Classic/evoClassicTaco.vl2 and b/Classic/evoClassicTaco.vl2 differ diff --git a/Classic/scripts/DMGame.cs b/Classic/scripts/DMGame.cs new file mode 100644 index 0000000..0c0fd77 --- /dev/null +++ b/Classic/scripts/DMGame.cs @@ -0,0 +1,607 @@ +// -------------------------------------------------------- +// Deathmatch mission type +// -------------------------------------------------------- + +// DisplayName = Deathmatch + +//--- GAME RULES BEGIN --- +//There aren't many rules... +//Kill +//Don't get killed +//Points are scored for each kill you make and subtracted each time you die +//--- GAME RULES END --- + +$InvBanList[DM, "TurretOutdoorDeployable"] = 1; +$InvBanList[DM, "TurretIndoorDeployable"] = 1; +$InvBanList[DM, "ElfBarrelPack"] = 1; +$InvBanList[DM, "MortarBarrelPack"] = 1; +$InvBanList[DM, "PlasmaBarrelPack"] = 1; +$InvBanList[DM, "AABarrelPack"] = 1; +$InvBanList[DM, "MissileBarrelPack"] = 1; +$InvBanList[DM, "AmmoPack"] = 1; +$InvBanList[DM, "CloakingPack"] = 1; +$InvBanList[DM, "MotionSensorDeployable"] = 1; +$InvBanList[DM, "PulseSensorDeployable"] = 1; +$InvBanList[DM, "CameraGrenade"] = 1; + +$Host::DMSLOnlyMode = 0; + +function DMGame::setUpTeams(%game) +{ + %group = nameToID("MissionGroup/Teams"); + if(%group == -1) + return; + + // create a team0 if it does not exist + %team = nameToID("MissionGroup/Teams/team0"); + if(%team == -1) + { + %team = new SimGroup("team0"); + %group.add(%team); + } + + // 'team0' is not counted as a team here + %game.numTeams = 0; + while(%team != -1) + { + // create drop set and add all spawnsphere objects into it + %dropSet = new SimSet("TeamDrops" @ %game.numTeams); + MissionCleanup.add(%dropSet); + + %spawns = nameToID("MissionGroup/Teams/team" @ %game.numTeams @ "/SpawnSpheres"); + if(%spawns != -1) + { + %count = %spawns.getCount(); + for(%i = 0; %i < %count; %i++) + %dropSet.add(%spawns.getObject(%i)); + } + + // set the 'team' field for all the objects in this team + %team.setTeam(0); + + clearVehicleCount(%team+1); + // get next group + %team = nameToID("MissionGroup/Teams/team" @ %game.numTeams + 1); + if (%team != -1) + %game.numTeams++; + } + + // set the number of sensor groups (including team0) that are processed + setSensorGroupCount(%game.numTeams + 1); + %game.numTeams = 1; + + // allow teams 1->31 to listen to each other (team 0 can only listen to self) + for(%i = 1; %i < 32; %i++) + setSensorGroupListenMask(%i, 0xfffffffe); +} + +function DMGame::initGameVars(%game) +{ + %game.SCORE_PER_KILL = 1; + %game.SCORE_PER_DEATH = -1; + %game.SCORE_PER_SUICIDE = -1; +} + +exec("scripts/aiDeathMatch.cs"); + +function DMGame::allowsProtectedStatics(%game) +{ + return true; +} + +function DMGame::equip(%game, %player) +{ + for(%i =0; %i<$InventoryHudCount; %i++) + %player.client.setInventoryHudItem($InventoryHudData[%i, itemDataName], 0, 1); + %player.client.clearBackpackIcon(); + + if( $Host::DMSLOnlyMode ) + { + %player.clearInventory(); + %player.setInventory(EnergyPack, 1); + %player.setInventory(Shocklance, 1); + %player.setInventory(RepairKit, 1); + %player.setInventory(TargetingLaser, 1); + %player.use("Shocklance"); + } + else + { + buyDeployableFavorites(%player.client); + %player.setEnergyLevel(%player.getDataBlock().maxEnergy); + %player.selectWeaponSlot( 0 ); + + // do we want to give players a disc launcher instead? GJL: Yes we do! + %player.use("Disc"); + } +} + +function DMGame::pickPlayerSpawn(%game, %client, %respawn) +{ + // all spawns come from team 1 + return %game.pickTeamSpawn(1); +} + +function DMGame::clientJoinTeam( %game, %client, %team, %respawn ) +{ + %game.assignClientTeam( %client ); + + // Spawn the player: + %game.spawnPlayer( %client, %respawn ); +} + +function DMGame::assignClientTeam(%game, %client) +{ + for(%i = 1; %i < 32; %i++) + $DMTeamArray[%i] = false; + + %maxSensorGroup = 0; + %count = ClientGroup.getCount(); + for(%i = 0; %i < %count; %i++) + { + %cl = ClientGroup.getObject(%i); + if(%cl != %client) + { + $DMTeamArray[%cl.team] = true; + if (%cl.team > %maxSensorGroup) + %maxSensorGroup = %cl.team; + } + } + + //now loop through the team array, looking for an empty team + for(%i = 1; %i < 32; %i++) + { + if (! $DMTeamArray[%i]) + { + %client.team = %i; + if (%client.team > %maxSensorGroup) + %maxSensorGroup = %client.team; + break; + } + } + + // set player's skin pref here + setTargetSkin(%client.target, %client.skin); + + // Let everybody know you are no longer an observer: + messageAll( 'MsgClientJoinTeam', '\c1%1 has joined the fray.', %client.name, "", %client, 1 ); + updateCanListenState( %client ); + + //now set the max number of sensor groups... + setSensorGroupCount(%maxSensorGroup + 1); +} + +function DMGame::clientMissionDropReady(%game, %client) +{ + messageClient(%client, 'MsgClientReady',"", %game.class); + messageClient(%client, 'MsgYourScoreIs', "", 0); + messageClient(%client, 'MsgDMPlayerDies', "", 0); + messageClient(%client, 'MsgDMKill', "", 0); + %game.resetScore(%client); + + messageClient(%client, 'MsgMissionDropInfo', '\c0You are in mission %1 (%2).', $MissionDisplayName, $MissionTypeDisplayName, $ServerName ); + + DefaultGame::clientMissionDropReady(%game, %client); +} + +function DMGame::AIHasJoined(%game, %client) +{ + //let everyone know the player has joined the game + //messageAllExcept(%client, -1, 'MsgClientJoinTeam', '%1 has joined the fray.', %client.name, "", %client, 1 ); +} + +function DMGame::checkScoreLimit(%game, %client) +{ + //there's no score limit in DM +} + +function DMGame::createPlayer(%game, %client, %spawnLoc, %respawn) +{ + DefaultGame::createPlayer(%game, %client, %spawnLoc, %respawn); + %client.setSensorGroup(%client.team); +} + +function DMGame::resetScore(%game, %client) +{ + %client.deaths = 0; + %client.kills = 0; + %client.score = 0; + %client.efficiency = 0.0; + %client.suicides = 0; +} + +function DMGame::onClientKilled(%game, %clVictim, %clKiller, %damageType, %implement, %damageLoc) +{ + cancel(%clVictim.player.alertThread); + DefaultGame::onClientKilled(%game, %clVictim, %clKiller, %damageType, %implement, %damageLoc); +} + +function DMGame::updateKillScores(%game, %clVictim, %clKiller, %damageType, %implement) +{ + if (%game.testKill(%clVictim, %clKiller)) //verify victim was an enemy + { + %game.awardScoreKill(%clKiller); + messageClient(%clKiller, 'MsgDMKill', "", %clKiller.kills); + %game.awardScoreDeath(%clVictim); + } + else if (%game.testSuicide(%clVictim, %clKiller, %damageType)) //otherwise test for suicide + %game.awardScoreSuicide(%clVictim); + + messageClient(%clVictim, 'MsgDMPlayerDies', "", %clVictim.deaths + %clVictim.suicides); +} + +function DMGame::recalcScore(%game, %client) +{ + %killValue = %client.kills * %game.SCORE_PER_KILL; + %deathValue = %client.deaths * %game.SCORE_PER_DEATH; + %suicideValue = %client.suicides * %game.SCORE_PER_SUICIDE; + + if (%killValue - %deathValue == 0) + %client.efficiency = %suicideValue; + else + %client.efficiency = ((%killValue * %killValue) / (%killValue - %deathValue)) + %suicideValue; + + %client.score = mFloatLength(%client.efficiency, 1); + messageClient(%client, 'MsgYourScoreIs', "", %client.score); + %game.recalcTeamRanks(%client); + %game.checkScoreLimit(%client); +} + +function DMGame::timeLimitReached(%game) +{ + logEcho("game over (timelimit)"); + %game.gameOver(); + cycleMissions(); +} + +function DMGame::scoreLimitReached(%game) +{ + logEcho("game over (scorelimit)"); + %game.gameOver(); + cycleMissions(); +} + +function DMGame::gameOver(%game) +{ + //call the default + DefaultGame::gameOver(%game); + + messageAll('MsgGameOver', "Match has ended.~wvoice/announcer/ann.gameover.wav" ); + + cancel(%game.timeThread); + messageAll('MsgClearObjHud', ""); + for(%i = 0; %i < ClientGroup.getCount(); %i ++) { + %client = ClientGroup.getObject(%i); + %game.resetScore(%client); + } +} + +function DMGame::enterMissionArea(%game, %playerData, %player) +{ + %player.client.outOfBounds = false; + messageClient(%player.client, 'EnterMissionArea', '\c1You are back in the mission area.'); + logEcho(%player.client.nameBase@" (pl "@%player@"/cl "@%player.client@") entered mission area"); + cancel(%player.alertThread); +} + +// borlak -- TAKEN FROM TR2 -- thanks! :D +function plzBounceOffGrid(%obj, %bounceForce, %count) +{ + %bounds = MissionArea.area; + %boundsWest = firstWord(%bounds); + %boundsNorth = getWord(%bounds, 1); + %boundsEast = %boundsWest + getWord(%bounds, 2); + %boundsSouth = %boundsNorth + getWord(%bounds, 3); + + %shapePos = %obj.getPosition(); + %shapex = firstWord(%shapePos); + %shapey = getWord(%shapePos, 1); + + if( %shapex >= %boundsWest && %shapex <= %boundsEast && %shapey >= %boundsNorth && %shapey <= %boundsSouth) { + // we don't need to bounce at all + return; + } + + if( %count == 8 ) { + // just kill this retard + %obj.scriptKill($DamageType::OutOfBounds); + return; + } + + if (%bounceForce $= "") + %bounceForce = 65; + + %oldVel = %obj.getVelocity(); + %obj.setVelocity("0 0 0"); + + %vecx = firstWord(%oldVel); + %vecy = getWord(%oldVel, 1); + %vecz = getWord(%oldVel, 2); + + // four cases, not two cases you fucktard kineticpoet + // no wonder the trives of vengrances failed + if(%shapex <= %boundsWest) { + %vecx = mAbs(%vecx); + } + else if(%shapex >= %boundsEast) { + %vecx = -mAbs(%vecx); + } + + if(%shapey <= %boundsNorth) { + %vecy = mAbs(%vecy); + } + else if(%shapey >= %boundsSouth) { + %vecy = -mAbs(%vecy); + } + + %vec = %vecx SPC %vecy SPC %vecz; + + // If the object's speed was pretty slow, give it a boost + %oldSpeed = VectorLen(%oldVel); + if (%oldSpeed < 25) + { + %vec = VectorNormalize(%vec); + %vec = VectorScale(%vec, 25); + } + else + %vec = VectorScale(%vec, 1.15); + + // apply the impulse to the object + //%obj.applyImpulse(%obj.getWorldBoxCenter(), %vec); + %obj.setVelocity(%vec); + + // repeat this bounce 4 times per second. if we're oob for 2 seconds, take action + // don't do this with the flag because that has its own thread + if( %obj.dataBlock !$= "Flag" ) { + schedule(250, 0, plzBounceOffGrid, %obj, %bounceForce, %count + 1); + } +} +function isOutOfBounds(%position) +{ + %shapePos = %position; + %shapex = firstWord(%shapePos); + %shapey = getWord(%shapePos, 1); + %bounds = MissionArea.area; + %boundsWest = firstWord(%bounds); + %boundsNorth = getWord(%bounds, 1); + %boundsEast = %boundsWest + getWord(%bounds, 2); + %boundsSouth = %boundsNorth + getWord(%bounds, 3); + + return (%shapex < %boundsWest || %shapex > %boundsEast || + %shapey < %boundsNorth || %shapey > %boundsSouth); +} + +function DMGame::leaveMissionArea(%game, %playerData, %player) +{ + if(%player.getState() $= "Dead") + return; + + plzBounceOffGrid(%player, 65); +} + +function DMGame::DMAlertPlayer(%game, %count, %player) +{ + // MES - I commented below line out because it prints a blank line to chat window + //messageClient(%player.client, 'MsgDMLeftMisAreaWarn', '~wfx/misc/red_alert.wav'); + if(%count > 1) + %player.alertThread = %game.schedule(1000, "DMAlertPlayer", %count - 1, %player); + else + %player.alertThread = %game.schedule(1000, "MissionAreaDamage", %player); +} + +function DMGame::MissionAreaDamage(%game, %player) +{ + if(%player.getState() !$= "Dead") { + %player.setDamageFlash(0.1); + %prevHurt = %player.getDamageLevel(); + %player.setDamageLevel(%prevHurt + 0.05); + %player.alertThread = %game.schedule(1000, "MissionAreaDamage", %player); + } + else + %game.onClientKilled(%player.client, 0, $DamageType::OutOfBounds); +} + +function DMGame::updateScoreHud(%game, %client, %tag) +{ + // Clear the header: + messageClient( %client, 'SetScoreHudHeader', "", "" ); + + // Send the subheader: + messageClient(%client, 'SetScoreHudSubheader', "", '\tPLAYER\tRATING\tKILLS\tDEATHS'); + + for (%index = 0; %index < $TeamRank[0, count]; %index++) + { + //get the client info + %cl = $TeamRank[0, %index]; + + //get the score + %clScore = mFloatLength( %cl.efficiency, 1 ); + + %clKills = mFloatLength( %cl.kills, 0 ); + %clDeaths = mFloatLength( %cl.deaths + %cl.suicides, 0 ); + %clStyle = %cl == %client ? "" : ""; + + //if the client is not an observer, send the message + if (%client.team != 0) + { + messageClient( %client, 'SetLineHud', "", %tag, %index, '%5\t%1%2%3%4', + %cl.name, %clScore, %clKills, %clDeaths, %clStyle ); + } + //else for observers, create an anchor around the player name so they can be observed + else + { + messageClient( %client, 'SetLineHud', "", %tag, %index, '%5\t%1%2%3%4', + %cl.name, %clScore, %clKills, %clDeaths, %clStyle, %cl ); + } + } + + // Tack on the list of observers: + %observerCount = 0; + for (%i = 0; %i < ClientGroup.getCount(); %i++) + { + %cl = ClientGroup.getObject(%i); + if (%cl.team == 0) + %observerCount++; + } + + if (%observerCount > 0) + { + messageClient( %client, 'SetLineHud', "", %tag, %index, ""); + %index++; + messageClient(%client, 'SetLineHud', "", %tag, %index, '\tOBSERVERS (%1)TIME', %observerCount); + %index++; + for (%i = 0; %i < ClientGroup.getCount(); %i++) + { + %cl = ClientGroup.getObject(%i); + //if this is an observer + if (%cl.team == 0) + { + %obsTime = getSimTime() - %cl.observerStartTime; + %obsTimeStr = %game.formatTime(%obsTime, false); + messageClient( %client, 'SetLineHud', "", %tag, %index, '\t%1%2', + %cl.name, %obsTimeStr ); + %index++; + } + } + } + + //clear the rest of Hud so we don't get old lines hanging around... + messageClient( %client, 'ClearHud', "", %tag, %index ); +} + +//function DMGame::applyConcussion(%game, %player) +//{ +//} + +package DMGame +{ + +function deployMineCheck(%mineObj, %player) +{ + // explode it vgc + schedule(2000, %mineObj, "explodeMine", %mineObj, true); +} + +}; + +function DMGame::sendGameVoteMenu(%game, %client, %key) +{ + parent::sendGameVoteMenu( %game, %client, %key ); + + %isAdmin = ( %client.isAdmin || %client.isSuperAdmin ); + + if ( %game.scheduleVote $= "" ) + { + if(!%client.isAdmin) + { + if(!$Host::DMSLOnlyMode) + messageClient( %client, 'MsgVoteItem', "", %key, 'DMSLOnlyMode', 'vote to enable Shocklance Only Mode', 'Vote to enable Shocklance Only Mode' ); + else + messageClient( %client, 'MsgVoteItem', "", %key, 'DMSLOnlyMode', 'vote to disable Shocklance Only Mode', 'Vote to disable Shocklance Only Mode' ); + } + else if (%client.ForceVote > 0) + { + if(!$Host::DMSLOnlyMode) + messageClient( %client, 'MsgVoteItem', "", %key, 'DMSLOnlyMode', 'vote to enable Shocklance Only Mode', 'Vote to enable Shocklance Only Mode' ); + else + messageClient( %client, 'MsgVoteItem', "", %key, 'DMSLOnlyMode', 'vote to disable Shocklance Only Mode', 'Vote to disable Shocklance Only Mode' ); + } + else + { + if(!$Host::DMSLOnlyMode) + messageClient( %client, 'MsgVoteItem', "", %key, 'DMSLOnlyMode', 'change to enable Shocklance Only Mode', 'Enable Shocklance Only Mode' ); + else + messageClient( %client, 'MsgVoteItem', "", %key, 'DMSLOnlyMode', 'change to disable Shocklance Only Mode', 'Disable Shocklance Only Mode' ); + } + } +} + +function DMGame::evalVote(%game, %typeName, %admin, %arg1, %arg2, %arg3, %arg4) +{ + switch$ (%typeName) + { + case "DMSLOnlyMode": + %game.DMSLOnlyMode(%admin, %arg1, %arg2, %arg3, %arg4); + } + + parent::evalVote(%game, %typeName, %admin, %arg1, %arg2, %arg3, %arg4); +} + +//--------------------------------DMSLOnlyMode-------------------------------- +// +$VoteMessage["DMSLOnlyMode"] = "turn"; + +function DMGame::DMSLOnlyMode(%game, %admin, %arg1, %arg2, %arg3, %arg4) +{ + if( $countdownStarted && $MatchStarted ) + { + if(%admin) + { + killeveryone(); + + if(%game.DMSLOnlyMode) + { + messageAll('MsgAdminForce', '\c2The Admin has disabled Shocklance Only Mode.'); + + %game.DMSLOnlyMode = false; + } + else + { + messageAll('MsgAdminForce', '\c2The Admin has enabled Shocklance Only Mode.'); + + %game.DMSLOnlyMode = true; + } + } + else + { + %totalVotes = %game.totalVotesFor + %game.totalVotesAgainst; + if(%totalVotes > 0 && (%game.totalVotesFor / ClientGroup.getCount()) > ($Host::VotePasspercent / 100)) + { + killeveryone(); + + if(%game.DMSLOnlyMode) + { + messageAll('MsgVotePassed', '\c2Shocklance Only Mode Disabled.'); + + %game.DMSLOnlyMode = false; + } + else + { + messageAll('MsgVotePassed', '\c2Shocklance Only Mode Enabled.'); + + %game.DMSLOnlyMode = true; + } + } + else + messageAll('MsgVoteFailed', '\c2Mode change did not pass: %1 percent.', mFloor(%game.totalVotesFor/ClientGroup.getCount() * 100)); + } + + $Host::DMSLOnlyMode = %game.DMSLOnlyMode; + } +} +// For voting to work properly - evo admin.ovl +// +// case "DMSLOnlyMode": +// if( %isAdmin && !%client.ForceVote ) +// { +// adminStartNewVote(%client, %typename, %arg1, %arg2, %arg3, %arg4); +// adminLog(%client, " has toggled " @ %arg1 @ " (" @ %arg2 @ ")"); +// } +// else +// { +// if(Game.scheduleVote !$= "") +// { +// messageClient(%client, 'voteAlreadyRunning', '\c2A vote is already in progress.'); +// return; +// } +// %actionMsg = ($Host::DMSLOnlyMode ? "disable Shocklance Only Mode" : "enable Shocklance Only Mode"); +// for(%idx = 0; %idx < ClientGroup.getCount(); %idx++) +// { +// %cl = ClientGroup.getObject(%idx); +// if(!%cl.isAIControlled()) +// { +// messageClient(%cl, 'VoteStarted', '\c2%1 initiated a vote to %2.', %client.name, %actionMsg); +// %clientsVoting++; +// } +// } +// playerStartNewVote(%client, %typename, %arg1, %arg2, %arg3, %arg4, %clientsVoting); +// }