From a67d86c49b640a9469f6a9b20142c34a48208bed Mon Sep 17 00:00:00 2001 From: Robert Fritzen Date: Wed, 26 Feb 2014 14:03:16 -0600 Subject: [PATCH 01/16] Renamed serverControl The git version doesn't need the "developer/release" files stored, renamed accordingly. --- serverControl_R.cs => serverControl.cs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename serverControl_R.cs => serverControl.cs (100%) diff --git a/serverControl_R.cs b/serverControl.cs similarity index 100% rename from serverControl_R.cs rename to serverControl.cs From e49ad657a3364bdb6acb3897576d59bd39124d22 Mon Sep 17 00:00:00 2001 From: Robert Fritzen Date: Wed, 26 Feb 2014 14:18:09 -0600 Subject: [PATCH 02/16] Removed Old Unused/Un-Needed PCM code Removed some old and unnecessary code from the PCM days, TWM2 doesn't use a player ban system anymore, it's all handled by PGD Connect... --- .../TWM2/ExteriorFunctioning/PconFunctions.cs | 94 ------------------- 1 file changed, 94 deletions(-) diff --git a/scripts/TWM2/ExteriorFunctioning/PconFunctions.cs b/scripts/TWM2/ExteriorFunctioning/PconFunctions.cs index d9b3670..459d69e 100644 --- a/scripts/TWM2/ExteriorFunctioning/PconFunctions.cs +++ b/scripts/TWM2/ExteriorFunctioning/PconFunctions.cs @@ -25,100 +25,6 @@ function ServerReturnDate() { // echo(%IntVal); return %IntVal; } - -function DownloadBanList() { - if($Host::UseGlobalBanList) { - $Phantom::BanCount = 0; - %server = "www.phantomdev.net:80"; - if (!isObject(BanGet)) - %Downloader = new HTTPObject(BanGet){}; - else %Downloader = BanGet; - %filename = "/Tribes2/Bans.txt"; - %Downloader.get(%server, %filename); - Error("SERVER: Downloading Global Ban List From PGD.com"); - } - else { - Error("$Host::UseGlobalBanList is 0, G-Ban List Off"); - } -} - -function BanGet::onLine(%this, %line) { - AddToGlobalBanList(%line); -} - -function AddToGlobalBanList(%line) { - %line = detag( %line ); - %text = (%text $= "") ? %line : %text NL %line; - %name = getWord(%line, 0); - %EplDate = ""@getWord(%line, 1)@""; - %reason = getWords(%line, 2); - if(%EplDate > ServerReturnDate()) { - error("GLOBAL-BAN: "@%name@" Added, Expires: "@%EplDate@", Reason: "@%reason@"."); - $Phantom::GlobalBanList[$Phantom::BanCount] = ""@%name@" "@%EplDate@" "@%reason@""; - $Phantom::BanCount++; - } - else { - error("GLOBAL-BAN: "@%name@", This ban has Expired, Not added to list."); - } -} - -function BanGet::onConnectFailed() { - echo("-- Could not connect to PGD."); - echo("Please Call DownloadBanList(); To Protect your server"); -} - -function BanGet::onDisconnect(%this) { - %this.delete(); -} - -function CheckBans(%client) { - for(%i= 0; %i < $Phantom::BanCount; %i++) { - %nametotest = getWord($Phantom::GlobalBanList[%i], 0); - %target = plnametocid(%nametotest); - if(%target != 0) { - %EplDate = getWord($Phantom::GlobalBanList[%i], 1); - if(%EplDate > ServerReturnDate()) { - %reason = getWords($Phantom::GlobalBanList[%i], 2); - banthesucker(%target, %reason, %EplDate); - } - else { - echo(""@getTaggedString(%client.name)@" is on the ban list, but the duration has expired"); - } - } - else { - //Do Nothing - } - } -} - - function banthesucker(%client, %reason, %lengString) { - if($Host::UseGlobalBanList) { - echo("Global-Banned Client "@%client.namebase@" Attempting to Connect"); - MessageAll('Message', "\c2"@%client.namebase@" is Banned Until "@%lengString@" - "@%reason@"."); - if(%lengString > 90000000) { - ban(%client); - %client.setDisconnectReason( "You are Perm. Banned From This Server, "@%reason@"" ); - $HostGamePlayerCount = ClientGroup.getCount(); - return; - } - ban(%client); - %client.setDisconnectReason( "You are G-Banned Until "@%lengString@", "@%reason@"" ); - $HostGamePlayerCount = ClientGroup.getCount(); - } - else { - echo("Global-Banned Client "@%client.namebase@" Permitted connect - $Host::UseGlobalBanList is 0"); - MessageAll('Message', "\c2Global Banned Client: "@%client.namebase@" Permitted Access, $Host::UseGlobalBanList is 0."); - } - } - -DownloadBanList(); //download the list -package ServerRunFunctioning { - function GameConnection::onConnect(%client, %name, %raceGender, %skin, %voice, %voicePitch) { - parent::onConnect(%client, %name, %raceGender, %skin, %voice, %voicePitch); - checkBans(%client); - } -}; -activatePackage(ServerRunFunctioning); ////////// function spawnprojectile(%proj,%type,%pos,%direction,%src) { From 2a57809c8cd2b47ef361be64c77026a85e053b98 Mon Sep 17 00:00:00 2001 From: Robert Fritzen Date: Wed, 26 Feb 2014 14:27:38 -0600 Subject: [PATCH 03/16] Removed EditGun Pulse Replaced the EditGun pulse with a simple raycast call to save an extra datablock, not to mention this functioning is a little more advanced and provides some more control. --- scripts/weapons/Construction/EditGun.cs | 338 +++++++++++------------- 1 file changed, 155 insertions(+), 183 deletions(-) diff --git a/scripts/weapons/Construction/EditGun.cs b/scripts/weapons/Construction/EditGun.cs index 3c1996d..182b818 100644 --- a/scripts/weapons/Construction/EditGun.cs +++ b/scripts/weapons/Construction/EditGun.cs @@ -33,50 +33,7 @@ $EditTool::PadModes[18] = "DeployedCrate12"; $EditTool::PadModes[19] = "DeployedDecoration6"; $EditTool::PadModes[20] = "DeployedDecoration16"; - -datablock LinearFlareProjectileData(EditorBolt) -{ - emitterDelay = -1; - directDamage = 0; - directDamageType = $DamageType::Default; - kickBackStrength = 0.0; - bubbleEmitTime = 1.0; - - sound = PlasmaProjectileSound; - velInheritFactor = 0.5; - - explosion = "BlasterExplosion"; - splash = BlasterSplash; - - grenadeElasticity = 0.998; - grenadeFriction = 0.0; - armingDelayMS = 500; - - muzzleVelocity = 100.0; - - drag = 0.05; - - gravityMod = 0.0; - - dryVelocity = 100.0; - wetVelocity = 80.0; - - reflectOnWaterImpactAngle = 0.0; - explodeOnWaterImpact = false; - deflectionOnWaterImpact = 0.0; - fizzleUnderwaterMS = 6000; - - lifetimeMS = 6000; - - scale = "1 1 1"; - numFlares = 48; - flareColor = "1 0 0"; - flareModTexture = "special/shrikeBoltCross"; - flareBaseTexture = "special/shrikeBolt"; -}; - -datablock ItemData(EditTool) -{ +datablock ItemData(EditTool) { className = Weapon; catagory = "Spawn Items"; shapeFile = "weapon_disc.dts"; @@ -88,8 +45,7 @@ datablock ItemData(EditTool) pickUpName = "a Editing Tool"; }; -datablock ShapeBaseImageData(EditGunImage) -{ +datablock ShapeBaseImageData(EditGunImage) { className = WeaponImage; shapeFile = "weapon_disc.dts"; item = EditTool; @@ -98,9 +54,8 @@ datablock ShapeBaseImageData(EditGunImage) usesEnergy = true; minEnergy = 0.01; - projectile = EditorBolt; - projectileType = LinearFlareProjectile; - + //projectile = EditorBolt; + //projectileType = LinearFlareProjectile; stateName[0] = "Activate"; stateTransitionOnTimeout[0] = "ActivateReady"; @@ -145,6 +100,37 @@ datablock ShapeBaseImageData(EditGunImage) stateTransitionOnTimeout[6] = "Ready"; }; +//Phantom139: I'll take a datablock over a function any-day... +function EditGunImage::onFire(%data, %obj, %slot) { + //RAYCAST + %vector = %obj.getMuzzleVector(%slot); + %mp = %obj.getMuzzlePoint(%slot); + %targetpos = vectoradd(%mp,vectorscale(%vector, 2500)); + %targ = containerraycast(%mp, %targetpos, $typemasks::staticshapeobjecttype, %obj); + %targetObject = getword(%targ, 0); + if(%targetObject == 0) { + BottomPrint(%obj.client, "No Object Found", 2, 2); + return; + } + if (!Deployables.isMember(%targetObject)) { + messageclient(%obj.client, 'MsgClient', "\c2TextureTool: Error, Map Object Selected."); + return; + } + //APPLY EDITS + switch$(%obj.EditPMode) { + case 0: + EToolswaping(%targetObject, %obj, 0, %obj.EditSMode); + case 1: + EToolswaping(%targetObject, %obj, 1, %obj.EditSMode); + case 2: + EToolTurrets(%targetObject, %obj, %obj.EditSMode); + case 3: + EToolCloakandFade(%targetObject, %obj, %obj.EditSMode); + case 4: + EToolDeleting(%targetObject, %obj, %obj.EditSMode); + } +} + function EditGunImage::onMount(%this, %obj, %slot) { Parent::onMount(%this, %obj, %slot); DispEditorToolInfo(%obj); @@ -157,59 +143,58 @@ function EditGunImage::onMount(%this, %obj, %slot) { %obj.UsingEditTool = true; } -function EditGunImage::onunmount(%this,%obj,%slot) -{ -Parent::onUnmount(%this, %obj, %slot); -%obj.UsingEditTool = false; +function EditGunImage::onunmount(%this,%obj,%slot) { + Parent::onUnmount(%this, %obj, %slot); + %obj.UsingEditTool = false; } function DispEditorToolInfo(%obj) { -switch(%obj.EditPMode) { - case 0: - %primary = "Pad Swapping"; - switch(%obj.EditSMode) { - case 0: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Blue Pad - [LSB] - MSB", 5, 3); - case 1: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: LSB - [MSB] - Walkway", 5, 3); - case 2: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: MSB - [Walkway] - Medium Floor ", 5, 3); - case 3: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Walkway - [Medium Floor] - Dark Pad", 5, 3); - case 4: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Medium Floor - [Dark Pad] - V-Pad", 5, 3); - case 5: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Dark Pad - [V-Pad] - C.1 Backpack", 5, 3); - case 6: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: V-Pad - [C.1 Backpack] - C.2 Small Containment", 5, 3); - case 7: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.1 Backpack - [C.2 Small Containment] - C.3 Large Containment", 5, 3); - case 8: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.2 Small Containment - [C.3 Large Containment] - C.4 Compressor", 5, 3); - case 9: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.3 Large Containment - [C.4 Compressor] - C.5 Tubes", 5, 3); - case 10: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.4 Compressor - [C.5 Tubes] - C.6 Quantium Bat.", 5, 3); - case 11: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.5 Tubes - [C.6 Quantium Bat.] - C.7 Proton Acc.", 5, 3); - case 12: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.6 Quantium Bat. - [C.7 Proton Acc.] - C.8 Cargo Crate", 5, 3); - case 13: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.7 Proton Acc. - [C.8 Cargo Crate] - C.9 Mag Cooler", 5, 3); - case 14: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.8 Cargo Crate - [C.9 Mag Cooler] - C.10 Recycle Unit", 5, 3); - case 15: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.9 Mag Cooler - [C.10 Recycle Unit] - C.11 Fuel Canister", 5, 3); - case 16: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.10 Recycle Unit - [C.11 Fuel Canister] - C.12 Wooden Box", 5, 3); - case 17: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.11 Fuel Canister - [C.12 Wooden Box] - C.13 Plasma Router", 5, 3); - case 18: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.12 Wooden Box - [C.13 Plasma Router] - Statue Base", 5, 3); - case 19: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.13 Plasma Router - [Statue Base] - Blue Pad", 5, 3); - case 20: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Statue Base - [Blue Pad] - LSB", 5, 3); + switch(%obj.EditPMode) { + case 0: + %primary = "Pad Swapping"; + switch(%obj.EditSMode) { + case 0: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Blue Pad - [LSB] - MSB", 5, 3); + case 1: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: LSB - [MSB] - Walkway", 5, 3); + case 2: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: MSB - [Walkway] - Medium Floor ", 5, 3); + case 3: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Walkway - [Medium Floor] - Dark Pad", 5, 3); + case 4: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Medium Floor - [Dark Pad] - V-Pad", 5, 3); + case 5: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Dark Pad - [V-Pad] - C.1 Backpack", 5, 3); + case 6: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: V-Pad - [C.1 Backpack] - C.2 Small Containment", 5, 3); + case 7: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.1 Backpack - [C.2 Small Containment] - C.3 Large Containment", 5, 3); + case 8: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.2 Small Containment - [C.3 Large Containment] - C.4 Compressor", 5, 3); + case 9: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.3 Large Containment - [C.4 Compressor] - C.5 Tubes", 5, 3); + case 10: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.4 Compressor - [C.5 Tubes] - C.6 Quantium Bat.", 5, 3); + case 11: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.5 Tubes - [C.6 Quantium Bat.] - C.7 Proton Acc.", 5, 3); + case 12: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.6 Quantium Bat. - [C.7 Proton Acc.] - C.8 Cargo Crate", 5, 3); + case 13: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.7 Proton Acc. - [C.8 Cargo Crate] - C.9 Mag Cooler", 5, 3); + case 14: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.8 Cargo Crate - [C.9 Mag Cooler] - C.10 Recycle Unit", 5, 3); + case 15: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.9 Mag Cooler - [C.10 Recycle Unit] - C.11 Fuel Canister", 5, 3); + case 16: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.10 Recycle Unit - [C.11 Fuel Canister] - C.12 Wooden Box", 5, 3); + case 17: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.11 Fuel Canister - [C.12 Wooden Box] - C.13 Plasma Router", 5, 3); + case 18: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.12 Wooden Box - [C.13 Plasma Router] - Statue Base", 5, 3); + case 19: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.13 Plasma Router - [Statue Base] - Blue Pad", 5, 3); + case 20: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Statue Base - [Blue Pad] - LSB", 5, 3); } case 1: %primary = "Force-Field Swapping"; @@ -293,57 +278,44 @@ switch(%obj.EditPMode) { } function ChangeEditGunMode(%this, %data, %PriSec) { //This Is Easier To use -if(%PriSec == 1) { //Primary -if (!(getSimTime() > (%this.mineModeTime + 100))) -return; -%this.mineModeTime = getSimTime(); -%this.EditPMode++; -%this.EditSMode = 0; //Reset Secondary Mode TO Prevent Errors -if (%this.EditPMode > 4) { -%this.EditPMode = 0; -} -DispEditorToolInfo(%this); -return; -} -else { //Secondary -if (!(getSimTime() > (%this.grenadeModeTime + 100))) -return; -%this.grenadeModeTime = getSimTime(); -%this.EditSMode++; -//Check Primaries -if(%this.EditPMode == 0 && %this.EditSMode > 20) { -%this.EditSMode = 0; -} -else if(%this.EditPMode == 1 && %this.EditSMode > 20) { -%this.EditSMode = 0; -} -else if(%this.EditPMode == 2 && %this.EditSMode > 4) { -%this.EditSMode = 0; -} -else if(%this.EditPMode == 3 && %this.EditSMode > 3) { -%this.EditSMode = 0; -} -else if(%this.EditPMode == 4 && %this.EditSMode > 1) { -%this.EditSMode = 0; -} -DispEditorToolInfo(%this); -return; -} -} - -function EditorBolt::onCollision(%data,%projectile,%targetObject,%modifier,%position,%normal) { - switch$(%projectile.sourceObject.EditPMode) { - case 0: - EToolswaping(%targetObject,%projectile.sourceObject,0,%projectile.sourceObject.EditSMode); - case 1: - EToolswaping(%targetObject,%projectile.sourceObject,1,%projectile.sourceObject.EditSMode); - case 2: - EToolTurrets(%targetObject,%projectile.sourceObject,%projectile.sourceObject.EditSMode); - case 3: - EToolCloakandFade(%targetObject,%projectile.sourceObject,%projectile.sourceObject.EditSMode); - case 4: - EToolDeleting(%targetObject,%projectile.sourceObject,%projectile.sourceObject.EditSMode); + if(%PriSec == 1) { //Primary + if (!(getSimTime() > (%this.mineModeTime + 100))) { + return; } + %this.mineModeTime = getSimTime(); + %this.EditPMode++; + %this.EditSMode = 0; //Reset Secondary Mode TO Prevent Errors + if (%this.EditPMode > 4) { + %this.EditPMode = 0; + } + DispEditorToolInfo(%this); + return; + } + else { //Secondary + if (!(getSimTime() > (%this.grenadeModeTime + 100))) { + return; + } + %this.grenadeModeTime = getSimTime(); + %this.EditSMode++; + //Check Primaries + if(%this.EditPMode == 0 && %this.EditSMode > 20) { + %this.EditSMode = 0; + } + else if(%this.EditPMode == 1 && %this.EditSMode > 20) { + %this.EditSMode = 0; + } + else if(%this.EditPMode == 2 && %this.EditSMode > 4) { + %this.EditSMode = 0; + } + else if(%this.EditPMode == 3 && %this.EditSMode > 3) { + %this.EditSMode = 0; + } + else if(%this.EditPMode == 4 && %this.EditSMode > 1) { + %this.EditSMode = 0; + } + DispEditorToolInfo(%this); + return; + } } //Editor Tool Functioning @@ -351,42 +323,42 @@ function EditorBolt::onCollision(%data,%projectile,%targetObject,%modifier,%posi // // function EToolDeleting(%tobj,%plyr,%Mode) { - %cl=%plyr.client; - if ( %tobj.ownerGUID != %cl.guid){ - if (!%cl.isadmin && !%cl.issuperadmin){ - if (%tobj.ownerGUID !$=""){ - messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, You Do Not Own This Piece."); - return; - } - } + %cl = %plyr.client; + if ( %tobj.ownerGUID != %cl.guid) { + if (!%cl.isadmin && !%cl.issuperadmin){ + if (%tobj.ownerGUID !$=""){ + messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, You Do Not Own This Piece."); + return; + } + } } if (%tobj.squaresize !$="") { - messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Unknown Object Selected."); - return; + messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Unknown Object Selected."); + return; } if (!Deployables.isMember(%tobj)) { - messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Map Object Selected."); - return; + messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Map Object Selected."); + return; } switch(%Mode) { - case 0: - messageclient(%cl, 'MsgClient', "\c2TextureTool: Deleting Object."); - %tobj.getDataBlock().disassemble(%plyr, %tobj); //this found in constructionTool.cs - case 1: - messageclient(%cl, 'MsgClient', "\c2TextureTool: Cascade Deleting Object (All Conective Objects)."); - cascade(%tobj,true); + case 0: + messageclient(%cl, 'MsgClient', "\c2TextureTool: Deleting Object."); + %tobj.getDataBlock().disassemble(%plyr, %tobj); //this found in constructionTool.cs + case 1: + messageclient(%cl, 'MsgClient', "\c2TextureTool: Cascade Deleting Object (All Conective Objects)."); + cascade(%tobj,true); } } // function EToolCloakandFade(%tobj,%plyr,%Mode) { - %cl=%plyr.client; - if ( %tobj.ownerGUID != %cl.guid){ - if (!%cl.isadmin && !%cl.issuperadmin){ - if (%tobj.ownerGUID !$=""){ - messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, You Do Not Own This Piece."); - return; - } - } + %cl = %plyr.client; + if ( %tobj.ownerGUID != %cl.guid) { + if (!%cl.isadmin && !%cl.issuperadmin){ + if (%tobj.ownerGUID !$=""){ + messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, You Do Not Own This Piece."); + return; + } + } } if (%tobj.squaresize !$="") { messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Unknown Object Selected."); @@ -415,14 +387,14 @@ function EToolCloakandFade(%tobj,%plyr,%Mode) { } // function EToolTurrets(%tobj,%plyr,%Mode) { - %cl=%plyr.client; - if ( %tobj.ownerGUID != %cl.guid){ - if (!%cl.isadmin && !%cl.issuperadmin){ - if (%tobj.ownerGUID !$=""){ - messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, You Do Not Own This Piece."); - return; - } - } + %cl = %plyr.client; + if ( %tobj.ownerGUID != %cl.guid) { + if (!%cl.isadmin && !%cl.issuperadmin){ + if (%tobj.ownerGUID !$=""){ + messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, You Do Not Own This Piece."); + return; + } + } } if (%tobj.squaresize !$="") { messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Unknown Object Selected."); From fb31c7492613add03c5dd69610ab4146d19b70ef Mon Sep 17 00:00:00 2001 From: Robert Fritzen Date: Wed, 26 Feb 2014 15:05:04 -0600 Subject: [PATCH 04/16] News Panel Updated the News Panel to point to the thread on the current PGD Forums... --- scripts/TWM2/Systems/NewsPanel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/TWM2/Systems/NewsPanel.cs b/scripts/TWM2/Systems/NewsPanel.cs index 7c9eb62..4627202 100644 --- a/scripts/TWM2/Systems/NewsPanel.cs +++ b/scripts/TWM2/Systems/NewsPanel.cs @@ -1,10 +1,10 @@ function DownloadNewsPage() { $TWM::Ticks = 0; - %server = "www.public.phantomdev.net:80"; // + %server = "www.forums.phantomdev.net:80"; // if (!isObject(PageGrabber)) %Downloader = new HTTPObject(PageGrabber){}; else %Downloader = PageGrabber; - %filename = "/SMF/index.php/topic,422.0.html"; //File Location + %filename = "/viewtopic.php?f=11&t=416"; //File Location %Downloader.get(%server, %filename); } From 47f81b3f85699681cdd664b92fd3c82dcfc1b9e6 Mon Sep 17 00:00:00 2001 From: Robert Fritzen Date: Thu, 29 May 2014 10:06:32 -0500 Subject: [PATCH 05/16] Merge In Main Server The current version has many crashes for clients trying to connect to the server. Reverting back to 3.8 main server. --- scripts/TWM2/Bosses/ColonelWindshear.cs | 47 +- scripts/TWM2/Bosses/GeneralVegenor.cs | 159 ++++ scripts/TWM2/Bosses/GhostOfFire.cs | 411 ++++++++- scripts/TWM2/Bosses/GhostOfLightning.cs | 140 ++++ scripts/TWM2/Bosses/LordRog.cs | 242 ++++++ scripts/TWM2/Bosses/LordVardison.cs | 719 +++++++++++++++- scripts/TWM2/Bosses/LordYvex.cs | 611 +++++++++++++- scripts/TWM2/Bosses/LordraniusTrebor.cs | 32 + scripts/TWM2/Bosses/MajorInsignia.cs | 161 +++- scripts/TWM2/Bosses/ShadeLord.cs | 366 ++++++++ scripts/TWM2/Bosses/Stormrider.cs | 779 ++++++++++++------ .../TWM2/ExteriorFunctioning/PconFunctions.cs | 94 +++ scripts/TWM2/Missions/MissionCore.cs | 3 +- scripts/TWM2/Systems/AdvancedRankSystem.cs | 2 +- scripts/TWM2/Systems/BossSystem.cs | 4 +- scripts/TWM2/Systems/DChalg.cs | 5 +- scripts/TWM2/Systems/HarbingersWrath.cs | 2 +- scripts/TWM2/Systems/MainControl.cs | 5 +- scripts/TWM2/Systems/NewsPanel.cs | 4 +- scripts/weapons/Construction/EditGun.cs | 338 ++++---- scripts/weapons/Melee/BOV.cs | 102 +-- scripts/weapons/T2Guns/shockLance.cs | 141 ++++ serverControl.cs | 5 + 23 files changed, 3858 insertions(+), 514 deletions(-) diff --git a/scripts/TWM2/Bosses/ColonelWindshear.cs b/scripts/TWM2/Bosses/ColonelWindshear.cs index f3572ed..26719bc 100644 --- a/scripts/TWM2/Bosses/ColonelWindshear.cs +++ b/scripts/TWM2/Bosses/ColonelWindshear.cs @@ -109,6 +109,50 @@ function DroneFindNearestPilot(%radius, %drone) { return %closestClient; } + +datablock SeekerProjectileData(BossMissiles) +{ + casingShapeName = "weapon_missile_casement.dts"; + projectileShapeName = "weapon_missile_projectile.dts"; + hasDamageRadius = true; + indirectDamage = 0.1; + damageRadius = 6.0; + radiusDamageType = $DamageType::MissileTurret; + kickBackStrength = 500; + + flareDistance = 200; + flareAngle = 30; + minSeekHeat = 0.0; + + explosion = "MissileExplosion"; + velInheritFactor = 1.0; + + splash = MissileSplash; + baseEmitter = MortarSmokeEmitter; + delayEmitter = MissileFireEmitter; + puffEmitter = MissilePuffEmitter; + + lifetimeMS = 15000; // z0dd - ZOD, 4/14/02. Was 6000 + muzzleVelocity = 12.0; + maxVelocity = 225.0; // z0dd - ZOD, 4/14/02. Was 80.0 + turningSpeed = 50.0; + acceleration = 100.0; + + proximityRadius = 4; + + terrainAvoidanceSpeed = 100; + terrainScanAhead = 50; + terrainHeightFail = 50; + terrainAvoidanceRadius = 150; + + useFlechette = true; + flechetteDelayMs = 225; + casingDeb = FlechetteDebris; +}; + + + + function WindshearAttacks(%drone) { if(!isObject(%drone)) { return; @@ -216,7 +260,6 @@ function WindshearAttack_FUNC(%att, %args) { FlareSet.add(%p2); MissionCleanup.add(%p1); MissionCleanup.add(%p2); - case "HeatLoop": %t = getWord(%args, 0); %v = getWord(%args, 1); @@ -230,7 +273,6 @@ function WindshearAttack_FUNC(%att, %args) { %v++; %t.setHeat(100); schedule(100, 0, "WindshearAttack_FUNC", "HeatLoop", %t SPC %v); - case "MissileDrop": %t = getWord(%args, 0); %m = getWord(%args, 1); @@ -239,7 +281,6 @@ function WindshearAttack_FUNC(%att, %args) { %m.setObjectTarget(%t); //HeatLoop(%t,0); WindshearAttack_FUNC("HeatLoop", %t SPC 0); - case "SidewinderLaunch": %d = getWord(%args, 0); %t = getWord(%args, 1); diff --git a/scripts/TWM2/Bosses/GeneralVegenor.cs b/scripts/TWM2/Bosses/GeneralVegenor.cs index c41ed39..fc29bb4 100644 --- a/scripts/TWM2/Bosses/GeneralVegenor.cs +++ b/scripts/TWM2/Bosses/GeneralVegenor.cs @@ -1,3 +1,162 @@ +datablock SeekerProjectileData(VegenorFireMissile) : YvexZombieMakerMissile { + indirectDamage = 0.5; + damageRadius = 5.0; + radiusDamageType = $DamageType::Fire; +}; + +datablock GrenadeProjectileData(VegenorFireMeteor) : JTLMeteorStormFireball { + projectileShapeName = "plasmabolt.dts"; + scale = "40.0 40.0 40.0"; + emitterDelay = -1; + directDamage = 0; + directDamageType = $DamageType::Fire; + hasDamageRadius = true; // true; + indirectDamage = 0.5; // 0.5; + damageRadius = 150.0; + radiusDamageType = $DamageType::Fire; +}; + +datablock PlayerData(VegenorZombieArmor) : HeavyMaleBiodermArmor { + maxDamage = 600.0; + minImpactSpeed = 50; + speedDamageScale = 0.015; + + damageScale[$DamageType::M1700] = 2.0; + damageScale[$DamageType::Fire] = 0.1; + damageScale[$DamageType::Burn] = 0.1; + damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs + + max[RepairKit] = 0; + max[Mine] = 0; + max[Grenade] = 0; + max[SmokeGrenade] = 0; + max[BeaconSmokeGrenade] = 0; + max[Blaster] = 0; + max[Plasma] = 0; + max[PlasmaAmmo] = 0; + max[Disc] = 0; + max[DiscAmmo] = 0; + max[SniperRifle] = 0; + max[GrenadeLauncher] = 0; + max[GrenadeLauncherAmmo] = 0; + max[Mortar] = 0; + max[MortarAmmo] = 0; + max[MissileLauncher] = 0; + max[MissileLauncherAmmo] = 0; + max[Chaingun] = 0; + max[ChaingunAmmo] = 0; + max[RepairGun] = 0; + max[CloakingPack] = 0; + max[SensorJammerPack] = 0; + max[EnergyPack] = 0; + max[RepairPack] = 0; + max[ShieldPack] = 0; + max[AmmoPack] = 0; + max[SatchelCharge] = 0; + max[MortarBarrelPack] = 0; + max[MissileBarrelPack] = 0; + max[AABarrelPack] = 0; + max[PlasmaBarrelPack] = 0; + max[ELFBarrelPack] = 0; + max[artillerybarrelpack] = 0; + max[InventoryDeployable] = 0; + max[MotionSensorDeployable] = 0; + max[PulseSensorDeployable] = 0; + max[TurretOutdoorDeployable] = 0; + max[TurretIndoorDeployable] = 0; + max[FlashGrenade] = 0; + max[ConcussionGrenade] = 0; + max[FlareGrenade] = 0; + max[TargetingLaser] = 0; + max[ELFGun] = 0; + max[ShockLance] = 0; + max[CameraGrenade] = 0; + max[Beacon] = 0; + max[flamerAmmoPack] = 0; + max[ParachutePack] = 0; + max[MedPack] = 0; + //Guns + max[ConstructionTool] = 0; + max[MergeTool] = 0; + max[NerfGun] = 0; + max[NerfBallLauncher] = 0; + max[NerfBallLauncherAmmo] = 0; + max[SuperChaingun] = 0; + max[SuperChaingunAmmo] = 0; + max[RPChaingun] = 0; + max[RPChaingunAmmo] = 0; + max[MGClip] = 0; + max[LSMG] = 0; + max[LSMGAmmo] = 0; + max[LSMGClip] = 0; + max[snipergun] = 0; + max[snipergunAmmo] = 0; + max[Bazooka] = 0; + max[BazookaAmmo] = 0; + max[nukeme] = 0; + max[nukemeAmmo] = 0; + max[MG42] = 0; + max[MG42Ammo] = 0; + max[SPistol] = 0; + max[Pistol] = 0; + max[PistolAmmo] = 0; + max[Pistolclip] = 0; + max[flamer] = 0; + max[flamerAmmo] = 0; + max[AALauncher] = 0; + max[AALauncherAmmo] = 0; + max[melee] = 0; + max[SOmelee] = 0; + max[KriegRifle] = 0; + max[KriegAmmo] = 0; + max[Rifleclip] = 0; + max[Shotgun] = 0; + max[ShotgunAmmo] = 0; + max[ShotgunClip] = 0; + max[RShotgun] = 0; + max[RShotgunAmmo] = 0; + max[RShotgunClip] = 0; + max[LMissileLauncher] = 0; + max[LMissileLauncherAmmo] = 0; + max[HRPChaingun] = 0; + max[RPGAmmo] = 0; + max[RPGItem] = 0; + //Building parts + max[spineDeployable] = 0; + max[mspineDeployable] = 0; + max[wWallDeployable] = 0; + max[floorDeployable] = 0; + max[WallDeployable] = 0; + max[DoorDeployable] = 0; + //Turrets + max[TurretLaserDeployable] = 0; + max[TurretMissileRackDeployable]= 0; + max[DiscTurretDeployable] = 0; + //Largepacks + max[EnergizerDeployable] = 0; + max[TreeDeployable] = 0; + max[CrateDeployable] = 0; + max[DecorationDeployable] = 0; + max[LogoProjectorDeployable] = 0; + max[LightDeployable] = 0; + max[TripwireDeployable] = 0; + max[TelePadPack] = 0; + max[TurretBasePack] = 0; + max[LargeInventoryDeployable] = 0; + max[GeneratorDeployable] = 0; + max[SolarPanelDeployable] = 0; + max[SwitchDeployable] = 0; + max[MediumSensorDeployable] = 0; + max[LargeSensorDeployable] = 0; + max[SpySatelliteDeployable] = 0; + //Misc + max[JumpadDeployable] = 0; + max[EscapePodDeployable] = 0; + max[ForceFieldDeployable] = 0; + max[GravityFieldDeployable] = 0; + max[VehiclePadPack] = 0; +}; + function SpawnVegenor(%position) { %Zombie = new player(){ Datablock = "VegenorZombieArmor"; diff --git a/scripts/TWM2/Bosses/GhostOfFire.cs b/scripts/TWM2/Bosses/GhostOfFire.cs index 30477df..73a5fae 100644 --- a/scripts/TWM2/Bosses/GhostOfFire.cs +++ b/scripts/TWM2/Bosses/GhostOfFire.cs @@ -1,6 +1,411 @@ -//Ghost of Fire -//Phantom139 -//Ported From TWM1 +//DBs +datablock ParticleData(GhostflameParticle) +{ + dragCoeffiecient = 0.0; + gravityCoefficient = -0.1; + inheritedVelFactor = 0.1; + + lifetimeMS = 500; + lifetimeVarianceMS = 50; + + textureName = "particleTest"; + + spinRandomMin = -10.0; + spinRandomMax = 10.0; + + colors[0] = "0 1 0 0.4"; + colors[1] = "0 1 0 0.3"; + colors[2] = "0 1 0 0.0"; + sizes[0] = 2.0; + sizes[1] = 1.0; + sizes[2] = 0.8; + times[0] = 0.0; + times[1] = 0.6; + times[2] = 1.0; +}; + +datablock ParticleEmitterData(GhostflameEmitter) +{ + ejectionPeriodMS = 3; + periodVarianceMS = 0; + + ejectionOffset = 0.2; + ejectionVelocity = 10.0; + velocityVariance = 0.0; + + thetaMin = 0.0; + thetaMax = 10.0; + + particles = "GhostflameParticle"; +}; + +datablock LinearFlareProjectileData(GhostFlameboltMain) +{ + projectileShapeName = "turret_muzzlepoint.dts"; + scale = "1.0 1.0 1.0"; + faceViewer = true; + directDamage = 0.05; + hasDamageRadius = true; + indirectDamage = 0.1; + damageRadius = 4.0; + kickBackStrength = 0.0; + radiusDamageType = $DamageType::Plasma; + + explosion = "ThrowerExplosion"; + splash = PlasmaSplash; + + baseEmitter = GhostflameEmitter; + + dryVelocity = 50.0; // z0dd - ZOD, 7/20/02. Faster plasma projectile. was 55 + wetVelocity = -1; + velInheritFactor = 0.3; + fizzleTimeMS = 250; + lifetimeMS = 30000; + explodeOnDeath = false; + reflectOnWaterImpactAngle = 0.0; + explodeOnWaterImpact = true; + deflectionOnWaterImpact = 0.0; + fizzleUnderwaterMS = -1; + + //activateDelayMS = 100; + activateDelayMS = -1; + + size[0] = 0.2; + size[1] = 0.5; + size[2] = 0.1; + + + numFlares = 35; + flareColor = "1 0.18 0.03"; + flareModTexture = "flaremod"; + flareBaseTexture = "flarebase"; + + sound = PlasmaProjectileSound; + fireSound = FlamethrowerFireSound; + wetFireSound = PlasmaFireWetSound; + + hasLight = true; + lightRadius = 10.0; + lightColor = "0.94 0.03 0.12"; +}; + +datablock ParticleData(NapalmExplosionParticle) +{ + dragCoefficient = 2; + gravityCoefficient = 0.2; + inheritedVelFactor = 0.2; + constantAcceleration = 0.0; + lifetimeMS = 450; + lifetimeVarianceMS = 150; + textureName = "particleTest"; + colors[0] = "1 0 0"; + colors[1] = "1 0 0"; + sizes[0] = 0.5; + sizes[1] = 2; +}; + +datablock ParticleEmitterData(NapalmExplosionEmitter) +{ + ejectionPeriodMS = 7; + periodVarianceMS = 0; + ejectionVelocity = 5; + velocityVariance = 1.0; + ejectionOffset = 0.0; + thetaMin = 0; + thetaMax = 60; + phiReferenceVel = 0; + phiVariance = 360; + overrideAdvances = false; + particles = "NapalmExplosionParticle"; +}; + +datablock ExplosionData(NapalmExplosion) +{ + explosionShape = "effect_plasma_explosion.dts"; + soundProfile = plasmaExpSound; + particleEmitter = NapalmExplosionEmitter; + particleDensity = 150; + particleRadius = 1.25; + faceViewer = true; + + sizes[0] = "3.0 3.0 3.0"; + sizes[1] = "3.0 3.0 3.0"; + times[0] = 0.0; + times[1] = 1.5; +}; + +//-------------------------------------- +//Napalm projectile +//-------------------------------------- +datablock LinearProjectileData(NapalmShot) +{ + projectileShapeName = "mortar_projectile.dts"; + emitterDelay = -1; + directDamage = 0.0; + hasDamageRadius = true; + indirectDamage = 0.5; + damageRadius = 20.0; + radiusDamageType = $DamageType::Plasma; + kickBackStrength = 3000; + + explosion = "NapalmExplosion"; +// underwaterExplosion = "UnderwaterNapalmExplosion"; + velInheritFactor = 0.5; +// splash = NapalmSplash; + depthTolerance = 10.0; // depth at which it uses underwater explosion + + baseEmitter = MissileFireEmitter; + bubbleEmitter = GrenadeBubbleEmitter; + + grenadeElasticity = 0.15; + grenadeFriction = 0.4; + armingDelayMS = 2000; + muzzleVelocity = 63.7; + drag = 0.1; + + sound = MortarProjectileSound; + + hasLight = true; + lightRadius = 4; + lightColor = "1.00 0.9 1.00"; + + hasLightUnderwaterColor = true; + underWaterLightColor = "0.05 0.075 0.2"; + + dryVelocity = 90; + wetVelocity = 50; + velInheritFactor = 0.5; + fizzleTimeMS = 5000; + lifetimeMS = 2700; + explodeOnDeath = true; + reflectOnWaterImpactAngle = 15.0; + explodeOnWaterImpact = true; + deflectionOnWaterImpact = 0.0; + fizzleUnderwaterMS = 5000; + +}; + +datablock PlayerData(GhostFireArmor) : MediumPlayerDamageProfile +{ + emap = true; + + className = Armor; + shapeFile = "medium_male.dts"; + cameraMaxDist = 3; + computeCRC = true; + + debrisShapeName = "debris_player.dts"; + debris = HumanRedPlayerDebris; + + canObserve = true; + cmdCategory = "Clients"; + cmdIcon = CMDPlayerIcon; + cmdMiniIconName = "commander/MiniIcons/com_player_grey"; + + hudImageNameFriendly[0] = "gui/hud_playertriangle"; + hudImageNameEnemy[0] = "gui/hud_playertriangle_enemy"; + hudRenderModulated[0] = true; + + hudImageNameFriendly[1] = "commander/MiniIcons/com_flag_grey"; + hudImageNameEnemy[1] = "commander/MiniIcons/com_flag_grey"; + hudRenderModulated[1] = true; + hudRenderAlways[1] = true; + hudRenderCenter[1] = true; + hudRenderDistance[1] = true; + + hudImageNameFriendly[2] = "commander/MiniIcons/com_flag_grey"; + hudImageNameEnemy[2] = "commander/MiniIcons/com_flag_grey"; + hudRenderModulated[2] = true; + hudRenderAlways[2] = true; + hudRenderCenter[2] = true; + hudRenderDistance[2] = true; + + aiAvoidThis = true; + + minLookAngle = -1.5; + maxLookAngle = 1.5; + maxFreelookAngle = 3.0; + + mass = 70; + drag = 0.3; + maxdrag = 0.5; + density = 10; + maxDamage = 500.0; + maxEnergy = 400; + repairRate = 0.0053; + energyPerDamagePoint = 75.0; // shield energy required to block one point of damage + + rechargeRate = 0.456; + jetForce = 21.22 * 230; + underwaterJetForce = 25.22 * 130 * 1.5; + underwaterVertJetFactor = 1.5; + jetEnergyDrain = 4.0; + underwaterJetEnergyDrain = 1.0; + minJetEnergy = 10; + maxJetHorizontalPercentage = 0.8; + + runForce = 60 * 150; + runEnergyDrain = 0; + minRunEnergy = 0; + maxForwardSpeed = 18; + maxBackwardSpeed = 18; + maxSideSpeed = 18; + + maxUnderwaterForwardSpeed = 10.5; + maxUnderwaterBackwardSpeed = 9.5; + maxUnderwaterSideSpeed = 9.5; + + recoverDelay = 4; + recoverRunForceScale = 0.7; + + // heat inc'ers and dec'ers + heatDecayPerSec = 1.0 / 5.0; // takes 4 seconds to clear heat sig. + heatIncreasePerSec = 1.0 / 2.0; // takes 3.0 seconds of constant jet to get full heat sig. + + jumpForce = 8.3 * 130; + jumpEnergyDrain = 0; + minJumpEnergy = 0; + jumpSurfaceAngle = 75; + jumpDelay = 0; + + // Controls over slope of runnable/jumpable surfaces + runSurfaceAngle = 85; + jumpSurfaceAngle = 85; + + minJumpSpeed = 25; + maxJumpSpeed = 35; + + horizMaxSpeed = 70; + horizResistSpeed = 28; + horizResistFactor = 0.32; + maxJetForwardSpeed = 18; + + upMaxSpeed = 80; + upResistSpeed = 30; + upResistFactor = 0.23; + + minImpactSpeed = 45; + speedDamageScale = 0.006; + + jetSound = ArmorJetSound; + wetJetSound = ArmorWetJetSound; + + jetEmitter = FlammerArmorJetEmitter; //Pyro jets + jetEffect = HumanMediumArmorJetEffect; + + boundingBox = "1.45 1.45 2.4"; + pickupRadius = 0.75; + + // damage location details + boxNormalHeadPercentage = 0.83; + boxNormalTorsoPercentage = 0.49; + boxHeadLeftPercentage = 0; + boxHeadRightPercentage = 1; + boxHeadBackPercentage = 0; + boxHeadFrontPercentage = 1; + + //Foot Prints + decalData = MediumMaleFootprint; + decalOffset = 0.35; + + footPuffEmitter = LightPuffEmitter; + footPuffNumParts = 15; + footPuffRadius = 0.25; + + dustEmitter = LiftoffDustEmitter; + + splash = PlayerSplash; + splashVelocity = 4.0; + splashAngle = 67.0; + splashFreqMod = 300.0; + splashVelEpsilon = 0.60; + bubbleEmitTime = 0.4; + splashEmitter[0] = PlayerFoamDropletsEmitter; + splashEmitter[1] = PlayerFoamEmitter; + splashEmitter[2] = PlayerBubbleEmitter; + mediumSplashSoundVelocity = 10.0; + hardSplashSoundVelocity = 20.0; + exitSplashSoundVelocity = 5.0; + + footstepSplashHeight = 0.35; + //Footstep Sounds + LFootSoftSound = LFootMediumSoftSound; + RFootSoftSound = RFootMediumSoftSound; + LFootHardSound = LFootMediumHardSound; + RFootHardSound = RFootMediumHardSound; + LFootMetalSound = LFootMediumMetalSound; + RFootMetalSound = RFootMediumMetalSound; + LFootSnowSound = LFootMediumSnowSound; + RFootSnowSound = RFootMediumSnowSound; + LFootShallowSound = LFootMediumShallowSplashSound; + RFootShallowSound = RFootMediumShallowSplashSound; + LFootWadingSound = LFootMediumWadingSound; + RFootWadingSound = RFootMediumWadingSound; + LFootUnderwaterSound = LFootMediumUnderwaterSound; + RFootUnderwaterSound = RFootMediumUnderwaterSound; + LFootBubblesSound = LFootMediumBubblesSound; + RFootBubblesSound = RFootMediumBubblesSound; + movingBubblesSound = ArmorMoveBubblesSound; + waterBreathSound = WaterBreathMaleSound; + + impactSoftSound = ImpactMediumSoftSound; + impactHardSound = ImpactMediumHardSound; + impactMetalSound = ImpactMediumMetalSound; + impactSnowSound = ImpactMediumSnowSound; + + skiSoftSound = SkiAllSoftSound; + skiHardSound = SkiAllHardSound; + skiMetalSound = SkiAllMetalSound; + skiSnowSound = SkiAllSnowSound; + + impactWaterEasy = ImpactMediumWaterEasySound; + impactWaterMedium = ImpactMediumWaterMediumSound; + impactWaterHard = ImpactMediumWaterHardSound; + + groundImpactMinSpeed = 10.0; + groundImpactShakeFreq = "4.0 4.0 4.0"; + groundImpactShakeAmp = "1.0 1.0 1.0"; + groundImpactShakeDuration = 0.8; + groundImpactShakeFalloff = 10.0; + + exitingWater = ExitingWaterMediumSound; + + maxWeapons = 2; // Max number of different weapons the player can have + maxGrenades = 1; // Max number of different grenades the player can have + maxMines = 1; // Max number of different mines the player can have + + damageScale[$DamageType::plasma] = 0.05; + damageScale[$DamageType::Burn] = 0.05; + damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs + + // Inventory restrictions + max[RepairKit] = 4; + max[Mine] = 0; + max[ZapMine] = 0; + max[CrispMine] = 5; + max[flamerAmmoPack] = 1; + max[Deagle] = 1; + max[SPistol] = 1; + max[Pistol] = 1; + max[PistolAmmo] = 10; + max[Pistolclip] = 8; + max[PulsePhaser] = 1; + max[flamer] = 1; + max[flamerAmmo] = 0; + max[Napalm] = 1; + max[NapalmAmmo] = 20; + max[melee] = 1; + max[BOV] = 1; + max[SOmelee] = 1; + max[IncindinaryGrenade] = 7; + max[Beacon] = 3; + // -END + + observeParameters = "0.5 4.5 4.5"; + + shieldEffectScale = "0.7 0.7 1.0"; +}; +// function StartGhostFire(%pos) { %Ghost = new player(){ diff --git a/scripts/TWM2/Bosses/GhostOfLightning.cs b/scripts/TWM2/Bosses/GhostOfLightning.cs index 37d1008..1c8eea4 100644 --- a/scripts/TWM2/Bosses/GhostOfLightning.cs +++ b/scripts/TWM2/Bosses/GhostOfLightning.cs @@ -1,5 +1,145 @@ //DBS +datablock PlayerData(LightningGhostArmor) : MediumMaleHumanArmor /// ooooo scary +{ + boundingBox = "1.63 1.63 2.6"; + maxDamage = 550.0; + minImpactSpeed = 35; + shapeFile = "medium_male.dts"; + debrisShapeName = "bio_player_debris.dts"; + + //Foot Prints + decalData = HeavyBiodermFootprint; + decalOffset = 0.4; + + waterBreathSound = WaterBreathBiodermSound; + + damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs + + max[RepairKit] = 0; + max[Mine] = 0; + max[Grenade] = 0; + max[SmokeGrenade] = 0; + max[BeaconSmokeGrenade] = 0; + max[Blaster] = 0; + max[Plasma] = 0; + max[PlasmaAmmo] = 0; + max[Disc] = 0; + max[DiscAmmo] = 0; + max[SniperRifle] = 0; + max[GrenadeLauncher] = 0; + max[GrenadeLauncherAmmo] = 0; + max[Mortar] = 0; + max[MortarAmmo] = 0; + max[MissileLauncher] = 0; + max[MissileLauncherAmmo] = 0; + max[Chaingun] = 0; + max[ChaingunAmmo] = 0; + max[RepairGun] = 0; + max[CloakingPack] = 0; + max[SensorJammerPack] = 0; + max[EnergyPack] = 0; + max[RepairPack] = 0; + max[ShieldPack] = 0; + max[AmmoPack] = 0; + max[SatchelCharge] = 0; + max[MortarBarrelPack] = 0; + max[MissileBarrelPack] = 0; + max[AABarrelPack] = 0; + max[PlasmaBarrelPack] = 0; + max[ELFBarrelPack] = 0; + max[artillerybarrelpack] = 0; + max[MedPack] = 0; + max[InventoryDeployable] = 0; + max[MotionSensorDeployable] = 0; + max[PulseSensorDeployable] = 0; + max[TurretOutdoorDeployable] = 0; + max[TurretIndoorDeployable] = 0; + max[FlashGrenade] = 0; + max[ConcussionGrenade] = 0; + max[FlareGrenade] = 0; + max[TargetingLaser] = 0; + max[ELFGun] = 0; + max[ShockLance] = 0; + max[CameraGrenade] = 0; + max[Beacon] = 0; + max[flamerAmmoPack] = 0; + max[ParachutePack] = 0; + max[ConstructionTool] = 0; + max[MergeTool] = 0; + max[NerfGun] = 0; + max[NerfBallLauncher] = 0; + max[NerfBallLauncherAmmo] = 0; + max[SuperChaingun] = 0; + max[SuperChaingunAmmo] = 0; + max[RPChaingun] = 0; + max[RPChaingunAmmo] = 0; + max[MGClip] = 0; + max[LSMG] = 0; + max[LSMGAmmo] = 0; + max[LSMGClip] = 0; + max[snipergun] = 0; + max[snipergunAmmo] = 0; + max[Bazooka] = 0; + max[BazookaAmmo] = 0; + max[BunkerBuster] = 0; + max[MG42] = 0; + max[MG42Ammo] = 0; + max[SPistol] = 0; + max[Pistol] = 0; + max[PistolAmmo] = 0; + max[Pistolclip] = 0; + max[flamer] = 0; + max[flamerAmmo] = 0; + max[AALauncher] = 0; + max[AALauncherAmmo] = 0; + max[melee] = 0; + max[SOmelee] = 0; + max[KriegRifle] = 0; + max[KriegAmmo] = 0; + max[Rifleclip] = 0; + max[Shotgun] = 0; + max[ShotgunAmmo] = 0; + max[ShotgunClip] = 0; + max[RShotgun] = 0; + max[RShotgunAmmo] = 0; + max[RShotgunClip] = 0; + max[LMissileLauncher] = 0; + max[LMissileLauncherAmmo] = 0; + max[HRPChaingun] = 0; + max[RPGAmmo] = 0; + max[RPGItem] = 0; + max[spineDeployable] = 0; + max[mspineDeployable] = 0; + max[wWallDeployable] = 0; + max[floorDeployable] = 0; + max[WallDeployable] = 0; + max[DoorDeployable] = 0; + max[TurretLaserDeployable] = 0; + max[TurretMissileRackDeployable]= 0; + max[DiscTurretDeployable] = 0; + max[EnergizerDeployable] = 0; + max[TreeDeployable] = 0; + max[CrateDeployable] = 0; + max[DecorationDeployable] = 0; + max[LogoProjectorDeployable] = 0; + max[LightDeployable] = 0; + max[TripwireDeployable] = 0; + max[TelePadPack] = 0; + max[TurretBasePack] = 0; + max[LargeInventoryDeployable] = 0; + max[GeneratorDeployable] = 0; + max[SolarPanelDeployable] = 0; + max[SwitchDeployable] = 0; + max[MediumSensorDeployable] = 0; + max[LargeSensorDeployable] = 0; + max[SpySatelliteDeployable] = 0; + max[JumpadDeployable] = 0; + max[EscapePodDeployable] = 0; + max[ForceFieldDeployable] = 0; + max[GravityFieldDeployable] = 0; + max[VehiclePadPack] = 0; +}; //CREATION diff --git a/scripts/TWM2/Bosses/LordRog.cs b/scripts/TWM2/Bosses/LordRog.cs index a1ad5e7..3c10036 100644 --- a/scripts/TWM2/Bosses/LordRog.cs +++ b/scripts/TWM2/Bosses/LordRog.cs @@ -1,3 +1,245 @@ +datablock ParticleData(PBCParticle) { + dragCoefficient = 0.5; + WindCoefficient = 0; + gravityCoefficient = 0.0; + inheritedVelFactor = 1; + constantAcceleration = 0; + lifetimeMS = 3000; + lifetimeVarianceMS = 0; + textureName = "special/lightning1frame2"; + useInvAlpha = 0; + + spinRandomMin = -800; + spinRandomMax = 800; + + spinspeed = 50; + colors[0] = "0.1 1.0 0.1 1.0"; + colors[1] = "0.6 0.9 0.6 1.0"; + colors[2] = "0.8 0.8 1.0 1.0"; + colors[3] = "0.8 0.8 1.0 0.0"; + sizes[0] = 0.5; + sizes[1] = 1; + sizes[2] = 1.5; + sizes[3] = 1.5; + times[0] = 0.0; + times[1] = 0.1; + times[2] = 0.3; + times[3] = 1.0; +}; + +datablock ParticleEmitterData(PBCExpEmitter) { + ejectionPeriodMS = 2; + periodVarianceMS = 0; + + ejectionVelocity = 2.5; + velocityVariance = 2.5; + + thetaMin = 0.0; + thetaMax = 180.0; + + lifetimeMS = 200; + + particles = "PBCParticle"; +}; + +datablock SeekerProjectileData(LordRogStiloutte) { + casingShapeName = "weapon_missile_casement.dts"; + projectileShapeName = "weapon_missile_projectile.dts"; + hasDamageRadius = true; + indirectDamage = 0.5; + damageRadius = 5.0; + radiusDamageType = $DamageType::Zombie; + kickBackStrength = 2000; + + explosion = "MissileExplosion"; + splash = MissileSplash; + velInheritFactor = 1.0; // to compensate for slow starting velocity, this value + // is cranked up to full so the missile doesn't start + // out behind the player when the player is moving + // very quickly - bramage + + baseEmitter = MortarSmokeEmitter; + delayEmitter = MissileFireEmitter; + puffEmitter = MissilePuffEmitter; + bubbleEmitter = GrenadeBubbleEmitter; + bubbleEmitTime = 1.0; + + exhaustEmitter = MissileLauncherExhaustEmitter; + exhaustTimeMs = 300; + exhaustNodeName = "muzzlePoint1"; + + lifetimeMS = 20000; // z0dd - ZOD, 4/14/02. Was 6000 + muzzleVelocity = 10.0; + maxVelocity = 80.0; // z0dd - ZOD, 4/14/02. Was 80.0 + turningSpeed = 23.0; + acceleration = 15.0; + + proximityRadius = 2.5; + + terrainAvoidanceSpeed = 10; + terrainScanAhead = 7; + terrainHeightFail = 1; + terrainAvoidanceRadius = 3; + + flareDistance = 40; + flareAngle = 20; + minSeekHeat = 0.0; + + sound = MissileProjectileSound; + + hasLight = true; + lightRadius = 5.0; + lightColor = "0.2 0.05 0"; + + useFlechette = true; + flechetteDelayMs = 250; + casingDeb = FlechetteDebris; + + explodeOnWaterImpact = false; +}; + +datablock PlayerData(LordRogZombieArmor) : LightMaleHumanArmor { + boundingBox = "1.63 1.63 2.6"; + maxDamage = 650.0; + minImpactSpeed = 35; + shapeFile = "bioderm_heavy.dts"; + + debrisShapeName = "bio_player_debris.dts"; + + //Foot Prints + decalData = HeavyBiodermFootprint; + decalOffset = 0.4; + + damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs + + waterBreathSound = WaterBreathBiodermSound; + + max[RepairKit] = 0; + max[Mine] = 0; + max[Grenade] = 0; + max[SmokeGrenade] = 0; + max[BeaconSmokeGrenade] = 0; + max[Blaster] = 0; + max[Plasma] = 0; + max[PlasmaAmmo] = 0; + max[Disc] = 0; + max[DiscAmmo] = 0; + max[SniperRifle] = 0; + max[GrenadeLauncher] = 0; + max[GrenadeLauncherAmmo] = 0; + max[Mortar] = 0; + max[MortarAmmo] = 0; + max[MissileLauncher] = 0; + max[MissileLauncherAmmo] = 0; + max[Chaingun] = 0; + max[ChaingunAmmo] = 0; + max[RepairGun] = 0; + max[CloakingPack] = 0; + max[SensorJammerPack] = 0; + max[EnergyPack] = 0; + max[RepairPack] = 0; + max[ShieldPack] = 0; + max[AmmoPack] = 0; + max[SatchelCharge] = 0; + max[MortarBarrelPack] = 0; + max[MissileBarrelPack] = 0; + max[AABarrelPack] = 0; + max[PlasmaBarrelPack] = 0; + max[ELFBarrelPack] = 0; + max[artillerybarrelpack] = 0; + max[MedPack] = 0; + max[InventoryDeployable] = 0; + max[MotionSensorDeployable] = 0; + max[PulseSensorDeployable] = 0; + max[TurretOutdoorDeployable] = 0; + max[TurretIndoorDeployable] = 0; + max[FlashGrenade] = 0; + max[ConcussionGrenade] = 0; + max[FlareGrenade] = 0; + max[TargetingLaser] = 0; + max[ELFGun] = 0; + max[ShockLance] = 0; + max[CameraGrenade] = 0; + max[Beacon] = 0; + max[flamerAmmoPack] = 0; + max[ParachutePack] = 0; + max[ConstructionTool] = 0; + max[MergeTool] = 0; + max[NerfGun] = 0; + max[NerfBallLauncher] = 0; + max[NerfBallLauncherAmmo] = 0; + max[SuperChaingun] = 0; + max[SuperChaingunAmmo] = 0; + max[RPChaingun] = 0; + max[RPChaingunAmmo] = 0; + max[MGClip] = 0; + max[LSMG] = 0; + max[LSMGAmmo] = 0; + max[LSMGClip] = 0; + max[snipergun] = 0; + max[snipergunAmmo] = 0; + max[Bazooka] = 0; + max[BazookaAmmo] = 0; + max[BunkerBuster] = 0; + max[MG42] = 0; + max[MG42Ammo] = 0; + max[SPistol] = 0; + max[Pistol] = 0; + max[PistolAmmo] = 0; + max[Pistolclip] = 0; + max[flamer] = 0; + max[flamerAmmo] = 0; + max[AALauncher] = 0; + max[AALauncherAmmo] = 0; + max[melee] = 0; + max[SOmelee] = 0; + max[KriegRifle] = 0; + max[KriegAmmo] = 0; + max[Rifleclip] = 0; + max[Shotgun] = 0; + max[ShotgunAmmo] = 0; + max[ShotgunClip] = 0; + max[RShotgun] = 0; + max[RShotgunAmmo] = 0; + max[RShotgunClip] = 0; + max[LMissileLauncher] = 0; + max[LMissileLauncherAmmo] = 0; + max[HRPChaingun] = 0; + max[RPGAmmo] = 0; + max[RPGItem] = 0; + max[spineDeployable] = 0; + max[mspineDeployable] = 0; + max[wWallDeployable] = 0; + max[floorDeployable] = 0; + max[WallDeployable] = 0; + max[DoorDeployable] = 0; + max[TurretLaserDeployable] = 0; + max[TurretMissileRackDeployable]= 0; + max[DiscTurretDeployable] = 0; + max[EnergizerDeployable] = 0; + max[TreeDeployable] = 0; + max[CrateDeployable] = 0; + max[DecorationDeployable] = 0; + max[LogoProjectorDeployable] = 0; + max[LightDeployable] = 0; + max[TripwireDeployable] = 0; + max[TelePadPack] = 0; + max[TurretBasePack] = 0; + max[LargeInventoryDeployable] = 0; + max[GeneratorDeployable] = 0; + max[SolarPanelDeployable] = 0; + max[SwitchDeployable] = 0; + max[MediumSensorDeployable] = 0; + max[LargeSensorDeployable] = 0; + max[SpySatelliteDeployable] = 0; + max[JumpadDeployable] = 0; + max[EscapePodDeployable] = 0; + max[ForceFieldDeployable] = 0; + max[GravityFieldDeployable] = 0; + max[VehiclePadPack] = 0; +}; + + function SpawnLordRog(%position) { %Zombie = new player(){ Datablock = "LordRogZombieArmor"; diff --git a/scripts/TWM2/Bosses/LordVardison.cs b/scripts/TWM2/Bosses/LordVardison.cs index 2a7a8e2..d60a120 100644 --- a/scripts/TWM2/Bosses/LordVardison.cs +++ b/scripts/TWM2/Bosses/LordVardison.cs @@ -1,6 +1,254 @@ //LORD \/ARDISON & Dark Archmage Vardison //THIS BOSS WILL MURDER OCCULTBADBOY //Yeah, he really will +datablock LinearFlareProjectileData(SuperlaserProjectile) { + scale = "15.0 15.0 15.0"; + faceViewer = false; + directDamage = 1.0; + hasDamageRadius = true; + indirectDamage = 0.9; + damageRadius = 30.0; + kickBackStrength = 1000.0; + radiusDamageType = $DamageType::Explosion; + + explosion[0] = "HyperDevCannonExplosion2"; + explosion[1] = "SatchelMainExplosion"; + splash = PlasmaSplash; + baseEmitter = HyperDevCannonBaseEmitter; + + + dryVelocity = 200.0; + wetVelocity = 200; + velInheritFactor = 0.5; + fizzleTimeMS = 10000; + lifetimeMS = 10000; + explodeOnDeath = false; + reflectOnWaterImpactAngle = 0.0; + explodeOnWaterImpact = true; + deflectionOnWaterImpact = 0.0; + fizzleUnderwaterMS = -1; + + //activateDelayMS = 100; + activateDelayMS = -1; + + size[0] = 9; + size[1] = 10; + size[2] = 11; + + + numFlares = 400; + flareColor = "0.0 1.0 0"; + flareModTexture = "flaremod"; + flareBaseTexture = "flarebase"; + + sound = MissileProjectileSound; + fireSound = PlasmaFireSound; + wetFireSound = PlasmaFireWetSound; + + hasLight = true; + lightRadius = 3.0; + lightColor = "0 0.75 0.25"; + +}; + +// +datablock ParticleData(ShadowBaseParticle) { + dragCoeffiecient = 0.0; + gravityCoefficient = -0.2; + inheritedVelFactor = 0.0; + + lifetimeMS = 800; + lifetimeVarianceMS = 500; + + useInvAlpha = true; + spinRandomMin = -160.0; + spinRandomMax = 160.0; + + animateTexture = true; + framesPerSec = 15; + + textureName = "special/cloudflash"; + + colors[0] = "0.1 0.1 0.1 1.0";// //////////////////// + colors[1] = "0.1 0.1 0.1 1.0";// //////////////////// + colors[2] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ + + sizes[0] = 2.5; + sizes[1] = 2.7; + sizes[2] = 3.0; + + times[0] = 0.0; + times[1] = 0.7; + times[2] = 1.0; +}; + +datablock ParticleEmitterData(ShadowBaseEmitter) { + ejectionPeriodMS = 10; + periodVarianceMS = 0; + + ejectionVelocity = 1.5; + velocityVariance = 0.3; + + thetaMin = 0.0; + thetaMax = 30.0; + + particles = "ShadowBaseParticle"; +}; + +datablock ParticleData(SmallShadowBaseParticle) { + dragCoeffiecient = 0.0; + gravityCoefficient = -0.2; + inheritedVelFactor = 0.0; + + lifetimeMS = 9999999999999; + lifetimeVarianceMS = 9999999999999; + + useInvAlpha = true; + spinRandomMin = -160.0; + spinRandomMax = 160.0; + + animateTexture = true; + framesPerSec = 15; + + textureName = "special/cloudflash"; + + colors[0] = "0.1 0.1 0.1 1.0";// //////////////////// + colors[1] = "0.1 0.1 0.1 1.0";// //////////////////// + colors[2] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ + + sizes[0] = 0.5; + sizes[1] = 0.7; + sizes[2] = 1.0; + + times[0] = 0.0; + times[1] = 0.7; + times[2] = 1.0; +}; + +datablock ParticleEmitterData(SmallShadowBaseEmitter) { + ejectionPeriodMS = 10; + periodVarianceMS = 0; + + ejectionVelocity = 1.5; + velocityVariance = 0.3; + + thetaMin = 0.0; + thetaMax = 30.0; + + particles = "SmallShadowBaseParticle"; +}; + +datablock ParticleData(JetShadowParticle) { + dragCoeffiecient = 0.0; + gravityCoefficient = 0; + inheritedVelFactor = 0.0; + + lifetimeMS = 2500; + lifetimeVarianceMS = 0; + + textureName = "particleTest"; + + useInvAlpha = true; + spinRandomMin = -160.0; + spinRandomMax = 160.0; + + animateTexture = true; + framesPerSec = 15; + + animTexName[0] = "special/Explosion/exp_0016"; + animTexName[1] = "special/Explosion/exp_0018"; + animTexName[2] = "special/Explosion/exp_0020"; + animTexName[3] = "special/Explosion/exp_0022"; + animTexName[4] = "special/Explosion/exp_0024"; + animTexName[5] = "special/Explosion/exp_0026"; + animTexName[6] = "special/Explosion/exp_0028"; + animTexName[7] = "special/Explosion/exp_0030"; + animTexName[8] = "special/Explosion/exp_0032"; + + colors[0] = "0.1 0.1 0.1 1.0";// //////////////////// + colors[1] = "0.1 0.1 0.1 1.0";// //////////////////// + colors[2] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ + sizes[0] = 2.5; + sizes[1] = 1.25; + sizes[2] = 0.625; + times[0] = 0.0; + times[1] = 0.7; + times[2] = 1.0; +}; + +datablock ParticleEmitterData(JetShadowEmitter) { + ejectionPeriodMS = 2; + periodVarianceMS = 0; + + ejectionVelocity = 0; + velocityVariance = 0; + ejectionOffset = 5; + thetaMin = 22.5; + thetaMax = 45; + phiReferenceVel = 0; + phiVariance = 360; + spinRandomMin = "200"; + spinRandomMax = "-200"; + overrideAdvances = false; + particles = "JetShadowParticle"; +}; + +datablock ParticleData(LaserBallGlobeSmoke) { + dragCoefficient = 50;/////////----------------------- + gravityCoefficient = 0.0; + inheritedVelFactor = 1.0; + constantAcceleration = 0.0; + lifetimeMS = 1000; + lifetimeVarianceMS = 0; + useInvAlpha = true; + spinRandomMin = -360.0; + spinRandomMax = 360.0; + textureName = "particleTest"; + colors[0] = "0.1 0.1 0.1 1.0";// //////////////////// + colors[1] = "0.1 0.1 0.1 1.0";// //////////////////// + colors[2] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ + colors[3] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ + sizes[0] = 1.0; + sizes[1] = 1.0; + sizes[2] = 1.0; + sizes[3] = 1.0; + times[0] = 0.0; + times[1] = 0.33; + times[2] = 0.66; + times[3] = 1.0; + mass = 0.7; + elasticity = 0.2; + friction = 1; + computeCRC = true; + haslight = true; + lightType = "PulsingLight"; + lightColor = "0.2 0.0 0.5 1.0"; + lightTime = "200"; + lightRadius = "2.0"; +}; + +datablock ParticleEmitterData(MiniShadowBallEmitter) { + ejectionPeriodMS = 0.3; + periodVarianceMS = 0; + ejectionVelocity = 0.0; + velocityVariance = 0.0; + ejectionOffset = 2; + thetaMin = 0; + thetaMax = 180; + overrideAdvances = false; + particles = "LaserBallGlobeSmoke"; +}; + +datablock LinearFlareProjectileData(ShadowBomb) : FlamethrowerBolt { + baseEmitter = ShadowBaseEmitter; + fizzleTimeMS = 14000; + lifetimeMS = 10000; // z0dd - ZOD, 4/25/02. Was 6000 +}; + +datablock SeekerProjectileData(VardisonLaserBallMissile) : YvexNightmareMissile { + baseEmitter = ShadowBaseEmitter; +}; + function VardisonLaserBallMissile::OnExplode(%data, %proj, %pos, %mod) { //LaserBall %ball = CreateEmitter(%pos, "MiniShadowBallEmitter", "0 0 0 0"); @@ -30,6 +278,262 @@ function LaserBallStrike(%position, %count) { schedule(100, 0, "LaserBallStrike", %position, %count); } +datablock LinearFlareProjectileData(VardisonSubShadowBomb) : DMPlasma { + explosion = MortarExplosion; + dryVelocity = 500.0; // z0dd - ZOD, 4/25/02. Was 50. Velocity of projectile out of water + wetVelocity = -1; + velInheritFactor = 1.0; + fizzleTimeMS = 14000; + lifetimeMS = 10000; // z0dd - ZOD, 4/25/02. Was 6000 +}; + +//ARMOR DBs +datablock PlayerData(VardisonStage1Armor) : LightMaleHumanArmor { + runForce = 60.20 * 90; + runEnergyDrain = 0.0; + minRunEnergy = 10; + maxForwardSpeed = 9; + maxBackwardSpeed = 7; + maxSideSpeed = 7; + + jumpForce = 14.0 * 90; + + maxDamage = 300.0; + minImpactSpeed = 35; + shapeFile = "light_male.dts"; + jetEmitter = BiodermArmorJetEmitter; + jetEffect = BiodermArmorJetEffect; + + debrisShapeName = "bio_player_debris.dts"; + + //Foot Prints + decalData = LightBiodermFootprint; + decalOffset = 0.3; + + waterBreathSound = WaterBreathBiodermSound; + + damageScale[$DamageType::M1700] = 3.0; + damageScale[$DamageType::Missile] = 0.0000000000000001; + damageScale[$DamageType::Nuclear] = 0.0000000000000001; + damageScale[$DamageType::EMP] = 0.0000000000000001; + damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs + + max[RepairKit] = 0; + max[Mine] = 0; + max[Grenade] = 0; +}; + +datablock PlayerData(DarkArchmageVardisonArmor) : VardisonStage1Armor { + maxDamage = 1000.0; + minImpactSpeed = 35; + shapeFile = "light_male.dts"; + jetEmitter = BiodermArmorJetEmitter; + jetEffect = BiodermArmorJetEffect; + + damageScale[$DamageType::M1700] = 3.0; + damageScale[$DamageType::Missile] = 0.0000000000000001; + damageScale[$DamageType::Nuclear] = 0.0000000000000001; + damageScale[$DamageType::EMP] = 0.0000000000000001; + damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs + + max[RepairKit] = 0; + max[Mine] = 0; + max[Grenade] = 0; +}; + +datablock FlyingVehicleData(VardisonStage2Flyer) : ShrikeDamageProfile { + spawnOffset = "0 0 2"; + canControl = false; + catagory = "Vehicles"; + shapeFile = "vehicle_air_bomber.dts"; + multipassenger = false; + computeCRC = true; + + debrisShapeName = "vehicle_air_bomber.dts"; + debris = MeShapeDebris; + renderWhenDestroyed = false; + + drag = 0.15; + density = 1.0; + + mountPose[0] = sitting; + numMountPoints = 1; + isProtectedMountPoint[0] = false; + cameraMaxDist = 15; + cameraOffset = 2.5; + cameraLag = 0.9; + explosion = MeVehicleExplosion; + explosionDamage = 1.0; + explosionRadius = 10.0; + + maxDamage = 50.0; + destroyedLevel = 50.0; + + HDAddMassLevel = 49.9; + HDMassImage = LflyerHDMassImage; + + isShielded = false; + energyPerDamagePoint = 0; + maxEnergy = 5000; // Afterburner and any energy weapon pool + rechargeRate = 4; + + minDrag = 22; // Linear Drag (eventually slows you down when not thrusting...constant drag) + rotationalDrag = 900; // Anguler Drag (dampens the drift after you stop moving the mouse...also tumble drag) + + maxAutoSpeed = 50; // Autostabilizer kicks in when less than this speed. (meters/second) + autoAngularForce = 400; // Angular stabilizer force (this force levels you out when autostabilizer kicks in) + autoLinearForce = 1; // Linear stabilzer force (this slows you down when autostabilizer kicks in) + autoInputDamping = 0.8; // Dampen control input so you don't` whack out at very slow speeds + + + // Maneuvering + maxSteeringAngle = 4.5; // Max radiens you can rotate the wheel. Smaller number is more maneuverable. + horizontalSurfaceForce = 6; // Horizontal center "wing" (provides "bite" into the wind for climbing/diving and turning) + verticalSurfaceForce = 4; // Vertical center "wing" (controls side slip. lower numbers make MORE slide.) + maneuveringForce = 5250; // Horizontal jets (W,S,D,A key thrust) + steeringForce = 675; // Steering jets (force applied when you move the mouse) + steeringRollForce = 3000; // Steering jets (how much you heel over when you turn) + rollForce = 1; // Auto-roll (self-correction to right you after you roll/invert) + hoverHeight = 2.5; // Height off the ground at rest + createHoverHeight = 1; // Height off the ground when created + maxForwardSpeed = 165; // speed in which forward thrust force is no longer applied (meters/second) + + // Turbo Jet + jetForce = 2500; // Afterburner thrust (this is in addition to normal thrust) + minJetEnergy = 40; // Afterburner can't be used if below this threshhold. + jetEnergyDrain = 10; // Energy use of the afterburners (low number is less drain...can be fractional) // Auto stabilize speed + vertThrustMultiple = 1.25; + + // Rigid body + mass = 150; // Mass of the vehicle + bodyFriction = 0; // Don't mess with this. + bodyRestitution = 0.5; // When you hit the ground, how much you rebound. (between 0 and 1) + minRollSpeed = 0; // Don't mess with this. + softImpactSpeed = 14; // Sound hooks. This is the soft hit. + hardImpactSpeed = 25; // Sound hooks. This is the hard hit. + + // Ground Impact Damage (uses DamageType::Ground) + minImpactSpeed = 20; // If hit ground at speed above this then it's an impact. Meters/second + speedDamageScale = 0.06; + + // Object Impact Damage (uses DamageType::Impact) + collDamageThresholdVel = 23.0; + collDamageMultiplier = 0.02; + + // + minTrailSpeed = 70; // The speed your contrail shows up at. + trailEmitter = JetShadowEmitter; + forwardJetEmitter = JetShadowEmitter; + downJetEmitter = JetShadowEmitter; + + // + jetSound = ScoutFlyerThrustSound; + engineSound = ScoutFlyerEngineSound; + softImpactSound = SoftImpactSound; + hardImpactSound = HardImpactSound; + //wheelImpactSound = WheelImpactSound; + + // + softSplashSoundVelocity = 10.0; + mediumSplashSoundVelocity = 15.0; + hardSplashSoundVelocity = 20.0; + exitSplashSoundVelocity = 10.0; + + exitingWater = VehicleExitWaterMediumSound; + impactWaterEasy = VehicleImpactWaterSoftSound; + impactWaterMedium = VehicleImpactWaterMediumSound; + impactWaterHard = VehicleImpactWaterMediumSound; + waterWakeSound = VehicleWakeMediumSplashSound; + + dustEmitter = VehicleLiftoffDustEmitter; + triggerDustHeight = 4.0; + dustHeight = 1.0; + + damageEmitter[0] = MeLightDamageSmoke; + damageEmitter[1] = MeHeavyDamageSmoke; + damageEmitter[2] = MeDamageBubbles; + damageEmitterOffset[0] = "0.0 -3.0 0.0 "; + damageLevelTolerance[0] = 0.4; + damageLevelTolerance[1] = 0.75; + numDmgEmitterAreas = 1; + + // + max[chaingunAmmo] = 2000; + max[MissileLauncherAmmo] = 200; + max[MortarAmmo] = 200; + + damageScale[$DamageType::Nuclear] = 0.0000000000000001; + damageScale[$DamageType::EMP] = 0.0000000000000001; + damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs + ShieldDamageScale[$DamageType::Bullet] = 0.01; //I deny you shrike n0bs + + minMountDist = 7; + + splashEmitter[0] = VehicleFoamDropletsEmitter; + splashEmitter[1] = VehicleFoamEmitter; + + shieldImpact = VehicleShieldImpact; + + cmdCategory = "Tactical"; + cmdIcon = CMDFlyingScoutIcon; + cmdMiniIconName = "commander/MiniIcons/com_scout_grey"; + targetNameTag = 'Lord Vardison'; + targetTypeTag = ''; + sensorData = SSTurretBaseSensorObj; + sensorRadius = SSTurretBaseSensorObj.detectRadius; + sensorColor = "9 9 255"; + + checkRadius = 5.5; + observeParameters = "1 10 10"; + + runningLight[0] = ShrikeLight1; +// runningLight[1] = ShrikeLight2; + + shieldEffectScale = "0.937 1.125 0.60"; + + numWeapons = 3; + + replaceTime = 90; +}; + +datablock PlayerData(VardisonStage3Armor) : LightMaleHumanArmor { + runForce = 60.20 * 90; + runEnergyDrain = 0.0; + minRunEnergy = 10; + maxForwardSpeed = 9; + maxBackwardSpeed = 7; + maxSideSpeed = 7; + + jumpForce = 14.0 * 90; + + maxDamage = 500.0; + minImpactSpeed = 35; + shapeFile = "TR2Heavy_Male.dts"; + jetEmitter = BiodermArmorJetEmitter; + jetEffect = BiodermArmorJetEffect; + + debrisShapeName = "bio_player_debris.dts"; + + //Foot Prints + decalData = LightBiodermFootprint; + decalOffset = 0.3; + + boundingBox = "5 5 10"; + + waterBreathSound = WaterBreathBiodermSound; + + damageScale[$DamageType::M1700] = 3.0; + damageScale[$DamageType::PlasmaCannon] = 0.001; + damageScale[$DamageType::Missile] = 0.0000000000000001; + damageScale[$DamageType::Nuclear] = 0.0000000000000001; + damageScale[$DamageType::EMP] = 0.0000000000000001; + damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs + + max[RepairKit] = 0; + max[Mine] = 0; + max[Grenade] = 0; +}; + function StartDAVardison(%pos) { %Vardison = new player() { Datablock = "DarkArchmageVardisonArmor"; @@ -334,6 +838,137 @@ function DoVardisonSuperCloseKill(%source, %target, %count) { schedule(100, 0, "DoVardisonSuperCloseKill", %source, %target, %count); } +function ShadowBomb::onExplode(%data, %proj, %pos, %mod) { + %vec = %proj.spdvec; + %vec = getword(%vec, 0)@" "@getword(%vec, 1)@" 0"; + %vec = vectorNormalize(%vec); + %vec = vectorscale(%vec, 30); + %result = containerRayCast(vectoradd(%pos,"0 0 10"), vectoradd(%pos,%vec), $TypeMasks::StaticShapeObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::TerrainObjectType, %proj); + for(%i = 0; %i < 3; %i++) { + if(%result) + schedule((5 * %i), 0, "Napalm2FindNewDir", %pos, %vec, %proj.sourceobject, 0, 0); + else { + %rndvec = (getRandom(1, 15) - 7.5)@" "@(getRandom(1, 15) - 7.5)@" "@((getRandom() * 5) + 5); + %newvec = vectoradd(%vec,%rndvec); + %newvec = vectoradd(%pos,%newvec); + %p = new LinearFlareProjectile() { + dataBlock = VardisonSubShadowBomb; + initialDirection = "0 0 -1"; + initialPosition = %newvec; + sourceObject = %proj.sourceobject; + SourceSlot = 5; + }; + %p.sourceobject = %proj.sourceobject; + %p.vector = %vec; + %p.count = 1; + if(%proj.maxExplode $= "") { + %p.maxExplode = 15; + } + else { + %p.maxExplode = %proj.maxExplode; + } + } + } + if (%data.hasDamageRadius) + RadiusExplosion(%proj, %pos, %data.damageRadius, %data.indirectDamage, %data.kickBackStrength, %proj.sourceObject, %data.radiusDamageType); +} + +function VardisonSubShadowBomb::onExplode(%data, %proj, %pos, %mod) { + if(%proj.count < %proj.maxExplode) { //holy... christ + %vec = vectorscale(vectornormalize(%proj.vector), 24); + %result = containerRayCast(vectoradd(%pos,"0 0 10"), vectoradd(%pos,%vec), $TypeMasks::StaticShapeObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::TerrainObjectType, %proj); + if(%result) + schedule(5, 0, "Napalm2FindNewDir", %pos, %vec, %proj.sourceobject, %proj.count, 0); + else { + %rndvec = (getRandom(1, 10) - 5)@" "@(getRandom(1, 10) - 5)@" "@((getRandom() * 5) + 5); + %newvec = vectoradd(%vec,%rndvec); + %newvec = vectoradd(%pos,%newvec); + %p = new LinearFlareProjectile() { + dataBlock = VardisonSubShadowBomb; + initialDirection = "0 0 -1"; + initialPosition = %newvec; + sourceObject = %proj.sourceobject; + sourceSlot = 5; + }; + %p.sourceobject = %proj.sourceobject; + %p.vector = %vec; + %p.count = %proj.count + 1; + } + } + if (%data.hasDamageRadius) + RadiusExplosion(%proj, %pos, %data.damageRadius, %data.indirectDamage, %data.kickBackStrength, %proj.sourceObject, %data.radiusDamageType); +} + +function Napalm2FindNewDir(%pos, %vec, %source, %count, %count2) { + if(%count2 == 2) { + %rndvec = getRandom(1, 10)@" "@getRandom(1, 10)@" "@((getRandom() * 5) + 4); + %newvec = vectoradd(%pos,%rndvec); + %p = new LinearFlareProjectile() { + dataBlock = VardisonSubShadowBomb; + initialDirection = "0 0 -1"; + initialPosition = %newvec; + sourceObject = %source; + sourceSlot = 5; + }; + %p.sourceobject = %source; + %p.vector = %vec; + %p.count = %count+1; + return; + } + if(%count2 == 1) { + %vec = vectorscale(%vec,-1); + %result = containerRayCast(vectoradd(%pos,"0 0 10"), vectoradd(%pos,%vec), $TypeMasks::StaticShapeObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::TerrainObjectType, 0); + if(!(%result)){ + %rndvec = getRandom(1, 10)@" "@getRandom(1, 10)@" "@((getRandom() * 5) + 4); + %newvec = vectoradd(%vec,%rndvec); + %newvec = vectoradd(%pos,%newvec); + %p = new LinearFlareProjectile() { + dataBlock = VardisonSubShadowBomb; + initialDirection = "0 0 -1"; + initialPosition = %newvec; + sourceObject = %source; + sourceSlot = 5; + }; + %p.sourceobject = %source; + %p.vector = %vec; + %p.count = %count+1; + return; + } + } + else { + %chance = getrandom(1,4); + if(%chance <= 2){ + %nv2 = (getword(%vec, 0) * -1); + %nv1 = getword(%vec, 1); + %vec = %nv1@" "@%nv2@" 0"; + } + else { + %nv2 = getword(%vec, 0); + %nv1 = (getword(%vec, 1) * -1); + %vec = %nv1@" "@%nv2@" 0"; + } + %result = containerRayCast(vectoradd(%pos,"0 0 10"), vectoradd(%pos,%vec), $TypeMasks::StaticShapeObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::TerrainObjectType, 0); + if(!(%result)){ + %rndvec = getRandom(1, 10)@" "@getRandom(1, 10)@" "@((getRandom() * 5) + 4); + %newvec = vectoradd(%vec,%rndvec); + %newvec = vectoradd(%pos,%newvec); + %p = new LinearFlareProjectile() { + dataBlock = VardisonSubShadowBomb; + initialDirection = "0 0 -1"; + initialPosition = %newvec; + sourceObject = %source; + sourceSlot = 5; + }; + %p.sourceobject = %source; + %p.vector = %vec; + %p.count = %count+1; + return; + } + } + %count2++; + schedule(2, 0, "Napalm2FindNewDir", %pos, %vec, %source, %count, %count2); +} + function GOVDoFlameCano(%g, %target) { if(!isObject(%g) || %g.getState() $= "dead") { return; @@ -695,7 +1330,7 @@ function VardisonAttack(%boss, %att, %arg) { sourceObject = %boss; sourceSlot = 4; }; - //%p.maxExplode = %detCt; + %p.maxExplode = %detCt; MissionCleanup.add(%p); case "ShadowBombLaunchAbove": @@ -838,7 +1473,18 @@ function InvokeStillwallLoop(%boss) { %boss.InvokeLoop = schedule(100, 0, "InvokeStillwallLoop", %boss); } + + + + + + + //============================================================================== +datablock SeekerProjectileData(VardisonMiniDemonSpawner) : VardisonNightmareMissile { + baseEmitter = ShadowBaseEmitter; +}; + function VardisonMiniDemonSpawner::OnExplode(%data, %proj, %pos, %mod) { //LaserBall %ball = CreateEmitter(%pos, "MiniShadowBallEmitter", "0 0 0 0"); @@ -848,6 +1494,77 @@ function VardisonMiniDemonSpawner::OnExplode(%data, %proj, %pos, %mod) { CreateDemonAT(vectorAdd(%pos, "0 0 3")); } +datablock PlayerData(MiniDemonArmor) : LightMaleHumanArmor { + runForce = 60.20 * 90; + runEnergyDrain = 0.0; + minRunEnergy = 10; + maxForwardSpeed = 9; + maxBackwardSpeed = 7; + maxSideSpeed = 7; + + jumpForce = 14.0 * 90; + + maxDamage = 2.8; + minImpactSpeed = 1000; + shapeFile = "bioderm_medium.dts"; + jetEmitter = BiodermArmorJetEmitter; + jetEffect = BiodermArmorJetEffect; + + debrisShapeName = "bio_player_debris.dts"; + + //Foot Prints + decalData = LightBiodermFootprint; + decalOffset = 0.3; + + waterBreathSound = WaterBreathBiodermSound; + + damageScale[$DamageType::M1700] = 3.0; + damageScale[$DamageType::PlasmaCannon] = 0.001; + damageScale[$DamageType::Missile] = 0.0000000000000001; + damageScale[$DamageType::Nuclear] = 0.0000000000000001; + damageScale[$DamageType::EMP] = 0.0000000000000001; + + max[RepairKit] = 0; + max[Mine] = 0; + max[Grenade] = 0; +}; + +datablock GrenadeProjectileData(MiniDemonBlaster) { + projectileShapeName = "plasmabolt.dts"; + emitterDelay = -1; + directDamage = 0.0; + hasDamageRadius = true; + indirectDamage = 0.45; + damageRadius = 5.0; // z0dd - ZOD, 8/13/02. Was 20.0 + radiusDamageType = $DamageType::Demon; + kickBackStrength = 1500; + + explosion = "MortarExplosion"; + underwaterExplosion = "MortarExplosion"; + velInheritFactor = 0; + splash = PlasmaSplash; + depthTolerance = 100.0; + + baseEmitter = DemonFBSmokeEmitter; + bubbleEmitter = DemonFBSmokeEmitter; + + grenadeElasticity = 0; + grenadeFriction = 0.4; + armingDelayMS = -1; // z0dd - ZOD, 4/14/02. Was 2000 + + gravityMod = 0.4; // z0dd - ZOD, 5/18/02. Make mortar projectile heavier, less floaty + muzzleVelocity = 125.0; // z0dd - ZOD, 8/13/02. More velocity to compensate for higher gravity. Was 63.7 + drag = 0; + sound = PlasmaProjectileSound; + + hasLight = true; + lightRadius = 10; + lightColor = "1 0.75 0.25"; + + hasLightUnderwaterColor = true; + underWaterLightColor = "1 0.75 0.25"; +}; + function CreateDemon(%pos) { %p = new SeekerProjectile() { dataBlock = VardisonMiniDemonSpawner; diff --git a/scripts/TWM2/Bosses/LordYvex.cs b/scripts/TWM2/Bosses/LordYvex.cs index be63622..f111135 100644 --- a/scripts/TWM2/Bosses/LordYvex.cs +++ b/scripts/TWM2/Bosses/LordYvex.cs @@ -1,4 +1,198 @@ -//BLOCK FUNCTIONS +//DATABLOCKS +datablock ParticleData(InflictionNightmareGlobeSmoke) { + dragCoefficient = 50;/////////----------------------- + gravityCoefficient = 0.0; + inheritedVelFactor = 1.0; + constantAcceleration = 0.0; + lifetimeMS = 5050; + lifetimeVarianceMS = 0; + useInvAlpha = true; + spinRandomMin = -360.0; + spinRandomMax = 360.0; + textureName = "particleTest"; + colors[0] = "0.5 0.1 0.9 1.0"; + colors[1] = "0.5 0.1 0.9 1.0"; + colors[2] = "0.5 0.1 0.9 1.0"; + colors[3] = "0.5 0.1 0.9"; + sizes[0] = 1.0; + sizes[1] = 1.0; + sizes[2] = 1.0; + sizes[3] = 1.0; + times[0] = 0.0; + times[1] = 0.33; + times[2] = 0.66; + times[3] = 1.0; + mass = 0.7; + elasticity = 0.2; + friction = 1; + computeCRC = true; + haslight = true; + lightType = "PulsingLight"; + lightColor = "0.2 0.0 0.5 1.0"; + lightTime = "200"; + lightRadius = "2.0"; +}; + +datablock ParticleEmitterData(InfNightmareGlobeEmitter) { + ejectionPeriodMS = 0.1; + periodVarianceMS = 0; + ejectionVelocity = 0.0; + velocityVariance = 0.0; + ejectionOffset = 5; + thetaMin = 0; + thetaMax = 180; + overrideAdvances = false; + particles = "InflictionNightmareGlobeSmoke"; +}; + + +datablock ParticleData(NightmareGlobeSmoke) { + dragCoefficient = 50;/////////----------------------- + gravityCoefficient = 0.0; + inheritedVelFactor = 1.0; + constantAcceleration = 0.0; + lifetimeMS = 5050; + lifetimeVarianceMS = 0; + useInvAlpha = true; + spinRandomMin = -360.0; + spinRandomMax = 360.0; + textureName = "particleTest"; + colors[0] = "0.1 0.1 0.1 1.0";// //////////////////// + colors[1] = "0.1 0.1 0.1 1.0";// //////////////////// + colors[2] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ + colors[3] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ + sizes[0] = 1.0; + sizes[1] = 1.0; + sizes[2] = 1.0; + sizes[3] = 1.0; + times[0] = 0.0; + times[1] = 0.33; + times[2] = 0.66; + times[3] = 1.0; + mass = 0.7; + elasticity = 0.2; + friction = 1; + computeCRC = true; + haslight = true; + lightType = "PulsingLight"; + lightColor = "0.2 0.0 0.5 1.0"; + lightTime = "200"; + lightRadius = "2.0"; +}; + +datablock ParticleEmitterData(NightmareGlobeEmitter) { + ejectionPeriodMS = 0.1; + periodVarianceMS = 0; + ejectionVelocity = 0.0; + velocityVariance = 0.0; + ejectionOffset = 5; + thetaMin = 0; + thetaMax = 180; + overrideAdvances = false; + particles = "NightmareGlobeSmoke"; +}; + +//Yvex STUFF.. MORE +datablock ParticleData(GreenEmitParticle) { + dragCoeffiecient = 1; + gravityCoefficient = -0.3; // rises slowly + inheritedVelFactor = 0; + + lifetimeMS = 300; + lifetimeVarianceMS = 0; + useInvAlpha = false; + spinRandomMin = 0.0; + spinRandomMax = 0.0; + + animateTexture = false; + + textureName = "flareBase"; // "special/Smoke/bigSmoke" + + colors[0] = "0 1 0"; + colors[1] = "0 1 0"; + colors[2] = "0 1 0"; + + sizes[0] = 0.8; + sizes[1] = 0.8; + sizes[2] = 0.8; + + times[0] = 0.0; + times[1] = 1.0; + times[2] = 5.0; + +}; + +datablock ParticleEmitterData(PulseGreenEmitter) { + ejectionPeriodMS = 2; + periodVarianceMS = 1; + + ejectionVelocity = 10; + velocityVariance = 0; + + thetaMin = 89.0; + thetaMax = 90.0; + + orientParticles = false; + + particles = "GreenEmitParticle"; +}; + +datablock SeekerProjectileData(YvexNightmareMissile){ + casingShapeName = "weapon_missile_casement.dts"; + projectileShapeName = "weapon_missile_projectile.dts"; + hasDamageRadius = true; + indirectDamage = 0.8; + damageRadius = 8.0; + radiusDamageType = $DamageType::Missile; + kickBackStrength = 2000; + + explosion = "MissileExplosion"; + splash = MissileSplash; + velInheritFactor = 1.0; // to compensate for slow starting velocity, this value + // is cranked up to full so the missile doesn't start + // out behind the player when the player is moving + // very quickly - bramage + + delayEmitter = MissileFireEmitter; + puffEmitter = MissilePuffEmitter; + bubbleEmitter = GrenadeBubbleEmitter; + bubbleEmitTime = 1.0; + + exhaustEmitter = MissileLauncherExhaustEmitter; + exhaustTimeMs = 300; + exhaustNodeName = "muzzlePoint1"; + + lifetimeMS = 30000; + muzzleVelocity = 10.0; + maxVelocity = 150.0; + turningSpeed = 110.0; + acceleration = 350.0; + + proximityRadius = 3; + + terrainAvoidanceSpeed = 180; + terrainScanAhead = 25; + terrainHeightFail = 12; + terrainAvoidanceRadius = 100; + + flareDistance = 200; + flareAngle = 30; + + sound = MissileProjectileSound; + + hasLight = true; + lightRadius = 5.0; + lightColor = "0.2 0.05 0"; + + useFlechette = true; + flechetteDelayMs = 550; + casingDeb = FlechetteDebris; + + explodeOnWaterImpact = false; + + baseEmitter = NMMissileBaseEmitter; +}; + function YvexNightmareMissile::OnExplode(%data, %proj, %pos, %mod) { %source = %proj.SourceObject; InitContainerRadiusSearch(%proj.getPosition(), 6, $TypeMasks::PlayerObjectType); @@ -9,46 +203,344 @@ function YvexNightmareMissile::OnExplode(%data, %proj, %pos, %mod) { } } -function KillerPulse::onCollision(%data,%projectile,%targetObject,%modifier,%position,%normal) { - if (%targetObject.getClassName() $= "Player" && %targetObject.isBoss) { - messageall('msgkillcurse', "\c5"@getTaggedString(%targetObject.client.name)@" Took a fatal Hit from "@$TWM2::ZombieName[7]@"'s Dark Energy"); - %targetObject.throwWeapon(); - %targetObject.clearinventory(); - YvexAttack_FUNC("KillLoop", %targetObject); - } -} +datablock LinearFlareProjectileData(KillerPulse) { + scale = "1.0 1.0 1.0"; + faceViewer = false; + directDamage = 0.00001; + hasDamageRadius = false; + indirectDamage = 0.6; + damageRadius = 10.0; + kickBackStrength = 100.0; + directDamageType = $DamageType::Admin; + indirectDamageType = $DamageType::Admin; -function YvexZombieMakerMissile::OnExplode(%data, %proj, %pos, %mod) { - %c = CreateEmitter(%pos, NightmareGlobeEmitter, "0 0 1"); - %rand = getRandom(1, 6); - %c.schedule(%rand * 750, "delete"); - for(%i = 0; %i < %rand; %i++) { - %time = %i * 750; - %type = getRandomZombieType("1 2 3 4 5 9 12 13"); - schedule(%time, 0, "StartAZombie", vectoradd(%pos, "0 0 1"), %type); - } -} + explosion = "BlasterExplosion"; + splash = PlasmaSplash; -function YvexSniperShot::onCollision(%data, %projectile, %targetObject, %modifier, %position, %normal) { - if(!isplayer(%targetObject)) { - return; - } - %targ = %targetObject.client; - %Zombie = %projectile.sourceObject; - %targ.nightmareticks = 0; - Yvexnightmareloop(%zombie,%targ); - %randMessage = getrandom(3)+1; - switch(%randMessage) { - case 1: - MessageAll('MessageAll', "\c4"@$TWM2::ZombieName[7]@": Let the revenge begin, "@getTaggedString(%targ.name)@"."); - case 2: - MessageAll('MessageAll', "\c4"@$TWM2::ZombieName[7]@": Taste my vengance... "@getTaggedString(%targ.name)@"."); - case 3: - MessageAll('MessageAll', "\c4"@$TWM2::ZombieName[7]@": Sleep Forever... "@getTaggedString(%targ.name)@"."); - default: - MessageAll('MessageAll', "\c4"@$TWM2::ZombieName[7]@": This Nightmare will lock you forever "@getTaggedString(%targ.name)@"!"); - } -} + dryVelocity = 200.0; + wetVelocity = 10; + velInheritFactor = 0.5; + fizzleTimeMS = 30000; + lifetimeMS = 30000; + explodeOnDeath = false; + reflectOnWaterImpactAngle = 0.0; + explodeOnWaterImpact = true; + deflectionOnWaterImpact = 0.0; + fizzleUnderwaterMS = -1; + + baseEmitter = PulseGreenEmitter; + delayEmitter = PulseGreenEmitter; + bubbleEmitter = PulseGreenEmitter; + + //activateDelayMS = 100; + activateDelayMS = -1; + + size[0] = 0.2; + size[1] = 0.2; + size[2] = 0.2; + + + numFlares = 15; + flareColor = "0 1 0"; + flareModTexture = "flaremod"; + flareBaseTexture = "flarebase"; + + sound = MissileProjectileSound; + fireSound = PlasmaFireSound; + wetFireSound = PlasmaFireWetSound; + + hasLight = true; + lightRadius = 3.0; + lightColor = "0 1 0"; + +}; + +datablock ParticleData(PurpleNightmareEmitParticle) { + dragCoeffiecient = 1; + gravityCoefficient = -0.3; // rises slowly + inheritedVelFactor = 0; + + lifetimeMS = 300; + lifetimeVarianceMS = 0; + useInvAlpha = false; + spinRandomMin = 0.0; + spinRandomMax = 0.0; + + animateTexture = false; + + textureName = "flareBase"; // "special/Smoke/bigSmoke" + + colors[0] = "0.5 0.1 0.9 1.0"; + colors[1] = "0.5 0.1 0.9 1.0"; + colors[2] = "0.5 0.1 0.9"; + + sizes[0] = 0.4; + sizes[1] = 0.4; + sizes[2] = 0.4; + + times[0] = 0.0; + times[1] = 1.0; + times[2] = 5.0; + +}; + +datablock ParticleEmitterData(YvexSniperEmitter) { + ejectionPeriodMS = 2; + periodVarianceMS = 1; + + ejectionVelocity = 10; + velocityVariance = 0; + + thetaMin = 89.0; + thetaMax = 90.0; + + orientParticles = false; + + particles = "PurpleNightmareEmitParticle"; +}; + +datablock LinearFlareProjectileData(YvexSniperShot) { + projectileShapeName = "weapon_missile_projectile.dts"; + scale = "3.0 5.0 3.0"; + faceViewer = true; + directDamage = 0.01; + kickBackStrength = 4000.0; + DirectDamageType = $DamageType::Zombie; + + explosion = "BlasterExplosion"; + + dryVelocity = 150.0; + wetVelocity = -1; + velInheritFactor = 0.3; + fizzleTimeMS = 10000; + lifetimeMS = 10000; + explodeOnDeath = true; + reflectOnWaterImpactAngle = 0.0; + explodeOnWaterImpact = true; + deflectionOnWaterImpact = 0.0; + fizzleUnderwaterMS = -1; + + activateDelayMS = 100; + activateDelayMS = -1; + + baseEmitter = YvexSniperEmitter; + + size[0] = 0.0; + size[1] = 0.0; + size[2] = 0.0; + + + numFlares = 0; + flareColor = "0.0 0.0 0.0"; + flareModTexture = "flaremod"; + flareBaseTexture = "flarebase"; + + sound = PlasmaProjectileSound; + fireSound = PlasmaFireSound; + wetFireSound = PlasmaFireWetSound; + + hasLight = true; + lightRadius = 3.0; + lightColor = "1 0.75 0.25"; +}; + +datablock SeekerProjectileData(YvexZombieMakerMissile) { + casingShapeName = "weapon_missile_casement.dts"; + projectileShapeName = "weapon_missile_projectile.dts"; + hasDamageRadius = true; + indirectDamage = 0.5; + damageRadius = 5.0; + radiusDamageType = $DamageType::Zombie; + kickBackStrength = 2000; + + explosion = "MissileExplosion"; + splash = MissileSplash; + velInheritFactor = 1.0; // to compensate for slow starting velocity, this value + // is cranked up to full so the missile doesn't start + // out behind the player when the player is moving + // very quickly - bramage + + baseEmitter = MortarSmokeEmitter; + delayEmitter = MissileFireEmitter; + puffEmitter = MissilePuffEmitter; + bubbleEmitter = GrenadeBubbleEmitter; + bubbleEmitTime = 1.0; + + exhaustEmitter = MissileLauncherExhaustEmitter; + exhaustTimeMs = 300; + exhaustNodeName = "muzzlePoint1"; + + lifetimeMS = 30000; // z0dd - ZOD, 4/14/02. Was 6000 + muzzleVelocity = 30.0; + maxVelocity = 35.0; // z0dd - ZOD, 4/14/02. Was 80.0 + turningSpeed = 23.0; + acceleration = 15.0; + + proximityRadius = 2.5; + + terrainAvoidanceSpeed = 10; + terrainScanAhead = 7; + terrainHeightFail = 1; + terrainAvoidanceRadius = 3; + + flareDistance = 40; + flareAngle = 20; + minSeekHeat = 0.0; + + sound = MissileProjectileSound; + + hasLight = true; + lightRadius = 5.0; + lightColor = "0.2 0.05 0"; + + useFlechette = true; + flechetteDelayMs = 250; + casingDeb = FlechetteDebris; + + explodeOnWaterImpact = false; +}; + +datablock PlayerData(YvexZombieArmor) : LightMaleHumanArmor { + boundingBox = "1.63 1.63 2.6"; + maxDamage = 500.0; + minImpactSpeed = 35; + shapeFile = "medium_male.dts"; + + debrisShapeName = "bio_player_debris.dts"; + + //Foot Prints + decalData = HeavyBiodermFootprint; + decalOffset = 0.4; + + waterBreathSound = WaterBreathBiodermSound; + + damageScale[$DamageType::W1700] = 3.0; + damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs + + max[RepairKit] = 0; + max[Mine] = 0; + max[Grenade] = 0; + max[SmokeGrenade] = 0; + max[BeaconSmokeGrenade] = 0; + max[Blaster] = 0; + max[Plasma] = 0; + max[PlasmaAmmo] = 0; + max[Disc] = 0; + max[DiscAmmo] = 0; + max[SniperRifle] = 0; + max[GrenadeLauncher] = 0; + max[GrenadeLauncherAmmo] = 0; + max[Mortar] = 0; + max[MortarAmmo] = 0; + max[MissileLauncher] = 0; + max[MissileLauncherAmmo] = 0; + max[Chaingun] = 0; + max[ChaingunAmmo] = 0; + max[RepairGun] = 0; + max[CloakingPack] = 0; + max[SensorJammerPack] = 0; + max[EnergyPack] = 0; + max[RepairPack] = 0; + max[ShieldPack] = 0; + max[AmmoPack] = 0; + max[SatchelCharge] = 0; + max[MortarBarrelPack] = 0; + max[MissileBarrelPack] = 0; + max[AABarrelPack] = 0; + max[PlasmaBarrelPack] = 0; + max[ELFBarrelPack] = 0; + max[artillerybarrelpack] = 0; + max[MedPack] = 0; + max[InventoryDeployable] = 0; + max[MotionSensorDeployable] = 0; + max[PulseSensorDeployable] = 0; + max[TurretOutdoorDeployable] = 0; + max[TurretIndoorDeployable] = 0; + max[FlashGrenade] = 0; + max[ConcussionGrenade] = 0; + max[FlareGrenade] = 0; + max[TargetingLaser] = 0; + max[ELFGun] = 0; + max[ShockLance] = 0; + max[CameraGrenade] = 0; + max[Beacon] = 0; + max[flamerAmmoPack] = 0; + max[ParachutePack] = 0; + max[ConstructionTool] = 0; + max[MergeTool] = 0; + max[NerfGun] = 0; + max[NerfBallLauncher] = 0; + max[NerfBallLauncherAmmo] = 0; + max[SuperChaingun] = 0; + max[SuperChaingunAmmo] = 0; + max[RPChaingun] = 0; + max[RPChaingunAmmo] = 0; + max[MGClip] = 0; + max[LSMG] = 0; + max[LSMGAmmo] = 0; + max[LSMGClip] = 0; + max[snipergun] = 0; + max[snipergunAmmo] = 0; + max[Bazooka] = 0; + max[BazookaAmmo] = 0; + max[BunkerBuster] = 0; + max[MG42] = 0; + max[MG42Ammo] = 0; + max[SPistol] = 0; + max[Pistol] = 0; + max[PistolAmmo] = 0; + max[Pistolclip] = 0; + max[flamer] = 0; + max[flamerAmmo] = 0; + max[AALauncher] = 0; + max[AALauncherAmmo] = 0; + max[melee] = 0; + max[SOmelee] = 0; + max[KriegRifle] = 0; + max[KriegAmmo] = 0; + max[Rifleclip] = 0; + max[Shotgun] = 0; + max[ShotgunAmmo] = 0; + max[ShotgunClip] = 0; + max[RShotgun] = 0; + max[RShotgunAmmo] = 0; + max[RShotgunClip] = 0; + max[LMissileLauncher] = 0; + max[LMissileLauncherAmmo] = 0; + max[HRPChaingun] = 0; + max[RPGAmmo] = 0; + max[RPGItem] = 0; + max[spineDeployable] = 0; + max[mspineDeployable] = 0; + max[wWallDeployable] = 0; + max[floorDeployable] = 0; + max[WallDeployable] = 0; + max[DoorDeployable] = 0; + max[TurretLaserDeployable] = 0; + max[TurretMissileRackDeployable]= 0; + max[DiscTurretDeployable] = 0; + max[EnergizerDeployable] = 0; + max[TreeDeployable] = 0; + max[CrateDeployable] = 0; + max[DecorationDeployable] = 0; + max[LogoProjectorDeployable] = 0; + max[LightDeployable] = 0; + max[TripwireDeployable] = 0; + max[TelePadPack] = 0; + max[TurretBasePack] = 0; + max[LargeInventoryDeployable] = 0; + max[GeneratorDeployable] = 0; + max[SolarPanelDeployable] = 0; + max[SwitchDeployable] = 0; + max[MediumSensorDeployable] = 0; + max[LargeSensorDeployable] = 0; + max[SpySatelliteDeployable] = 0; + max[JumpadDeployable] = 0; + max[EscapePodDeployable] = 0; + max[ForceFieldDeployable] = 0; + max[GravityFieldDeployable] = 0; + max[VehiclePadPack] = 0; +}; //CREATION function SpawnYvex(%position) { @@ -310,6 +802,27 @@ function YvexAttack_FUNC(%att, %args) { } } +function YvexSniperShot::onCollision(%data, %projectile, %targetObject, %modifier, %position, %normal) { + if(!isplayer(%targetObject)) { + return; + } + %targ = %targetObject.client; + %Zombie = %projectile.sourceObject; + %targ.nightmareticks = 0; + Yvexnightmareloop(%zombie,%targ); + %randMessage = getrandom(3)+1; + switch(%randMessage) { + case 1: + MessageAll('MessageAll', "\c4"@$TWM2::ZombieName[7]@": Let the revenge begin, "@getTaggedString(%targ.name)@"."); + case 2: + MessageAll('MessageAll', "\c4"@$TWM2::ZombieName[7]@": Taste my vengance... "@getTaggedString(%targ.name)@"."); + case 3: + MessageAll('MessageAll', "\c4"@$TWM2::ZombieName[7]@": Sleep Forever... "@getTaggedString(%targ.name)@"."); + default: + MessageAll('MessageAll', "\c4"@$TWM2::ZombieName[7]@": This Nightmare will lock you forever "@getTaggedString(%targ.name)@"!"); + } +} + function Yvexnightmareloop(%zombie,%viewer) { %enum = getRandom(1,5); switch(%enum) { @@ -370,3 +883,23 @@ function Yvexnightmareloop(%zombie,%viewer) { schedule(55, 0, "messageclient", %viewer, 'MsgClient', "~wvoice/derm2/avo.deathcry_02.wav"); schedule(60, 0, "messageclient", %viewer, 'MsgClient', "~wvoice/derm3/avo.deathcry_02.wav"); } + +function KillerPulse::onCollision(%data,%projectile,%targetObject,%modifier,%position,%normal) { + if (%targetObject.getClassName() $= "Player" && %targetObject.isBoss) { + messageall('msgkillcurse', "\c5"@getTaggedString(%targetObject.client.name)@" Took a fatal Hit from "@$TWM2::ZombieName[7]@"'s Dark Energy"); + %targetObject.throwWeapon(); + %targetObject.clearinventory(); + YvexAttack_FUNC("KillLoop", %targetObject); + } +} + +function YvexZombieMakerMissile::OnExplode(%data, %proj, %pos, %mod) { + %c = CreateEmitter(%pos, NightmareGlobeEmitter, "0 0 1"); + %rand = getRandom(1, 6); + %c.schedule(%rand * 750, "delete"); + for(%i = 0; %i < %rand; %i++) { + %time = %i * 750; + %type = getRandomZombieType("1 2 3 4 5 9 12 13"); + schedule(%time, 0, "StartAZombie", vectoradd(%pos, "0 0 1"), %type); + } +} diff --git a/scripts/TWM2/Bosses/LordraniusTrebor.cs b/scripts/TWM2/Bosses/LordraniusTrebor.cs index e042f4c..d79919b 100644 --- a/scripts/TWM2/Bosses/LordraniusTrebor.cs +++ b/scripts/TWM2/Bosses/LordraniusTrebor.cs @@ -1,3 +1,35 @@ +datablock HoverVehicleData(TreborTank) : CentaurVehicle { + spawnOffset = "0 0 4"; + canControl = true; + floatingGravMag = 4.5; + + catagory = "Vehicles"; + shapeFile = "vehicle_grav_tank.dts"; + multipassenger = false; + computeCRC = true; + renderWhenDestroyed = false; + + mountPose[0] = sitting; + numMountPoints = 0; // <-- Ignore this + isProtectedMountPoint[0] = true; + + maxDamage = 100.15; + destroyedLevel = 100.15; + + isShielded = true; + rechargeRate = 1.0; + energyPerDamagePoint = 135; + maxEnergy = 400; + minJetEnergy = 15; + jetEnergyDrain = 2.0; + + targetNameTag = 'Centaur'; + targetTypeTag = 'MK III'; + + damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs + ShieldDamageScale[$DamageType::Bullet] = 0.01; //I deny you shrike n0bs +}; + function StartTrebor(%pos){ %team = 6; %rotation = "1 0 0 0"; diff --git a/scripts/TWM2/Bosses/MajorInsignia.cs b/scripts/TWM2/Bosses/MajorInsignia.cs index 57e8a78..e06f186 100644 --- a/scripts/TWM2/Bosses/MajorInsignia.cs +++ b/scripts/TWM2/Bosses/MajorInsignia.cs @@ -1,5 +1,23 @@ -//Major Insignia -//Gravity Zombie Boss +//DATABLOCKS +datablock StaticShapeData(NoCollideBio) : StaticShapeDamageProfile { + className = "player"; + shapeFile = "bioderm_light.dts"; // dmiscf.dts, alternate + mass = 1; + elasticity = 0.1; + friction = 0.9; + collideable = 0; + isInvincible = true; +}; + +datablock StaticShapeData(NoCollideHum) : StaticShapeDamageProfile { + className = "player"; + shapeFile = "light_male.dts"; // dmiscf.dts, alternate + mass = 1; + elasticity = 0.1; + friction = 0.9; + collideable = 0; + isInvincible = true; +}; //Stops console spammage function NoCollideBio::shouldApplyImpulse(%targetObject) { @@ -9,6 +27,145 @@ function NoCollideHum::shouldApplyImpulse(%targetObject) { return false; } +datablock PlayerData(InsigniaZombieArmor) : LightMaleBiodermArmor { + maxDamage = 700.0; + minImpactSpeed = 50; + speedDamageScale = 0.015; + + damageScale[$DamageType::M1700] = 2.0; + damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs + + max[RepairKit] = 0; + max[Mine] = 0; + max[Grenade] = 0; + max[SmokeGrenade] = 0; + max[BeaconSmokeGrenade] = 0; + max[Blaster] = 0; + max[Plasma] = 0; + max[PlasmaAmmo] = 0; + max[Disc] = 0; + max[DiscAmmo] = 0; + max[SniperRifle] = 0; + max[GrenadeLauncher] = 0; + max[GrenadeLauncherAmmo] = 0; + max[Mortar] = 0; + max[MortarAmmo] = 0; + max[MissileLauncher] = 0; + max[MissileLauncherAmmo] = 0; + max[Chaingun] = 0; + max[ChaingunAmmo] = 0; + max[RepairGun] = 0; + max[CloakingPack] = 0; + max[SensorJammerPack] = 0; + max[EnergyPack] = 0; + max[RepairPack] = 0; + max[ShieldPack] = 0; + max[AmmoPack] = 0; + max[SatchelCharge] = 0; + max[MortarBarrelPack] = 0; + max[MissileBarrelPack] = 0; + max[AABarrelPack] = 0; + max[PlasmaBarrelPack] = 0; + max[ELFBarrelPack] = 0; + max[artillerybarrelpack] = 0; + max[InventoryDeployable] = 0; + max[MotionSensorDeployable] = 0; + max[PulseSensorDeployable] = 0; + max[TurretOutdoorDeployable] = 0; + max[TurretIndoorDeployable] = 0; + max[FlashGrenade] = 0; + max[ConcussionGrenade] = 0; + max[FlareGrenade] = 0; + max[TargetingLaser] = 0; + max[ELFGun] = 0; + max[ShockLance] = 0; + max[CameraGrenade] = 0; + max[Beacon] = 0; + max[flamerAmmoPack] = 0; + max[ParachutePack] = 0; + max[MedPack] = 0; + //Guns + max[ConstructionTool] = 0; + max[MergeTool] = 0; + max[NerfGun] = 0; + max[NerfBallLauncher] = 0; + max[NerfBallLauncherAmmo] = 0; + max[SuperChaingun] = 0; + max[SuperChaingunAmmo] = 0; + max[RPChaingun] = 0; + max[RPChaingunAmmo] = 0; + max[MGClip] = 0; + max[LSMG] = 0; + max[LSMGAmmo] = 0; + max[LSMGClip] = 0; + max[snipergun] = 0; + max[snipergunAmmo] = 0; + max[Bazooka] = 0; + max[BazookaAmmo] = 0; + max[nukeme] = 0; + max[nukemeAmmo] = 0; + max[MG42] = 0; + max[MG42Ammo] = 0; + max[SPistol] = 0; + max[Pistol] = 0; + max[PistolAmmo] = 0; + max[Pistolclip] = 0; + max[flamer] = 0; + max[flamerAmmo] = 0; + max[AALauncher] = 0; + max[AALauncherAmmo] = 0; + max[melee] = 0; + max[SOmelee] = 0; + max[KriegRifle] = 0; + max[KriegAmmo] = 0; + max[Rifleclip] = 0; + max[Shotgun] = 0; + max[ShotgunAmmo] = 0; + max[ShotgunClip] = 0; + max[RShotgun] = 0; + max[RShotgunAmmo] = 0; + max[RShotgunClip] = 0; + max[LMissileLauncher] = 0; + max[LMissileLauncherAmmo] = 0; + max[HRPChaingun] = 0; + max[RPGAmmo] = 0; + max[RPGItem] = 0; + //Building parts + max[spineDeployable] = 0; + max[mspineDeployable] = 0; + max[wWallDeployable] = 0; + max[floorDeployable] = 0; + max[WallDeployable] = 0; + max[DoorDeployable] = 0; + //Turrets + max[TurretLaserDeployable] = 0; + max[TurretMissileRackDeployable]= 0; + max[DiscTurretDeployable] = 0; + //Largepacks + max[EnergizerDeployable] = 0; + max[TreeDeployable] = 0; + max[CrateDeployable] = 0; + max[DecorationDeployable] = 0; + max[LogoProjectorDeployable] = 0; + max[LightDeployable] = 0; + max[TripwireDeployable] = 0; + max[TelePadPack] = 0; + max[TurretBasePack] = 0; + max[LargeInventoryDeployable] = 0; + max[GeneratorDeployable] = 0; + max[SolarPanelDeployable] = 0; + max[SwitchDeployable] = 0; + max[MediumSensorDeployable] = 0; + max[LargeSensorDeployable] = 0; + max[SpySatelliteDeployable] = 0; + //Misc + max[JumpadDeployable] = 0; + max[EscapePodDeployable] = 0; + max[ForceFieldDeployable] = 0; + max[GravityFieldDeployable] = 0; + max[VehiclePadPack] = 0; +}; + //CREATION function SpawnInsignia(%position) { %Zombie = new player(){ diff --git a/scripts/TWM2/Bosses/ShadeLord.cs b/scripts/TWM2/Bosses/ShadeLord.cs index 33118a3..b0445bb 100644 --- a/scripts/TWM2/Bosses/ShadeLord.cs +++ b/scripts/TWM2/Bosses/ShadeLord.cs @@ -1,4 +1,103 @@ //SHADE LORD +datablock ParticleData(ShadeSwordParticle) { + dragCoeffiecient = 0.0; + gravityCoefficient = -0.2; + inheritedVelFactor = 0.0; + + lifetimeMS = 800; + lifetimeVarianceMS = 500; + + useInvAlpha = false; + spinRandomMin = -160.0; + spinRandomMax = 160.0; + + animateTexture = true; + framesPerSec = 15; + + textureName = "special/cloudflash"; + + colors[0] = "46 46 46 1.0"; + colors[1] = "46 46 46 1.0"; + colors[2] = "46 46 46 1.0"; + + sizes[0] = 2.5; + sizes[1] = 2.7; + sizes[2] = 3.0; + + times[0] = 0.0; + times[1] = 0.7; + times[2] = 1.0; +}; + +datablock ParticleEmitterData(ShadeSwordEmitter) { + ejectionPeriodMS = 10; + periodVarianceMS = 0; + + ejectionVelocity = 1.5; + velocityVariance = 0.3; + + thetaMin = 0.0; + thetaMax = 30.0; + + particles = "ShadeSwordParticle"; +}; + +datablock SeekerProjectileData(ShadeLordSword){ + casingShapeName = "weapon_missile_casement.dts"; + projectileShapeName = "weapon_missile_projectile.dts"; + hasDamageRadius = true; + indirectDamage = 0.8; + damageRadius = 8.0; + radiusDamageType = $DamageType::Missile; + kickBackStrength = 2000; + + explosion = "MissileExplosion"; + splash = MissileSplash; + velInheritFactor = 1.0; // to compensate for slow starting velocity, this value + // is cranked up to full so the missile doesn't start + // out behind the player when the player is moving + // very quickly - bramage + + delayEmitter = MissileFireEmitter; + puffEmitter = MissilePuffEmitter; + bubbleEmitter = GrenadeBubbleEmitter; + bubbleEmitTime = 1.0; + + exhaustEmitter = MissileLauncherExhaustEmitter; + exhaustTimeMs = 300; + exhaustNodeName = "muzzlePoint1"; + + lifetimeMS = 30000; + muzzleVelocity = 10.0; + maxVelocity = 250.0; + turningSpeed = 110.0; + acceleration = 450.0; + + proximityRadius = 3; + + terrainAvoidanceSpeed = 180; + terrainScanAhead = 25; + terrainHeightFail = 12; + terrainAvoidanceRadius = 100; + + flareDistance = 200; + flareAngle = 30; + + sound = MissileProjectileSound; + + hasLight = true; + lightRadius = 5.0; + lightColor = "0.2 0.05 0"; + + useFlechette = true; + flechetteDelayMs = 550; + casingDeb = FlechetteDebris; + + explodeOnWaterImpact = false; + + baseEmitter = ShadeSwordEmitter; +}; + function ShadeLordSword::OnExplode(%data, %proj, %pos, %mod) { %source = %proj.SourceObject; InitContainerRadiusSearch(%pos, 6, $TypeMasks::PlayerObjectType); @@ -35,7 +134,274 @@ function doReturnMissile(%ini, %src) { %p.sourceObject = %src; } +datablock ParticleData(ShadeStormParticle) { + dragCoefficient = 1.0; + gravityCoefficient = 0.00; + windcoefficient = 0.0; + inheritedVelFactor = 0.0; + constantAcceleration = 10.0; + lifetimeMS = 1000; + lifetimeVarianceMS = 100; + useInvAlpha = true; + spinRandomMin = -90.0; + spinRandomMax = 90.0; + textureName = "special/cloudFlash"; + + colors[0] = "46 46 46 0.5"; + colors[1] = "46 46 46 0.5"; + colors[2] = "46 46 46 0.0"; + sizes[0] = 500; + sizes[1] = 500; + sizes[2] = 500; + times[0] = 0.0; + times[1] = 0.5; + times[2] = 1.0; +}; + +datablock ParticleEmitterData(ShadeStormEmitter) { + ejectionPeriodMS = 1; + periodVarianceMS = 0; + ejectionVelocity = 400.0; + velocityVariance = 150.0; + ejectionOffset = 0.0; + thetaMin = 85; + thetaMax = 85; + phiReferenceVel = 0; + phiVariance = 360; + overrideAdvances = false; + particles = "ShadeStormParticle"; +}; + +datablock ParticleData(dayCloakSmokeParticles) { + dragCoefficient = 50;/////////----------------------- + gravityCoefficient = 0.0; + inheritedVelFactor = 1.0; + constantAcceleration = 1.0; + lifetimeMS = 1000; + lifetimeVarianceMS = 0; + useInvAlpha = true; + spinRandomMin = -360.0; + spinRandomMax = 360.0; + textureName = "particleTest"; + colors[0] = "0.1 0.1 0.1 1.0";// //////////////////// + colors[1] = "0.1 0.1 0.1 1.0";// //////////////////// + colors[2] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ + colors[3] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ + sizes[0] = 350.0; + sizes[1] = 350.0; + sizes[2] = 350.0; + sizes[3] = 350.0; + times[0] = 0.0; + times[1] = 0.33; + times[2] = 0.66; + times[3] = 1.0; + mass = 0.4; + elasticity = 0.2; + friction = 1; + computeCRC = true; + haslight = true; + lightType = "PulsingLight"; + lightColor = "0.2 0.0 0.5 1.0"; + lightTime = "200"; + lightRadius = "2.0"; +}; + +datablock ParticleEmitterData(dayCloakEmitter) { + ejectionPeriodMS = 50; + periodVarianceMS = 0; + ejectionVelocity = 10.0; + velocityVariance = 0.0; + ejectionOffset = 2; + thetaMin = 0; + thetaMax = 180; + overrideAdvances = false; + particles = "dayCloakSmokeParticles"; +}; + // +datablock ParticleData(ShadeLordScreamParticle) { + dragCoefficient = 1.0; + gravityCoefficient = 0.00; + windcoefficient = 0.0; + inheritedVelFactor = 0.0; + constantAcceleration = 10.0; + lifetimeMS = 1000; + lifetimeVarianceMS = 100; + useInvAlpha = true; + spinRandomMin = -90.0; + spinRandomMax = 90.0; + textureName = "special/cloudFlash"; + + colors[0] = "156 0 0 0.5"; + colors[1] = "156 0 0 0.5"; + colors[2] = "156 0 0 0.0"; + sizes[0] = 500; + sizes[1] = 500; + sizes[2] = 2; + times[0] = 0.0; + times[1] = 0.5; + times[2] = 1.0; +}; + +datablock ParticleEmitterData(ShadeLordScreamEmitter) { + ejectionPeriodMS = 1; + periodVarianceMS = 0; + ejectionVelocity = 400.0; + velocityVariance = 150.0; + ejectionOffset = 0.0; + thetaMin = 85; + thetaMax = 85; + phiReferenceVel = 0; + phiVariance = 360; + overrideAdvances = false; + particles = "ShadeLordScreamParticle"; +}; +// + +datablock PlayerData(ShadeLordArmor) : LightMaleHumanArmor { + boundingBox = "1.63 1.63 2.6"; + maxDamage = 900.0; + minImpactSpeed = 35; + shapeFile = "bioderm_heavy.dts"; + + debrisShapeName = "bio_player_debris.dts"; + + //Foot Prints + decalData = HeavyBiodermFootprint; + decalOffset = 0.4; + + waterBreathSound = WaterBreathBiodermSound; + + damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs + damageScale[$DamageType::Fire] = 3.0; + damageScale[$DamageType::Plasma] = 3.0; + damageScale[$DamageType::Burn] = 2.0; + + max[RepairKit] = 0; + max[Mine] = 0; + max[Grenade] = 0; + max[SmokeGrenade] = 0; + max[BeaconSmokeGrenade] = 0; + max[Blaster] = 0; + max[Plasma] = 0; + max[PlasmaAmmo] = 0; + max[Disc] = 0; + max[DiscAmmo] = 0; + max[SniperRifle] = 0; + max[GrenadeLauncher] = 0; + max[GrenadeLauncherAmmo] = 0; + max[Mortar] = 0; + max[MortarAmmo] = 0; + max[MissileLauncher] = 0; + max[MissileLauncherAmmo] = 0; + max[Chaingun] = 0; + max[ChaingunAmmo] = 0; + max[RepairGun] = 0; + max[CloakingPack] = 0; + max[SensorJammerPack] = 0; + max[EnergyPack] = 0; + max[RepairPack] = 0; + max[ShieldPack] = 0; + max[AmmoPack] = 0; + max[SatchelCharge] = 0; + max[MortarBarrelPack] = 0; + max[MissileBarrelPack] = 0; + max[AABarrelPack] = 0; + max[PlasmaBarrelPack] = 0; + max[ELFBarrelPack] = 0; + max[artillerybarrelpack] = 0; + max[MedPack] = 0; + max[InventoryDeployable] = 0; + max[MotionSensorDeployable] = 0; + max[PulseSensorDeployable] = 0; + max[TurretOutdoorDeployable] = 0; + max[TurretIndoorDeployable] = 0; + max[FlashGrenade] = 0; + max[ConcussionGrenade] = 0; + max[FlareGrenade] = 0; + max[TargetingLaser] = 0; + max[ELFGun] = 0; + max[ShockLance] = 0; + max[CameraGrenade] = 0; + max[Beacon] = 0; + max[flamerAmmoPack] = 0; + max[ParachutePack] = 0; + max[ConstructionTool] = 0; + max[MergeTool] = 0; + max[NerfGun] = 0; + max[NerfBallLauncher] = 0; + max[NerfBallLauncherAmmo] = 0; + max[SuperChaingun] = 0; + max[SuperChaingunAmmo] = 0; + max[RPChaingun] = 0; + max[RPChaingunAmmo] = 0; + max[MGClip] = 0; + max[LSMG] = 0; + max[LSMGAmmo] = 0; + max[LSMGClip] = 0; + max[snipergun] = 0; + max[snipergunAmmo] = 0; + max[Bazooka] = 0; + max[BazookaAmmo] = 0; + max[BunkerBuster] = 0; + max[MG42] = 0; + max[MG42Ammo] = 0; + max[SPistol] = 0; + max[Pistol] = 0; + max[PistolAmmo] = 0; + max[Pistolclip] = 0; + max[flamer] = 0; + max[flamerAmmo] = 0; + max[AALauncher] = 0; + max[AALauncherAmmo] = 0; + max[melee] = 0; + max[SOmelee] = 0; + max[KriegRifle] = 0; + max[KriegAmmo] = 0; + max[Rifleclip] = 0; + max[Shotgun] = 0; + max[ShotgunAmmo] = 0; + max[ShotgunClip] = 0; + max[RShotgun] = 0; + max[RShotgunAmmo] = 0; + max[RShotgunClip] = 0; + max[LMissileLauncher] = 0; + max[LMissileLauncherAmmo] = 0; + max[HRPChaingun] = 0; + max[RPGAmmo] = 0; + max[RPGItem] = 0; + max[spineDeployable] = 0; + max[mspineDeployable] = 0; + max[wWallDeployable] = 0; + max[floorDeployable] = 0; + max[WallDeployable] = 0; + max[DoorDeployable] = 0; + max[TurretLaserDeployable] = 0; + max[TurretMissileRackDeployable]= 0; + max[DiscTurretDeployable] = 0; + max[EnergizerDeployable] = 0; + max[TreeDeployable] = 0; + max[CrateDeployable] = 0; + max[DecorationDeployable] = 0; + max[LogoProjectorDeployable] = 0; + max[LightDeployable] = 0; + max[TripwireDeployable] = 0; + max[TelePadPack] = 0; + max[TurretBasePack] = 0; + max[LargeInventoryDeployable] = 0; + max[GeneratorDeployable] = 0; + max[SolarPanelDeployable] = 0; + max[SwitchDeployable] = 0; + max[MediumSensorDeployable] = 0; + max[LargeSensorDeployable] = 0; + max[SpySatelliteDeployable] = 0; + max[JumpadDeployable] = 0; + max[EscapePodDeployable] = 0; + max[ForceFieldDeployable] = 0; + max[GravityFieldDeployable] = 0; + max[VehiclePadPack] = 0; +}; + function SpawnShadeLord(%position) { %Boss = new player(){ Datablock = "ShadeLordArmor"; diff --git a/scripts/TWM2/Bosses/Stormrider.cs b/scripts/TWM2/Bosses/Stormrider.cs index 17bec57..ba636fb 100644 --- a/scripts/TWM2/Bosses/Stormrider.cs +++ b/scripts/TWM2/Bosses/Stormrider.cs @@ -1,42 +1,31 @@ -//Stormrider.cs -//Ported From TWM1 -//Code Updated By Phantom139 -// * 2-18-14: Did some housecleaning, harvested some unneeded functions here. - function UltrDroneBattle(%pos, %radius, %number, %teamlow, %teamhigh, %maxskill, %slth){ for(%i = 0; %i < %number; %i++){ - %startpos = vectorAdd(%pos,(getRandom(0, %radius) - (%radius / 2))@" "@(getRandom(0, %radius) - (%radius / 2))@" 0"); - %rotation = "0 0 1 "@getRandom(1,360); - if(%teamlow != %teamhigh) { - %team = getRandom(%teamlow, %teamhigh); - } - else { - %team = %teamlow; - } - StartUltrDrone(%startpos,%rotation,%team,getRandom(1,%maxskill), %slth); + %startpos = vectorAdd(%pos,(getRandom(0, %radius) - (%radius / 2))@" "@(getRandom(0, %radius) - (%radius / 2))@" 0"); + %rotation = "0 0 1 "@getRandom(1,360); + if(%teamlow != %teamhigh) + %team = getRandom(%teamlow,%teamhigh); + else + %team = %teamlow; + StartUltrDrone(%startpos,%rotation,%team,getRandom(1,%maxskill), %slth); } } //This sets up the drone and the functions needed to start the drone. -function StartUltrDrone(%pos, %rotation, %team, %skill, %slth) { - if(%team $= "") { - %team = 0; +function StartUltrDrone(%pos, %rotation, %team, %skill, %slth){ + if(%team $= "") + %team = 0; + if(%pos $= "") + %pos = "0 0 300"; + if(%rotation $= "") + %rotation = "1 0 0 0"; + if(%skill !$= "ace"){ + if(%skill $= "" || %skill < 1) + %skill = 10; + else if(%skill > 10) + %skill = 10; } - if(%pos $= "") { - %pos = "0 0 300"; - } - if(%rotation $= "") { - %rotation = "1 0 0 0"; - } - if(%skill !$= "ace") { - if(%skill $= "" || %skill < 1) { - %skill = 10; - } - else if(%skill > 10) { - %skill = 10; - } - } - %Drone = new FlyingVehicle() { + %Drone = new FlyingVehicle() + { dataBlock = StormSeigeDrone; position = %pos; rotation = %rotation; @@ -50,12 +39,12 @@ function StartUltrDrone(%pos, %rotation, %team, %skill, %slth) { %drone.dodgeGround = 0; if(%slth) { - %Drone.setCloaked(true); + %Drone.setCloaked(true); } if(%skill $= "ace"){ - %skill = 10; - %drone.isace = 1; + %skill = 10; + %drone.isace = 1; } %drone.skill = 0.2 + (%skill / 12.5); @@ -85,229 +74,241 @@ function StartStormrider(%position) { function UltraBossAbilities(%drone) { if(!isObject(%drone)) { - return; + return; } %drone.setCloaked(false); //disable cloak? %rand = getRandom(1,13); - +// %target = DroneFindNearestPilot(500,%drone); //this line for targeted abilities switch(%rand) { - - //1: Double Missile Strike: Targets Single Player with Two Missiles case 1: - %target = DroneFindNearestPilot(2000, %drone); + %target = DroneFindNearestPilot(2000,%drone); if(%target.player) { - %SPos1 = vectorAdd(%drone.getPosition(),"3 0 0"); - %SPos2 = vectorAdd(%drone.getPosition(),"-3 0 0"); - %p1 = new SeekerProjectile() { - dataBlock = LordRogStiloutte; - initialDirection = "0 0 10"; - initialPosition = %SPos1; - sourceObject = %drone; - sourceSlot = 6; - }; - %p2 = new SeekerProjectile() { - dataBlock = LordRogStiloutte; - initialDirection = "0 0 10"; - initialPosition = %SPos1; - sourceObject = %drone; - sourceSlot = 6; - }; - MissionCleanup.add(%p1); - MissionCleanup.add(%p2); - schedule(1000, 0, WindshearAttack_FUNC, "MissileDrop", %target.player SPC %p1); - schedule(1000, 0, WindshearAttack_FUNC, "MissileDrop", %target.player SPC %p2); - MessageAll('MessageAll', "\c4Stormrider: Fire!"); - } - else { - MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": No targets for me!"); - } - - //2: Quad Strike: Fire Four Missiles out in a + pattern which then aquire a single target. + %SPos1 = vectorAdd(%drone.getPosition(),"3 0 0"); + %SPos2 = vectorAdd(%drone.getPosition(),"-3 0 0"); + %p1 = new SeekerProjectile() + { + dataBlock = LordRogStiloutte; + initialDirection = "0 0 10"; + initialPosition = %SPos1; + sourceObject = %drone; + sourceSlot = 6; + }; + %p2 = new SeekerProjectile() + { + dataBlock = LordRogStiloutte; + initialDirection = "0 0 10"; + initialPosition = %SPos2; + sourceObject = %drone; + sourceSlot = 6; + }; + MissionCleanup.add(%p1); + MissionCleanup.add(%p2); + schedule(1000,0,"MissileDrop",%p1, %target.player); + schedule(1000,0,"MissileDrop",%p2, %target.player); + MessageAll('MessageAll', "\c4Stormrider: Fire!"); + } + else { + MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Heh, no targets for me!"); + } case 2: - %target = DroneFindNearestPilot(2000, %drone); + %target = DroneFindNearestPilot(2000,%drone); if(%target.player) { - %SPos = vectorAdd(%drone.getPosition(),"0 0 3"); - %dirs = "5 0 0\t-5 0 0\t0 5 0\t0 -5 0"; - for(%i = 0; %i < getFieldCount(%dirs); %i++) { - %newMissile = new SeekerProjectile() { - dataBlock = ShoulderMissile; - initialDirection = getField(%dirs, %i); - initialPosition = %SPos; - sourceObject = %drone; - sourceSlot = 6; - }; - MissionCleanup.add(%newMissile); - schedule(1000, 0, WindshearAttack_FUNC, "MissileDrop", %target.player SPC %newMissile); - } - MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Have fun with these "@getTaggedString(%target.name)@"!"); - } - else { - MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Bah, no targets, no fun."); - } - - //3: IR Beam: A single enemy target gets locked on with a heat beam making missiles 100% accurate for a time period + %SPos = vectorAdd(%drone.getPosition(),"0 0 3"); + %p1 = new SeekerProjectile() + { + dataBlock = ShoulderMissile; + initialDirection = "5 0 0"; + initialPosition = %SPos; + sourceObject = %drone; + sourceSlot = 6; + }; + %p2 = new SeekerProjectile() + { + dataBlock = ShoulderMissile; + initialDirection = "-5 0 0"; + initialPosition = %SPos; + sourceObject = %drone; + sourceSlot = 6; + }; + %p3 = new SeekerProjectile() + { + dataBlock = ShoulderMissile; + initialDirection = "0 5 0"; + initialPosition = %SPos; + sourceObject = %drone; + sourceSlot = 6; + }; + %p4 = new SeekerProjectile() + { + dataBlock = ShoulderMissile; + initialDirection = "0 -5 0"; + initialPosition = %SPos; + sourceObject = %drone; + sourceSlot = 6; + }; + MissionCleanup.add(%p1); + MissionCleanup.add(%p2); + MissionCleanup.add(%p3); + MissionCleanup.add(%p4); + schedule(1000, 0, WindshearAttack_FUNC, "MissileDrop", %target.player SPC %p1); + schedule(1000, 0, WindshearAttack_FUNC, "MissileDrop", %target.player SPC %p2); + schedule(1000, 0, WindshearAttack_FUNC, "MissileDrop", %target.player SPC %p3); + schedule(1000, 0, WindshearAttack_FUNC, "MissileDrop", %target.player SPC %p4); + + MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Have fun with these "@getTaggedString(%target.name)@"!"); + } + else { + MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Bah, no targets, no fun."); + } case 3: - %target = DroneFindNearestPilot(2000, %drone); + %target = DroneFindNearestPilot(2000,%drone); if(%target.player) { - HeatLoop(%target.player, 0); - MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Lets see what happens when missiles are completely precice on you, "@getTaggedString(%target.name)@"!"); - } - else { - MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": I guess it's time to start scanning."); - } - - //4: Auxilary Pod Swarm: Unleash a swarm of hybrid strike missiles on a single enemy target + HeatLoop(%target.player, 0); + MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Lets see what happens when missiles are completely precice on you, "@getTaggedString(%target.name)@"!"); + } + else { + MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": I guess it's time to start scanning."); + } case 4: - %target = DroneFindNearestPilot(2000, %drone); + %target = DroneFindNearestPilot(2000,%drone); if(%target.player) { - FireanotherSidewinder(%drone, %target.player, 3); - schedule(700, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); - schedule(1400, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); - schedule(2100, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); - schedule(2800, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); - schedule(3500, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); - schedule(4200, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); - schedule(4900, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); - //Rapid Shot Missiles - schedule(5000, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); - schedule(5200, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); - schedule(5400, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); - schedule(5600, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); - schedule(5800, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); - schedule(6000, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); - schedule(6200, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); - schedule(6400, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); - schedule(6500, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); - MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Taste my fury "@getTaggedString(%target.name)@"!"); - } - else { - MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Aww, My missiles were ready."); - } - - //5: Focused Missile Fire: Similar to APS, but more accurate with less shots near the end + FireanotherSidewinder(%drone, %target.player, 3); + schedule(700,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); + schedule(1400,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); + schedule(2100,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); + schedule(2800,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); + schedule(3500,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); + schedule(4200,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); + schedule(4900,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); + //Rapid Shot Missiles + schedule(5000,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); + schedule(5200,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); + schedule(5400,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); + schedule(5600,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); + schedule(5800,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); + schedule(6000,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); + schedule(6200,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); + schedule(6400,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); + schedule(6500,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); + MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Taste my fury "@getTaggedString(%target.name)@"!"); + } + else { + MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Aww, My missiles were ready."); + } case 5: - %target = DroneFindNearestPilot(2000, %drone); + %target = DroneFindNearestPilot(2000,%drone); if(%target.player) { - FireanotherSidewinder(%drone, %target.player, 3); - schedule(700, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); - schedule(1400, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); - schedule(2100, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); - schedule(2800, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); - schedule(3500, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); - schedule(4200, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); - schedule(4900, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); - schedule(5600, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); - schedule(6300, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); - schedule(7000, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); - // Quick Shots - schedule(8000, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); - schedule(8100, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); - schedule(8200, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); - schedule(8300, 0, "WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); - MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": I have missiles with your name on them "@getTaggedString(%target.name)@"!"); - } - else { - MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Aww, My missile strike was ready."); - } - - //6: Clear Skies: Launch a wave on anti-missile flares blocking all missiles from striking Stormrider for a short time. + FireanotherSidewinder(%drone, %target.player, 3); + schedule(700,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); + schedule(1400,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); + schedule(2100,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); + schedule(2800,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); + schedule(3500,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); + schedule(4200,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); + schedule(4900,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); + schedule(5600,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); + schedule(6300,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); + schedule(7000,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 3); + // Quick Shots + schedule(8000,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); + schedule(8100,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); + schedule(8200,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); + schedule(8300,0,"WindshearAttack_FUNC", "SidewinderLaunch", %drone SPC %target.player SPC 1); + MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": I have missiles with your name on them "@getTaggedString(%target.name)@"!"); + } + else { + MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Aww, My missile strike was ready."); + } case 6: - schedule(700, 0, "WindshearAttack_FUNC", "Flare", %drone); - schedule(1400, 0, "WindshearAttack_FUNC", "Flare", %drone); - schedule(2100, 0, "WindshearAttack_FUNC", "Flare", %drone); - schedule(2800, 0, "WindshearAttack_FUNC", "Flare", %drone); - schedule(3500, 0, "WindshearAttack_FUNC", "Flare", %drone); - schedule(4200, 0, "WindshearAttack_FUNC", "Flare", %drone); - schedule(4900, 0, "WindshearAttack_FUNC", "Flare", %drone); - schedule(5600, 0, "WindshearAttack_FUNC", "Flare", %drone); - schedule(6300, 0, "WindshearAttack_FUNC", "Flare", %drone); - schedule(7000, 0, "WindshearAttack_FUNC", "Flare", %drone); - // Quick Shots - schedule(8000, 0, "WindshearAttack_FUNC", "Flare", %drone); - schedule(8100, 0, "WindshearAttack_FUNC", "Flare", %drone); - schedule(8200, 0, "WindshearAttack_FUNC", "Flare", %drone); - schedule(8300, 0, "WindshearAttack_FUNC", "Flare", %drone); - MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Hahaha, Your Missiles are worthless Now!"); - - //7: Anti-Ground Chaingun: Fire a rapid strike anti-matter chaingun which does heavy damage to hit targets + schedule(700,0,"WindshearAttack_FUNC", "Flare", %drone); + schedule(1400,0,"WindshearAttack_FUNC", "Flare", %drone); + schedule(2100,0,"WindshearAttack_FUNC", "Flare", %drone); + schedule(2800,0,"WindshearAttack_FUNC", "Flare", %drone); + schedule(3500,0,"WindshearAttack_FUNC", "Flare", %drone); + schedule(4200,0,"WindshearAttack_FUNC", "Flare", %drone); + schedule(4900,0,"WindshearAttack_FUNC", "Flare", %drone); + schedule(5600,0,"WindshearAttack_FUNC", "Flare", %drone); + schedule(6300,0,"WindshearAttack_FUNC", "Flare", %drone); + schedule(7000,0,"WindshearAttack_FUNC", "Flare", %drone); + // Quick Shots + schedule(8000,0,"WindshearAttack_FUNC", "Flare", %drone); + schedule(8100,0,"WindshearAttack_FUNC", "Flare", %drone); + schedule(8200,0,"WindshearAttack_FUNC", "Flare", %drone); + schedule(8300,0,"WindshearAttack_FUNC", "Flare", %drone); + MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Hahaha, Your Missiles are worthless Now!"); case 7: - %target = DroneFindNearestPilot(2000, %drone); + %target = DroneFindNearestPilot(2000,%drone); if(%target.player) { - FireSniperShots(%drone, %target.player, 3); - for(%i = 0; %i < 700; %i++) { - %time = %i * 10; - schedule(%time, 0,"FireSniperShots",%drone, %target.player); - } - MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Time to Use My CG, "@getTaggedString(%target.name)@"!"); - } - else { - MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": We'll see who can withstand the CG... Oh wait, there's nobody there."); - } - - //8: Photon Seekers: Launch a wave of Photon Seekers to strike a single target + FireSniperShots(%drone, %target.player, 3); + for(%i = 0; %i < 700; %i++) { + %time = %i * 10; + schedule(%time, 0,"FireSniperShots",%drone, %target.player); + } + // Quick Shots + schedule(8000,0,"FireSniperShots",%drone, %target.player); + schedule(8100,0,"FireSniperShots",%drone, %target.player); + schedule(8200,0,"FireSniperShots",%drone, %target.player); + schedule(8300,0,"FireSniperShots",%drone, %target.player); + MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Time to Use My CG, "@getTaggedString(%target.name)@"!"); + } + else { + MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Heh, you fewls cant withstand this."); + } case 8: - %target = DroneFindNearestPilot(2000, %drone); + %target = DroneFindNearestPilot(2000,%drone); if(%target.player) { - FireSeekerPhotons(%drone, %target.player); - schedule(1500, 0, "FireSeekerPhotons", %drone, %target.player); - schedule(3000, 0, "FireSeekerPhotons", %drone, %target.player); - schedule(4500, 0, "FireSeekerPhotons", %drone, %target.player); - schedule(6000, 0, "FireSeekerPhotons", %drone, %target.player); - MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Here, "@getTaggedString(%target.name)@", Catch!"); - } - else { - MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Close up the Seekers. No Targets To hit."); - } - - //9: Advanced Photon Wave: Launch an additional Photon Missile compared to #8 + FireSeekerPhotons(%drone,%target.player); + schedule(1500,0,"FireSeekerPhotons",%drone,%target.player); + schedule(3000,0,"FireSeekerPhotons",%drone,%target.player); + schedule(4500,0,"FireSeekerPhotons",%drone,%target.player); + schedule(6000,0,"FireSeekerPhotons",%drone,%target.player); + MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Here, "@getTaggedString(%target.name)@", Catch!"); + } + else { + MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Close up the Seekers. No Targets To hit."); + } case 9: %target = DroneFindNearestPilot(2000,%drone); if(%target.player) { - FireSeekerPhotons(%drone,%target.player); - schedule(700, 0, "FireSeekerPhotons",%drone,%target.player); - schedule(1400, 0, "FireSeekerPhotons",%drone,%target.player); - schedule(2100, 0, "FireSeekerPhotons",%drone,%target.player); - schedule(2800, 0, "FireSeekerPhotons",%drone,%target.player); - schedule(3500, 0, "FireSeekerPhotons",%drone,%target.player); - MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Try these out for size, "@getTaggedString(%target.name)@"!"); - } - else { - MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Heh, No enemies in the area."); - } - - //10: Photon Storm: Launch Photon Missiles to the point of overheating the internal system. + FireSeekerPhotons(%drone,%target.player); + schedule(700,0,"FireSeekerPhotons",%drone,%target.player); + schedule(1400,0,"FireSeekerPhotons",%drone,%target.player); + schedule(2100,0,"FireSeekerPhotons",%drone,%target.player); + schedule(2800,0,"FireSeekerPhotons",%drone,%target.player); + schedule(3500,0,"FireSeekerPhotons",%drone,%target.player); + MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Try these out for size, "@getTaggedString(%target.name)@"!"); + } + else { + MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Heh, No enemies in the area."); + } case 10: - %target = DroneFindNearestPilot(2000, %drone); + %target = DroneFindNearestPilot(2000,%drone); if(%target.player) { - FireSeekerPhotons(%drone, %target.player); - schedule(500, 0, "FireSeekerPhotons", %drone, %target.player); - schedule(1000, 0, "FireSeekerPhotons", %drone, %target.player); - schedule(1500, 0, "FireSeekerPhotons", %drone, %target.player); - schedule(2000, 0, "FireSeekerPhotons", %drone, %target.player); - schedule(2500, 0, "FireSeekerPhotons", %drone, %target.player); - schedule(3000, 0, "FireSeekerPhotons", %drone, %target.player); - schedule(3500, 0, "FireSeekerPhotons", %drone, %target.player); - schedule(4000, 0, "FireSeekerPhotons", %drone, %target.player); - schedule(4500, 0, "FireSeekerPhotons", %drone, %target.player); - schedule(5000, 0, "FireSeekerPhotons", %drone, %target.player); - MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": I have some fun plasma missiles for you, "@getTaggedString(%target.name)@"!"); - } - else { - MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Meh, No targets for my plasma seekers."); - } - - //11: Tactical Camo: Engage an invisibility module to blend in with the sky. + FireSeekerPhotons(%drone,%target.player); + schedule(500,0,"FireSeekerPhotons",%drone,%target.player); + schedule(1000,0,"FireSeekerPhotons",%drone,%target.player); + schedule(1500,0,"FireSeekerPhotons",%drone,%target.player); + schedule(2000,0,"FireSeekerPhotons",%drone,%target.player); + schedule(2500,0,"FireSeekerPhotons",%drone,%target.player); + schedule(3000,0,"FireSeekerPhotons",%drone,%target.player); + schedule(3500,0,"FireSeekerPhotons",%drone,%target.player); + schedule(4000,0,"FireSeekerPhotons",%drone,%target.player); + schedule(4500,0,"FireSeekerPhotons",%drone,%target.player); + schedule(5000,0,"FireSeekerPhotons",%drone,%target.player); + MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": I have some fun plasma missiles for you, "@getTaggedString(%target.name)@"!"); + } + else { + MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Meh, No targets for my plasma seekers."); + } case 11: - MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Engage Stealth!"); - %drone.setCloaked(true); - - //11: Wingmen: Call in 4 Harbinger Aerial Drones to engage air and ground targets. + MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": Engage Stealth!"); + %drone.setCloaked(true); case 12: - MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": My Buddies will handle You!"); - %SPos1 = vectorAdd(%drone.getPosition(), "15 0 0"); - %SPos2 = vectorAdd(%drone.getPosition(), "-15 0 0"); - %SPos3 = vectorAdd(%drone.getPosition(), "0 15 0"); - %SPos4 = vectorAdd(%drone.getPosition(), "0 -15 0"); + MessageAll('MessageAll', "\c4"@$TWM2::BossName["Stormrider"]@": My Buddies will handle You!"); + %SPos1 = vectorAdd(%drone.getPosition(),"15 0 0"); + %SPos2 = vectorAdd(%drone.getPosition(),"-15 0 0"); + %SPos3 = vectorAdd(%drone.getPosition(),"0 15 0"); + %SPos4 = vectorAdd(%drone.getPosition(),"0 -15 0"); %d2 = DroneBattle(%SPos1, 500, 1, 6, 6, 100, 0); //his Pal %d3 = DroneBattle(%SPos2, 500, 1, 6, 6, 100, 0); //his Other Pal %d4 = DroneBattle(%SPos3, 500, 1, 6, 6, 100, 0); //his Pal's Pal @@ -316,8 +317,6 @@ function UltraBossAbilities(%drone) { %d3.isUltrally = 1; %d4.isUltrally = 1; %d5.isUltrally = 1; - - //DE: Reinforcements: Call in support from Harbinger Drones default: %SPos1 = vectorAdd(%drone.getPosition(),"15 0 0"); %SPos2 = vectorAdd(%drone.getPosition(),"15 0 0"); @@ -355,21 +354,189 @@ sourceSlot = 6; } function FireSeekerPhotons(%drone,%target){ - if(!isObject(%drone) || !isObject(%target) || %target.getState() $= "dead") { - return; - } - - %proj = createSeekingProjectile(PhotonMissileProj, linearflareprojectile, vectorAdd(%drone.getPosition(), "0 0 5") - , "0 0 3", %drone, %target, 100); - - MissionCleanup.add(%proj); - %proj.PhotonMuzVec = %drone.getMuzzleVector(5); - schedule( 100,0, "PhotonShockwaveFunc" ,%drone,%Proj); +if(!isObject(%drone) || !isObject(%target) || %target.getState() $= "dead") { +return; } +%proj = new (linearflareprojectile)() { +dataBlock = PhotonMissileProj; +initialDirection = "0 0 3"; +initialPosition = vectorAdd(%drone.getPosition(), "0 0 5"); +sourceObject = %drone; +sourceSlot = 0; +}; + +MissionCleanup.add(%proj); +%proj.PhotonMuzVec = %drone.getMuzzleVector(5); +schedule( 100,0, "seekingprojs" , %drone, %Proj, %target); +schedule( 100,0, "PhotonShockwaveFunc" ,%drone,%Proj); +} + +//Seeker Plasma Stuff +//Credit To Abrikcham +//-abirikcham@yahoo.com +datablock ShockwaveData(FakePhotonMissileShockwave)//this is the shockwave trail effect +{ +width = 0.5; +numSegments = 30; +numVertSegments = 2; +velocity = 8; +verticalcurve = 0; +acceleration = -17.0; +lifetimeMS = 600; +height = 0.00001; +is2D = false; +texture[0] = "special/shockwave4"; +texture[1] = "special/gradient"; +texWrap = 10.0; +mapToTerrain = false; +orientToNormal = true; +renderBottom = true; +times[0] = 0.0; +times[1] = 0.5; +times[2] = 1.0; +colors[0] = "0 1 0 1"; +colors[1] = "0.0 1.1 0.0 0.60";//0.4 0.1 1.0 +colors[2] = "0.0 1.1 0.0 0.0"; +}; + +datablock AudioProfile(FakePhotonMissileShockwaveSound)//sound thing for shockwave +{ + filename = "fx/misc/gridjump.wav"; + description = AudioExplosion3d; + preload = true; +}; + +datablock ExplosionData(FakePhotonShockwaveExp)//dont touch thx +{ + soundProfile = FakePhotonMissileShockwaveSound; + faceViewer = false; + shockwave = FakePhotonMissileShockwave; + + shakeCamera = true; + camShakeFreq = "10.0 6.0 9.0"; + camShakeAmp = "20.0 20.0 20.0"; + camShakeDuration = 0.5; + camShakeRadius = 3.0; +}; + +datablock LinearProjectileData(FakePhotonShockwaveProj)//dont touch thx +{ + projectileShapeName = "turret_muzzlepoint.dts"; + scale = "0.1 0.1 0.1"; + faceViewer = true; + directDamage = 0; + hasDamageRadius = false; + indirectDamage = 0.1; + damageRadius = 10; + kickBackStrength = 1; + radiusDamageType = $DamageType::Photon; + explosion = "FakePhotonShockwaveExp"; + dryVelocity = 0.0001; + wetVelocity = 0.00001; + velInheritFactor = 0.0; + lifetimeMS = 0.00000001; + explodeOnDeath = true; + reflectOnWaterImpactAngle = 0.0; + explodeOnWaterImpact = true; + deflectionOnWaterImpact = 0.0; +}; + +datablock ParticleData(PhotonMissileExpPart)//explosion particle stuff ... mitzi +{ + dragCoefficient = 2; + gravityCoefficient = 0.0; + inheritedVelFactor = 0.2; + constantAcceleration = 0.0; + lifetimeMS = 750; + lifetimeVarianceMS = 150; + textureName = "particleTest"; + colors[0] = "0 1 0 1.0"; + colors[1] = "0 1 0 0.0"; + sizes[0] = 3; + sizes[1] = 2; +}; + +datablock ParticleEmitterData(PhotonMissileExpEmit)//explosion particle stuff ... mitzi +{ + ejectionPeriodMS = 7; + periodVarianceMS = 0; + ejectionVelocity = 3; + velocityVariance = 1.0; + ejectionOffset = 0.0; + thetaMin = 0; + thetaMax = 60; + phiReferenceVel = 0; + phiVariance = 360; + overrideAdvances = false; + particles = "PhotonMissileExpPart"; +}; + +datablock ExplosionData(PhotonMissileExplosion)//main proj exp +{ + explosionShape = "disc_explosion.dts"; + soundProfile = UnderwaterGrenadeExplosionSound;//plasmaexpsound orig + + shakeCamera = true; + camShakeFreq = "8.0 9.0 7.0"; + camShakeAmp = "25.0 25.0 25.0"; + camShakeDuration = 1.3; + camShakeRadius = 25.0; + + particleEmitter = PhotonMissileExpEmit; + particleDensity = 150; + particleRadius = 3.5; + faceViewer = true; +}; + //********************************** //* Projectiles * //********************************** +datablock LinearFlareProjectileData(PhotonMissileProj) +{ + scale = "4 4 4";//6 + sound = PlasmaProjectileSound; + + faceViewer = true; + directDamage = 0.0; + hasDamageRadius = true; + indirectDamage = 1.0; + damageRadius = 10.0; + kickBackStrength = 4000; + radiusDamageType = $DamageType::Photon; //obviously change this + + explosion = "PhotonMissileExplosion"; + underwaterExplosion = "PhotonMissileExplosion"; + splash = BlasterSplash; + + dryVelocity = 200.0; + wetVelocity = 200.0; + velInheritFactor = 0.6; + fizzleTimeMS = 8000; + lifetimeMS = 8000; + explodeOnDeath = true; + + reflectOnWaterImpactAngle = 0.0; + explodeOnWaterImpact = false; + deflectionOnWaterImpact = 0.0; + fizzleUnderwaterMS = 15000; + + activateDelayMS = 0; + numFlares = 35; + flareColor = "0.0 1.1 0"; + flareModTexture = "flaremod"; + flareBaseTexture = "flarebase"; + + size[0] = 1; + size[1] = 10; + size[2] = 2; + + + hasLight = true; + lightRadius = 1.0; + lightColor = "0.6 1.1 0"; +}; + function PhotonMissileProj::onExplode(%data, %proj, %pos, %mod)// ok this is where everything is canceled... the scheds.. this is the buggy part { parent::onexplode(%data, %proj, %pos, %mod); @@ -377,3 +544,127 @@ cancel(%proj.seeksched); cancel(%proj.PhotonShockwaveSched); cancel(%proj.seekschedcheck); } + +function seekingprojcheck(%obj,%proj, %type) { + %searchmask = $TypeMasks::PlayerObjectType | $TypeMasks::VehicleObjectType; + + if(%type $= "") { + InitContainerRadiusSearch(%proj.position, 100, %searchmask); + } + else { + InitContainerRadiusSearch(%proj.position, 9999, %searchmask); //For Stormrider + } + while ((%target = containerSearchNext())) + { + if(%target != %obj) + { + if(%target.team == %obj.team && !$TWM::TeamWars) + { + %proj.seekschedcheck = schedule( 50,0, "seekingprojcheck" ,%obj,%Proj,%type); + return; + } + %reptarg = %target; + seekingprojs(%obj,%proj,%reptarg); + return; + } + } +%proj.seekschedcheck = schedule( 50,0, "seekingprojcheck" ,%obj,%Proj,%type); +} + + +function seekingprojs(%obj,%Proj,%reptarg) +{ +%projpos = %proj.position; + +%projdir = %proj.initialdirection; + +%type = %reptarg.getClassName(); + +if(!isobject(%proj)) +{ +return; +} + + if(isobject(%proj)) + { + %proj.delete(); + } + + if(!isobject(%obj)) + { + return; + } + + if(!isobject(%reptarg)) + { + return; + } + + if(%type $= "Player") { + if(%reptarg.getState() $= "Dead") + { + return; + } + } + +//( ... )the projs now have a max turn angle like real missile ub3r l33t;;;; nm wtf afasdf +%test = getWord(%projdir, 0); +%test2 = getWord(%projdir, 1); +%test3 = getWord(%projdir, 2); + +%projdir = vectornormalize(vectorsub(%reptarg.position,%projpos)); +%testa = getWord(%projdir, 0); +%testa2 = getWord(%projdir, 1); +%testa3 = getWord(%projdir, 2); + +// now it's time for my mad math skills..... i used microsoft calculator to figure this one out =0... was a brainbuster for me to think of how this would work +%testthing = %test - %testa; //oh u can rename all this test stuff but make sure u get it right =/ dont break plz +%testfin = %testthing / 8; //!!!!!!!!!! OK HERE!!!! is where the max angle thing is... increase for lower turn angle and reduce for a higher turn angle +%testfinal = %testfin * -1; //^^^^^ *side note for the one above this* dont div by zero unless yer dumb (...) div by i think 1 if you want it to seek with a 360 max turn angle angle... kinda gay though if u do that +%testfinale = %testfinal + %test; + +%testthing2 = %test2 - %testa2; +%testfin2 = %testthing2 / 10; //change here too .. this is for the y axis btw it's best if u leave my setting of 10 on ... it's the most balanced well nm change it to what u want but you really should leave it around this number like 9ish +%testfinal2 = %testfin2 * -1; +%testfinale2 = %testfinal2 + %test2; + +%testthing3 = %test3 - %testa3; +%testfin3 = %testthing3 / 10; //z- axis this one is for i think.. mmm idea... you try playing with dif max angles for xyz for maybe like a sidewinder effect =? +%testfinal3 = %testfin3 * -1; +%testfinale3 = %testfinal3 + %test3; + +%haxordir = %testfinale SPC %testfinale2 SPC %testfinale3; //final dir.. ..... + +%proj = new (linearflareprojectile)() { +dataBlock = PhotonMissileProj; +initialDirection = %haxordir; +initialPosition = %projpos; +sourceslot = %obj; +}; +%proj.sourceobject = %obj; +MissionCleanup.add(%proj); + +%fake = new (linearprojectile)() { +dataBlock = "FakePhotonShockwaveProj"; +initialDirection = %haxordir; +initialPosition = %projpos; +sourceSlot = %obj; +}; +%fake.sourceobject = %obj; +MissionCleanup.add(%fake); + +%searchmask = $TypeMasks::ProjectileObjectType; + +InitContainerRadiusSearch(%projpos, 12, %searchmask); +while ((%target = containerSearchNext())) +{ + if(%target.getdatablock().getname() $= "FlareGrenadeProj") //btw u can add other projs that will cancel out seeking linear flare + { + %target.delete(); + return; + } +} + +%proj.seeksched = schedule( 80,0, "seekingprojs" ,%obj,%Proj,%reptarg); +} + diff --git a/scripts/TWM2/ExteriorFunctioning/PconFunctions.cs b/scripts/TWM2/ExteriorFunctioning/PconFunctions.cs index 459d69e..d9b3670 100644 --- a/scripts/TWM2/ExteriorFunctioning/PconFunctions.cs +++ b/scripts/TWM2/ExteriorFunctioning/PconFunctions.cs @@ -25,6 +25,100 @@ function ServerReturnDate() { // echo(%IntVal); return %IntVal; } + +function DownloadBanList() { + if($Host::UseGlobalBanList) { + $Phantom::BanCount = 0; + %server = "www.phantomdev.net:80"; + if (!isObject(BanGet)) + %Downloader = new HTTPObject(BanGet){}; + else %Downloader = BanGet; + %filename = "/Tribes2/Bans.txt"; + %Downloader.get(%server, %filename); + Error("SERVER: Downloading Global Ban List From PGD.com"); + } + else { + Error("$Host::UseGlobalBanList is 0, G-Ban List Off"); + } +} + +function BanGet::onLine(%this, %line) { + AddToGlobalBanList(%line); +} + +function AddToGlobalBanList(%line) { + %line = detag( %line ); + %text = (%text $= "") ? %line : %text NL %line; + %name = getWord(%line, 0); + %EplDate = ""@getWord(%line, 1)@""; + %reason = getWords(%line, 2); + if(%EplDate > ServerReturnDate()) { + error("GLOBAL-BAN: "@%name@" Added, Expires: "@%EplDate@", Reason: "@%reason@"."); + $Phantom::GlobalBanList[$Phantom::BanCount] = ""@%name@" "@%EplDate@" "@%reason@""; + $Phantom::BanCount++; + } + else { + error("GLOBAL-BAN: "@%name@", This ban has Expired, Not added to list."); + } +} + +function BanGet::onConnectFailed() { + echo("-- Could not connect to PGD."); + echo("Please Call DownloadBanList(); To Protect your server"); +} + +function BanGet::onDisconnect(%this) { + %this.delete(); +} + +function CheckBans(%client) { + for(%i= 0; %i < $Phantom::BanCount; %i++) { + %nametotest = getWord($Phantom::GlobalBanList[%i], 0); + %target = plnametocid(%nametotest); + if(%target != 0) { + %EplDate = getWord($Phantom::GlobalBanList[%i], 1); + if(%EplDate > ServerReturnDate()) { + %reason = getWords($Phantom::GlobalBanList[%i], 2); + banthesucker(%target, %reason, %EplDate); + } + else { + echo(""@getTaggedString(%client.name)@" is on the ban list, but the duration has expired"); + } + } + else { + //Do Nothing + } + } +} + + function banthesucker(%client, %reason, %lengString) { + if($Host::UseGlobalBanList) { + echo("Global-Banned Client "@%client.namebase@" Attempting to Connect"); + MessageAll('Message', "\c2"@%client.namebase@" is Banned Until "@%lengString@" - "@%reason@"."); + if(%lengString > 90000000) { + ban(%client); + %client.setDisconnectReason( "You are Perm. Banned From This Server, "@%reason@"" ); + $HostGamePlayerCount = ClientGroup.getCount(); + return; + } + ban(%client); + %client.setDisconnectReason( "You are G-Banned Until "@%lengString@", "@%reason@"" ); + $HostGamePlayerCount = ClientGroup.getCount(); + } + else { + echo("Global-Banned Client "@%client.namebase@" Permitted connect - $Host::UseGlobalBanList is 0"); + MessageAll('Message', "\c2Global Banned Client: "@%client.namebase@" Permitted Access, $Host::UseGlobalBanList is 0."); + } + } + +DownloadBanList(); //download the list +package ServerRunFunctioning { + function GameConnection::onConnect(%client, %name, %raceGender, %skin, %voice, %voicePitch) { + parent::onConnect(%client, %name, %raceGender, %skin, %voice, %voicePitch); + checkBans(%client); + } +}; +activatePackage(ServerRunFunctioning); ////////// function spawnprojectile(%proj,%type,%pos,%direction,%src) { diff --git a/scripts/TWM2/Missions/MissionCore.cs b/scripts/TWM2/Missions/MissionCore.cs index 3ca6765..42f06e5 100644 --- a/scripts/TWM2/Missions/MissionCore.cs +++ b/scripts/TWM2/Missions/MissionCore.cs @@ -187,8 +187,7 @@ function CreateTWM2Mission(%client, %mission) { //this group holds our mission aspects }; - echo("TWM2: Activating Mission Package: "@%mission); - activatePackage("TWM2Mission_"@%mission@""); + activatePackage("TWM2Mission_"@%missionname@""); %group.initiateSettings(); %group.schedule(%group.timeToBegin * 1000, "StartTWM2MissionTimer"); diff --git a/scripts/TWM2/Systems/AdvancedRankSystem.cs b/scripts/TWM2/Systems/AdvancedRankSystem.cs index f98ea76..e80351d 100644 --- a/scripts/TWM2/Systems/AdvancedRankSystem.cs +++ b/scripts/TWM2/Systems/AdvancedRankSystem.cs @@ -374,7 +374,7 @@ function GeneratePrestigeChallengeMenu(%client, %tag, %index) { %index++; } else { - messageClient( %client, 'SetLineHud', "", %tag, %index, "Phantom's Vengeance - Reach Officer Level 9."); + messageClient( %client, 'SetLineHud', "", %tag, %index, "Phantom's Vengeance - Reach The Final Officer Level(9)."); %index++; } // diff --git a/scripts/TWM2/Systems/BossSystem.cs b/scripts/TWM2/Systems/BossSystem.cs index 55b5c9a..c455401 100644 --- a/scripts/TWM2/Systems/BossSystem.cs +++ b/scripts/TWM2/Systems/BossSystem.cs @@ -161,8 +161,7 @@ function GameConnection::GiveBossAward(%client, %bossName) { %ratio = %damageCount / %maxHP; - //%award = mFloor(($TWM2::BossXPAward[%bossName] * %ratio) / %scriptController.bossDefeatCount[%bossName]); - %award = $TWM2::BossXPAward[%bossName] / %scriptController.bossDefeatCount[%bossName]; + %award = mFloor(($TWM2::BossXPAward[%bossName] * %ratio) / %scriptController.bossDefeatCount[%bossName]); GainExperience(%client, %award, ""@%bossName@" defeated, congratulations! "); CheckBossChallenge(%client, %bossName); } @@ -435,7 +434,6 @@ function GenerateBossChallengeMenu(%client, %tag, %index) { } //Load The Boss Files -exec("scripts/TWM2/Bosses/BossDatablocks.cs"); exec("scripts/TWM2/Bosses/LordYvex.cs"); exec("scripts/TWM2/Bosses/ColonelWindshear.cs"); exec("scripts/TWM2/Bosses/GhostOfLightning.cs"); diff --git a/scripts/TWM2/Systems/DChalg.cs b/scripts/TWM2/Systems/DChalg.cs index 124d6a8..48557a4 100644 --- a/scripts/TWM2/Systems/DChalg.cs +++ b/scripts/TWM2/Systems/DChalg.cs @@ -691,9 +691,6 @@ function loadChallengeData(%client) { //file update function updateChallengeFile(%client) { - if($Server::StopUpdates) { - return; - } if(!isSet(%client) || !ClientGroup.isMember(%client)) { return; } @@ -728,7 +725,7 @@ function updateChallengeFile(%client) { // echo("Daily Challenge File Expired for "@%client@", preparing new file."); // - %client.resetAttemps++; + %client.resetAtttempts++; if(%client.resetAttemps >= 3) { error("Client "@%client@" reset attempts > 3, disabling challenge interpreter"); %client.cannotReset = 1; diff --git a/scripts/TWM2/Systems/HarbingersWrath.cs b/scripts/TWM2/Systems/HarbingersWrath.cs index 3da5f16..5451d36 100644 --- a/scripts/TWM2/Systems/HarbingersWrath.cs +++ b/scripts/TWM2/Systems/HarbingersWrath.cs @@ -246,7 +246,7 @@ function GetNextGunshipPoint(%obj) { %zPosToGo = getWord(%groundPos, 2) + getWord(%tpos, 2); %posToGo = getWords(%posToGo1, 0, 1) SPC %zPosToGo; //End 2.7 modification - if($HarbinsWrath::PointVec[%obj.goPoint] $= "") { + if(%obj.GoPoint >= 4) { %obj.GoPoint = 0; } //echo("Go to "@%posToGo@""); diff --git a/scripts/TWM2/Systems/MainControl.cs b/scripts/TWM2/Systems/MainControl.cs index bce5ffb..0ac7cdd 100644 --- a/scripts/TWM2/Systems/MainControl.cs +++ b/scripts/TWM2/Systems/MainControl.cs @@ -1,5 +1,5 @@ //TWM2 Functions -$TWM2::Version = 3.9; +$TWM2::Version = 3.8; function FormatTWM2Time(%time) { %min = MFloor(%time / 60); @@ -620,9 +620,6 @@ $ProjectileSeek["GhostFlameboltMain", "CancelList"] = "FlareGrenadeProj"; $ProjectileSeek["RapierShieldForwardProjectile", "ProjectileControls"] = "8 10 10 1"; $ProjectileSeek["RapierShieldForwardProjectile", "CancelList"] = "FlareGrenadeProj"; -$ProjectileSeek["PhotonMissileProj", "ProjectileControls"] = "8 10 10 1"; -$ProjectileSeek["PhotonMissileProj", "CancelList"] = "FlareGrenadeProj"; - function createSeekingProjectile(%projectile, %pType, %iPos, %iDir, %source, %target, %seekActivation) { %proj = spawnprojectile(%projectile, %pTYpe, %iPos, %iDir, %source); schedule(%seekActivation, 0, projectileSeeking, %proj, %target); diff --git a/scripts/TWM2/Systems/NewsPanel.cs b/scripts/TWM2/Systems/NewsPanel.cs index 4627202..7c9eb62 100644 --- a/scripts/TWM2/Systems/NewsPanel.cs +++ b/scripts/TWM2/Systems/NewsPanel.cs @@ -1,10 +1,10 @@ function DownloadNewsPage() { $TWM::Ticks = 0; - %server = "www.forums.phantomdev.net:80"; // + %server = "www.public.phantomdev.net:80"; // if (!isObject(PageGrabber)) %Downloader = new HTTPObject(PageGrabber){}; else %Downloader = PageGrabber; - %filename = "/viewtopic.php?f=11&t=416"; //File Location + %filename = "/SMF/index.php/topic,422.0.html"; //File Location %Downloader.get(%server, %filename); } diff --git a/scripts/weapons/Construction/EditGun.cs b/scripts/weapons/Construction/EditGun.cs index 182b818..3c1996d 100644 --- a/scripts/weapons/Construction/EditGun.cs +++ b/scripts/weapons/Construction/EditGun.cs @@ -33,7 +33,50 @@ $EditTool::PadModes[18] = "DeployedCrate12"; $EditTool::PadModes[19] = "DeployedDecoration6"; $EditTool::PadModes[20] = "DeployedDecoration16"; -datablock ItemData(EditTool) { + +datablock LinearFlareProjectileData(EditorBolt) +{ + emitterDelay = -1; + directDamage = 0; + directDamageType = $DamageType::Default; + kickBackStrength = 0.0; + bubbleEmitTime = 1.0; + + sound = PlasmaProjectileSound; + velInheritFactor = 0.5; + + explosion = "BlasterExplosion"; + splash = BlasterSplash; + + grenadeElasticity = 0.998; + grenadeFriction = 0.0; + armingDelayMS = 500; + + muzzleVelocity = 100.0; + + drag = 0.05; + + gravityMod = 0.0; + + dryVelocity = 100.0; + wetVelocity = 80.0; + + reflectOnWaterImpactAngle = 0.0; + explodeOnWaterImpact = false; + deflectionOnWaterImpact = 0.0; + fizzleUnderwaterMS = 6000; + + lifetimeMS = 6000; + + scale = "1 1 1"; + numFlares = 48; + flareColor = "1 0 0"; + flareModTexture = "special/shrikeBoltCross"; + flareBaseTexture = "special/shrikeBolt"; +}; + +datablock ItemData(EditTool) +{ className = Weapon; catagory = "Spawn Items"; shapeFile = "weapon_disc.dts"; @@ -45,7 +88,8 @@ datablock ItemData(EditTool) { pickUpName = "a Editing Tool"; }; -datablock ShapeBaseImageData(EditGunImage) { +datablock ShapeBaseImageData(EditGunImage) +{ className = WeaponImage; shapeFile = "weapon_disc.dts"; item = EditTool; @@ -54,8 +98,9 @@ datablock ShapeBaseImageData(EditGunImage) { usesEnergy = true; minEnergy = 0.01; - //projectile = EditorBolt; - //projectileType = LinearFlareProjectile; + projectile = EditorBolt; + projectileType = LinearFlareProjectile; + stateName[0] = "Activate"; stateTransitionOnTimeout[0] = "ActivateReady"; @@ -100,37 +145,6 @@ datablock ShapeBaseImageData(EditGunImage) { stateTransitionOnTimeout[6] = "Ready"; }; -//Phantom139: I'll take a datablock over a function any-day... -function EditGunImage::onFire(%data, %obj, %slot) { - //RAYCAST - %vector = %obj.getMuzzleVector(%slot); - %mp = %obj.getMuzzlePoint(%slot); - %targetpos = vectoradd(%mp,vectorscale(%vector, 2500)); - %targ = containerraycast(%mp, %targetpos, $typemasks::staticshapeobjecttype, %obj); - %targetObject = getword(%targ, 0); - if(%targetObject == 0) { - BottomPrint(%obj.client, "No Object Found", 2, 2); - return; - } - if (!Deployables.isMember(%targetObject)) { - messageclient(%obj.client, 'MsgClient', "\c2TextureTool: Error, Map Object Selected."); - return; - } - //APPLY EDITS - switch$(%obj.EditPMode) { - case 0: - EToolswaping(%targetObject, %obj, 0, %obj.EditSMode); - case 1: - EToolswaping(%targetObject, %obj, 1, %obj.EditSMode); - case 2: - EToolTurrets(%targetObject, %obj, %obj.EditSMode); - case 3: - EToolCloakandFade(%targetObject, %obj, %obj.EditSMode); - case 4: - EToolDeleting(%targetObject, %obj, %obj.EditSMode); - } -} - function EditGunImage::onMount(%this, %obj, %slot) { Parent::onMount(%this, %obj, %slot); DispEditorToolInfo(%obj); @@ -143,58 +157,59 @@ function EditGunImage::onMount(%this, %obj, %slot) { %obj.UsingEditTool = true; } -function EditGunImage::onunmount(%this,%obj,%slot) { - Parent::onUnmount(%this, %obj, %slot); - %obj.UsingEditTool = false; +function EditGunImage::onunmount(%this,%obj,%slot) +{ +Parent::onUnmount(%this, %obj, %slot); +%obj.UsingEditTool = false; } function DispEditorToolInfo(%obj) { - switch(%obj.EditPMode) { - case 0: - %primary = "Pad Swapping"; - switch(%obj.EditSMode) { - case 0: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Blue Pad - [LSB] - MSB", 5, 3); - case 1: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: LSB - [MSB] - Walkway", 5, 3); - case 2: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: MSB - [Walkway] - Medium Floor ", 5, 3); - case 3: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Walkway - [Medium Floor] - Dark Pad", 5, 3); - case 4: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Medium Floor - [Dark Pad] - V-Pad", 5, 3); - case 5: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Dark Pad - [V-Pad] - C.1 Backpack", 5, 3); - case 6: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: V-Pad - [C.1 Backpack] - C.2 Small Containment", 5, 3); - case 7: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.1 Backpack - [C.2 Small Containment] - C.3 Large Containment", 5, 3); - case 8: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.2 Small Containment - [C.3 Large Containment] - C.4 Compressor", 5, 3); - case 9: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.3 Large Containment - [C.4 Compressor] - C.5 Tubes", 5, 3); - case 10: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.4 Compressor - [C.5 Tubes] - C.6 Quantium Bat.", 5, 3); - case 11: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.5 Tubes - [C.6 Quantium Bat.] - C.7 Proton Acc.", 5, 3); - case 12: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.6 Quantium Bat. - [C.7 Proton Acc.] - C.8 Cargo Crate", 5, 3); - case 13: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.7 Proton Acc. - [C.8 Cargo Crate] - C.9 Mag Cooler", 5, 3); - case 14: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.8 Cargo Crate - [C.9 Mag Cooler] - C.10 Recycle Unit", 5, 3); - case 15: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.9 Mag Cooler - [C.10 Recycle Unit] - C.11 Fuel Canister", 5, 3); - case 16: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.10 Recycle Unit - [C.11 Fuel Canister] - C.12 Wooden Box", 5, 3); - case 17: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.11 Fuel Canister - [C.12 Wooden Box] - C.13 Plasma Router", 5, 3); - case 18: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.12 Wooden Box - [C.13 Plasma Router] - Statue Base", 5, 3); - case 19: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.13 Plasma Router - [Statue Base] - Blue Pad", 5, 3); - case 20: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Statue Base - [Blue Pad] - LSB", 5, 3); +switch(%obj.EditPMode) { + case 0: + %primary = "Pad Swapping"; + switch(%obj.EditSMode) { + case 0: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Blue Pad - [LSB] - MSB", 5, 3); + case 1: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: LSB - [MSB] - Walkway", 5, 3); + case 2: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: MSB - [Walkway] - Medium Floor ", 5, 3); + case 3: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Walkway - [Medium Floor] - Dark Pad", 5, 3); + case 4: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Medium Floor - [Dark Pad] - V-Pad", 5, 3); + case 5: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Dark Pad - [V-Pad] - C.1 Backpack", 5, 3); + case 6: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: V-Pad - [C.1 Backpack] - C.2 Small Containment", 5, 3); + case 7: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.1 Backpack - [C.2 Small Containment] - C.3 Large Containment", 5, 3); + case 8: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.2 Small Containment - [C.3 Large Containment] - C.4 Compressor", 5, 3); + case 9: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.3 Large Containment - [C.4 Compressor] - C.5 Tubes", 5, 3); + case 10: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.4 Compressor - [C.5 Tubes] - C.6 Quantium Bat.", 5, 3); + case 11: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.5 Tubes - [C.6 Quantium Bat.] - C.7 Proton Acc.", 5, 3); + case 12: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.6 Quantium Bat. - [C.7 Proton Acc.] - C.8 Cargo Crate", 5, 3); + case 13: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.7 Proton Acc. - [C.8 Cargo Crate] - C.9 Mag Cooler", 5, 3); + case 14: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.8 Cargo Crate - [C.9 Mag Cooler] - C.10 Recycle Unit", 5, 3); + case 15: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.9 Mag Cooler - [C.10 Recycle Unit] - C.11 Fuel Canister", 5, 3); + case 16: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.10 Recycle Unit - [C.11 Fuel Canister] - C.12 Wooden Box", 5, 3); + case 17: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.11 Fuel Canister - [C.12 Wooden Box] - C.13 Plasma Router", 5, 3); + case 18: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.12 Wooden Box - [C.13 Plasma Router] - Statue Base", 5, 3); + case 19: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.13 Plasma Router - [Statue Base] - Blue Pad", 5, 3); + case 20: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Statue Base - [Blue Pad] - LSB", 5, 3); } case 1: %primary = "Force-Field Swapping"; @@ -278,44 +293,57 @@ function DispEditorToolInfo(%obj) { } function ChangeEditGunMode(%this, %data, %PriSec) { //This Is Easier To use - if(%PriSec == 1) { //Primary - if (!(getSimTime() > (%this.mineModeTime + 100))) { - return; +if(%PriSec == 1) { //Primary +if (!(getSimTime() > (%this.mineModeTime + 100))) +return; +%this.mineModeTime = getSimTime(); +%this.EditPMode++; +%this.EditSMode = 0; //Reset Secondary Mode TO Prevent Errors +if (%this.EditPMode > 4) { +%this.EditPMode = 0; +} +DispEditorToolInfo(%this); +return; +} +else { //Secondary +if (!(getSimTime() > (%this.grenadeModeTime + 100))) +return; +%this.grenadeModeTime = getSimTime(); +%this.EditSMode++; +//Check Primaries +if(%this.EditPMode == 0 && %this.EditSMode > 20) { +%this.EditSMode = 0; +} +else if(%this.EditPMode == 1 && %this.EditSMode > 20) { +%this.EditSMode = 0; +} +else if(%this.EditPMode == 2 && %this.EditSMode > 4) { +%this.EditSMode = 0; +} +else if(%this.EditPMode == 3 && %this.EditSMode > 3) { +%this.EditSMode = 0; +} +else if(%this.EditPMode == 4 && %this.EditSMode > 1) { +%this.EditSMode = 0; +} +DispEditorToolInfo(%this); +return; +} +} + +function EditorBolt::onCollision(%data,%projectile,%targetObject,%modifier,%position,%normal) { + switch$(%projectile.sourceObject.EditPMode) { + case 0: + EToolswaping(%targetObject,%projectile.sourceObject,0,%projectile.sourceObject.EditSMode); + case 1: + EToolswaping(%targetObject,%projectile.sourceObject,1,%projectile.sourceObject.EditSMode); + case 2: + EToolTurrets(%targetObject,%projectile.sourceObject,%projectile.sourceObject.EditSMode); + case 3: + EToolCloakandFade(%targetObject,%projectile.sourceObject,%projectile.sourceObject.EditSMode); + case 4: + EToolDeleting(%targetObject,%projectile.sourceObject,%projectile.sourceObject.EditSMode); } - %this.mineModeTime = getSimTime(); - %this.EditPMode++; - %this.EditSMode = 0; //Reset Secondary Mode TO Prevent Errors - if (%this.EditPMode > 4) { - %this.EditPMode = 0; - } - DispEditorToolInfo(%this); - return; - } - else { //Secondary - if (!(getSimTime() > (%this.grenadeModeTime + 100))) { - return; - } - %this.grenadeModeTime = getSimTime(); - %this.EditSMode++; - //Check Primaries - if(%this.EditPMode == 0 && %this.EditSMode > 20) { - %this.EditSMode = 0; - } - else if(%this.EditPMode == 1 && %this.EditSMode > 20) { - %this.EditSMode = 0; - } - else if(%this.EditPMode == 2 && %this.EditSMode > 4) { - %this.EditSMode = 0; - } - else if(%this.EditPMode == 3 && %this.EditSMode > 3) { - %this.EditSMode = 0; - } - else if(%this.EditPMode == 4 && %this.EditSMode > 1) { - %this.EditSMode = 0; - } - DispEditorToolInfo(%this); - return; - } } //Editor Tool Functioning @@ -323,42 +351,42 @@ function ChangeEditGunMode(%this, %data, %PriSec) { //This Is Easier To use // // function EToolDeleting(%tobj,%plyr,%Mode) { - %cl = %plyr.client; - if ( %tobj.ownerGUID != %cl.guid) { - if (!%cl.isadmin && !%cl.issuperadmin){ - if (%tobj.ownerGUID !$=""){ - messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, You Do Not Own This Piece."); - return; - } - } + %cl=%plyr.client; + if ( %tobj.ownerGUID != %cl.guid){ + if (!%cl.isadmin && !%cl.issuperadmin){ + if (%tobj.ownerGUID !$=""){ + messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, You Do Not Own This Piece."); + return; + } + } } if (%tobj.squaresize !$="") { - messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Unknown Object Selected."); - return; + messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Unknown Object Selected."); + return; } if (!Deployables.isMember(%tobj)) { - messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Map Object Selected."); - return; + messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Map Object Selected."); + return; } switch(%Mode) { - case 0: - messageclient(%cl, 'MsgClient', "\c2TextureTool: Deleting Object."); - %tobj.getDataBlock().disassemble(%plyr, %tobj); //this found in constructionTool.cs - case 1: - messageclient(%cl, 'MsgClient', "\c2TextureTool: Cascade Deleting Object (All Conective Objects)."); - cascade(%tobj,true); + case 0: + messageclient(%cl, 'MsgClient', "\c2TextureTool: Deleting Object."); + %tobj.getDataBlock().disassemble(%plyr, %tobj); //this found in constructionTool.cs + case 1: + messageclient(%cl, 'MsgClient', "\c2TextureTool: Cascade Deleting Object (All Conective Objects)."); + cascade(%tobj,true); } } // function EToolCloakandFade(%tobj,%plyr,%Mode) { - %cl = %plyr.client; - if ( %tobj.ownerGUID != %cl.guid) { - if (!%cl.isadmin && !%cl.issuperadmin){ - if (%tobj.ownerGUID !$=""){ - messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, You Do Not Own This Piece."); - return; - } - } + %cl=%plyr.client; + if ( %tobj.ownerGUID != %cl.guid){ + if (!%cl.isadmin && !%cl.issuperadmin){ + if (%tobj.ownerGUID !$=""){ + messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, You Do Not Own This Piece."); + return; + } + } } if (%tobj.squaresize !$="") { messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Unknown Object Selected."); @@ -387,14 +415,14 @@ function EToolCloakandFade(%tobj,%plyr,%Mode) { } // function EToolTurrets(%tobj,%plyr,%Mode) { - %cl = %plyr.client; - if ( %tobj.ownerGUID != %cl.guid) { - if (!%cl.isadmin && !%cl.issuperadmin){ - if (%tobj.ownerGUID !$=""){ - messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, You Do Not Own This Piece."); - return; - } - } + %cl=%plyr.client; + if ( %tobj.ownerGUID != %cl.guid){ + if (!%cl.isadmin && !%cl.issuperadmin){ + if (%tobj.ownerGUID !$=""){ + messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, You Do Not Own This Piece."); + return; + } + } } if (%tobj.squaresize !$="") { messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Unknown Object Selected."); diff --git a/scripts/weapons/Melee/BOV.cs b/scripts/weapons/Melee/BOV.cs index 7fe754e..3649493 100644 --- a/scripts/weapons/Melee/BOV.cs +++ b/scripts/weapons/Melee/BOV.cs @@ -189,61 +189,63 @@ function BOVImage::onFire(%data, %obj, %node) { } function BOVhit::onCollision(%data, %projectile, %targetObject, %modifier, %position, %normal) { - if(%targetObject.isBoss) { - %targetObject.playShieldEffect("1 1 1"); - MessageClient(%projectile.sourceObject.client, 'MsgDeflect', "The Boss Deflects The Swipe"); - return; - } - if(%targetObject.rapierShield) { - MessageClient(%projectile.sourceObject.client, 'MsgDeflect', "The Target Is Immortal."); - return; - } - %source = %projectile.SourceObject; - %hitObj = %targetObject; + if(%targetObject.isBoss) { + %targetObject.playShieldEffect("1 1 1"); + MessageClient(%projectile.sourceObject.client, 'MsgDeflect', "The Boss Deflects The Swipe"); + return; + } + if(%targetObject.rapierShield) { + MessageClient(%projectile.sourceObject.client, 'MsgDeflect', "The Target Is Immortal."); + return; + } + %source = %projectile.SourceObject; + %hitObj = %targetObject; - %muzzlePos = %source.getMuzzlePoint(0); - %muzzleVec = %source.getMuzzleVector(0); + %muzzlePos = %source.getMuzzlePoint(0); + %muzzleVec = %source.getMuzzleVector(0); - // extra damage for head shot or less for close range shots - if(!(%hitObj.getType() & ($TypeMasks::InteriorObjectType | $TypeMasks::TerrainObjectType)) && (%hitObj.getDataBlock().getClassName() $= "PlayerData")) { - if(%hitObj.getDataBlock().getClassName() $= "PlayerData") { - // Now we see if we hit from behind... - %forwardVec = %hitobj.getForwardVector(); - %objDir2D = getWord(%forwardVec, 0) @ " " @ getWord(%forwardVec,1) @ " " @ "0.0"; - %objPos = %hitObj.getPosition(); - %dif = VectorSub(%objPos, %muzzlePos); - %dif = getWord(%dif, 0) @ " " @ getWord(%dif, 1) @ " 0"; - %dif = VectorNormalize(%dif); - %dot = VectorDot(%dif, %objDir2D); - // 120 Deg angle test... - // 1.05 == 60 degrees in radians - if (%dot >= mCos(1.05)) { - // Rear hit - if(%source.isAlive()) { + // extra damage for head shot or less for close range shots + if(!(%hitObj.getType() & ($TypeMasks::InteriorObjectType | $TypeMasks::TerrainObjectType)) && + (%hitObj.getDataBlock().getClassName() $= "PlayerData")) { + + if(%hitObj.getDataBlock().getClassName() $= "PlayerData") { + // Now we see if we hit from behind... + %forwardVec = %hitobj.getForwardVector(); + %objDir2D = getWord(%forwardVec, 0) @ " " @ getWord(%forwardVec,1) @ " " @ "0.0"; + %objPos = %hitObj.getPosition(); + %dif = VectorSub(%objPos, %muzzlePos); + %dif = getWord(%dif, 0) @ " " @ getWord(%dif, 1) @ " 0"; + %dif = VectorNormalize(%dif); + %dot = VectorDot(%dif, %objDir2D); + + // 120 Deg angle test... + // 1.05 == 60 degrees in radians + if (%dot >= mCos(1.05)) { + // Rear hit %source.applyRepair("0.45"); //we get a bonus repair for rear + if(%source.team == %hitObj.team && !$TeamDamage) { + ServerPlay3d(BOVHitSound, %targetObject.getPosition()); + return; //stops shredding + } + %source.cannotuseBOV = 1; + if(!%hitObj.IsinvincibleC) { + DoBOVRearKill(%source, %hitObj, 0); + } + return; } - if(%source.team == %hitObj.team && !$TeamDamage) { - ServerPlay3d(BOVHitSound, %targetObject.getPosition()); - return; //stops shredding - } - %source.cannotuseBOV = 1; - if(!%hitObj.IsinvincibleC) { - DoBOVRearKill(%source, %hitObj, 0); - } - return; } - } - ServerPlay3d(BOVHitSound, %targetObject.getPosition()); - //The Blade Only Works On Players - %targetObject.damage(%projectile.sourceObject, %position, %data.directDamage, %data.directDamageType); - if(%source.isAlive()) { - %source.applyRepair("0.15"); //15% - } - if(%targetObject.client !$= "") { //a Player.. goodie - if(%targetObject.getState() $= "dead") { - MessageAll('MessageAll', "\c0"@%targetObject.client.namebase@" was stabbed by "@%source.client.namebase@"'s Sword."); - } - } + + ServerPlay3d(BOVHitSound, %targetObject.getPosition()); + //The Blade Only Works On Players + %targetObject.damage(%projectile.sourceObject, %position, %data.directDamage, %data.directDamageType); + if(isObject(%source) || %source.getState() !$= "dead") { + %source.applyRepair("0.15"); //15% + } + if(%targetObject.client !$= "") { //a Player.. goodie + if(%targetObject.getState() $= "dead") { + MessageAll('MessageAll', "\c0"@%targetObject.client.namebase@" was stabbed by "@%source.client.namebase@"'s Sword."); + } + } } } diff --git a/scripts/weapons/T2Guns/shockLance.cs b/scripts/weapons/T2Guns/shockLance.cs index b6afea2..244dff2 100644 --- a/scripts/weapons/T2Guns/shockLance.cs +++ b/scripts/weapons/T2Guns/shockLance.cs @@ -44,6 +44,110 @@ datablock AudioProfile(ShockLanceMissSound) //-------------------------------------------------------------------------- // Particle data //-------------------------------------------------------------------------- +datablock ParticleData(ShockParticle) +{ + dragCoeffiecient = 0.0; + gravityCoefficient = -0.0; + inheritedVelFactor = 0.0; + + lifetimeMS = 1000; + lifetimeVarianceMS = 0; + + textureName = "particleTest"; + + useInvAlpha = false; + spinRandomMin = -100.0; + spinRandomMax = 100.0; + + numParts = 50; + + animateTexture = true; + framesPerSec = 26; + + animTexName[00] = "special/Explosion/exp_0002"; + animTexName[01] = "special/Explosion/exp_0004"; + animTexName[02] = "special/Explosion/exp_0006"; + animTexName[03] = "special/Explosion/exp_0008"; + animTexName[04] = "special/Explosion/exp_0010"; + animTexName[05] = "special/Explosion/exp_0012"; + animTexName[06] = "special/Explosion/exp_0014"; + animTexName[07] = "special/Explosion/exp_0016"; + animTexName[08] = "special/Explosion/exp_0018"; + animTexName[09] = "special/Explosion/exp_0020"; + animTexName[10] = "special/Explosion/exp_0022"; + animTexName[11] = "special/Explosion/exp_0024"; + animTexName[12] = "special/Explosion/exp_0026"; + animTexName[13] = "special/Explosion/exp_0028"; + animTexName[14] = "special/Explosion/exp_0030"; + animTexName[15] = "special/Explosion/exp_0032"; + animTexName[16] = "special/Explosion/exp_0034"; + animTexName[17] = "special/Explosion/exp_0036"; + animTexName[18] = "special/Explosion/exp_0038"; + animTexName[19] = "special/Explosion/exp_0040"; + animTexName[20] = "special/Explosion/exp_0042"; + animTexName[21] = "special/Explosion/exp_0044"; + animTexName[22] = "special/Explosion/exp_0046"; + animTexName[23] = "special/Explosion/exp_0048"; + animTexName[24] = "special/Explosion/exp_0050"; + animTexName[25] = "special/Explosion/exp_0052"; + + + colors[0] = "0.5 0.5 1.0 1.0"; + colors[1] = "0.5 0.5 1.0 0.5"; + colors[2] = "0.25 0.25 1.0 0.0"; + sizes[0] = 0.5; + sizes[1] = 0.5; + sizes[2] = 0.5; + times[0] = 0.0; + times[1] = 0.5; + times[2] = 1.0; +}; + +datablock ParticleEmitterData(ShockParticleEmitter) +{ + ejectionPeriodMS = 1; + periodVarianceMS = 0; + + ejectionVelocity = 0.25; + velocityVariance = 0.0; + + thetaMin = 0.0; + thetaMax = 30.0; + + particles = "ShockParticle"; +}; + +//-------------------------------------------------------------------------- +// Shockwave +//-------------------------------------------------------------------------- +datablock ShockwaveData( ShocklanceHit ) +{ + width = 0.5; + numSegments = 20; + numVertSegments = 1; + velocity = 0.25; + acceleration = 1.0; + lifetimeMS = 600; + height = 0.1; + verticalCurve = 0.5; + + mapToTerrain = false; + renderBottom = false; + orientToNormal = true; + + texture[0] = "special/shocklanceHit"; + texture[1] = "special/gradient"; + texWrap = 3.0; + + times[0] = 0.0; + times[1] = 0.5; + times[2] = 1.0; + + colors[0] = "1.0 1.0 1.0 1.0"; + colors[1] = "1.0 1.0 1.0 0.5"; + colors[2] = "1.0 1.0 1.0 0.0"; +}; + //-------------------------------------- // Projectile @@ -86,6 +190,43 @@ datablock ShockLanceProjectileData(BasicShocker) emitter[0] = ShockParticleEmitter; }; +datablock ShockLanceProjectileData(GoLShocker) { + directDamage = 0.45; + radiusDamageType = $DamageType::ShockLance; + kickBackStrength = 2500; + velInheritFactor = 0; + sound = ""; + + zapDuration = 1.0; + impulse = 1800; + boltLength = 50.0; + extension = 50.0; // script variable indicating distance you can shock people from + lightningFreq = 25.0; + lightningDensity = 3.0; + lightningAmp = 0.25; + lightningWidth = 0.05; + + shockwave = ShocklanceHit; + + boltSpeed[0] = 2.0; + boltSpeed[1] = -0.5; + + texWrap[0] = 1.5; + texWrap[1] = 1.5; + + startWidth[0] = 0.3; + endWidth[0] = 0.6; + startWidth[1] = 0.3; + endWidth[1] = 0.6; + + texture[0] = "special/shockLightning01"; + texture[1] = "special/shockLightning02"; + texture[2] = "special/shockLightning03"; + texture[3] = "special/ELFBeam"; + + emitter[0] = ShockParticleEmitter; +}; + datablock ShockLanceProjectileData(S3Shocker) { directDamage = 0.50; radiusDamageType = $DamageType::ShockLance; diff --git a/serverControl.cs b/serverControl.cs index c189688..9826507 100644 --- a/serverControl.cs +++ b/serverControl.cs @@ -5,6 +5,11 @@ $TWM2::DisabledMissionTypes = ""; //Horde\tHorde4 $ScoreHudInventory::Active = 0; //0 returns the inv. hud to the normal one +//PGD Connect has been removed from www.phantomdev.net. I will restore it if mod +// support returns to it's original status, for the time being, this GVar will +// disable the PGD Connect stuff, allowing the mod to function without it. +$TWM2::PGDConnectDisabled = 1; + //CHAT BOT //Now you can control 'Cynthia', or whatever you wish on naming it $ChatBot::Name = "Cynthia"; //The Name of the Bot From 939d1ed06d1df54c5c09b90ece86865896aa74d5 Mon Sep 17 00:00:00 2001 From: Robert Fritzen Date: Mon, 2 Jun 2014 14:15:07 -0500 Subject: [PATCH 06/16] Added a PGD Connect Toggler PGD Connect can now be enabled/disabled via a global variable in serverControl.cs, in the event the system is re-enabled, simply turn the var off. --- scripts/TWM2/ChatCommands/Public.cs | 16 ++++++++++++++++ scripts/TWM2/PGDConnect/ServerInteraction.cs | 4 ++++ scripts/TWM2/PGDConnect/UniversalLoading.cs | 4 ++++ scripts/TWM2/PGDConnect/UniversalRanks.cs | 12 ++++++++++++ .../TWM2/PGDConnect/UniversalSaving_Client.cs | 8 ++++++++ scripts/TWM2/PGDConnect/UniversalSupport.cs | 8 ++++++++ scripts/TWM2/Systems/AdvancedRankSystem.cs | 4 +++- scripts/TWM2/Systems/DChalg.cs | 4 ++++ scripts/TWM2/Systems/scoremenucmds.cs | 18 ++++++++++++++++++ 9 files changed, 77 insertions(+), 1 deletion(-) diff --git a/scripts/TWM2/ChatCommands/Public.cs b/scripts/TWM2/ChatCommands/Public.cs index 41b4951..80c1f71 100644 --- a/scripts/TWM2/ChatCommands/Public.cs +++ b/scripts/TWM2/ChatCommands/Public.cs @@ -935,6 +935,10 @@ function parsePublicCommands(%sender, %command, %args) { //uSave: univerally save a building in a CSS slot case "usave": + if($TWM2::PGDConnectDisabled) { + messageClient(%sender, 'msgPGDRequired', "\c5PGD: PGD Connect has been disabled."); + return 1; + } if(!%sender.IsPGDConnected()) { messageClient(%client, 'msgPGDRequired', "\c5PGD: PGD Connect account required to perform this action."); return 1; @@ -956,6 +960,10 @@ function parsePublicCommands(%sender, %command, %args) { //uLoad: load a universally saved building case "uload": + if($TWM2::PGDConnectDisabled) { + messageClient(%sender, 'msgPGDRequired', "\c5PGD: PGD Connect has been disabled."); + return 1; + } if(!%sender.IsPGDConnected()) { messageClient(%sender, 'msgPGDRequired', "\c5PGD: PGD Connect account required to perform this action."); return 1; @@ -973,6 +981,10 @@ function parsePublicCommands(%sender, %command, %args) { //saveRank: save your rank to PGD case "saverank": + if($TWM2::PGDConnectDisabled) { + messageClient(%sender, 'msgPGDRequired', "\c5PGD: PGD Connect has been disabled."); + return 1; + } if(!%sender.canSaveRank) { messageClient(%sender, 'MsgClient', "\c5PGD: You have only recently saved your rank."); return 1; @@ -993,6 +1005,10 @@ function parsePublicCommands(%sender, %command, %args) { //loadRank: load your rank from PGD case "loadrank": + if($TWM2::PGDConnectDisabled) { + messageClient(%sender, 'msgPGDRequired', "\c5PGD: PGD Connect has been disabled."); + return 1; + } if(!%sender.canLoadRank) { messageClient(%sender, 'MsgClient', "\c5PGD: You have only recently re-loaded your rank."); return 1; diff --git a/scripts/TWM2/PGDConnect/ServerInteraction.cs b/scripts/TWM2/PGDConnect/ServerInteraction.cs index dd4840b..3ba3484 100644 --- a/scripts/TWM2/PGDConnect/ServerInteraction.cs +++ b/scripts/TWM2/PGDConnect/ServerInteraction.cs @@ -17,6 +17,10 @@ $TWM2ServerInfo_Loc = "/ssiInterface.php"; //connects to the server function establishPGDConnection() { + if($TWM2::PGDConnectDisabled) { + echo("PGD Connect is disabled."); + return; + } echo("ServerInteraction Initiated... wait for connection..."); if (!isObject(serverInterfacing)) { %connection = new TCPObject(serverInterfacing); diff --git a/scripts/TWM2/PGDConnect/UniversalLoading.cs b/scripts/TWM2/PGDConnect/UniversalLoading.cs index 0adc650..761f524 100644 --- a/scripts/TWM2/PGDConnect/UniversalLoading.cs +++ b/scripts/TWM2/PGDConnect/UniversalLoading.cs @@ -1,5 +1,9 @@ // ---- PGD Loader ------------------------------------------------------------- function LoadUniversalBuilding(%client, %file) { + if($TWM2::PGDConnectDisabled) { + echo("PGD Connect is disabled."); + return; + } %server = ""@$PGDServer@":"@$PGDPort@""; %filename = "/public/Univ/Data/"@%client.guid@"/Buildings/"@%file@".cs"; if (!isObject(Univ_Loader)) { diff --git a/scripts/TWM2/PGDConnect/UniversalRanks.cs b/scripts/TWM2/PGDConnect/UniversalRanks.cs index 4c04850..a72a6c6 100644 --- a/scripts/TWM2/PGDConnect/UniversalRanks.cs +++ b/scripts/TWM2/PGDConnect/UniversalRanks.cs @@ -45,6 +45,10 @@ function IsServerMain() { //function GetKey(){CheckCore();} function CheckCore() { + if($TWM2::PGDConnectDisabled) { + echo("PGD Connect is disabled."); + return; + } echo("*PGD: Performing Server Core Status Check"); $TCP::ConnectionContainer.addTaskToList($PGDServer, $PGDKeyHandler, @@ -91,6 +95,10 @@ function PGDConnection::validatePGDCore(%this, %line) { //------------------------------------------------------------------------ function LoadUniversalRank(%client) { + if($TWM2::PGDConnectDisabled) { + schedule(500, 0, "LoadClientRankfile", %client); + return; + } //A Little PGD Connect Ad. %client.donotupdate = 1; if(!%client.IsPGDConnected()) { @@ -150,6 +158,10 @@ function PGDConnection_HTTP::onCompleteRankDownload(%this) { //------------------------------------------------------------------------ function PrepareUpload(%client) { + if($TWM2::PGDConnectDisabled) { + echo("PGD Connect is disabled."); + return; + } if (!isServerMain()) { return; } diff --git a/scripts/TWM2/PGDConnect/UniversalSaving_Client.cs b/scripts/TWM2/PGDConnect/UniversalSaving_Client.cs index 64111cd..2c4bba1 100644 --- a/scripts/TWM2/PGDConnect/UniversalSaving_Client.cs +++ b/scripts/TWM2/PGDConnect/UniversalSaving_Client.cs @@ -9,6 +9,10 @@ //5. Deletes Saved Files on the Server function GameConnection::IsPGDConnected(%client) { + if($TWM2::PGDConnectDisabled) { + echo("PGD Connect is disabled."); + return 0; + } %guid = %client.guid; if(!%client) { return 0; @@ -49,6 +53,10 @@ function GUIDGrabber::onLine(%this, %line) { } function Univ_ServerConnect(%client, %file, %svDl) { + if($TWM2::PGDConnectDisabled) { + echo("PGD Connect is disabled."); + return; + } %connection = Univ_SaveClient; if(!%client || %client $= "") { error("Error: No Client Specified"); diff --git a/scripts/TWM2/PGDConnect/UniversalSupport.cs b/scripts/TWM2/PGDConnect/UniversalSupport.cs index 9c3f5ec..395599a 100644 --- a/scripts/TWM2/PGDConnect/UniversalSupport.cs +++ b/scripts/TWM2/PGDConnect/UniversalSupport.cs @@ -15,6 +15,10 @@ $PGDServer = "www.phantomdev.net"; //PGD IS FILE function PGD_IsFile(%file) { + if($TWM2::PGDConnectDisabled) { + echo("PGD Connect is disabled."); + return false; + } if($PGD::IsFile[%file] $= "" || $PGD::IsFile[%file] == -1) { PGD_IsFileDL(%file); return schedule(5000, 0, "PGD_IsFile", %file); @@ -25,6 +29,10 @@ function PGD_IsFile(%file) { } function PGD_IsFileDL(%file) { + if($TWM2::PGDConnectDisabled) { + echo("PGD Connect is disabled."); + return; + } %server = ""@$PGDServer@":"@$PGDPort@""; %filename = "/public/Univ/IsFile.php?File="@%file@""; if (!isObject(PGDISFile)) { diff --git a/scripts/TWM2/Systems/AdvancedRankSystem.cs b/scripts/TWM2/Systems/AdvancedRankSystem.cs index e80351d..0361423 100644 --- a/scripts/TWM2/Systems/AdvancedRankSystem.cs +++ b/scripts/TWM2/Systems/AdvancedRankSystem.cs @@ -167,7 +167,9 @@ function runRankUpdateLoop(%client, %j, %continue) { //UpdateRankFile(%client); SaveClientFile(%client); // - PrepareUpload(%client); + if(!$TWM2::PGDConnectDisabled) { + PrepareUpload(%client); + } %j = 1; runRankUpdateLoop(%client, %j, 0); } diff --git a/scripts/TWM2/Systems/DChalg.cs b/scripts/TWM2/Systems/DChalg.cs index 48557a4..3c9aa91 100644 --- a/scripts/TWM2/Systems/DChalg.cs +++ b/scripts/TWM2/Systems/DChalg.cs @@ -5,6 +5,10 @@ //downloads challenges from PGD function downloadChallenges() { + if($TWM2::PGDConnectDisabled) { + echo("PGD Connect is disabled."); + return; + } if(!IsServerMain()) { error("* Daily Challenges: Restricted To Core Servers Only"); return; diff --git a/scripts/TWM2/Systems/scoremenucmds.cs b/scripts/TWM2/Systems/scoremenucmds.cs index 35056e4..e913c76 100644 --- a/scripts/TWM2/Systems/scoremenucmds.cs +++ b/scripts/TWM2/Systems/scoremenucmds.cs @@ -270,6 +270,13 @@ switch$ (%arg1) case "PGDConn1": %client.SCMPage = "SM"; messageClient( %client, 'SetScoreHudSubheader', "", "PGD Connect" ); + if($TWM2::PGDConnectDisabled) { + messageClient( %client, 'SetLineHud', "", %tag, %index, "PGD Connect is disabled on this server."); + %index++; + messageClient( %client, 'SetLineHud', "", %tag, %index, 'Back to main menu'); + %index++; + return; + } messageClient( %client, 'SetLineHud', "", %tag, %index, "Set email with: /setEmail"); %index++; messageClient( %client, 'SetLineHud', "", %tag, %index, "Current Email: "@%client.emailSet); @@ -283,6 +290,13 @@ switch$ (%arg1) case "PGDConn2": %client.SCMPage = "SM"; messageClient( %client, 'SetScoreHudSubheader', "", "PGD Connect" ); + if($TWM2::PGDConnectDisabled) { + messageClient( %client, 'SetLineHud', "", %tag, %index, "PGD Connect is disabled on this server."); + %index++; + messageClient( %client, 'SetLineHud', "", %tag, %index, 'Back to main menu'); + %index++; + return; + } messageClient( %client, 'SetLineHud', "", %tag, %index, "Connecting... please wait for response"); %index++; messageClient( %client, 'SetLineHud', "", %tag, %index, 'Back to main menu'); @@ -1214,6 +1228,10 @@ function RunDeleteCheck(%cl, %slot) { //------------------------------------ function PGDConnect_FromInGame(%client) { + if($TWM2::PGDConnectDisabled) { + echo("PGD Connect is disabled."); + return; + } %guid = %client.guid; %email = %client.emailSet; if(!isSet(%email)) { From bf6ac36fa3936b4cc47f3be3bbc6c02c205229a3 Mon Sep 17 00:00:00 2001 From: Robert Fritzen Date: Sat, 2 Aug 2014 10:28:56 -0500 Subject: [PATCH 07/16] A few fixes, adjusted SSI location --- scripts/TWM2/PGDConnect/ServerInteraction.cs | 6 +++--- scripts/TWM2/Systems/DChalg.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/TWM2/PGDConnect/ServerInteraction.cs b/scripts/TWM2/PGDConnect/ServerInteraction.cs index 3ba3484..80ac95f 100644 --- a/scripts/TWM2/PGDConnect/ServerInteraction.cs +++ b/scripts/TWM2/PGDConnect/ServerInteraction.cs @@ -11,9 +11,9 @@ // : Servers: [CORE] [SATELITE] // ============================================================ -$Generic_Rank_Cap = 75000; //if we cannot get a valid connection -$TWM2Core_Interface = "www.phantomdev.net" TAB "www.tacticaluprising.phantomdev.net"; //don't touch, server connections -$TWM2ServerInfo_Loc = "/ssiInterface.php"; +$Generic_Rank_Cap = 3000000; //if we cannot get a valid connection +$TWM2Core_Interface = "www.phantomdev.net" TAB "www.public.phantomdev.net"; //don't touch, server connections +$TWM2ServerInfo_Loc = "/Univ/ssiInterface.php"; //connects to the server function establishPGDConnection() { diff --git a/scripts/TWM2/Systems/DChalg.cs b/scripts/TWM2/Systems/DChalg.cs index 3c9aa91..8dbda60 100644 --- a/scripts/TWM2/Systems/DChalg.cs +++ b/scripts/TWM2/Systems/DChalg.cs @@ -729,7 +729,7 @@ function updateChallengeFile(%client) { // echo("Daily Challenge File Expired for "@%client@", preparing new file."); // - %client.resetAtttempts++; + %client.resetAttemps++; if(%client.resetAttemps >= 3) { error("Client "@%client@" reset attempts > 3, disabling challenge interpreter"); %client.cannotReset = 1; From e353d67b45e918b8c10f0bac9266e51027cbb96b Mon Sep 17 00:00:00 2001 From: Robert Fritzen Date: Sat, 2 Aug 2014 10:51:35 -0500 Subject: [PATCH 08/16] Some Quick Fixes --- scripts/TWM2/Bosses/BossDatablocks.cs | 2369 ------------------------- scripts/TWM2/Systems/NewsPanel.cs | 4 +- serverControl.cs | 8 +- 3 files changed, 6 insertions(+), 2375 deletions(-) delete mode 100644 scripts/TWM2/Bosses/BossDatablocks.cs diff --git a/scripts/TWM2/Bosses/BossDatablocks.cs b/scripts/TWM2/Bosses/BossDatablocks.cs deleted file mode 100644 index cc5ef1e..0000000 --- a/scripts/TWM2/Bosses/BossDatablocks.cs +++ /dev/null @@ -1,2369 +0,0 @@ -//BossDatablocks.cs -//Phantom139 -//Contains all datablocks for bosses... - -// -// BOSS ARMORS / VEHICLES / OBJECTS -// - -// ============================================================================ -// YVEX -// ============================================================================ -datablock PlayerData(YvexZombieArmor) : LightMaleHumanArmor { - boundingBox = "1.63 1.63 2.6"; - maxDamage = 500.0; - minImpactSpeed = 35; - shapeFile = "medium_male.dts"; - - debrisShapeName = "bio_player_debris.dts"; - - //Foot Prints - decalData = HeavyBiodermFootprint; - decalOffset = 0.4; - - waterBreathSound = WaterBreathBiodermSound; - - damageScale[$DamageType::W1700] = 3.0; - damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs - - max[RepairKit] = 0; - max[Mine] = 0; - max[Grenade] = 0; -}; - -// ============================================================================ -// WINDSHEAR -// ============================================================================ - -// * Windshear's Vehicle Object is handled & Loaded in vehicles/vehicle_WindshearPlatform.cs - -// ============================================================================ -// GHOST OF LIGHTNING -// ============================================================================ -datablock PlayerData(LightningGhostArmor) : MediumMaleHumanArmor { - boundingBox = "1.63 1.63 2.6"; - maxDamage = 550.0; - minImpactSpeed = 35; - shapeFile = "medium_male.dts"; - - debrisShapeName = "bio_player_debris.dts"; - - //Foot Prints - decalData = HeavyBiodermFootprint; - decalOffset = 0.4; - - waterBreathSound = WaterBreathBiodermSound; - - damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs - - max[RepairKit] = 0; - max[Mine] = 0; - max[Grenade] = 0; -}; - -// ============================================================================ -// VEGENOR -// ============================================================================ -datablock PlayerData(VegenorZombieArmor) : HeavyMaleBiodermArmor { - maxDamage = 600.0; - minImpactSpeed = 50; - speedDamageScale = 0.015; - - damageScale[$DamageType::M1700] = 2.0; - damageScale[$DamageType::Fire] = 0.1; - damageScale[$DamageType::Burn] = 0.1; - damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs - - max[RepairKit] = 0; - max[Mine] = 0; - max[Grenade] = 0; -}; - -// ============================================================================ -// LORD ROG -// ============================================================================ -datablock PlayerData(LordRogZombieArmor) : HeavyMaleBiodermArmor { - boundingBox = "1.63 1.63 2.6"; - maxDamage = 650.0; - minImpactSpeed = 35; - shapeFile = "bioderm_heavy.dts"; - - debrisShapeName = "bio_player_debris.dts"; - - //Foot Prints - decalData = HeavyBiodermFootprint; - decalOffset = 0.4; - - damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs - - waterBreathSound = WaterBreathBiodermSound; - - max[RepairKit] = 0; - max[Mine] = 0; - max[Grenade] = 0; -}; - -// ============================================================================ -// INSIGNIA -// ============================================================================ -datablock StaticShapeData(NoCollideBio) : StaticShapeDamageProfile { - className = "player"; - shapeFile = "bioderm_light.dts"; // dmiscf.dts, alternate - mass = 1; - elasticity = 0.1; - friction = 0.9; - collideable = 0; - isInvincible = true; -}; - -datablock StaticShapeData(NoCollideHum) : StaticShapeDamageProfile { - className = "player"; - shapeFile = "light_male.dts"; // dmiscf.dts, alternate - mass = 1; - elasticity = 0.1; - friction = 0.9; - collideable = 0; - isInvincible = true; -}; - -datablock PlayerData(InsigniaZombieArmor) : LightMaleBiodermArmor { - maxDamage = 700.0; - minImpactSpeed = 50; - speedDamageScale = 0.015; - - damageScale[$DamageType::M1700] = 2.0; - damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs - - max[RepairKit] = 0; - max[Mine] = 0; - max[Grenade] = 0; -}; - -// ============================================================================ -// TREVOR -// ============================================================================ -datablock HoverVehicleData(TreborTank) : CentaurVehicle { - spawnOffset = "0 0 4"; - canControl = true; - floatingGravMag = 4.5; - - catagory = "Vehicles"; - shapeFile = "vehicle_grav_tank.dts"; - multipassenger = false; - computeCRC = true; - renderWhenDestroyed = false; - - mountPose[0] = sitting; - numMountPoints = 0; // <-- Ignore this - isProtectedMountPoint[0] = true; - - maxDamage = 100.15; - destroyedLevel = 100.15; - - isShielded = true; - rechargeRate = 1.0; - energyPerDamagePoint = 135; - maxEnergy = 400; - minJetEnergy = 15; - jetEnergyDrain = 2.0; - - targetNameTag = 'Centaur'; - targetTypeTag = 'MK III'; - - damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs - ShieldDamageScale[$DamageType::Bullet] = 0.01; //I deny you shrike n0bs -}; - -// ============================================================================ -// LORD VARDISON / D.A. VARDISON -// ============================================================================ -datablock PlayerData(VardisonStage1Armor) : LightMaleHumanArmor { - runForce = 60.20 * 90; - runEnergyDrain = 0.0; - minRunEnergy = 10; - maxForwardSpeed = 9; - maxBackwardSpeed = 7; - maxSideSpeed = 7; - - jumpForce = 14.0 * 90; - - maxDamage = 300.0; - minImpactSpeed = 35; - shapeFile = "light_male.dts"; - jetEmitter = BiodermArmorJetEmitter; - jetEffect = BiodermArmorJetEffect; - - debrisShapeName = "bio_player_debris.dts"; - - //Foot Prints - decalData = LightBiodermFootprint; - decalOffset = 0.3; - - waterBreathSound = WaterBreathBiodermSound; - - damageScale[$DamageType::M1700] = 3.0; - damageScale[$DamageType::Missile] = 0.0000000000000001; - damageScale[$DamageType::Nuclear] = 0.0000000000000001; - damageScale[$DamageType::EMP] = 0.0000000000000001; - damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs - - max[RepairKit] = 0; - max[Mine] = 0; - max[Grenade] = 0; -}; - -datablock PlayerData(DarkArchmageVardisonArmor) : VardisonStage1Armor { - maxDamage = 1000.0; - minImpactSpeed = 35; - shapeFile = "light_male.dts"; - jetEmitter = BiodermArmorJetEmitter; - jetEffect = BiodermArmorJetEffect; - - damageScale[$DamageType::M1700] = 3.0; - damageScale[$DamageType::Missile] = 0.0000000000000001; - damageScale[$DamageType::Nuclear] = 0.0000000000000001; - damageScale[$DamageType::EMP] = 0.0000000000000001; - damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs - - max[RepairKit] = 0; - max[Mine] = 0; - max[Grenade] = 0; -}; - -datablock FlyingVehicleData(VardisonStage2Flyer) : ShrikeDamageProfile { - spawnOffset = "0 0 2"; - canControl = false; - catagory = "Vehicles"; - shapeFile = "vehicle_air_bomber.dts"; - multipassenger = false; - computeCRC = true; - - debrisShapeName = "vehicle_air_bomber.dts"; - debris = MeShapeDebris; - renderWhenDestroyed = false; - - drag = 0.15; - density = 1.0; - - mountPose[0] = sitting; - numMountPoints = 1; - isProtectedMountPoint[0] = false; - cameraMaxDist = 15; - cameraOffset = 2.5; - cameraLag = 0.9; - explosion = MeVehicleExplosion; - explosionDamage = 1.0; - explosionRadius = 10.0; - - maxDamage = 50.0; - destroyedLevel = 50.0; - - HDAddMassLevel = 49.9; - HDMassImage = LflyerHDMassImage; - - isShielded = false; - energyPerDamagePoint = 0; - maxEnergy = 5000; // Afterburner and any energy weapon pool - rechargeRate = 4; - - minDrag = 22; // Linear Drag (eventually slows you down when not thrusting...constant drag) - rotationalDrag = 900; // Anguler Drag (dampens the drift after you stop moving the mouse...also tumble drag) - - maxAutoSpeed = 50; // Autostabilizer kicks in when less than this speed. (meters/second) - autoAngularForce = 400; // Angular stabilizer force (this force levels you out when autostabilizer kicks in) - autoLinearForce = 1; // Linear stabilzer force (this slows you down when autostabilizer kicks in) - autoInputDamping = 0.8; // Dampen control input so you don't` whack out at very slow speeds - - - // Maneuvering - maxSteeringAngle = 4.5; // Max radiens you can rotate the wheel. Smaller number is more maneuverable. - horizontalSurfaceForce = 6; // Horizontal center "wing" (provides "bite" into the wind for climbing/diving and turning) - verticalSurfaceForce = 4; // Vertical center "wing" (controls side slip. lower numbers make MORE slide.) - maneuveringForce = 5250; // Horizontal jets (W,S,D,A key thrust) - steeringForce = 675; // Steering jets (force applied when you move the mouse) - steeringRollForce = 3000; // Steering jets (how much you heel over when you turn) - rollForce = 1; // Auto-roll (self-correction to right you after you roll/invert) - hoverHeight = 2.5; // Height off the ground at rest - createHoverHeight = 1; // Height off the ground when created - maxForwardSpeed = 165; // speed in which forward thrust force is no longer applied (meters/second) - - // Turbo Jet - jetForce = 2500; // Afterburner thrust (this is in addition to normal thrust) - minJetEnergy = 40; // Afterburner can't be used if below this threshhold. - jetEnergyDrain = 10; // Energy use of the afterburners (low number is less drain...can be fractional) // Auto stabilize speed - vertThrustMultiple = 1.25; - - // Rigid body - mass = 150; // Mass of the vehicle - bodyFriction = 0; // Don't mess with this. - bodyRestitution = 0.5; // When you hit the ground, how much you rebound. (between 0 and 1) - minRollSpeed = 0; // Don't mess with this. - softImpactSpeed = 14; // Sound hooks. This is the soft hit. - hardImpactSpeed = 25; // Sound hooks. This is the hard hit. - - // Ground Impact Damage (uses DamageType::Ground) - minImpactSpeed = 20; // If hit ground at speed above this then it's an impact. Meters/second - speedDamageScale = 0.06; - - // Object Impact Damage (uses DamageType::Impact) - collDamageThresholdVel = 23.0; - collDamageMultiplier = 0.02; - - // - minTrailSpeed = 70; // The speed your contrail shows up at. - trailEmitter = JetShadowEmitter; - forwardJetEmitter = JetShadowEmitter; - downJetEmitter = JetShadowEmitter; - - // - jetSound = ScoutFlyerThrustSound; - engineSound = ScoutFlyerEngineSound; - softImpactSound = SoftImpactSound; - hardImpactSound = HardImpactSound; - //wheelImpactSound = WheelImpactSound; - - // - softSplashSoundVelocity = 10.0; - mediumSplashSoundVelocity = 15.0; - hardSplashSoundVelocity = 20.0; - exitSplashSoundVelocity = 10.0; - - exitingWater = VehicleExitWaterMediumSound; - impactWaterEasy = VehicleImpactWaterSoftSound; - impactWaterMedium = VehicleImpactWaterMediumSound; - impactWaterHard = VehicleImpactWaterMediumSound; - waterWakeSound = VehicleWakeMediumSplashSound; - - dustEmitter = VehicleLiftoffDustEmitter; - triggerDustHeight = 4.0; - dustHeight = 1.0; - - damageEmitter[0] = MeLightDamageSmoke; - damageEmitter[1] = MeHeavyDamageSmoke; - damageEmitter[2] = MeDamageBubbles; - damageEmitterOffset[0] = "0.0 -3.0 0.0 "; - damageLevelTolerance[0] = 0.4; - damageLevelTolerance[1] = 0.75; - numDmgEmitterAreas = 1; - - // - max[chaingunAmmo] = 2000; - max[MissileLauncherAmmo] = 200; - max[MortarAmmo] = 200; - - damageScale[$DamageType::Nuclear] = 0.0000000000000001; - damageScale[$DamageType::EMP] = 0.0000000000000001; - damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs - ShieldDamageScale[$DamageType::Bullet] = 0.01; //I deny you shrike n0bs - - minMountDist = 7; - - splashEmitter[0] = VehicleFoamDropletsEmitter; - splashEmitter[1] = VehicleFoamEmitter; - - shieldImpact = VehicleShieldImpact; - - cmdCategory = "Tactical"; - cmdIcon = CMDFlyingScoutIcon; - cmdMiniIconName = "commander/MiniIcons/com_scout_grey"; - targetNameTag = 'Lord Vardison'; - targetTypeTag = ''; - sensorData = SSTurretBaseSensorObj; - sensorRadius = SSTurretBaseSensorObj.detectRadius; - sensorColor = "9 9 255"; - - checkRadius = 5.5; - observeParameters = "1 10 10"; - - runningLight[0] = ShrikeLight1; -// runningLight[1] = ShrikeLight2; - - shieldEffectScale = "0.937 1.125 0.60"; - - numWeapons = 3; - - replaceTime = 90; -}; - -datablock PlayerData(VardisonStage3Armor) : LightMaleHumanArmor { - runForce = 60.20 * 90; - runEnergyDrain = 0.0; - minRunEnergy = 10; - maxForwardSpeed = 9; - maxBackwardSpeed = 7; - maxSideSpeed = 7; - - jumpForce = 14.0 * 90; - - maxDamage = 500.0; - minImpactSpeed = 35; - shapeFile = "TR2Heavy_Male.dts"; - jetEmitter = BiodermArmorJetEmitter; - jetEffect = BiodermArmorJetEffect; - - debrisShapeName = "bio_player_debris.dts"; - - //Foot Prints - decalData = LightBiodermFootprint; - decalOffset = 0.3; - - boundingBox = "5 5 10"; - - waterBreathSound = WaterBreathBiodermSound; - - damageScale[$DamageType::M1700] = 3.0; - damageScale[$DamageType::PlasmaCannon] = 0.001; - damageScale[$DamageType::Missile] = 0.0000000000000001; - damageScale[$DamageType::Nuclear] = 0.0000000000000001; - damageScale[$DamageType::EMP] = 0.0000000000000001; - damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs - - max[RepairKit] = 0; - max[Mine] = 0; - max[Grenade] = 0; -}; - -datablock PlayerData(MiniDemonArmor) : LightMaleHumanArmor { - runForce = 60.20 * 90; - runEnergyDrain = 0.0; - minRunEnergy = 10; - maxForwardSpeed = 9; - maxBackwardSpeed = 7; - maxSideSpeed = 7; - - jumpForce = 14.0 * 90; - - maxDamage = 2.8; - minImpactSpeed = 1000; - shapeFile = "bioderm_medium.dts"; - jetEmitter = BiodermArmorJetEmitter; - jetEffect = BiodermArmorJetEffect; - - debrisShapeName = "bio_player_debris.dts"; - - //Foot Prints - decalData = LightBiodermFootprint; - decalOffset = 0.3; - - waterBreathSound = WaterBreathBiodermSound; - - damageScale[$DamageType::M1700] = 3.0; - damageScale[$DamageType::PlasmaCannon] = 0.001; - damageScale[$DamageType::Missile] = 0.0000000000000001; - damageScale[$DamageType::Nuclear] = 0.0000000000000001; - damageScale[$DamageType::EMP] = 0.0000000000000001; - - max[RepairKit] = 0; - max[Mine] = 0; - max[Grenade] = 0; -}; - -// ============================================================================ -// STORMRIDER -// ============================================================================ - -// * See notes on Windshear... - -// ============================================================================ -// GHOST OF FIRE -// ============================================================================ -datablock PlayerData(GhostFireArmor) : MediumPlayerDamageProfile { - emap = true; - - className = Armor; - shapeFile = "medium_male.dts"; - cameraMaxDist = 3; - computeCRC = true; - - debrisShapeName = "debris_player.dts"; - debris = HumanRedPlayerDebris; - - canObserve = true; - cmdCategory = "Clients"; - cmdIcon = CMDPlayerIcon; - cmdMiniIconName = "commander/MiniIcons/com_player_grey"; - - hudImageNameFriendly[0] = "gui/hud_playertriangle"; - hudImageNameEnemy[0] = "gui/hud_playertriangle_enemy"; - hudRenderModulated[0] = true; - - hudImageNameFriendly[1] = "commander/MiniIcons/com_flag_grey"; - hudImageNameEnemy[1] = "commander/MiniIcons/com_flag_grey"; - hudRenderModulated[1] = true; - hudRenderAlways[1] = true; - hudRenderCenter[1] = true; - hudRenderDistance[1] = true; - - hudImageNameFriendly[2] = "commander/MiniIcons/com_flag_grey"; - hudImageNameEnemy[2] = "commander/MiniIcons/com_flag_grey"; - hudRenderModulated[2] = true; - hudRenderAlways[2] = true; - hudRenderCenter[2] = true; - hudRenderDistance[2] = true; - - aiAvoidThis = true; - - minLookAngle = -1.5; - maxLookAngle = 1.5; - maxFreelookAngle = 3.0; - - mass = 70; - drag = 0.3; - maxdrag = 0.5; - density = 10; - maxDamage = 500.0; - maxEnergy = 400; - repairRate = 0.0053; - energyPerDamagePoint = 75.0; // shield energy required to block one point of damage - - rechargeRate = 0.456; - jetForce = 21.22 * 230; - underwaterJetForce = 25.22 * 130 * 1.5; - underwaterVertJetFactor = 1.5; - jetEnergyDrain = 4.0; - underwaterJetEnergyDrain = 1.0; - minJetEnergy = 10; - maxJetHorizontalPercentage = 0.8; - - runForce = 60 * 150; - runEnergyDrain = 0; - minRunEnergy = 0; - maxForwardSpeed = 18; - maxBackwardSpeed = 18; - maxSideSpeed = 18; - - maxUnderwaterForwardSpeed = 10.5; - maxUnderwaterBackwardSpeed = 9.5; - maxUnderwaterSideSpeed = 9.5; - - recoverDelay = 4; - recoverRunForceScale = 0.7; - - // heat inc'ers and dec'ers - heatDecayPerSec = 1.0 / 5.0; // takes 4 seconds to clear heat sig. - heatIncreasePerSec = 1.0 / 2.0; // takes 3.0 seconds of constant jet to get full heat sig. - - jumpForce = 8.3 * 130; - jumpEnergyDrain = 0; - minJumpEnergy = 0; - jumpSurfaceAngle = 75; - jumpDelay = 0; - - // Controls over slope of runnable/jumpable surfaces - runSurfaceAngle = 85; - jumpSurfaceAngle = 85; - - minJumpSpeed = 25; - maxJumpSpeed = 35; - - horizMaxSpeed = 70; - horizResistSpeed = 28; - horizResistFactor = 0.32; - maxJetForwardSpeed = 18; - - upMaxSpeed = 80; - upResistSpeed = 30; - upResistFactor = 0.23; - - minImpactSpeed = 45; - speedDamageScale = 0.006; - - jetSound = ArmorJetSound; - wetJetSound = ArmorWetJetSound; - - jetEmitter = FlammerArmorJetEmitter; //Pyro jets - jetEffect = HumanMediumArmorJetEffect; - - boundingBox = "1.45 1.45 2.4"; - pickupRadius = 0.75; - - // damage location details - boxNormalHeadPercentage = 0.83; - boxNormalTorsoPercentage = 0.49; - boxHeadLeftPercentage = 0; - boxHeadRightPercentage = 1; - boxHeadBackPercentage = 0; - boxHeadFrontPercentage = 1; - - //Foot Prints - decalData = MediumMaleFootprint; - decalOffset = 0.35; - - footPuffEmitter = LightPuffEmitter; - footPuffNumParts = 15; - footPuffRadius = 0.25; - - dustEmitter = LiftoffDustEmitter; - - splash = PlayerSplash; - splashVelocity = 4.0; - splashAngle = 67.0; - splashFreqMod = 300.0; - splashVelEpsilon = 0.60; - bubbleEmitTime = 0.4; - splashEmitter[0] = PlayerFoamDropletsEmitter; - splashEmitter[1] = PlayerFoamEmitter; - splashEmitter[2] = PlayerBubbleEmitter; - mediumSplashSoundVelocity = 10.0; - hardSplashSoundVelocity = 20.0; - exitSplashSoundVelocity = 5.0; - - footstepSplashHeight = 0.35; - //Footstep Sounds - LFootSoftSound = LFootMediumSoftSound; - RFootSoftSound = RFootMediumSoftSound; - LFootHardSound = LFootMediumHardSound; - RFootHardSound = RFootMediumHardSound; - LFootMetalSound = LFootMediumMetalSound; - RFootMetalSound = RFootMediumMetalSound; - LFootSnowSound = LFootMediumSnowSound; - RFootSnowSound = RFootMediumSnowSound; - LFootShallowSound = LFootMediumShallowSplashSound; - RFootShallowSound = RFootMediumShallowSplashSound; - LFootWadingSound = LFootMediumWadingSound; - RFootWadingSound = RFootMediumWadingSound; - LFootUnderwaterSound = LFootMediumUnderwaterSound; - RFootUnderwaterSound = RFootMediumUnderwaterSound; - LFootBubblesSound = LFootMediumBubblesSound; - RFootBubblesSound = RFootMediumBubblesSound; - movingBubblesSound = ArmorMoveBubblesSound; - waterBreathSound = WaterBreathMaleSound; - - impactSoftSound = ImpactMediumSoftSound; - impactHardSound = ImpactMediumHardSound; - impactMetalSound = ImpactMediumMetalSound; - impactSnowSound = ImpactMediumSnowSound; - - skiSoftSound = SkiAllSoftSound; - skiHardSound = SkiAllHardSound; - skiMetalSound = SkiAllMetalSound; - skiSnowSound = SkiAllSnowSound; - - impactWaterEasy = ImpactMediumWaterEasySound; - impactWaterMedium = ImpactMediumWaterMediumSound; - impactWaterHard = ImpactMediumWaterHardSound; - - groundImpactMinSpeed = 10.0; - groundImpactShakeFreq = "4.0 4.0 4.0"; - groundImpactShakeAmp = "1.0 1.0 1.0"; - groundImpactShakeDuration = 0.8; - groundImpactShakeFalloff = 10.0; - - exitingWater = ExitingWaterMediumSound; - - maxWeapons = 2; // Max number of different weapons the player can have - maxGrenades = 1; // Max number of different grenades the player can have - maxMines = 1; // Max number of different mines the player can have - - damageScale[$DamageType::plasma] = 0.05; - damageScale[$DamageType::Burn] = 0.05; - damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs - - // Inventory restrictions - max[RepairKit] = 4; - max[Mine] = 0; - max[ZapMine] = 0; - max[CrispMine] = 5; - max[flamerAmmoPack] = 1; - max[Deagle] = 1; - max[SPistol] = 1; - max[Pistol] = 1; - max[PistolAmmo] = 10; - max[Pistolclip] = 8; - max[PulsePhaser] = 1; - max[flamer] = 1; - max[flamerAmmo] = 0; - max[Napalm] = 1; - max[NapalmAmmo] = 20; - max[melee] = 1; - max[BOV] = 1; - max[SOmelee] = 1; - max[IncindinaryGrenade] = 7; - max[Beacon] = 3; - // -END - - observeParameters = "0.5 4.5 4.5"; - - shieldEffectScale = "0.7 0.7 1.0"; -}; - -// ============================================================================ -// SHADE LORD -// ============================================================================ -datablock PlayerData(ShadeLordArmor) : LightMaleHumanArmor { - boundingBox = "1.63 1.63 2.6"; - maxDamage = 900.0; - minImpactSpeed = 35; - shapeFile = "bioderm_heavy.dts"; - - debrisShapeName = "bio_player_debris.dts"; - - //Foot Prints - decalData = HeavyBiodermFootprint; - decalOffset = 0.4; - - waterBreathSound = WaterBreathBiodermSound; - - damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs - damageScale[$DamageType::Fire] = 3.0; - damageScale[$DamageType::Plasma] = 3.0; - damageScale[$DamageType::Burn] = 2.0; - - max[RepairKit] = 0; - max[Mine] = 0; - max[Grenade] = 0; -}; - -// -// PARTICLES -// - -// ============================================================================ -// YVEX -// ============================================================================ -datablock ParticleData(InflictionNightmareGlobeSmoke) { - dragCoefficient = 50;/////////----------------------- - gravityCoefficient = 0.0; - inheritedVelFactor = 1.0; - constantAcceleration = 0.0; - lifetimeMS = 5050; - lifetimeVarianceMS = 0; - useInvAlpha = true; - spinRandomMin = -360.0; - spinRandomMax = 360.0; - textureName = "particleTest"; - colors[0] = "0.5 0.1 0.9 1.0"; - colors[1] = "0.5 0.1 0.9 1.0"; - colors[2] = "0.5 0.1 0.9 1.0"; - colors[3] = "0.5 0.1 0.9"; - sizes[0] = 1.0; - sizes[1] = 1.0; - sizes[2] = 1.0; - sizes[3] = 1.0; - times[0] = 0.0; - times[1] = 0.33; - times[2] = 0.66; - times[3] = 1.0; - mass = 0.7; - elasticity = 0.2; - friction = 1; - computeCRC = true; - haslight = true; - lightType = "PulsingLight"; - lightColor = "0.2 0.0 0.5 1.0"; - lightTime = "200"; - lightRadius = "2.0"; -}; - -datablock ParticleEmitterData(InfNightmareGlobeEmitter) { - ejectionPeriodMS = 0.1; - periodVarianceMS = 0; - ejectionVelocity = 0.0; - velocityVariance = 0.0; - ejectionOffset = 5; - thetaMin = 0; - thetaMax = 180; - overrideAdvances = false; - particles = "InflictionNightmareGlobeSmoke"; -}; - - -datablock ParticleData(NightmareGlobeSmoke) { - dragCoefficient = 50;/////////----------------------- - gravityCoefficient = 0.0; - inheritedVelFactor = 1.0; - constantAcceleration = 0.0; - lifetimeMS = 5050; - lifetimeVarianceMS = 0; - useInvAlpha = true; - spinRandomMin = -360.0; - spinRandomMax = 360.0; - textureName = "particleTest"; - colors[0] = "0.1 0.1 0.1 1.0";// //////////////////// - colors[1] = "0.1 0.1 0.1 1.0";// //////////////////// - colors[2] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ - colors[3] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ - sizes[0] = 1.0; - sizes[1] = 1.0; - sizes[2] = 1.0; - sizes[3] = 1.0; - times[0] = 0.0; - times[1] = 0.33; - times[2] = 0.66; - times[3] = 1.0; - mass = 0.7; - elasticity = 0.2; - friction = 1; - computeCRC = true; - haslight = true; - lightType = "PulsingLight"; - lightColor = "0.2 0.0 0.5 1.0"; - lightTime = "200"; - lightRadius = "2.0"; -}; - -datablock ParticleEmitterData(NightmareGlobeEmitter) { - ejectionPeriodMS = 0.1; - periodVarianceMS = 0; - ejectionVelocity = 0.0; - velocityVariance = 0.0; - ejectionOffset = 5; - thetaMin = 0; - thetaMax = 180; - overrideAdvances = false; - particles = "NightmareGlobeSmoke"; -}; - -datablock ParticleData(GreenEmitParticle) { - dragCoeffiecient = 1; - gravityCoefficient = -0.3; // rises slowly - inheritedVelFactor = 0; - - lifetimeMS = 300; - lifetimeVarianceMS = 0; - useInvAlpha = false; - spinRandomMin = 0.0; - spinRandomMax = 0.0; - - animateTexture = false; - - textureName = "flareBase"; // "special/Smoke/bigSmoke" - - colors[0] = "0 1 0"; - colors[1] = "0 1 0"; - colors[2] = "0 1 0"; - - sizes[0] = 0.8; - sizes[1] = 0.8; - sizes[2] = 0.8; - - times[0] = 0.0; - times[1] = 1.0; - times[2] = 5.0; - -}; - -datablock ParticleEmitterData(PulseGreenEmitter) { - ejectionPeriodMS = 2; - periodVarianceMS = 1; - - ejectionVelocity = 10; - velocityVariance = 0; - - thetaMin = 89.0; - thetaMax = 90.0; - - orientParticles = false; - - particles = "GreenEmitParticle"; -}; - -datablock ParticleData(PurpleNightmareEmitParticle) { - dragCoeffiecient = 1; - gravityCoefficient = -0.3; // rises slowly - inheritedVelFactor = 0; - - lifetimeMS = 300; - lifetimeVarianceMS = 0; - useInvAlpha = false; - spinRandomMin = 0.0; - spinRandomMax = 0.0; - - animateTexture = false; - - textureName = "flareBase"; // "special/Smoke/bigSmoke" - - colors[0] = "0.5 0.1 0.9 1.0"; - colors[1] = "0.5 0.1 0.9 1.0"; - colors[2] = "0.5 0.1 0.9"; - - sizes[0] = 0.4; - sizes[1] = 0.4; - sizes[2] = 0.4; - - times[0] = 0.0; - times[1] = 1.0; - times[2] = 5.0; - -}; - -datablock ParticleEmitterData(YvexSniperEmitter) { - ejectionPeriodMS = 2; - periodVarianceMS = 1; - - ejectionVelocity = 10; - velocityVariance = 0; - - thetaMin = 89.0; - thetaMax = 90.0; - - orientParticles = false; - - particles = "PurpleNightmareEmitParticle"; -}; - -// ============================================================================ -// WINDSHEAR -// ============================================================================ - -// ============================================================================ -// GHOST OF LIGHTNING -// ============================================================================ -datablock ParticleData(ShockParticle) { - dragCoeffiecient = 0.0; - gravityCoefficient = -0.0; - inheritedVelFactor = 0.0; - - lifetimeMS = 1000; - lifetimeVarianceMS = 0; - - textureName = "particleTest"; - - useInvAlpha = false; - spinRandomMin = -100.0; - spinRandomMax = 100.0; - - numParts = 50; - - animateTexture = true; - framesPerSec = 26; - - animTexName[00] = "special/Explosion/exp_0002"; - animTexName[01] = "special/Explosion/exp_0004"; - animTexName[02] = "special/Explosion/exp_0006"; - animTexName[03] = "special/Explosion/exp_0008"; - animTexName[04] = "special/Explosion/exp_0010"; - animTexName[05] = "special/Explosion/exp_0012"; - animTexName[06] = "special/Explosion/exp_0014"; - animTexName[07] = "special/Explosion/exp_0016"; - animTexName[08] = "special/Explosion/exp_0018"; - animTexName[09] = "special/Explosion/exp_0020"; - animTexName[10] = "special/Explosion/exp_0022"; - animTexName[11] = "special/Explosion/exp_0024"; - animTexName[12] = "special/Explosion/exp_0026"; - animTexName[13] = "special/Explosion/exp_0028"; - animTexName[14] = "special/Explosion/exp_0030"; - animTexName[15] = "special/Explosion/exp_0032"; - animTexName[16] = "special/Explosion/exp_0034"; - animTexName[17] = "special/Explosion/exp_0036"; - animTexName[18] = "special/Explosion/exp_0038"; - animTexName[19] = "special/Explosion/exp_0040"; - animTexName[20] = "special/Explosion/exp_0042"; - animTexName[21] = "special/Explosion/exp_0044"; - animTexName[22] = "special/Explosion/exp_0046"; - animTexName[23] = "special/Explosion/exp_0048"; - animTexName[24] = "special/Explosion/exp_0050"; - animTexName[25] = "special/Explosion/exp_0052"; - - - colors[0] = "0.5 0.5 1.0 1.0"; - colors[1] = "0.5 0.5 1.0 0.5"; - colors[2] = "0.25 0.25 1.0 0.0"; - sizes[0] = 0.5; - sizes[1] = 0.5; - sizes[2] = 0.5; - times[0] = 0.0; - times[1] = 0.5; - times[2] = 1.0; -}; - -datablock ParticleEmitterData(ShockParticleEmitter) { - ejectionPeriodMS = 1; - periodVarianceMS = 0; - - ejectionVelocity = 0.25; - velocityVariance = 0.0; - - thetaMin = 0.0; - thetaMax = 30.0; - - particles = "ShockParticle"; -}; - -datablock ShockwaveData( ShocklanceHit ) { - width = 0.5; - numSegments = 20; - numVertSegments = 1; - velocity = 0.25; - acceleration = 1.0; - lifetimeMS = 600; - height = 0.1; - verticalCurve = 0.5; - - mapToTerrain = false; - renderBottom = false; - orientToNormal = true; - - texture[0] = "special/shocklanceHit"; - texture[1] = "special/gradient"; - texWrap = 3.0; - - times[0] = 0.0; - times[1] = 0.5; - times[2] = 1.0; - - colors[0] = "1.0 1.0 1.0 1.0"; - colors[1] = "1.0 1.0 1.0 0.5"; - colors[2] = "1.0 1.0 1.0 0.0"; -}; - -// ============================================================================ -// VEGENOR -// ============================================================================ - -// ============================================================================ -// LORD ROG -// ============================================================================ -datablock ParticleData(PBCParticle) { - dragCoefficient = 0.5; - WindCoefficient = 0; - gravityCoefficient = 0.0; - inheritedVelFactor = 1; - constantAcceleration = 0; - lifetimeMS = 3000; - lifetimeVarianceMS = 0; - textureName = "special/lightning1frame2"; - useInvAlpha = 0; - - spinRandomMin = -800; - spinRandomMax = 800; - - spinspeed = 50; - colors[0] = "0.1 1.0 0.1 1.0"; - colors[1] = "0.6 0.9 0.6 1.0"; - colors[2] = "0.8 0.8 1.0 1.0"; - colors[3] = "0.8 0.8 1.0 0.0"; - sizes[0] = 0.5; - sizes[1] = 1; - sizes[2] = 1.5; - sizes[3] = 1.5; - times[0] = 0.0; - times[1] = 0.1; - times[2] = 0.3; - times[3] = 1.0; -}; - -datablock ParticleEmitterData(PBCExpEmitter) { - ejectionPeriodMS = 2; - periodVarianceMS = 0; - - ejectionVelocity = 2.5; - velocityVariance = 2.5; - - thetaMin = 0.0; - thetaMax = 180.0; - - lifetimeMS = 200; - - particles = "PBCParticle"; -}; - -// ============================================================================ -// INSIGNIA -// ============================================================================ - -// ============================================================================ -// TREVOR -// ============================================================================ - -// ============================================================================ -// LORD VARDISON / D.A. VARDISON -// ============================================================================ -datablock ParticleData(ShadowBaseParticle) { - dragCoeffiecient = 0.0; - gravityCoefficient = -0.2; - inheritedVelFactor = 0.0; - - lifetimeMS = 800; - lifetimeVarianceMS = 500; - - useInvAlpha = true; - spinRandomMin = -160.0; - spinRandomMax = 160.0; - - animateTexture = true; - framesPerSec = 15; - - textureName = "special/cloudflash"; - - colors[0] = "0.1 0.1 0.1 1.0";// //////////////////// - colors[1] = "0.1 0.1 0.1 1.0";// //////////////////// - colors[2] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ - - sizes[0] = 2.5; - sizes[1] = 2.7; - sizes[2] = 3.0; - - times[0] = 0.0; - times[1] = 0.7; - times[2] = 1.0; -}; - -datablock ParticleEmitterData(ShadowBaseEmitter) { - ejectionPeriodMS = 10; - periodVarianceMS = 0; - - ejectionVelocity = 1.5; - velocityVariance = 0.3; - - thetaMin = 0.0; - thetaMax = 30.0; - - particles = "ShadowBaseParticle"; -}; - -datablock ParticleData(SmallShadowBaseParticle) { - dragCoeffiecient = 0.0; - gravityCoefficient = -0.2; - inheritedVelFactor = 0.0; - - lifetimeMS = 9999999999999; - lifetimeVarianceMS = 9999999999999; - - useInvAlpha = true; - spinRandomMin = -160.0; - spinRandomMax = 160.0; - - animateTexture = true; - framesPerSec = 15; - - textureName = "special/cloudflash"; - - colors[0] = "0.1 0.1 0.1 1.0";// //////////////////// - colors[1] = "0.1 0.1 0.1 1.0";// //////////////////// - colors[2] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ - - sizes[0] = 0.5; - sizes[1] = 0.7; - sizes[2] = 1.0; - - times[0] = 0.0; - times[1] = 0.7; - times[2] = 1.0; -}; - -datablock ParticleEmitterData(SmallShadowBaseEmitter) { - ejectionPeriodMS = 10; - periodVarianceMS = 0; - - ejectionVelocity = 1.5; - velocityVariance = 0.3; - - thetaMin = 0.0; - thetaMax = 30.0; - - particles = "SmallShadowBaseParticle"; -}; - -datablock ParticleData(JetShadowParticle) { - dragCoeffiecient = 0.0; - gravityCoefficient = 0; - inheritedVelFactor = 0.0; - - lifetimeMS = 2500; - lifetimeVarianceMS = 0; - - textureName = "particleTest"; - - useInvAlpha = true; - spinRandomMin = -160.0; - spinRandomMax = 160.0; - - animateTexture = true; - framesPerSec = 15; - - animTexName[0] = "special/Explosion/exp_0016"; - animTexName[1] = "special/Explosion/exp_0018"; - animTexName[2] = "special/Explosion/exp_0020"; - animTexName[3] = "special/Explosion/exp_0022"; - animTexName[4] = "special/Explosion/exp_0024"; - animTexName[5] = "special/Explosion/exp_0026"; - animTexName[6] = "special/Explosion/exp_0028"; - animTexName[7] = "special/Explosion/exp_0030"; - animTexName[8] = "special/Explosion/exp_0032"; - - colors[0] = "0.1 0.1 0.1 1.0";// //////////////////// - colors[1] = "0.1 0.1 0.1 1.0";// //////////////////// - colors[2] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ - sizes[0] = 2.5; - sizes[1] = 1.25; - sizes[2] = 0.625; - times[0] = 0.0; - times[1] = 0.7; - times[2] = 1.0; -}; - -datablock ParticleEmitterData(JetShadowEmitter) { - ejectionPeriodMS = 2; - periodVarianceMS = 0; - - ejectionVelocity = 0; - velocityVariance = 0; - ejectionOffset = 5; - thetaMin = 22.5; - thetaMax = 45; - phiReferenceVel = 0; - phiVariance = 360; - spinRandomMin = "200"; - spinRandomMax = "-200"; - overrideAdvances = false; - particles = "JetShadowParticle"; -}; - -datablock ParticleData(LaserBallGlobeSmoke) { - dragCoefficient = 50;/////////----------------------- - gravityCoefficient = 0.0; - inheritedVelFactor = 1.0; - constantAcceleration = 0.0; - lifetimeMS = 1000; - lifetimeVarianceMS = 0; - useInvAlpha = true; - spinRandomMin = -360.0; - spinRandomMax = 360.0; - textureName = "particleTest"; - colors[0] = "0.1 0.1 0.1 1.0";// //////////////////// - colors[1] = "0.1 0.1 0.1 1.0";// //////////////////// - colors[2] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ - colors[3] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ - sizes[0] = 1.0; - sizes[1] = 1.0; - sizes[2] = 1.0; - sizes[3] = 1.0; - times[0] = 0.0; - times[1] = 0.33; - times[2] = 0.66; - times[3] = 1.0; - mass = 0.7; - elasticity = 0.2; - friction = 1; - computeCRC = true; - haslight = true; - lightType = "PulsingLight"; - lightColor = "0.2 0.0 0.5 1.0"; - lightTime = "200"; - lightRadius = "2.0"; -}; - -datablock ParticleEmitterData(MiniShadowBallEmitter) { - ejectionPeriodMS = 0.3; - periodVarianceMS = 0; - ejectionVelocity = 0.0; - velocityVariance = 0.0; - ejectionOffset = 2; - thetaMin = 0; - thetaMax = 180; - overrideAdvances = false; - particles = "LaserBallGlobeSmoke"; -}; - -// ============================================================================ -// STORMRIDER -// ============================================================================ -//Seeker Plasma Stuff -//Credit To Abrikcham -//-abirikcham@yahoo.com -datablock ShockwaveData(FakePhotonMissileShockwave) { - width = 0.5; - numSegments = 30; - numVertSegments = 2; - velocity = 8; - verticalcurve = 0; - acceleration = -17.0; - lifetimeMS = 600; - height = 0.00001; - is2D = false; - texture[0] = "special/shockwave4"; - texture[1] = "special/gradient"; - texWrap = 10.0; - mapToTerrain = false; - orientToNormal = true; - renderBottom = true; - times[0] = 0.0; - times[1] = 0.5; - times[2] = 1.0; - colors[0] = "0 1 0 1"; - colors[1] = "0.0 1.1 0.0 0.60";//0.4 0.1 1.0 - colors[2] = "0.0 1.1 0.0 0.0"; -}; - -datablock AudioProfile(FakePhotonMissileShockwaveSound) { - filename = "fx/misc/gridjump.wav"; - description = AudioExplosion3d; - preload = true; -}; - -datablock ExplosionData(FakePhotonShockwaveExp) { - soundProfile = FakePhotonMissileShockwaveSound; - faceViewer = false; - shockwave = FakePhotonMissileShockwave; - - shakeCamera = true; - camShakeFreq = "10.0 6.0 9.0"; - camShakeAmp = "20.0 20.0 20.0"; - camShakeDuration = 0.5; - camShakeRadius = 3.0; -}; - -datablock ParticleData(PhotonMissileExpPart) { - dragCoefficient = 2; - gravityCoefficient = 0.0; - inheritedVelFactor = 0.2; - constantAcceleration = 0.0; - lifetimeMS = 750; - lifetimeVarianceMS = 150; - textureName = "particleTest"; - colors[0] = "0 1 0 1.0"; - colors[1] = "0 1 0 0.0"; - sizes[0] = 3; - sizes[1] = 2; -}; - -datablock ParticleEmitterData(PhotonMissileExpEmit) { - ejectionPeriodMS = 7; - periodVarianceMS = 0; - ejectionVelocity = 3; - velocityVariance = 1.0; - ejectionOffset = 0.0; - thetaMin = 0; - thetaMax = 60; - phiReferenceVel = 0; - phiVariance = 360; - overrideAdvances = false; - particles = "PhotonMissileExpPart"; -}; - -datablock ExplosionData(PhotonMissileExplosion) { - explosionShape = "disc_explosion.dts"; - soundProfile = UnderwaterGrenadeExplosionSound;//plasmaexpsound orig - - shakeCamera = true; - camShakeFreq = "8.0 9.0 7.0"; - camShakeAmp = "25.0 25.0 25.0"; - camShakeDuration = 1.3; - camShakeRadius = 25.0; - - particleEmitter = PhotonMissileExpEmit; - particleDensity = 150; - particleRadius = 3.5; - faceViewer = true; -}; - -// ============================================================================ -// GHOST OF FIRE -// ============================================================================ -datablock ParticleData(GhostflameParticle) { - dragCoeffiecient = 0.0; - gravityCoefficient = -0.1; - inheritedVelFactor = 0.1; - - lifetimeMS = 500; - lifetimeVarianceMS = 50; - - textureName = "particleTest"; - - spinRandomMin = -10.0; - spinRandomMax = 10.0; - - colors[0] = "0 1 0 0.4"; - colors[1] = "0 1 0 0.3"; - colors[2] = "0 1 0 0.0"; - sizes[0] = 2.0; - sizes[1] = 1.0; - sizes[2] = 0.8; - times[0] = 0.0; - times[1] = 0.6; - times[2] = 1.0; -}; - -datablock ParticleEmitterData(GhostflameEmitter) { - ejectionPeriodMS = 3; - periodVarianceMS = 0; - - ejectionOffset = 0.2; - ejectionVelocity = 10.0; - velocityVariance = 0.0; - - thetaMin = 0.0; - thetaMax = 10.0; - - particles = "GhostflameParticle"; -}; - -datablock ParticleData(NapalmExplosionParticle) { - dragCoefficient = 2; - gravityCoefficient = 0.2; - inheritedVelFactor = 0.2; - constantAcceleration = 0.0; - lifetimeMS = 450; - lifetimeVarianceMS = 150; - textureName = "particleTest"; - colors[0] = "1 0 0"; - colors[1] = "1 0 0"; - sizes[0] = 0.5; - sizes[1] = 2; -}; - -datablock ParticleEmitterData(NapalmExplosionEmitter) { - ejectionPeriodMS = 7; - periodVarianceMS = 0; - ejectionVelocity = 5; - velocityVariance = 1.0; - ejectionOffset = 0.0; - thetaMin = 0; - thetaMax = 60; - phiReferenceVel = 0; - phiVariance = 360; - overrideAdvances = false; - particles = "NapalmExplosionParticle"; -}; - -datablock ExplosionData(NapalmExplosion) { - explosionShape = "effect_plasma_explosion.dts"; - soundProfile = plasmaExpSound; - particleEmitter = NapalmExplosionEmitter; - particleDensity = 150; - particleRadius = 1.25; - faceViewer = true; - - sizes[0] = "3.0 3.0 3.0"; - sizes[1] = "3.0 3.0 3.0"; - times[0] = 0.0; - times[1] = 1.5; -}; - -// ============================================================================ -// SHADE LORD -// ============================================================================ -datablock ParticleData(ShadeSwordParticle) { - dragCoeffiecient = 0.0; - gravityCoefficient = -0.2; - inheritedVelFactor = 0.0; - - lifetimeMS = 800; - lifetimeVarianceMS = 500; - - useInvAlpha = false; - spinRandomMin = -160.0; - spinRandomMax = 160.0; - - animateTexture = true; - framesPerSec = 15; - - textureName = "special/cloudflash"; - - colors[0] = "46 46 46 1.0"; - colors[1] = "46 46 46 1.0"; - colors[2] = "46 46 46 1.0"; - - sizes[0] = 2.5; - sizes[1] = 2.7; - sizes[2] = 3.0; - - times[0] = 0.0; - times[1] = 0.7; - times[2] = 1.0; -}; - -datablock ParticleEmitterData(ShadeSwordEmitter) { - ejectionPeriodMS = 10; - periodVarianceMS = 0; - - ejectionVelocity = 1.5; - velocityVariance = 0.3; - - thetaMin = 0.0; - thetaMax = 30.0; - - particles = "ShadeSwordParticle"; -}; - -datablock ParticleData(ShadeStormParticle) { - dragCoefficient = 1.0; - gravityCoefficient = 0.00; - windcoefficient = 0.0; - inheritedVelFactor = 0.0; - constantAcceleration = 10.0; - lifetimeMS = 1000; - lifetimeVarianceMS = 100; - useInvAlpha = true; - spinRandomMin = -90.0; - spinRandomMax = 90.0; - textureName = "special/cloudFlash"; - - colors[0] = "46 46 46 0.5"; - colors[1] = "46 46 46 0.5"; - colors[2] = "46 46 46 0.0"; - sizes[0] = 500; - sizes[1] = 500; - sizes[2] = 500; - times[0] = 0.0; - times[1] = 0.5; - times[2] = 1.0; -}; - -datablock ParticleEmitterData(ShadeStormEmitter) { - ejectionPeriodMS = 1; - periodVarianceMS = 0; - ejectionVelocity = 400.0; - velocityVariance = 150.0; - ejectionOffset = 0.0; - thetaMin = 85; - thetaMax = 85; - phiReferenceVel = 0; - phiVariance = 360; - overrideAdvances = false; - particles = "ShadeStormParticle"; -}; - -datablock ParticleData(dayCloakSmokeParticles) { - dragCoefficient = 50;/////////----------------------- - gravityCoefficient = 0.0; - inheritedVelFactor = 1.0; - constantAcceleration = 1.0; - lifetimeMS = 1000; - lifetimeVarianceMS = 0; - useInvAlpha = true; - spinRandomMin = -360.0; - spinRandomMax = 360.0; - textureName = "particleTest"; - colors[0] = "0.1 0.1 0.1 1.0";// //////////////////// - colors[1] = "0.1 0.1 0.1 1.0";// //////////////////// - colors[2] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ - colors[3] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ - sizes[0] = 350.0; - sizes[1] = 350.0; - sizes[2] = 350.0; - sizes[3] = 350.0; - times[0] = 0.0; - times[1] = 0.33; - times[2] = 0.66; - times[3] = 1.0; - mass = 0.4; - elasticity = 0.2; - friction = 1; - computeCRC = true; - haslight = true; - lightType = "PulsingLight"; - lightColor = "0.2 0.0 0.5 1.0"; - lightTime = "200"; - lightRadius = "2.0"; -}; - -datablock ParticleEmitterData(dayCloakEmitter) { - ejectionPeriodMS = 50; - periodVarianceMS = 0; - ejectionVelocity = 10.0; - velocityVariance = 0.0; - ejectionOffset = 2; - thetaMin = 0; - thetaMax = 180; - overrideAdvances = false; - particles = "dayCloakSmokeParticles"; -}; - -// -datablock ParticleData(ShadeLordScreamParticle) { - dragCoefficient = 1.0; - gravityCoefficient = 0.00; - windcoefficient = 0.0; - inheritedVelFactor = 0.0; - constantAcceleration = 10.0; - lifetimeMS = 1000; - lifetimeVarianceMS = 100; - useInvAlpha = true; - spinRandomMin = -90.0; - spinRandomMax = 90.0; - textureName = "special/cloudFlash"; - - colors[0] = "156 0 0 0.5"; - colors[1] = "156 0 0 0.5"; - colors[2] = "156 0 0 0.0"; - sizes[0] = 500; - sizes[1] = 500; - sizes[2] = 2; - times[0] = 0.0; - times[1] = 0.5; - times[2] = 1.0; -}; - -datablock ParticleEmitterData(ShadeLordScreamEmitter) { - ejectionPeriodMS = 1; - periodVarianceMS = 0; - ejectionVelocity = 400.0; - velocityVariance = 150.0; - ejectionOffset = 0.0; - thetaMin = 85; - thetaMax = 85; - phiReferenceVel = 0; - phiVariance = 360; - overrideAdvances = false; - particles = "ShadeLordScreamParticle"; -}; - -// -// PROJECTILES -// - -// ============================================================================ -// YVEX -// ============================================================================ -datablock SeekerProjectileData(YvexNightmareMissile){ - casingShapeName = "weapon_missile_casement.dts"; - projectileShapeName = "weapon_missile_projectile.dts"; - hasDamageRadius = true; - indirectDamage = 0.8; - damageRadius = 8.0; - radiusDamageType = $DamageType::Missile; - kickBackStrength = 2000; - - explosion = "MissileExplosion"; - splash = MissileSplash; - velInheritFactor = 1.0; // to compensate for slow starting velocity, this value - // is cranked up to full so the missile doesn't start - // out behind the player when the player is moving - // very quickly - bramage - - delayEmitter = MissileFireEmitter; - puffEmitter = MissilePuffEmitter; - bubbleEmitter = GrenadeBubbleEmitter; - bubbleEmitTime = 1.0; - - exhaustEmitter = MissileLauncherExhaustEmitter; - exhaustTimeMs = 300; - exhaustNodeName = "muzzlePoint1"; - - lifetimeMS = 30000; - muzzleVelocity = 10.0; - maxVelocity = 150.0; - turningSpeed = 110.0; - acceleration = 350.0; - - proximityRadius = 3; - - terrainAvoidanceSpeed = 180; - terrainScanAhead = 25; - terrainHeightFail = 12; - terrainAvoidanceRadius = 100; - - flareDistance = 200; - flareAngle = 30; - - sound = MissileProjectileSound; - - hasLight = true; - lightRadius = 5.0; - lightColor = "0.2 0.05 0"; - - useFlechette = true; - flechetteDelayMs = 550; - casingDeb = FlechetteDebris; - - explodeOnWaterImpact = false; - - baseEmitter = NMMissileBaseEmitter; -}; - -datablock LinearFlareProjectileData(KillerPulse) { - scale = "1.0 1.0 1.0"; - faceViewer = false; - directDamage = 0.00001; - hasDamageRadius = false; - indirectDamage = 0.6; - damageRadius = 10.0; - kickBackStrength = 100.0; - directDamageType = $DamageType::Admin; - indirectDamageType = $DamageType::Admin; - - explosion = "BlasterExplosion"; - splash = PlasmaSplash; - - dryVelocity = 200.0; - wetVelocity = 10; - velInheritFactor = 0.5; - fizzleTimeMS = 30000; - lifetimeMS = 30000; - explodeOnDeath = false; - reflectOnWaterImpactAngle = 0.0; - explodeOnWaterImpact = true; - deflectionOnWaterImpact = 0.0; - fizzleUnderwaterMS = -1; - - baseEmitter = PulseGreenEmitter; - delayEmitter = PulseGreenEmitter; - bubbleEmitter = PulseGreenEmitter; - - //activateDelayMS = 100; - activateDelayMS = -1; - - size[0] = 0.2; - size[1] = 0.2; - size[2] = 0.2; - - - numFlares = 15; - flareColor = "0 1 0"; - flareModTexture = "flaremod"; - flareBaseTexture = "flarebase"; - - sound = MissileProjectileSound; - fireSound = PlasmaFireSound; - wetFireSound = PlasmaFireWetSound; - - hasLight = true; - lightRadius = 3.0; - lightColor = "0 1 0"; - -}; - -datablock LinearFlareProjectileData(YvexSniperShot) { - projectileShapeName = "weapon_missile_projectile.dts"; - scale = "3.0 5.0 3.0"; - faceViewer = true; - directDamage = 0.01; - kickBackStrength = 4000.0; - DirectDamageType = $DamageType::Zombie; - - explosion = "BlasterExplosion"; - - dryVelocity = 150.0; - wetVelocity = -1; - velInheritFactor = 0.3; - fizzleTimeMS = 10000; - lifetimeMS = 10000; - explodeOnDeath = true; - reflectOnWaterImpactAngle = 0.0; - explodeOnWaterImpact = true; - deflectionOnWaterImpact = 0.0; - fizzleUnderwaterMS = -1; - - activateDelayMS = 100; - activateDelayMS = -1; - - baseEmitter = YvexSniperEmitter; - - size[0] = 0.0; - size[1] = 0.0; - size[2] = 0.0; - - - numFlares = 0; - flareColor = "0.0 0.0 0.0"; - flareModTexture = "flaremod"; - flareBaseTexture = "flarebase"; - - sound = PlasmaProjectileSound; - fireSound = PlasmaFireSound; - wetFireSound = PlasmaFireWetSound; - - hasLight = true; - lightRadius = 3.0; - lightColor = "1 0.75 0.25"; -}; - -datablock SeekerProjectileData(YvexZombieMakerMissile) { - casingShapeName = "weapon_missile_casement.dts"; - projectileShapeName = "weapon_missile_projectile.dts"; - hasDamageRadius = true; - indirectDamage = 0.5; - damageRadius = 5.0; - radiusDamageType = $DamageType::Zombie; - kickBackStrength = 2000; - - explosion = "MissileExplosion"; - splash = MissileSplash; - velInheritFactor = 1.0; // to compensate for slow starting velocity, this value - // is cranked up to full so the missile doesn't start - // out behind the player when the player is moving - // very quickly - bramage - - baseEmitter = MortarSmokeEmitter; - delayEmitter = MissileFireEmitter; - puffEmitter = MissilePuffEmitter; - bubbleEmitter = GrenadeBubbleEmitter; - bubbleEmitTime = 1.0; - - exhaustEmitter = MissileLauncherExhaustEmitter; - exhaustTimeMs = 300; - exhaustNodeName = "muzzlePoint1"; - - lifetimeMS = 30000; // z0dd - ZOD, 4/14/02. Was 6000 - muzzleVelocity = 30.0; - maxVelocity = 35.0; // z0dd - ZOD, 4/14/02. Was 80.0 - turningSpeed = 23.0; - acceleration = 15.0; - - proximityRadius = 2.5; - - terrainAvoidanceSpeed = 10; - terrainScanAhead = 7; - terrainHeightFail = 1; - terrainAvoidanceRadius = 3; - - flareDistance = 40; - flareAngle = 20; - minSeekHeat = 0.0; - - sound = MissileProjectileSound; - - hasLight = true; - lightRadius = 5.0; - lightColor = "0.2 0.05 0"; - - useFlechette = true; - flechetteDelayMs = 250; - casingDeb = FlechetteDebris; - - explodeOnWaterImpact = false; -}; - -// ============================================================================ -// WINDSHEAR -// ============================================================================ -datablock SeekerProjectileData(BossMissiles) { - casingShapeName = "weapon_missile_casement.dts"; - projectileShapeName = "weapon_missile_projectile.dts"; - hasDamageRadius = true; - indirectDamage = 0.1; - damageRadius = 6.0; - radiusDamageType = $DamageType::MissileTurret; - kickBackStrength = 500; - - flareDistance = 200; - flareAngle = 30; - minSeekHeat = 0.0; - - explosion = "MissileExplosion"; - velInheritFactor = 1.0; - - splash = MissileSplash; - baseEmitter = MortarSmokeEmitter; - delayEmitter = MissileFireEmitter; - puffEmitter = MissilePuffEmitter; - - lifetimeMS = 15000; // z0dd - ZOD, 4/14/02. Was 6000 - muzzleVelocity = 12.0; - maxVelocity = 225.0; // z0dd - ZOD, 4/14/02. Was 80.0 - turningSpeed = 50.0; - acceleration = 100.0; - - proximityRadius = 4; - - terrainAvoidanceSpeed = 100; - terrainScanAhead = 50; - terrainHeightFail = 50; - terrainAvoidanceRadius = 150; - - useFlechette = true; - flechetteDelayMs = 225; - casingDeb = FlechetteDebris; -}; - -// ============================================================================ -// GHOST OF LIGHTNING -// ============================================================================ -datablock ShockLanceProjectileData(GoLShocker) { - directDamage = 0.45; - radiusDamageType = $DamageType::ShockLance; - kickBackStrength = 2500; - velInheritFactor = 0; - sound = ""; - - zapDuration = 1.0; - impulse = 1800; - boltLength = 50.0; - extension = 50.0; // script variable indicating distance you can shock people from - lightningFreq = 25.0; - lightningDensity = 3.0; - lightningAmp = 0.25; - lightningWidth = 0.05; - - shockwave = ShocklanceHit; - - boltSpeed[0] = 2.0; - boltSpeed[1] = -0.5; - - texWrap[0] = 1.5; - texWrap[1] = 1.5; - - startWidth[0] = 0.3; - endWidth[0] = 0.6; - startWidth[1] = 0.3; - endWidth[1] = 0.6; - - texture[0] = "special/shockLightning01"; - texture[1] = "special/shockLightning02"; - texture[2] = "special/shockLightning03"; - texture[3] = "special/ELFBeam"; - - emitter[0] = ShockParticleEmitter; -}; - -// ============================================================================ -// VEGENOR -// ============================================================================ -datablock SeekerProjectileData(VegenorFireMissile) : YvexZombieMakerMissile { - indirectDamage = 0.5; - damageRadius = 5.0; - radiusDamageType = $DamageType::Fire; -}; - -datablock GrenadeProjectileData(VegenorFireMeteor) : JTLMeteorStormFireball { - projectileShapeName = "plasmabolt.dts"; - scale = "40.0 40.0 40.0"; - emitterDelay = -1; - directDamage = 0; - directDamageType = $DamageType::Fire; - hasDamageRadius = true; // true; - indirectDamage = 0.5; // 0.5; - damageRadius = 150.0; - radiusDamageType = $DamageType::Fire; -}; - -// ============================================================================ -// LORD ROG -// ============================================================================ -datablock SeekerProjectileData(LordRogStiloutte) { - casingShapeName = "weapon_missile_casement.dts"; - projectileShapeName = "weapon_missile_projectile.dts"; - hasDamageRadius = true; - indirectDamage = 0.5; - damageRadius = 5.0; - radiusDamageType = $DamageType::Zombie; - kickBackStrength = 2000; - - explosion = "MissileExplosion"; - splash = MissileSplash; - velInheritFactor = 1.0; // to compensate for slow starting velocity, this value - // is cranked up to full so the missile doesn't start - // out behind the player when the player is moving - // very quickly - bramage - - baseEmitter = MortarSmokeEmitter; - delayEmitter = MissileFireEmitter; - puffEmitter = MissilePuffEmitter; - bubbleEmitter = GrenadeBubbleEmitter; - bubbleEmitTime = 1.0; - - exhaustEmitter = MissileLauncherExhaustEmitter; - exhaustTimeMs = 300; - exhaustNodeName = "muzzlePoint1"; - - lifetimeMS = 20000; // z0dd - ZOD, 4/14/02. Was 6000 - muzzleVelocity = 10.0; - maxVelocity = 80.0; // z0dd - ZOD, 4/14/02. Was 80.0 - turningSpeed = 23.0; - acceleration = 15.0; - - proximityRadius = 2.5; - - terrainAvoidanceSpeed = 10; - terrainScanAhead = 7; - terrainHeightFail = 1; - terrainAvoidanceRadius = 3; - - flareDistance = 40; - flareAngle = 20; - minSeekHeat = 0.0; - - sound = MissileProjectileSound; - - hasLight = true; - lightRadius = 5.0; - lightColor = "0.2 0.05 0"; - - useFlechette = true; - flechetteDelayMs = 250; - casingDeb = FlechetteDebris; - - explodeOnWaterImpact = false; -}; - -// ============================================================================ -// INSIGNIA -// ============================================================================ - -// ============================================================================ -// TREVOR -// ============================================================================ - -// ============================================================================ -// LORD VARDISON / D.A. VARDISON -// ============================================================================ -datablock LinearFlareProjectileData(SuperlaserProjectile) { - scale = "15.0 15.0 15.0"; - faceViewer = false; - directDamage = 1.0; - hasDamageRadius = true; - indirectDamage = 0.9; - damageRadius = 30.0; - kickBackStrength = 1000.0; - radiusDamageType = $DamageType::Explosion; - - explosion[0] = "HyperDevCannonExplosion2"; - explosion[1] = "SatchelMainExplosion"; - splash = PlasmaSplash; - baseEmitter = HyperDevCannonBaseEmitter; - - - dryVelocity = 200.0; - wetVelocity = 200; - velInheritFactor = 0.5; - fizzleTimeMS = 10000; - lifetimeMS = 10000; - explodeOnDeath = false; - reflectOnWaterImpactAngle = 0.0; - explodeOnWaterImpact = true; - deflectionOnWaterImpact = 0.0; - fizzleUnderwaterMS = -1; - - //activateDelayMS = 100; - activateDelayMS = -1; - - size[0] = 9; - size[1] = 10; - size[2] = 11; - - - numFlares = 400; - flareColor = "0.0 1.0 0"; - flareModTexture = "flaremod"; - flareBaseTexture = "flarebase"; - - sound = MissileProjectileSound; - fireSound = PlasmaFireSound; - wetFireSound = PlasmaFireWetSound; - - hasLight = true; - lightRadius = 3.0; - lightColor = "0 0.75 0.25"; - -}; - -datablock LinearFlareProjectileData(ShadowBomb) { - projectileShapeName = "turret_muzzlepoint.dts"; - scale = "1.0 1.0 1.0"; - faceViewer = true; - directDamage = 0.02; - hasDamageRadius = true; - indirectDamage = 0.02; - damageRadius = 4.0; - kickBackStrength = 0.0; - radiusDamageType = $DamageType::Fire; - - explosion = "ThrowerExplosion"; - splash = PlasmaSplash; - - baseEmitter = ShadowBaseEmitter; - - dryVelocity = 50.0; // z0dd - ZOD, 7/20/02. Faster plasma projectile. was 55 - wetVelocity = -1; - velInheritFactor = 0.3; - fizzleTimeMS = 14000; - lifetimeMS = 10000; // z0dd - ZOD, 4/25/02. Was 6000 - explodeOnDeath = false; - reflectOnWaterImpactAngle = 0.0; - explodeOnWaterImpact = true; - deflectionOnWaterImpact = 0.0; - fizzleUnderwaterMS = -1; - - //activateDelayMS = 100; - activateDelayMS = -1; - - size[0] = 0.2; - size[1] = 0.5; - size[2] = 0.1; - - - numFlares = 35; - flareColor = "1 0.18 0.03"; - flareModTexture = "flaremod"; - flareBaseTexture = "flarebase"; - - sound = PlasmaProjectileSound; - fireSound = FlamethrowerFireSound; - wetFireSound = PlasmaFireWetSound; - - hasLight = true; - lightRadius = 10.0; - lightColor = "0.94 0.03 0.12"; -}; - -datablock SeekerProjectileData(VardisonLaserBallMissile) : YvexNightmareMissile { - baseEmitter = ShadowBaseEmitter; -}; - -datablock LinearFlareProjectileData(VardisonSubShadowBomb) : DMPlasma { - explosion = MortarExplosion; - dryVelocity = 500.0; // z0dd - ZOD, 4/25/02. Was 50. Velocity of projectile out of water - wetVelocity = -1; - velInheritFactor = 1.0; - fizzleTimeMS = 14000; - lifetimeMS = 10000; // z0dd - ZOD, 4/25/02. Was 6000 -}; - -datablock SeekerProjectileData(VardisonMiniDemonSpawner) : VardisonNightmareMissile { - baseEmitter = ShadowBaseEmitter; -}; - -datablock GrenadeProjectileData(MiniDemonBlaster) { - projectileShapeName = "plasmabolt.dts"; - emitterDelay = -1; - directDamage = 0.0; - hasDamageRadius = true; - indirectDamage = 0.45; - damageRadius = 5.0; // z0dd - ZOD, 8/13/02. Was 20.0 - radiusDamageType = $DamageType::Demon; - kickBackStrength = 1500; - - explosion = "MortarExplosion"; - underwaterExplosion = "MortarExplosion"; - velInheritFactor = 0; - splash = PlasmaSplash; - depthTolerance = 100.0; - - baseEmitter = DemonFBSmokeEmitter; - bubbleEmitter = DemonFBSmokeEmitter; - - grenadeElasticity = 0; - grenadeFriction = 0.4; - armingDelayMS = -1; // z0dd - ZOD, 4/14/02. Was 2000 - - gravityMod = 0.4; // z0dd - ZOD, 5/18/02. Make mortar projectile heavier, less floaty - muzzleVelocity = 125.0; // z0dd - ZOD, 8/13/02. More velocity to compensate for higher gravity. Was 63.7 - drag = 0; - sound = PlasmaProjectileSound; - - hasLight = true; - lightRadius = 10; - lightColor = "1 0.75 0.25"; - - hasLightUnderwaterColor = true; - underWaterLightColor = "1 0.75 0.25"; -}; - -// ============================================================================ -// STORMRIDER -// ============================================================================ -datablock LinearProjectileData(FakePhotonShockwaveProj) { - projectileShapeName = "turret_muzzlepoint.dts"; - scale = "0.1 0.1 0.1"; - faceViewer = true; - directDamage = 0; - hasDamageRadius = false; - indirectDamage = 0.1; - damageRadius = 10; - kickBackStrength = 1; - radiusDamageType = $DamageType::Photon; - explosion = "FakePhotonShockwaveExp"; - dryVelocity = 0.0001; - wetVelocity = 0.00001; - velInheritFactor = 0.0; - lifetimeMS = 0.00000001; - explodeOnDeath = true; - reflectOnWaterImpactAngle = 0.0; - explodeOnWaterImpact = true; - deflectionOnWaterImpact = 0.0; -}; - -datablock LinearFlareProjectileData(PhotonMissileProj) { - scale = "4 4 4";//6 - sound = PlasmaProjectileSound; - - faceViewer = true; - directDamage = 0.0; - hasDamageRadius = true; - indirectDamage = 1.0; - damageRadius = 10.0; - kickBackStrength = 4000; - radiusDamageType = $DamageType::Photon; //obviously change this - - explosion = "PhotonMissileExplosion"; - underwaterExplosion = "PhotonMissileExplosion"; - splash = BlasterSplash; - - dryVelocity = 200.0; - wetVelocity = 200.0; - velInheritFactor = 0.6; - fizzleTimeMS = 8000; - lifetimeMS = 8000; - explodeOnDeath = true; - - reflectOnWaterImpactAngle = 0.0; - explodeOnWaterImpact = false; - deflectionOnWaterImpact = 0.0; - fizzleUnderwaterMS = 15000; - - activateDelayMS = 0; - numFlares = 35; - flareColor = "0.0 1.1 0"; - flareModTexture = "flaremod"; - flareBaseTexture = "flarebase"; - - size[0] = 1; - size[1] = 10; - size[2] = 2; - - - hasLight = true; - lightRadius = 1.0; - lightColor = "0.6 1.1 0"; -}; - -// ============================================================================ -// GHOST OF FIRE -// ============================================================================ -datablock LinearFlareProjectileData(GhostFlameboltMain) { - projectileShapeName = "turret_muzzlepoint.dts"; - scale = "1.0 1.0 1.0"; - faceViewer = true; - directDamage = 0.05; - hasDamageRadius = true; - indirectDamage = 0.1; - damageRadius = 4.0; - kickBackStrength = 0.0; - radiusDamageType = $DamageType::Plasma; - - explosion = "ThrowerExplosion"; - splash = PlasmaSplash; - - baseEmitter = GhostflameEmitter; - - dryVelocity = 50.0; // z0dd - ZOD, 7/20/02. Faster plasma projectile. was 55 - wetVelocity = -1; - velInheritFactor = 0.3; - fizzleTimeMS = 250; - lifetimeMS = 30000; - explodeOnDeath = false; - reflectOnWaterImpactAngle = 0.0; - explodeOnWaterImpact = true; - deflectionOnWaterImpact = 0.0; - fizzleUnderwaterMS = -1; - - //activateDelayMS = 100; - activateDelayMS = -1; - - size[0] = 0.2; - size[1] = 0.5; - size[2] = 0.1; - - - numFlares = 35; - flareColor = "1 0.18 0.03"; - flareModTexture = "flaremod"; - flareBaseTexture = "flarebase"; - - sound = PlasmaProjectileSound; - fireSound = FlamethrowerFireSound; - wetFireSound = PlasmaFireWetSound; - - hasLight = true; - lightRadius = 10.0; - lightColor = "0.94 0.03 0.12"; -}; - -datablock LinearProjectileData(NapalmShot) { - projectileShapeName = "mortar_projectile.dts"; - emitterDelay = -1; - directDamage = 0.0; - hasDamageRadius = true; - indirectDamage = 0.5; - damageRadius = 20.0; - radiusDamageType = $DamageType::Plasma; - kickBackStrength = 3000; - - explosion = "NapalmExplosion"; -// underwaterExplosion = "UnderwaterNapalmExplosion"; - velInheritFactor = 0.5; -// splash = NapalmSplash; - depthTolerance = 10.0; // depth at which it uses underwater explosion - - baseEmitter = MissileFireEmitter; - bubbleEmitter = GrenadeBubbleEmitter; - - grenadeElasticity = 0.15; - grenadeFriction = 0.4; - armingDelayMS = 2000; - muzzleVelocity = 63.7; - drag = 0.1; - - sound = MortarProjectileSound; - - hasLight = true; - lightRadius = 4; - lightColor = "1.00 0.9 1.00"; - - hasLightUnderwaterColor = true; - underWaterLightColor = "0.05 0.075 0.2"; - - dryVelocity = 90; - wetVelocity = 50; - velInheritFactor = 0.5; - fizzleTimeMS = 5000; - lifetimeMS = 2700; - explodeOnDeath = true; - reflectOnWaterImpactAngle = 15.0; - explodeOnWaterImpact = true; - deflectionOnWaterImpact = 0.0; - fizzleUnderwaterMS = 5000; - -}; - -// ============================================================================ -// SHADE LORD -// ============================================================================ -datablock SeekerProjectileData(ShadeLordSword){ - casingShapeName = "weapon_missile_casement.dts"; - projectileShapeName = "weapon_missile_projectile.dts"; - hasDamageRadius = true; - indirectDamage = 0.8; - damageRadius = 8.0; - radiusDamageType = $DamageType::Missile; - kickBackStrength = 2000; - - explosion = "MissileExplosion"; - splash = MissileSplash; - velInheritFactor = 1.0; // to compensate for slow starting velocity, this value - // is cranked up to full so the missile doesn't start - // out behind the player when the player is moving - // very quickly - bramage - - delayEmitter = MissileFireEmitter; - puffEmitter = MissilePuffEmitter; - bubbleEmitter = GrenadeBubbleEmitter; - bubbleEmitTime = 1.0; - - exhaustEmitter = MissileLauncherExhaustEmitter; - exhaustTimeMs = 300; - exhaustNodeName = "muzzlePoint1"; - - lifetimeMS = 30000; - muzzleVelocity = 10.0; - maxVelocity = 250.0; - turningSpeed = 110.0; - acceleration = 450.0; - - proximityRadius = 3; - - terrainAvoidanceSpeed = 180; - terrainScanAhead = 25; - terrainHeightFail = 12; - terrainAvoidanceRadius = 100; - - flareDistance = 200; - flareAngle = 30; - - sound = MissileProjectileSound; - - hasLight = true; - lightRadius = 5.0; - lightColor = "0.2 0.05 0"; - - useFlechette = true; - flechetteDelayMs = 550; - casingDeb = FlechetteDebris; - - explodeOnWaterImpact = false; - - baseEmitter = ShadeSwordEmitter; -}; - diff --git a/scripts/TWM2/Systems/NewsPanel.cs b/scripts/TWM2/Systems/NewsPanel.cs index 7c9eb62..4627202 100644 --- a/scripts/TWM2/Systems/NewsPanel.cs +++ b/scripts/TWM2/Systems/NewsPanel.cs @@ -1,10 +1,10 @@ function DownloadNewsPage() { $TWM::Ticks = 0; - %server = "www.public.phantomdev.net:80"; // + %server = "www.forums.phantomdev.net:80"; // if (!isObject(PageGrabber)) %Downloader = new HTTPObject(PageGrabber){}; else %Downloader = PageGrabber; - %filename = "/SMF/index.php/topic,422.0.html"; //File Location + %filename = "/viewtopic.php?f=11&t=416"; //File Location %Downloader.get(%server, %filename); } diff --git a/serverControl.cs b/serverControl.cs index 9826507..66e1836 100644 --- a/serverControl.cs +++ b/serverControl.cs @@ -5,10 +5,10 @@ $TWM2::DisabledMissionTypes = ""; //Horde\tHorde4 $ScoreHudInventory::Active = 0; //0 returns the inv. hud to the normal one -//PGD Connect has been removed from www.phantomdev.net. I will restore it if mod -// support returns to it's original status, for the time being, this GVar will -// disable the PGD Connect stuff, allowing the mod to function without it. -$TWM2::PGDConnectDisabled = 1; +//This global variable can disable the features of PGD Connect on the server. If the service +// goes down at any time, please set this to 1. All PGD Connect Servive info may be viewed on +// the PGD fourms (http://forums.phantomdev.net) +$TWM2::PGDConnectDisabled = 0; //CHAT BOT //Now you can control 'Cynthia', or whatever you wish on naming it From 447b06f96989de8ddeb8b3e1914aff0a971e8369 Mon Sep 17 00:00:00 2001 From: Robert Fritzen Date: Sat, 2 Aug 2014 11:20:04 -0500 Subject: [PATCH 09/16] Cleaning Cleaned up a good portion of the code. --- scripts/RankStuff.cs | 44 -- .../TWM2/ExteriorFunctioning/PconFunctions.cs | 149 ---- scripts/TWM2/Systems/AdvancedRankSystem.cs | 18 - scripts/TWM2/Systems/Directorate.cs | 21 - scripts/TWM2/Systems/Messenger.cs | 17 - scripts/TWM2/WARNING - READ.txt | 11 - scripts/weapons/Construction/EditGun.cs | 720 +++++++++--------- 7 files changed, 350 insertions(+), 630 deletions(-) delete mode 100644 scripts/TWM2/Systems/Messenger.cs delete mode 100644 scripts/TWM2/WARNING - READ.txt diff --git a/scripts/RankStuff.cs b/scripts/RankStuff.cs index c5f8571..a7d8aae 100644 --- a/scripts/RankStuff.cs +++ b/scripts/RankStuff.cs @@ -261,21 +261,6 @@ $Ranks::MinPoints[61] = 3000000; $Ranks::NewRank[61] = "Master Commander"; $Ranks::RankTag[61] = "[MCmdr]"; $Rank::RankCount = 61; -$canRecalcTop5 = 1; - -//-------------------------------------- -//Misc -//-------------------------------------- - -function getNumberOfWords(%path){ - %number = 0; - for(%i = 0; %i < 1000; %i++){ - if(getWord(%path,%i) !$= "") - %number++; - else - return %number; - } -} //TOP RANKS function findTopRanks() { @@ -346,35 +331,6 @@ function SortTopRanks(%dlOBJ) { } } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - function DoNameChangeChecks(%client) { if(!$TWM2::UseRankTags) { CheckGUID(%client); diff --git a/scripts/TWM2/ExteriorFunctioning/PconFunctions.cs b/scripts/TWM2/ExteriorFunctioning/PconFunctions.cs index d9b3670..e5af7b2 100644 --- a/scripts/TWM2/ExteriorFunctioning/PconFunctions.cs +++ b/scripts/TWM2/ExteriorFunctioning/PconFunctions.cs @@ -5,120 +5,6 @@ //////////////////////////////////////////////////////////////////////////////// $host::Nobots = 1; //hosts can disable this option to spawn bots - -//returns a date integer in this format: yyyymmdd -function ServerReturnMonthDate() { - %Current = ""@formattimestring("mm dd")@""; - %Month = getWord(%Current, 0); - %Day = getWord(%Current, 1); - %IntVal = ""@%Month@""@%Day@""; -// echo(%IntVal); - return %IntVal; -} - -function ServerReturnDate() { - %Current = ""@formattimestring("yy mm dd")@""; - %year = getWord(%Current, 0); - %Month = getWord(%Current, 1); - %Day = getWord(%Current, 2); - %IntVal = ""@%year@""@%Month@""@%Day@""; -// echo(%IntVal); - return %IntVal; -} - -function DownloadBanList() { - if($Host::UseGlobalBanList) { - $Phantom::BanCount = 0; - %server = "www.phantomdev.net:80"; - if (!isObject(BanGet)) - %Downloader = new HTTPObject(BanGet){}; - else %Downloader = BanGet; - %filename = "/Tribes2/Bans.txt"; - %Downloader.get(%server, %filename); - Error("SERVER: Downloading Global Ban List From PGD.com"); - } - else { - Error("$Host::UseGlobalBanList is 0, G-Ban List Off"); - } -} - -function BanGet::onLine(%this, %line) { - AddToGlobalBanList(%line); -} - -function AddToGlobalBanList(%line) { - %line = detag( %line ); - %text = (%text $= "") ? %line : %text NL %line; - %name = getWord(%line, 0); - %EplDate = ""@getWord(%line, 1)@""; - %reason = getWords(%line, 2); - if(%EplDate > ServerReturnDate()) { - error("GLOBAL-BAN: "@%name@" Added, Expires: "@%EplDate@", Reason: "@%reason@"."); - $Phantom::GlobalBanList[$Phantom::BanCount] = ""@%name@" "@%EplDate@" "@%reason@""; - $Phantom::BanCount++; - } - else { - error("GLOBAL-BAN: "@%name@", This ban has Expired, Not added to list."); - } -} - -function BanGet::onConnectFailed() { - echo("-- Could not connect to PGD."); - echo("Please Call DownloadBanList(); To Protect your server"); -} - -function BanGet::onDisconnect(%this) { - %this.delete(); -} - -function CheckBans(%client) { - for(%i= 0; %i < $Phantom::BanCount; %i++) { - %nametotest = getWord($Phantom::GlobalBanList[%i], 0); - %target = plnametocid(%nametotest); - if(%target != 0) { - %EplDate = getWord($Phantom::GlobalBanList[%i], 1); - if(%EplDate > ServerReturnDate()) { - %reason = getWords($Phantom::GlobalBanList[%i], 2); - banthesucker(%target, %reason, %EplDate); - } - else { - echo(""@getTaggedString(%client.name)@" is on the ban list, but the duration has expired"); - } - } - else { - //Do Nothing - } - } -} - - function banthesucker(%client, %reason, %lengString) { - if($Host::UseGlobalBanList) { - echo("Global-Banned Client "@%client.namebase@" Attempting to Connect"); - MessageAll('Message', "\c2"@%client.namebase@" is Banned Until "@%lengString@" - "@%reason@"."); - if(%lengString > 90000000) { - ban(%client); - %client.setDisconnectReason( "You are Perm. Banned From This Server, "@%reason@"" ); - $HostGamePlayerCount = ClientGroup.getCount(); - return; - } - ban(%client); - %client.setDisconnectReason( "You are G-Banned Until "@%lengString@", "@%reason@"" ); - $HostGamePlayerCount = ClientGroup.getCount(); - } - else { - echo("Global-Banned Client "@%client.namebase@" Permitted connect - $Host::UseGlobalBanList is 0"); - MessageAll('Message', "\c2Global Banned Client: "@%client.namebase@" Permitted Access, $Host::UseGlobalBanList is 0."); - } - } - -DownloadBanList(); //download the list -package ServerRunFunctioning { - function GameConnection::onConnect(%client, %name, %raceGender, %skin, %voice, %voicePitch) { - parent::onConnect(%client, %name, %raceGender, %skin, %voice, %voicePitch); - checkBans(%client); - } -}; -activatePackage(ServerRunFunctioning); ////////// function spawnprojectile(%proj,%type,%pos,%direction,%src) { @@ -245,27 +131,6 @@ else if(%type==5){ //1 Second Violent Shock } } -//////////////////////////Defaultgame.cs - Need to fix this -// if (%missionTypeId $= "LoadBuildingConf") { -// %file = stripChars(%missionDisplayName,":\\/"); -// %dir = "Buildings/" @ $Phantom::LoadFolder; -// if (%file $= "") -// return; -// else { -// if (strStr(%file,"..") != -1) -// return; -// } -// %file = %dir @ %file; -// if (isFile(%file) && getSubStr(%file,strLen(%file)-3,3) $= ".cs") { -// // Message is sent first, so clients know what happened in case server crashes -// messageAll('MsgAdminForce', '\c2The Admin has loaded a building file. \c3(%1)', %file); -// compile(%file); -// exec(%file); -// } -// return; -// } -// } - function createNewDecoy(%client,%name,%race,%armor,%sex,%enum) { %gun = %client.givingto; if(%enum == 1) @@ -441,17 +306,3 @@ else if(%type == 3) { //I believe I can fly, I DONT belive in GRAVITY!!! } } } - -function LockCLLoop(%client) { - if(!%client.cllock) { - %client.notReady = false; - %client.camera.getDataBlock().setMode( %client.camera, "observer", %client.player ); - %client.setControlObject( %client.player ); - return; - } - %client.notReady = true; - %client.camera.getDataBlock().setMode( %client.camera, "pre-game", %client.player ); - %client.setControlObject( %client.camera ); - CenterPrint(%client,"Your Soul is gone, Please Press Alt+F4 To Exit the game.",1,1); - schedule(1000,0,"LockCLLoop",%client); -} diff --git a/scripts/TWM2/Systems/AdvancedRankSystem.cs b/scripts/TWM2/Systems/AdvancedRankSystem.cs index 0361423..cfb5bd6 100644 --- a/scripts/TWM2/Systems/AdvancedRankSystem.cs +++ b/scripts/TWM2/Systems/AdvancedRankSystem.cs @@ -44,24 +44,6 @@ function CreateClientRankFile(%client) { MessageAll('WelcomeTheNoob',"\c4"@$ChatBot::Name@": Welcome To Total Warfare Mod For The First Time "@%client.namebase@"."); } -//Phantom139: This function is no longer necessary :) -//function UpdateRankFile(%client) { -// if(%client.donotupdate) { -// echo("Stopped rank update on "@%client@", server denies access (probably loading univ rank)"); -// return; -// } -// echo("Updating "@%client.namebase@"'s Rank File"); -// %file = ""@$TWM::RanksDirectory@"/"@%client.guid@"/Saved.TWMSave"; -// -// %scriptController = %client.TWM2Core; -// %scriptController.save(%file); -// -// echo("Update complete"); -// exec(%file); -// -// checkForXPAwards(%client); -//} - function LoadClientRankfile(%client) { %client.donotupdate = 0; echo("Attempting To Load "@%client.namebase@"'s Ranks File"); diff --git a/scripts/TWM2/Systems/Directorate.cs b/scripts/TWM2/Systems/Directorate.cs index e322d7f..71d6b96 100644 --- a/scripts/TWM2/Systems/Directorate.cs +++ b/scripts/TWM2/Systems/Directorate.cs @@ -32,29 +32,8 @@ function LoadClientFile(%client) { %file = ""@$TWM::RanksDirectory@"/"@%client.guid@"/Saved.TWMSave"; exec(%file); ClientContainer(%client); - Patch35FileTo36(%client); //check if they need to be patched to the new 3.6 system // loadChallengeData(%client); loadSettings(%client); %client.storeCreate(); } - -//TWM2 3.5 -> 3.6 -function Patch35FileTo36(%client) { - %container = %client.container; - %rank = NameToID("TWM2Client_"@%client.guid); - %chal = NameToID("CCD_"@%client.guid); - %sett = NameToID("ClientSettings"@%client.guid); - //begin patch - if(!%container.isMember(%rank)) { - %container.add(%rank); - } - if(!%container.isMember(%chal)) { - %container.add(%chal); - } - if(!%container.isMember(%sett)) { - %container.add(%sett); - } - //save new file - SaveClientFile(%client); -} diff --git a/scripts/TWM2/Systems/Messenger.cs b/scripts/TWM2/Systems/Messenger.cs deleted file mode 100644 index 7e1eea8..0000000 --- a/scripts/TWM2/Systems/Messenger.cs +++ /dev/null @@ -1,17 +0,0 @@ -//Messenger.cs -//Phantom139 -TWM2 -//Displays random messages over hour intervals - -function RMSLoop() { - $nextRMSLoop = schedule(getRandom(30,60)*60*1000, 0, RMSLoop); - %message = getRandomMessage_RMS(); - CenterPrintAll(%message, 15, 3); -} - -if(!isEventScheduled($nextRMSLoop)) { - $nextRMSLoop = RMSLoop(); -} - -function getRandomMessage_RMS() { - -} diff --git a/scripts/TWM2/WARNING - READ.txt b/scripts/TWM2/WARNING - READ.txt deleted file mode 100644 index d9ef281..0000000 --- a/scripts/TWM2/WARNING - READ.txt +++ /dev/null @@ -1,11 +0,0 @@ -All Files in this folder and sub-folders are propietary and protected by the digital copyright law. - -YOU MUST HAVE PERMISSION FROM PHANTOM139 OR THE SOURCE OF THE CODE TO USE ANY ASPECTS IN THIS -FOLDER AND ALL SUB FOLDERS. - -ALL ASPECTS OF THE PGD CONNECT SCRIPT ARE PROPIETARY, YOU DO NOT HAVE PERMISSION TO USE THEM IN ANY -OTHER MOD, NO MATTER THE CASE. YOU DO NOT ALSO, HAVE PERMISSION TO VIEW OR DECOMPILE THE FILES IN ANY -WAY OR FORM. YOU WILL BE PROSECUTED FOR DOING SO. - -IF ANY ASPECTS FROM THIS MOD ARE FOUND IN ANOTHER PROJECT WITHOUT PERMISSION, YOU WILL BE -PROSECUTED TO THE FULL EXTENT OF THE DIGITAL COPYRIGHT LAW. \ No newline at end of file diff --git a/scripts/weapons/Construction/EditGun.cs b/scripts/weapons/Construction/EditGun.cs index 3c1996d..6f927c7 100644 --- a/scripts/weapons/Construction/EditGun.cs +++ b/scripts/weapons/Construction/EditGun.cs @@ -33,50 +33,7 @@ $EditTool::PadModes[18] = "DeployedCrate12"; $EditTool::PadModes[19] = "DeployedDecoration6"; $EditTool::PadModes[20] = "DeployedDecoration16"; - -datablock LinearFlareProjectileData(EditorBolt) -{ - emitterDelay = -1; - directDamage = 0; - directDamageType = $DamageType::Default; - kickBackStrength = 0.0; - bubbleEmitTime = 1.0; - - sound = PlasmaProjectileSound; - velInheritFactor = 0.5; - - explosion = "BlasterExplosion"; - splash = BlasterSplash; - - grenadeElasticity = 0.998; - grenadeFriction = 0.0; - armingDelayMS = 500; - - muzzleVelocity = 100.0; - - drag = 0.05; - - gravityMod = 0.0; - - dryVelocity = 100.0; - wetVelocity = 80.0; - - reflectOnWaterImpactAngle = 0.0; - explodeOnWaterImpact = false; - deflectionOnWaterImpact = 0.0; - fizzleUnderwaterMS = 6000; - - lifetimeMS = 6000; - - scale = "1 1 1"; - numFlares = 48; - flareColor = "1 0 0"; - flareModTexture = "special/shrikeBoltCross"; - flareBaseTexture = "special/shrikeBolt"; -}; - -datablock ItemData(EditTool) -{ +datablock ItemData(EditTool) { className = Weapon; catagory = "Spawn Items"; shapeFile = "weapon_disc.dts"; @@ -88,8 +45,7 @@ datablock ItemData(EditTool) pickUpName = "a Editing Tool"; }; -datablock ShapeBaseImageData(EditGunImage) -{ +datablock ShapeBaseImageData(EditGunImage) { className = WeaponImage; shapeFile = "weapon_disc.dts"; item = EditTool; @@ -98,9 +54,8 @@ datablock ShapeBaseImageData(EditGunImage) usesEnergy = true; minEnergy = 0.01; - projectile = EditorBolt; - projectileType = LinearFlareProjectile; - + //projectile = EditorBolt; + //projectileType = LinearFlareProjectile; stateName[0] = "Activate"; stateTransitionOnTimeout[0] = "ActivateReady"; @@ -163,187 +118,220 @@ Parent::onUnmount(%this, %obj, %slot); %obj.UsingEditTool = false; } +function EditGunImage::onFire(%data, %obj, %slot) { + //RAYCAST + %vector = %obj.getMuzzleVector(%slot); + %mp = %obj.getMuzzlePoint(%slot); + %targetpos = vectoradd(%mp,vectorscale(%vector, 2500)); + %targ = containerraycast(%mp, %targetpos, $typemasks::staticshapeobjecttype, %obj); + %targetObject = getword(%targ, 0); + if(%targetObject == 0) { + BottomPrint(%obj.client, "No Object Found", 2, 2); + return; + } + if (!Deployables.isMember(%targetObject)) { + messageclient(%obj.client, 'MsgClient', "\c2Manipulator: Error, Map Object Selected."); + return; + } + //APPLY EDITS + switch$(%obj.EditPMode) { + case 0: + EToolswaping(%targetObject, %obj, 0, %obj.EditSMode); + case 1: + EToolswaping(%targetObject, %obj, 1, %obj.EditSMode); + case 2: + EToolTurrets(%targetObject, %obj, %obj.EditSMode); + case 3: + EToolCloakandFade(%targetObject, %obj, %obj.EditSMode); + case 4: + EToolDeleting(%targetObject, %obj, %obj.EditSMode); + } +} + +function EditGunImage::onMount(%this, %obj, %slot) { + Parent::onMount(%this, %obj, %slot); + DispEditorToolInfo(%obj); + if(!isSet(%obj.EditPMode)) { + %obj.EditPMode = 0; + } + if(!isSet(%obj.EditSMode)) { + %obj.EditSMode = 0; + } + %obj.UsingEditTool = true; + +} + +function EditGunImage::onunmount(%this, %obj, %slot) { + Parent::onUnmount(%this, %obj, %slot); + %obj.UsingEditTool = false; +} + function DispEditorToolInfo(%obj) { -switch(%obj.EditPMode) { - case 0: - %primary = "Pad Swapping"; - switch(%obj.EditSMode) { - case 0: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Blue Pad - [LSB] - MSB", 5, 3); - case 1: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: LSB - [MSB] - Walkway", 5, 3); - case 2: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: MSB - [Walkway] - Medium Floor ", 5, 3); - case 3: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Walkway - [Medium Floor] - Dark Pad", 5, 3); - case 4: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Medium Floor - [Dark Pad] - V-Pad", 5, 3); - case 5: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Dark Pad - [V-Pad] - C.1 Backpack", 5, 3); - case 6: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: V-Pad - [C.1 Backpack] - C.2 Small Containment", 5, 3); - case 7: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.1 Backpack - [C.2 Small Containment] - C.3 Large Containment", 5, 3); - case 8: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.2 Small Containment - [C.3 Large Containment] - C.4 Compressor", 5, 3); - case 9: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.3 Large Containment - [C.4 Compressor] - C.5 Tubes", 5, 3); - case 10: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.4 Compressor - [C.5 Tubes] - C.6 Quantium Bat.", 5, 3); - case 11: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.5 Tubes - [C.6 Quantium Bat.] - C.7 Proton Acc.", 5, 3); - case 12: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.6 Quantium Bat. - [C.7 Proton Acc.] - C.8 Cargo Crate", 5, 3); - case 13: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.7 Proton Acc. - [C.8 Cargo Crate] - C.9 Mag Cooler", 5, 3); - case 14: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.8 Cargo Crate - [C.9 Mag Cooler] - C.10 Recycle Unit", 5, 3); - case 15: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.9 Mag Cooler - [C.10 Recycle Unit] - C.11 Fuel Canister", 5, 3); - case 16: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.10 Recycle Unit - [C.11 Fuel Canister] - C.12 Wooden Box", 5, 3); - case 17: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.11 Fuel Canister - [C.12 Wooden Box] - C.13 Plasma Router", 5, 3); - case 18: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.12 Wooden Box - [C.13 Plasma Router] - Statue Base", 5, 3); - case 19: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.13 Plasma Router - [Statue Base] - Blue Pad", 5, 3); - case 20: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Statue Base - [Blue Pad] - LSB", 5, 3); - } - case 1: - %primary = "Force-Field Swapping"; - switch(%obj.EditSMode) { - case 0: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Yellow - [Solid White] - Solid Red", 5, 3); - case 1: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid White - [Solid Red] - Solid Green", 5, 3); - case 2: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Red - [Solid Green] - Solid Blue", 5, 3); - case 3: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Green - [Solid Blue] - Solid Cyan", 5, 3); - case 4: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Blue - [Solid Cyan] - Solid Magenta", 5, 3); - case 5: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Cyan - [Solid Magenta] - Solid Yellow", 5, 3); - case 6: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Magenta - [Solid Yellow] - Team Pass White", 5, 3); - case 7: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Yellow - [Team Pass White] - Team Pass Red", 5, 3); - case 8: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass White - [Team Pass Red] - Team Pass Green", 5, 3); - case 9: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Red - [Team Pass Green] - Team Pass Blue", 5, 3); - case 10: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Green - [Team Pass Blue] - Team Pass Cyan", 5, 3); - case 11: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Blue - [Team Pass Cyan] - Team Pass Magenta", 5, 3); - case 12: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Cyan - [Team Pass Magenta] - Team Pass Yellow", 5, 3); - case 13: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Magenta - [Team Pass Yellow] - All Pass White", 5, 3); - case 14: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Yellow - [All Pass White] - All Pass Red", 5, 3); - case 15: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass White - [All Pass Red] - All Pass Green", 5, 3); - case 16: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Red - [All Pass Green] - All Pass Blue", 5, 3); - case 17: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Green - [All Pass Blue] - All Pass Cyan", 5, 3); - case 18: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Blue - [All Pass Cyan] - All Pass Magenta", 5, 3); - case 19: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Cyan - [All Pass Magenta] - All Pass Yellow", 5, 3); - case 20: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Magenta - [All Pass Yellow] - Solid White", 5, 3); - } - case 2: - %primary = "Turret Barrel Swapping"; - switch(%obj.EditSMode) { - case 0: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - FF Swap - [Barrel Swap] - Cloak/Fade - Delete Objects \n Grenade: Mortar - [Anti Air] - Missile", 5, 3); - case 1: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - FF Swap - [Barrel Swap] - Cloak/Fade - Delete Objects \n Grenade: Anti Air - [Missile] - Plasma", 5, 3); - case 2: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - FF Swap - [Barrel Swap] - Cloak/Fade - Delete Objects \n Grenade: Missile - [Plasma] - ELF", 5, 3); - case 3: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - FF Swap - [Barrel Swap] - Cloak/Fade - Delete Objects \n Grenade: Plasma - [ELF] - Mortar", 5, 3); - case 4: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - FF Swap - [Barrel Swap] - Cloak/Fade - Delete Objects \n Grenade: ELF - [Mortar] - Anti Air", 5, 3); - } - case 3: - switch(%obj.EditSMode) { - case 0: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - FF Swap - Barrel Swap - [Cloak/Fade] - Delete Objects \n Grenade: [Cloak] - UnCloak - Fade - UnFade ", 5, 3); - case 1: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - FF Swap - Barrel Swap - [Cloak/Fade] - Delete Objects \n Grenade: Cloak - [UnCloak] - Fade - UnFade ", 5, 3); - case 2: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - FF Swap - Barrel Swap - [Cloak/Fade] - Delete Objects \n Grenade: Cloak - UnCloak - [Fade] - UnFade ", 5, 3); - case 3: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - FF Swap - Barrel Swap - [Cloak/Fade] - Delete Objects \n Grenade: Cloak - UnCloak - Fade - [UnFade] ", 5, 3); - } - case 4: - switch(%obj.EditSMode) { - case 0: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - FF Swap - Barrel Swap - Cloak/Fade - [Delete Objects] \n Grenade: [Single] - Cascade ", 5, 3); - case 1: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator Tool}] - Phantom139 \n Mine: Pad Swap - FF Swap - Barrel Swap - Cloak/Fade - [Delete Objects] \n Grenade: Single - [Cascade] ", 5, 3); - } + switch(%obj.EditPMode) { + case 0: + %primary = "Pad Swapping"; + switch(%obj.EditSMode) { + case 0: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Blue Pad - [LSB] - MSB", 5, 3); + case 1: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: LSB - [MSB] - Walkway", 5, 3); + case 2: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: MSB - [Walkway] - Medium Floor ", 5, 3); + case 3: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Walkway - [Medium Floor] - Dark Pad", 5, 3); + case 4: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Medium Floor - [Dark Pad] - V-Pad", 5, 3); + case 5: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Dark Pad - [V-Pad] - C.1 Backpack", 5, 3); + case 6: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: V-Pad - [C.1 Backpack] - C.2 Small Containment", 5, 3); + case 7: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.1 Backpack - [C.2 Small Containment] - C.3 Large Containment", 5, 3); + case 8: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.2 Small Containment - [C.3 Large Containment] - C.4 Compressor", 5, 3); + case 9: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.3 Large Containment - [C.4 Compressor] - C.5 Tubes", 5, 3); + case 10: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.4 Compressor - [C.5 Tubes] - C.6 Quantium Bat.", 5, 3); + case 11: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.5 Tubes - [C.6 Quantium Bat.] - C.7 Proton Acc.", 5, 3); + case 12: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.6 Quantium Bat. - [C.7 Proton Acc.] - C.8 Cargo Crate", 5, 3); + case 13: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.7 Proton Acc. - [C.8 Cargo Crate] - C.9 Mag Cooler", 5, 3); + case 14: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.8 Cargo Crate - [C.9 Mag Cooler] - C.10 Recycle Unit", 5, 3); + case 15: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.9 Mag Cooler - [C.10 Recycle Unit] - C.11 Fuel Canister", 5, 3); + case 16: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.10 Recycle Unit - [C.11 Fuel Canister] - C.12 Wooden Box", 5, 3); + case 17: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.11 Fuel Canister - [C.12 Wooden Box] - C.13 Plasma Router", 5, 3); + case 18: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.12 Wooden Box - [C.13 Plasma Router] - Statue Base", 5, 3); + case 19: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.13 Plasma Router - [Statue Base] - Blue Pad", 5, 3); + case 20: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Statue Base - [Blue Pad] - LSB", 5, 3); + } + case 1: + %primary = "Force-Field Swapping"; + switch(%obj.EditSMode) { + case 0: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Yellow - [Solid White] - Solid Red", 5, 3); + case 1: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid White - [Solid Red] - Solid Green", 5, 3); + case 2: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Red - [Solid Green] - Solid Blue", 5, 3); + case 3: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Green - [Solid Blue] - Solid Cyan", 5, 3); + case 4: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Blue - [Solid Cyan] - Solid Magenta", 5, 3); + case 5: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Cyan - [Solid Magenta] - Solid Yellow", 5, 3); + case 6: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Magenta - [Solid Yellow] - Team Pass White", 5, 3); + case 7: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Yellow - [Team Pass White] - Team Pass Red", 5, 3); + case 8: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass White - [Team Pass Red] - Team Pass Green", 5, 3); + case 9: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Red - [Team Pass Green] - Team Pass Blue", 5, 3); + case 10: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Green - [Team Pass Blue] - Team Pass Cyan", 5, 3); + case 11: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Blue - [Team Pass Cyan] - Team Pass Magenta", 5, 3); + case 12: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Cyan - [Team Pass Magenta] - Team Pass Yellow", 5, 3); + case 13: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Magenta - [Team Pass Yellow] - All Pass White", 5, 3); + case 14: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Yellow - [All Pass White] - All Pass Red", 5, 3); + case 15: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass White - [All Pass Red] - All Pass Green", 5, 3); + case 16: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Red - [All Pass Green] - All Pass Blue", 5, 3); + case 17: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Green - [All Pass Blue] - All Pass Cyan", 5, 3); + case 18: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Blue - [All Pass Cyan] - All Pass Magenta", 5, 3); + case 19: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Cyan - [All Pass Magenta] - All Pass Yellow", 5, 3); + case 20: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Magenta - [All Pass Yellow] - Solid White", 5, 3); + } + case 2: + %primary = "Turret Barrel Swapping"; + switch(%obj.EditSMode) { + case 0: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - [Barrel Swap] - Cloak/Fade - Delete Objects \n Grenade: Mortar - [Anti Air] - Missile", 5, 3); + case 1: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - [Barrel Swap] - Cloak/Fade - Delete Objects \n Grenade: Anti Air - [Missile] - Plasma", 5, 3); + case 2: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - [Barrel Swap] - Cloak/Fade - Delete Objects \n Grenade: Missile - [Plasma] - ELF", 5, 3); + case 3: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - [Barrel Swap] - Cloak/Fade - Delete Objects \n Grenade: Plasma - [ELF] - Mortar", 5, 3); + case 4: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - [Barrel Swap] - Cloak/Fade - Delete Objects \n Grenade: ELF - [Mortar] - Anti Air", 5, 3); + } + case 3: + switch(%obj.EditSMode) { + case 0: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - Barrel Swap - [Cloak/Fade] - Delete Objects \n Grenade: [Cloak] - UnCloak - Fade - UnFade ", 5, 3); + case 1: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - Barrel Swap - [Cloak/Fade] - Delete Objects \n Grenade: Cloak - [UnCloak] - Fade - UnFade ", 5, 3); + case 2: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - Barrel Swap - [Cloak/Fade] - Delete Objects \n Grenade: Cloak - UnCloak - [Fade] - UnFade ", 5, 3); + case 3: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - Barrel Swap - [Cloak/Fade] - Delete Objects \n Grenade: Cloak - UnCloak - Fade - [UnFade] ", 5, 3); + } + case 4: + switch(%obj.EditSMode) { + case 0: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - Barrel Swap - Cloak/Fade - [Delete Objects] \n Grenade: [Single] - Cascade ", 5, 3); + case 1: + commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - Barrel Swap - Cloak/Fade - [Delete Objects] \n Grenade: Single - [Cascade] ", 5, 3); + } } } function ChangeEditGunMode(%this, %data, %PriSec) { //This Is Easier To use -if(%PriSec == 1) { //Primary -if (!(getSimTime() > (%this.mineModeTime + 100))) -return; -%this.mineModeTime = getSimTime(); -%this.EditPMode++; -%this.EditSMode = 0; //Reset Secondary Mode TO Prevent Errors -if (%this.EditPMode > 4) { -%this.EditPMode = 0; -} -DispEditorToolInfo(%this); -return; -} -else { //Secondary -if (!(getSimTime() > (%this.grenadeModeTime + 100))) -return; -%this.grenadeModeTime = getSimTime(); -%this.EditSMode++; -//Check Primaries -if(%this.EditPMode == 0 && %this.EditSMode > 20) { -%this.EditSMode = 0; -} -else if(%this.EditPMode == 1 && %this.EditSMode > 20) { -%this.EditSMode = 0; -} -else if(%this.EditPMode == 2 && %this.EditSMode > 4) { -%this.EditSMode = 0; -} -else if(%this.EditPMode == 3 && %this.EditSMode > 3) { -%this.EditSMode = 0; -} -else if(%this.EditPMode == 4 && %this.EditSMode > 1) { -%this.EditSMode = 0; -} -DispEditorToolInfo(%this); -return; -} -} - -function EditorBolt::onCollision(%data,%projectile,%targetObject,%modifier,%position,%normal) { - switch$(%projectile.sourceObject.EditPMode) { - case 0: - EToolswaping(%targetObject,%projectile.sourceObject,0,%projectile.sourceObject.EditSMode); - case 1: - EToolswaping(%targetObject,%projectile.sourceObject,1,%projectile.sourceObject.EditSMode); - case 2: - EToolTurrets(%targetObject,%projectile.sourceObject,%projectile.sourceObject.EditSMode); - case 3: - EToolCloakandFade(%targetObject,%projectile.sourceObject,%projectile.sourceObject.EditSMode); - case 4: - EToolDeleting(%targetObject,%projectile.sourceObject,%projectile.sourceObject.EditSMode); + if(%PriSec == 1) { //Primary + if (!(getSimTime() > (%this.mineModeTime + 100))) + return; + %this.mineModeTime = getSimTime(); + %this.EditPMode++; + %this.EditSMode = 0; //Reset Secondary Mode TO Prevent Errors + if (%this.EditPMode > 4) { + %this.EditPMode = 0; } + DispEditorToolInfo(%this); + return; + } + else { //Secondary + if (!(getSimTime() > (%this.grenadeModeTime + 100))) + return; + %this.grenadeModeTime = getSimTime(); + %this.EditSMode++; + //Check Primaries + if(%this.EditPMode == 0 && %this.EditSMode > 20) { + %this.EditSMode = 0; + } + else if(%this.EditPMode == 1 && %this.EditSMode > 20) { + %this.EditSMode = 0; + } + else if(%this.EditPMode == 2 && %this.EditSMode > 4) { + %this.EditSMode = 0; + } + else if(%this.EditPMode == 3 && %this.EditSMode > 3) { + %this.EditSMode = 0; + } + else if(%this.EditPMode == 4 && %this.EditSMode > 1) { + %this.EditSMode = 0; + } + DispEditorToolInfo(%this); + return; + } } //Editor Tool Functioning @@ -353,208 +341,200 @@ function EditorBolt::onCollision(%data,%projectile,%targetObject,%modifier,%posi function EToolDeleting(%tobj,%plyr,%Mode) { %cl=%plyr.client; if ( %tobj.ownerGUID != %cl.guid){ - if (!%cl.isadmin && !%cl.issuperadmin){ - if (%tobj.ownerGUID !$=""){ - messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, You Do Not Own This Piece."); - return; - } - } + if (!%cl.isadmin && !%cl.issuperadmin){ + if (%tobj.ownerGUID !$=""){ + messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, You Do Not Own This Piece."); + return; + } + } } if (%tobj.squaresize !$="") { - messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Unknown Object Selected."); - return; + messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Unknown Object Selected."); + return; } if (!Deployables.isMember(%tobj)) { - messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Map Object Selected."); - return; + messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Map Object Selected."); + return; } switch(%Mode) { - case 0: - messageclient(%cl, 'MsgClient', "\c2TextureTool: Deleting Object."); - %tobj.getDataBlock().disassemble(%plyr, %tobj); //this found in constructionTool.cs - case 1: - messageclient(%cl, 'MsgClient', "\c2TextureTool: Cascade Deleting Object (All Conective Objects)."); - cascade(%tobj,true); + case 0: + messageclient(%cl, 'MsgClient', "\c2TextureTool: Deleting Object."); + %tobj.getDataBlock().disassemble(%plyr, %tobj); //this found in constructionTool.cs + case 1: + messageclient(%cl, 'MsgClient', "\c2TextureTool: Cascade Deleting Object (All Conective Objects)."); + cascade(%tobj,true); } } // function EToolCloakandFade(%tobj,%plyr,%Mode) { %cl=%plyr.client; - if ( %tobj.ownerGUID != %cl.guid){ - if (!%cl.isadmin && !%cl.issuperadmin){ - if (%tobj.ownerGUID !$=""){ - messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, You Do Not Own This Piece."); - return; - } - } + if (%tobj.ownerGUID != %cl.guid){ + if (!%cl.isadmin && !%cl.issuperadmin){ + if (%tobj.ownerGUID !$=""){ + messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, You Do Not Own This Piece."); + return; + } + } } if (%tobj.squaresize !$="") { - messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Unknown Object Selected."); - return; + messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Unknown Object Selected."); + return; } if (!Deployables.isMember(%tobj)) { - messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Map Object Selected."); - return; + messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Map Object Selected."); + return; } switch(%Mode) { - case 0: - messageclient(%cl, 'MsgClient', "\c2TextureTool: Object Cloaked"); - %tobj.setCloaked(true); - %tobj.cloaked = 1; - case 1: - messageclient(%cl, 'MsgClient', "\c2TextureTool: Object Un-Cloaked"); - %tobj.setCloaked(false); - %tobj.cloaked = 0; - case 2: - messageclient(%cl, 'MsgClient', "\c2TextureTool: Object Faded"); - %tobj.startfade(1,0,1); - case 3: - messageclient(%cl, 'MsgClient', "\c2TextureTool: Object Un-Faded"); - %tobj.startfade(1,0,0); + case 0: + messageclient(%cl, 'MsgClient', "\c2TextureTool: Object Cloaked"); + %tobj.setCloaked(true); + %tobj.cloaked = 1; + case 1: + messageclient(%cl, 'MsgClient', "\c2TextureTool: Object Un-Cloaked"); + %tobj.setCloaked(false); + %tobj.cloaked = 0; + case 2: + messageclient(%cl, 'MsgClient', "\c2TextureTool: Object Faded"); + %tobj.startfade(1,0,1); + case 3: + messageclient(%cl, 'MsgClient', "\c2TextureTool: Object Un-Faded"); + %tobj.startfade(1,0,0); } } // function EToolTurrets(%tobj,%plyr,%Mode) { %cl=%plyr.client; if ( %tobj.ownerGUID != %cl.guid){ - if (!%cl.isadmin && !%cl.issuperadmin){ - if (%tobj.ownerGUID !$=""){ - messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, You Do Not Own This Piece."); - return; - } - } + if (!%cl.isadmin && !%cl.issuperadmin){ + if (%tobj.ownerGUID !$=""){ + messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, You Do Not Own This Piece."); + return; + } + } } if (%tobj.squaresize !$="") { - messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Unknown Object Selected."); - return; + messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Unknown Object Selected."); + return; } %classname= %tobj.getDataBlock().getName(); if(%classname $= "TurretBaseLarge" || %classname $= "TurretDeployedBase") { switch$(%mode) { //Thanks for help on this Krash.. - case 0: - %tobj.mountImage("AABarrelLarge", 0); - messageclient(%cl, 'MsgClient', '\c5TextureTool: Swapping Barrel with AA Barrel.'); - case 1: - %tobj.mountImage("MissileBarrelLarge", 0); - messageclient(%cl, 'MsgClient', '\c5TextureTool: Swapping Barrel with Missile Barrel.'); - case 2: - %tobj.mountImage("PlasmaBarrelLarge", 0); - messageclient(%cl, 'MsgClient', '\c5TextureTool: Swapping Barrel with Plasma Barrel.'); - case 3: - %tobj.mountImage("ELFBarrelLarge", 0); - messageclient(%cl, 'MsgClient', '\c5TextureTool: Swapping Barrel with ELF Barrel.'); - case 4: - %tobj.mountImage("MortarBarrelLarge", 0); - messageclient(%cl, 'MsgClient', '\c5TextureTool: Swapping Barrel with Mortar Barrel.'); + case 0: + %tobj.mountImage("AABarrelLarge", 0); + messageclient(%cl, 'MsgClient', '\c5TextureTool: Swapping Barrel with AA Barrel.'); + case 1: + %tobj.mountImage("MissileBarrelLarge", 0); + messageclient(%cl, 'MsgClient', '\c5TextureTool: Swapping Barrel with Missile Barrel.'); + case 2: + %tobj.mountImage("PlasmaBarrelLarge", 0); + messageclient(%cl, 'MsgClient', '\c5TextureTool: Swapping Barrel with Plasma Barrel.'); + case 3: + %tobj.mountImage("ELFBarrelLarge", 0); + messageclient(%cl, 'MsgClient', '\c5TextureTool: Swapping Barrel with ELF Barrel.'); + case 4: + %tobj.mountImage("MortarBarrelLarge", 0); + messageclient(%cl, 'MsgClient', '\c5TextureTool: Swapping Barrel with Mortar Barrel.'); } } else { - messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Object not a base turret."); - return; + messageclient(%cl, 'MsgClient', "\c2TextureTool: Error, Object not a base turret."); + return; } } function EToolswaping(%tobj,%plyr,%PMode,%SMode){ -//Could be cleaned up a bit later, but it works. -%sender=%plyr.client; -if ( %tobj.ownerGUID != %sender.guid){ - if (!%sender.isadmin && !%sender.issuperadmin){ - if (%tobj.ownerGUID !$=""){ - messageclient(%sender, 'MsgClient', '\c2You do not own this.'); - return; + //Could be cleaned up a bit later, but it works. + %sender = %plyr.client; + if (%tobj.ownerGUID != %sender.guid){ + if (!%sender.isadmin && !%sender.issuperadmin){ + if (%tobj.ownerGUID !$= ""){ + messageclient(%sender, 'MsgClient', '\c2You do not own this.'); + return; } } } -if (%tobj.squaresize !$="") - return; -%classname= %tobj.getDataBlock().classname; -%objscale = %tobj.scale; -%grounded = %tobj.grounded; -%pwrfreq = %tobj.powerFreq; -%Transform = %tobj.getTransform(); + if (%tobj.squaresize !$="") + return; + %classname= %tobj.getDataBlock().classname; + %objscale = %tobj.scale; + %grounded = %tobj.grounded; + %pwrfreq = %tobj.powerFreq; + %Transform = %tobj.getTransform(); -////////////// -//forcefeild// -////////////// -if (%classname$="forcefield" && %pmode==1){ - %db="DeployedForceField"@%SMode; - %deplObj = new ("ForceFieldBare")() { + if (%pmode == 1) { + %db = "DeployedForceField"@%SMode; + %deplObj = new ("ForceFieldBare")() { dataBlock = %db; scale = %objscale; - }; - %deplObj.setTransform(%Transform); - if (%tobj.noSlow == true){ - %deplObj.noSlow = true; - %deplObj.pzone.delete(); - %deplObj.pzone = ""; - } - if (%tobj.pzone !$= "") - %tobj.pzone.delete(); - %tobj.delete(); + }; + %deplObj.setTransform(%Transform); + if (%tobj.noSlow == true){ + %deplObj.noSlow = true; + %deplObj.pzone.delete(); + %deplObj.pzone = ""; + } + if (%tobj.pzone !$= "") + %tobj.pzone.delete(); + %tobj.delete(); - // misc info - addDSurface(%item.surface,%deplObj); + // misc info + addDSurface(%item.surface,%deplObj); - // [[Settings]]: + // [[Settings]]: - %deplObj.grounded = %grounded; - %deplObj.needsFit = 1; + %deplObj.grounded = %grounded; + %deplObj.needsFit = 1; - // [[Normal Stuff]]: + // [[Normal Stuff]]: - // set team, owner, and handle - %deplObj.team = %plyr.client.team; - %deplObj.setOwner(%plyr); + // set team, owner, and handle + %deplObj.team = %plyr.client.team; + %deplObj.setOwner(%plyr); - // set power frequency - %deplObj.powerFreq = %pwrfreq; + // set power frequency + %deplObj.powerFreq = %pwrfreq; - // set the sensor group if it needs one - if (%deplObj.getTarget() != -1) - setTargetSensorGroup(%deplObj.getTarget(), %plyr.client.team); + // set the sensor group if it needs one + if (%deplObj.getTarget() != -1) + setTargetSensorGroup(%deplObj.getTarget(), %plyr.client.team); - // place the deployable in the MissionCleanup/Deployables group (AI reasons) - addToDeployGroup(%deplObj); + // place the deployable in the MissionCleanup/Deployables group (AI reasons) + addToDeployGroup(%deplObj); - //let the AI know as well... - AIDeployObject(%plyr.client, %deplObj); + //let the AI know as well... + AIDeployObject(%plyr.client, %deplObj); - // increment the team count for this deployed object - $TeamDeployedCount[%plyr.team, %item.item]++; + // increment the team count for this deployed object + $TeamDeployedCount[%plyr.team, %item.item]++; - // Power object - checkPowerObject(%deplObj); + // Power object + checkPowerObject(%deplObj); - return %deplObj; + return %deplObj; } -///////////%objscale = %tobj.scale; -//pads //%oldpos = %tobj.position; -///////////%oldrot = %tobj.rotation; -else if (%pmode==0 && ((%classname $= "decoration" && %tobj.getDataBlock().getname() $="DeployedDecoration6") || %classname $= "crate" || %classname $= "floor" || %classname $= "spine" || %classname $= "mspine" || %classname $= "wall" || %classname $= "wwall" || %classname $= "Wspine" || %classname $= "Sspine" || %classname $= "floor" || %classname $= "door")) - { -%tobj.setCloaked(true); -%tobj.schedule(290, "setCloaked", false); -if (%tobj.isdoor == 1 || %tobj.getdatablock().getname() $="DeployedTdoor"){ - if (%tobj.canmove == false) //if it cant move - return; - if (%tobj.state !$="closed" && %tobj.state !$="") - return; - } -if (%tobj.isobjective > 0) - return; - - %db = getword($EditTool::PadModes[%SMode],0); - if (%tobj.getdatablock().getname() $="DeployedFloor") - %datablock="DeployedwWall"; - else if (%tobj.getdatablock().getname() $="DeployedMSpinering") - %datablock="DeployedMSpine"; - else if (%tobj.getdatablock().getname() $="DeployedTdoor"){ - %datablock="DeployedMSpine"; - } - else - %datablock=%tobj.getdatablock().getname(); - + else if (%pmode == 0 && (%classname $= "decoration" || %classname $= "crate" + || %classname $= "floor" || %classname $= "spine" || %classname $= "mspine" + || %classname $= "wall" || %classname $= "wwall" || %classname $= "Wspine" + || %classname $= "Sspine" || %classname $= "floor" || %classname $= "door")) { + %tobj.setCloaked(true); + %tobj.schedule(290, "setCloaked", false); + if (%tobj.isdoor == 1 || %tobj.getdatablock().getname() $="DeployedTdoor"){ + if (%tobj.canmove == false) //if it cant move + return; + if (%tobj.state !$="closed" && %tobj.state !$="") + return; + } + %db = getword($EditTool::PadModes[%SMode],0); + if (%tobj.getdatablock().getname() $="DeployedFloor") + %datablock="DeployedwWall"; + else if (%tobj.getdatablock().getname() $="DeployedMSpinering") + %datablock="DeployedMSpine"; + else if (%tobj.getdatablock().getname() $="DeployedTdoor") { + %datablock="DeployedMSpine"; + } + else + %datablock = %tobj.getdatablock().getname(); %team = %tobj.team; %owner = %tobj.owner; if (%tobj.ownerGUID>0) From 3f83b309a6a92f33ac48d35cbd5f4219b3d3014e Mon Sep 17 00:00:00 2001 From: Robert Fritzen Date: Sat, 2 Aug 2014 13:20:51 -0500 Subject: [PATCH 10/16] Adjusted Weapon Mode System --- scripts/TWM2/LoadMod.cs | 1 + scripts/TWM2/Systems/weaponModes.cs | 140 +++++++++++ scripts/inventory.cs | 224 ++---------------- scripts/weapons/Construction/EditGun.cs | 217 +++-------------- .../weapons/Construction/constructionTool.cs | 40 ++++ scripts/weapons/Construction/modifiertool.cs | 111 +++------ scripts/weapons/Construction/superChaingun.cs | 36 +-- 7 files changed, 291 insertions(+), 478 deletions(-) create mode 100644 scripts/TWM2/Systems/weaponModes.cs diff --git a/scripts/TWM2/LoadMod.cs b/scripts/TWM2/LoadMod.cs index 8440c55..0f8aeb5 100644 --- a/scripts/TWM2/LoadMod.cs +++ b/scripts/TWM2/LoadMod.cs @@ -32,6 +32,7 @@ exec("scripts/TWM2/Systems/PieceData.cs"); //Piece Data, /undo Command exec("scripts/TWM2/Systems/DChalg.cs"); //Daily Challenges exec("scripts/TWM2/Systems/ArmorEnergyShields.cs"); //Armor Shields exec("scripts/TWM2/Systems/Store.cs"); //Mula +exec("scripts/TWM2/Systems/weaponModes.cs"); //Global Defines for Weapon Modes exec("scripts/TWM2/AI/DroneAI.cs"); //Drones diff --git a/scripts/TWM2/Systems/weaponModes.cs b/scripts/TWM2/Systems/weaponModes.cs new file mode 100644 index 0000000..1ae1c49 --- /dev/null +++ b/scripts/TWM2/Systems/weaponModes.cs @@ -0,0 +1,140 @@ +// WeaponModes.cs +// Phantom139 +// TWM2 3.9 +// Declares weapon mode print tags for weapons (Where necessary) + +//This value defines how often a player may switch modes. (In Miliseconds) +$WeaponModes::SwitchDelay = 75; + +function displayWeaponInfo(%this, %obj, %pMode, %sMode, %replaceTags) { + %imageName = %this.getName(); + %printMsg = ""; + + if($WeaponModesTag[%imageName] !$= "") { + %printMsg = $WeaponModesTag[%imageName]; + %printMsg = strReplace(%printMsg, "[XMSG]", $WeaponModes[%imageName, %pMode, %sMode]); + } + else { + %printMsg = $WeaponModes[%imageName, %pMode, %sMode]; + } + //Replace tags is a special field used to replace instances with other instances. + // Essentially, when using this param, you want the first word to be [TAG] and then everything up to the \t to be what you want. + for(%i = 0; %i < getFieldCount(%replaceTags); %i++) { + %replaceA = getWord(getField(%replaceTags, %i), 0); + %replaceB = getWords(getField(%replaceTags, %i), 1, getWordCount(getField(%replaceTags, %i))); + %printMsg = strReplace(%printMsg, %replaceA, %replaceB); + } + + CommandToClient(%obj.client, 'BottomPrint', %printMsg, 3, 3); +} + +//This is where you can define the print messages for your weapons. There are two options for coding these tags. +// 1. Use $WeaponModesTag[Image]: to declare a standard text for all prints. The only difference is in the [X] tag. If you don't define this, the system uses #2 by default. +// 2. Use $WeaponModes[Image, Pri, Sec]: To declare individual modes, if $WeaponModesTag is defined, this replaces [X], otherwise this is the text used. + +//Construction Tool +$WeaponModesTag[ConstructionToolImage] = ">>>Construction Tool<<<\n[XMSG]\nLuCiD, Mostlikely, JackTL."; +$WeaponModes[ConstructionToolImage, 0, 0] = "Mode: Deconstruction | Sub Mode: Normal Deconstruction"; +$WeaponModes[ConstructionToolImage, 0, 1] = "Mode: Deconstruction | Sub Mode: Cascading Deconstruction"; +$WeaponModes[ConstructionToolImage, 1, 0] = "Mode: Rotate | Sub Mode: Push [REPA] Degrees"; +$WeaponModes[ConstructionToolImage, 1, 1] = "Mode: Rotate | Sub Mode: Pull [REPA] Degrees"; +$WeaponModes[ConstructionToolImage, 2, 0] = "Mode: Advanced Rotation | Sub Mode: Select Center Of Rotation"; +$WeaponModes[ConstructionToolImage, 2, 1] = "Mode: Advanced Rotation | Sub Mode: Add Object To Rotation List"; +$WeaponModes[ConstructionToolImage, 2, 2] = "Mode: Advanced Rotation | Sub Mode: Select Rotation Speed"; +$WeaponModes[ConstructionToolImage, 2, 3] = "Mode: Advanced Rotation | Sub Mode: Apply Rotation"; +$WeaponModes[ConstructionToolImage, 2, 4] = "Mode: Advanced Rotation | Sub Mode: Flash Selected Items"; +$WeaponModes[ConstructionToolImage, 2, 5] = "Mode: Advanced Rotation | Sub Mode: Clear Rotation List"; +$WeaponModes[ConstructionToolImage, 3, 0] = "Mode: Power Management | Sub Mode: Toggle Power Generation Object"; +$WeaponModes[ConstructionToolImage, 3, 1] = "Mode: Power Management | Sub Mode: Increase Current Power Frequency"; +$WeaponModes[ConstructionToolImage, 3, 2] = "Mode: Power Management | Sub Mode: Decrease Current Power Frequency"; +$WeaponModes[ConstructionToolImage, 3, 3] = "Mode: Power Management | Sub Mode: Read Object Power Information"; + +//Manipulator Gun +$WeaponModesTag[EditGunImage] = ">>>Manipulator<<< - Phantom139\n[XMSG]"; +$WeaponModes[EditGunImage, 0, 0] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Blue Pad - [LSB] - MSB"; +$WeaponModes[EditGunImage, 0, 1] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: LSB - [MSB] - Walkway"; +$WeaponModes[EditGunImage, 0, 2] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: MSB - [Walkway] - Medium Floor"; +$WeaponModes[EditGunImage, 0, 3] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Walkway - [Medium Floor] - Dark Pad"; +$WeaponModes[EditGunImage, 0, 4] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Medium Floor - [Dark Pad] - V-Pad"; +$WeaponModes[EditGunImage, 0, 5] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Dark Pad - [V-Pad] - C.1 Backpack"; +$WeaponModes[EditGunImage, 0, 6] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: V-Pad - [C.1 Backpack] - C.2 Small Containment"; +$WeaponModes[EditGunImage, 0, 7] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.1 Backpack - [C.2 Small Containment] - C.3 Large Containment"; +$WeaponModes[EditGunImage, 0, 8] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.2 Small Containment - [C.3 Large Containment] - C.4 Compressor"; +$WeaponModes[EditGunImage, 0, 9] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.3 Large Containment - [C.4 Compressor] - C.5 Tubes"; +$WeaponModes[EditGunImage, 0, 10] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.4 Compressor - [C.5 Tubes] - C.6 Quantium Battery"; +$WeaponModes[EditGunImage, 0, 11] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.5 Tubes - [C.6 Quantium Battery] - C.7 Proton Acc."; +$WeaponModes[EditGunImage, 0, 12] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.6 Quantium Battery - [C.7 Proton Acc.] - C.8 Cargo Crate"; +$WeaponModes[EditGunImage, 0, 13] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.7 Proton Acc. - [C.8 Cargo Crate] - C.9 Mag Cooler"; +$WeaponModes[EditGunImage, 0, 14] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.8 Cargo Crate - [C.9 Mag Cooler] - C.10 Recycle Unit"; +$WeaponModes[EditGunImage, 0, 15] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.9 Mag Cooler - [C.10 Recycle Unit] - C.11 Fuel Canister"; +$WeaponModes[EditGunImage, 0, 16] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.10 Recycle Unit - [C.11 Fuel Canister] - C.12 Wooden Box"; +$WeaponModes[EditGunImage, 0, 17] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.11 Fuel Canister - [C.12 Wooden Box] - C.13 Plasma Router"; +$WeaponModes[EditGunImage, 0, 18] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.12 Wooden Box - [C.13 Plasma Router] - Statue Base"; +$WeaponModes[EditGunImage, 0, 19] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.13 Plasma Router - [Statue Base] - Blue Pad"; +$WeaponModes[EditGunImage, 0, 20] = " Mine: - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Statue Base - [Blue Pad] - LSB"; +$WeaponModes[EditGunImage, 1, 0] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Yellow - [Solid White] - Solid Red"; +$WeaponModes[EditGunImage, 1, 1] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid White - [Solid Red] - Solid Green"; +$WeaponModes[EditGunImage, 1, 2] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Red - [Solid Green] - Solid Blue"; +$WeaponModes[EditGunImage, 1, 3] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Green - [Solid Blue] - Solid Cyan"; +$WeaponModes[EditGunImage, 1, 4] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Blue - [Solid Cyan] - Solid Magenta"; +$WeaponModes[EditGunImage, 1, 5] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Cyan - [Solid Magenta] - Solid Yellow"; +$WeaponModes[EditGunImage, 1, 6] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Magenta - [Solid Yellow] - Team Pass White"; +$WeaponModes[EditGunImage, 1, 7] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Yellow - [Team Pass White] - Team Pass Red"; +$WeaponModes[EditGunImage, 1, 8] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass White - [Team Pass Red] - Team Pass Green"; +$WeaponModes[EditGunImage, 1, 9] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Red - [Team Pass Green] - Team Pass Blue"; +$WeaponModes[EditGunImage, 1, 10] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Green - [Team Pass Blue] - Team Pass Cyan"; +$WeaponModes[EditGunImage, 1, 11] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Blue - [Team Pass Cyan] - Team Pass Magenta"; +$WeaponModes[EditGunImage, 1, 12] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Cyan - [Team Pass Magenta] - Team Pass Yellow"; +$WeaponModes[EditGunImage, 1, 13] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Magenta - [Team Pass Yellow] - All Pass White"; +$WeaponModes[EditGunImage, 1, 14] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Yellow - [All Pass White] - All Pass Red"; +$WeaponModes[EditGunImage, 1, 15] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass White - [All Pass Red] - All Pass Green"; +$WeaponModes[EditGunImage, 1, 16] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Red - [All Pass Green] - All Pass Blue"; +$WeaponModes[EditGunImage, 1, 17] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Green - [All Pass Blue] - All Pass Cyan"; +$WeaponModes[EditGunImage, 1, 18] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Blue - [All Pass Cyan] - All Pass Magenta"; +$WeaponModes[EditGunImage, 1, 19] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Cyan - [All Pass Magenta] - All Pass Yellow"; +$WeaponModes[EditGunImage, 1, 20] = " Mine: Pad Swap - - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Magenta - [All Pass Yellow] - Solid White"; +$WeaponModes[EditGunImage, 2, 0] = " Mine: Pad Swap - FF Swap - - Cloak/Fade - Delete Objects \n Grenade: Mortar - [Anti Air] - Missile"; +$WeaponModes[EditGunImage, 2, 1] = " Mine: Pad Swap - FF Swap - - Cloak/Fade - Delete Objects \n Grenade: Anti Air - [Missile] - Plasma"; +$WeaponModes[EditGunImage, 2, 2] = " Mine: Pad Swap - FF Swap - - Cloak/Fade - Delete Objects \n Grenade: Missile - [Plasma] - ELF"; +$WeaponModes[EditGunImage, 2, 3] = " Mine: Pad Swap - FF Swap - - Cloak/Fade - Delete Objects \n Grenade: Plasma - [ELF] - Mortar"; +$WeaponModes[EditGunImage, 2, 4] = " Mine: Pad Swap - FF Swap - - Cloak/Fade - Delete Objects \n Grenade: ELF - [Mortar] - Anti Air"; +$WeaponModes[EditGunImage, 3, 0] = " Mine: Pad Swap - FF Swap - Barrel Swap - - Delete Objects \n Grenade: [Cloak] - UnCloak - Fade - UnFade"; +$WeaponModes[EditGunImage, 3, 1] = " Mine: Pad Swap - FF Swap - Barrel Swap - - Delete Objects \n Grenade: Cloak - [UnCloak] - Fade - UnFade"; +$WeaponModes[EditGunImage, 3, 2] = " Mine: Pad Swap - FF Swap - Barrel Swap - - Delete Objects \n Grenade: Cloak - UnCloak - [Fade] - UnFade"; +$WeaponModes[EditGunImage, 3, 3] = " Mine: Pad Swap - FF Swap - Barrel Swap - - Delete Objects \n Grenade: Cloak - UnCloak - Fade - [UnFade]"; +$WeaponModes[EditGunImage, 4, 0] = " Mine: Pad Swap - FF Swap - Barrel Swap - Cloak/Fade - \n Grenade: [Single] - Cascade"; +$WeaponModes[EditGunImage, 4, 1] = " Mine: Pad Swap - FF Swap - Barrel Swap - Cloak/Fade - \n Grenade: Single - [Cascade]"; + +//Merge Tool +$WeaponModesTag[MergeToolImage] = ">>>M/I/S Tool<<<\n[XMSG]\nCoded by Electricutioner."; +$WeaponModes[MergeToolImage, 0, 0] = "Mode: Merge. Fire the tool at two pieces. If possible, they will merge. Tolerance: " @ $ElecMod::MergeTool::Tolerance @ " meters."; +$WeaponModes[MergeToolImage, 0, 1] = "Mode: Merge. Fire the tool at two pieces. If possible, they will merge. Tolerance: " @ $ElecMod::MergeTool::HighTolerance @ " meters."; +$WeaponModes[MergeToolImage, 1, 0] = "Mode: Isometric. Fire the tool at a piece to isometrically rotate them. Rotate: Default."; +$WeaponModes[MergeToolImage, 1, 1] = "Mode: Isometric. Fire the tool at a piece to isometrically rotate them. Rotate: Z-Axis."; +$WeaponModes[MergeToolImage, 2, 0] = "Mode: Split. Fire at a piece to split it in half. Axis: Automatic."; +$WeaponModes[MergeToolImage, 2, 1] = "Mode: Split. Fire at a piece to split it on crosshair. Axis: Automatic."; +$WeaponModes[MergeToolImage, 2, 2] = "Mode: Split. Fire at a piece to split it in half. Axis: X."; +$WeaponModes[MergeToolImage, 2, 3] = "Mode: Split. Fire at a piece to split it in half. Axis: Y."; +$WeaponModes[MergeToolImage, 2, 4] = "Mode: Split. Fire at a piece to split it in half. Axis: Z."; +$WeaponModes[MergeToolImage, 2, 5] = "Mode: Split. Fire at a piece to split it on crosshair. Axis: X."; +$WeaponModes[MergeToolImage, 2, 6] = "Mode: Split. Fire at a piece to split it on crosshair. Axis: Y."; +$WeaponModes[MergeToolImage, 2, 7] = "Mode: Split. Fire at a piece to split it on crosshair. Axis: Z."; +$WeaponModes[MergeToolImage, 3, 0] = "Mode: Nudge. Fire at a piece to move it. Nudge [REPA]M +X Axis."; +$WeaponModes[MergeToolImage, 3, 1] = "Mode: Nudge. Fire at a piece to move it. Nudge [REPA]M +Y Axis."; +$WeaponModes[MergeToolImage, 3, 2] = "Mode: Nudge. Fire at a piece to move it. Nudge [REPA]M +Z Axis."; +$WeaponModes[MergeToolImage, 3, 3] = "Mode: Nudge. Fire at a piece to move it. Nudge [REPA]M -X Axis."; +$WeaponModes[MergeToolImage, 3, 4] = "Mode: Nudge. Fire at a piece to move it. Nudge [REPA]M -Y Axis."; +$WeaponModes[MergeToolImage, 3, 5] = "Mode: Nudge. Fire at a piece to move it. Nudge [REPA]M -Z Axis."; +$WeaponModes[MergeToolImage, 4, 0] = "Mode: Full Scale. Fire at a piece to scale it. Grow .01M."; +$WeaponModes[MergeToolImage, 4, 1] = "Mode: Full Scale. Fire at a piece to scale it. Shrink .01M."; + +//Super Chain Gun +$WeaponModesTag[SuperChaingunImage] = ">>>Super Chaingun<<<\n[XMSG]\nConstruct, Mostlikely, JackTL."; +$WeaponModes[SuperChaingunImage, 0, 0] = "Rapid Fire O.P. Insta-Kill Bullets"; +$WeaponModes[SuperChaingunImage, 1, 0] = "Ion Shots: Ion Progression Disabled"; +$WeaponModes[SuperChaingunImage, 1, 1] = "Ion Shots: Ion Progression Enabled"; +$WeaponModes[SuperChaingunImage, 2, 0] = "Repair Pulse"; +$WeaponModes[SuperChaingunImage, 3, 0] = "Cloak Pulse"; +$WeaponModes[SuperChaingunImage, 4, 0] = "Deconstruction Pulse"; +$WeaponModes[SuperChaingunImage, 5, 0] = "EMP Pulse"; +$WeaponModes[SuperChaingunImage, 6, 0] = "Morphing Pulse"; diff --git a/scripts/inventory.cs b/scripts/inventory.cs index 5f85264..3731684 100644 --- a/scripts/inventory.cs +++ b/scripts/inventory.cs @@ -156,146 +156,18 @@ function ShapeBase::throw(%this,%data) } function ShapeBase::use(%this, %data) { -// if(%data.class $= "Weapon") -// error("ShapeBase::use " @ %data); if(%data $= Grenade) { - // Weapon modes - - //[most] 'ey lets do some unification here.. :D - if(%this.getMountedImage(0) && GetWord($weaponSettings1[%this.getMountedImage(0).getName()],0)) { - if (!(GetSimTime() > (%this.grenadeModeTime + 100))) - return; - %this.grenadeModeTime = getSimTime(); //not 'that' unified.. ;) - - return %this.getMountedImage(0).ChangeMode(%this,1,2); //looksie.. 2 stands for weapons (level 1) - - } - - //[most] - if (%this.getMountedImage(0) !$= "") { - if (%this.getMountedImage(0).getname() $= "MergeToolImage") { - %this.client.MTSubMode++; - if (%this.client.MTMode == 0 && %this.client.MTSubMode == 2) - %this.client.MTSubMode = 0; - if (%this.client.MTMode == 1 && %this.client.MTSubMode == 2) - %this.client.MTSubMode = 0; - if (%this.client.MTMode == 2 && %this.client.MTSubMode == 8) - %this.client.MTSubMode = 0; - if (%this.client.MTMode == 3 && %this.client.MTSubMode == 6) - %this.client.MTSubMode = 0; - if (%this.client.MTMode == 4 && %this.client.MTSubMode == 2) - %this.client.MTSubMode = 0; - - MTShowStatus(%this.client); - return; - } - } - //end of modifier modes - - if (%this.usingConstructionTool == 1 && getSimTime() > (%this.grenadeModeTime + 100) && %this.performing == 0) { - %this.grenadeModeTime = getSimTime(); - if (%this.constructionToolMode == 0) { - if (%this.constructionToolMode2 == 1) { - %this.constructionToolMode2 = 0; - bottomPrint(%this.client,"Normal deconstruction",2,1); - return; - } - else { - %this.constructionToolMode2 = 1; - bottomPrint(%this.client,"Cascading deconstruction",2,1); - return; - } - } - else if (%this.constructionToolMode == 1) { - if(%this.client.RotateAngle $= "") { - %this.client.RotateAngle = 22.5; - } - if (%this.constructionToolMode2 == 1) { - %this.constructionToolMode2 = 0; - bottomPrint(%this.client,"Rotate push ("@mfloor(%this.client.RotateAngle)@" Degrees)",2,1); - return; - } - else { - %this.constructionToolMode2 = 1; - bottomPrint(%this.client,"Rotate pull ("@mfloor(%this.client.RotateAngle)@" Degrees)",2,1); - return; - } - } - else if (%this.constructionToolMode == 2) { - if (%this.constructionToolMode2 == 5) { - %this.constructionToolMode2 = 0; - bottomPrint(%this.client,"Select target as center of rotation",2,1); - return; - } - else if (%this.constructionToolMode2 == 0) { - %this.constructionToolMode2 = 1; - bottomPrint(%this.client,"Select objects to rotate",2,1); - return; - } - else if (%this.constructionToolMode2 == 1) { - %this.constructionToolMode2 = 2; - bottomPrint(%this.client,"Select rotation speed",2,1); - return; - } - else if (%this.constructionToolMode2 == 2) { - %this.constructionToolMode2 = 3; - bottomPrint(%this.client,"Apply rotation",2,1); - return; - } - else if (%this.constructionToolMode2 == 3) { - %this.constructionToolMode2 = 4; - bottomPrint(%this.client,"Display selection",2,1); - return; - } - else { - %this.constructionToolMode2 = 5; - bottomPrint(%this.client,"Clear list",2,1); - return; - } - } - else { - if (%this.constructionToolMode2 == 3) { - %this.constructionToolMode2 = 0; - bottomPrint(%this.client,"Toggle generator power state",2,1); - return; - } - else if (%this.constructionToolMode2 == 0) { - %this.constructionToolMode2 = 1; - bottomPrint(%this.client,"Increase current frequency",2,1); - return; - } - else if (%this.constructionToolMode2 == 1) { - %this.constructionToolMode2 = 2; - bottomPrint(%this.client,"Decrease current frequency",2,1); - return; - } - else { - %this.constructionToolMode2 = 3; - bottomPrint(%this.client,"Read power state",2,1); - return; - } - } - } - if(%this.UsingEditTool == 1) { - ChangeEditGunMode(%this, %data, 2); //Secondary Modes + //[3.9] Phantom139: Stripped out all of the x specific stuff here in favor of a cleaner system + if(%this.hasGrenadeModes) { + //2: Grenade Modes + if(getSimTime() > (%this.changeModeTime + $WeaponModes::SwitchDelay)) { + %this.getMountedImage($WeaponSlot).changeMode(%this, 2); + %this.changeModeTime = getSimTime(); + } + if(%this.changingModeBlocksUse) { + return; + } } - if (%this.usingSuperChaingun == 1) { - if (!(getSimTime() > (%this.grenadeModeTime + 100))) - return; - %this.grenadeModeTime = getSimTime(); - if (%this.superChaingunMode == 1) { - if ($Ion::StopIon == 1) { - $Ion::StopIon = 0; - displaySCGStatus(%this); - return; - } - else { - $Ion::StopIon = 1; - displaySCGStatus(%this); - return; - } - } - } // figure out which grenade type you're using for(%x = 0; $InvGrenade[%x] !$= ""; %x++) { if(%this.inv[$NameToInv[$InvGrenade[%x]]] > 0) { @@ -447,73 +319,17 @@ function ShapeBase::use(%this, %data) { } // Weapon modes if (%data $= "Mine") { - - //[most] 'ey lets do some more unification here.. :D - if(%this.getMountedImage(0) && GetWord($weaponSettings2[%this.getMountedImage(0).getName()],0)) { - if(!GetSimTime() > (%this.grenadeModeTime + 100)) - return; - %this.grenadeModeTime = getSimTime(); //not 'that' unified.. ;) - - return %this.getMountedImage(0).ChangeMode(%this,1,3); //looksie.. 3 stands for weapons (level 2) - } - - //[most] - //modifier tool - if (%this.getMountedImage(0) !$= "") { - if (%this.getMountedImage(0).getname() $= "MergeToolImage") { - %this.client.MTMode++; - %this.client.MTSubMode = 0; - if (%this.client.MTMode >= 5) - %this.client.MTMode = 0; - - MTShowStatus(%this.client); - return; - } + //[3.9] Phantom139: Stripped out all of the x specific stuff here in favor of a cleaner system + if(%this.hasMineModes) { + //1: Mine Modes + if(getSimTime() > (%this.changeModeTime + $WeaponModes::SwitchDelay)) { + %this.getMountedImage($WeaponSlot).changeMode(%this, 1); + %this.changeModeTime = getSimTime(); + } + if(%this.changingModeBlocksUse) { + return; + } } - //end modifier tool - if (%this.usingConstructionTool == 1 && getSimTime() > (%this.mineModeTime + 100) && %this.performing == 0) { - %this.mineModeTime = getSimTime(); - if (%this.constructionToolMode == 3) { - %this.constructionToolMode = 0; - bottomPrint(%this.client,"Construction Tool mode set to deconstruct",2,1); - } - else if (%this.constructionToolMode == 0) { - %this.constructionToolMode = 1; - if(%this.client.RotateAngle $= "") { - %this.client.RotateAngle = 22.5; - } - bottomPrint(%this.client,"Construction Tool mode set to rotate ("@%this.client.RotateAngle@" Degrees)",2,1); - } - else if (%this.constructionToolMode == 1) { - %this.constructionToolMode = 2; - bottomPrint(%this.client,"Construction Tool mode set to advanced rotate",2,1); - } - else { - %powerFreq = %this.powerFreq; - if (%powerFreq < 1 || %powerFreq > upperPowerFreq(%this) || !%powerFreq) - %powerFreq = 1; - %this.powerFreq = %powerFreq; - %this.constructionToolMode = 3; - bottomPrint(%this.client,"Construction Tool mode set to power management\nPower frequency currently set to: " @ %this.powerFreq,2,2); - } - %this.constructionToolMode2 = 0; - return; - } - if(%this.UsingEditTool == 1) { - ChangeEditGunMode(%this, %data, 1); //Primary Modes - } - if (%this.usingSuperChaingun == 1) { - if (!(getSimTime() > (%this.mineModeTime + 100))) - return; - %this.mineModeTime = getSimTime(); - %this.superChaingunMode++; - if (%this.superChaingunMode > 6 - (5 * $host::nopulseSCG)) { - %this.superChaingunMode = 0; - } - displaySCGStatus(%this); - %this.superChaingunMode2 = 0; - return; - } } // default case if (isObject(%data)) { diff --git a/scripts/weapons/Construction/EditGun.cs b/scripts/weapons/Construction/EditGun.cs index 6f927c7..b5b6d92 100644 --- a/scripts/weapons/Construction/EditGun.cs +++ b/scripts/weapons/Construction/EditGun.cs @@ -109,13 +109,21 @@ function EditGunImage::onMount(%this, %obj, %slot) { if(!isSet(%obj.EditSMode)) { %obj.EditSMode = 0; } + //Phantom139: Added + %obj.hasMineModes = 1; + %obj.hasGrenadeModes = 1; + //Phantom139: End %obj.UsingEditTool = true; + displayWeaponInfo(%this, %obj, %obj.client.EditPMode, %obj.client.EditSMode); } -function EditGunImage::onunmount(%this,%obj,%slot) -{ -Parent::onUnmount(%this, %obj, %slot); -%obj.UsingEditTool = false; +function EditGunImage::onunmount(%this,%obj,%slot) { + Parent::onUnmount(%this, %obj, %slot); + %obj.UsingEditTool = false; + //Phantom139: Added + %obj.hasMineModes = 0; + %obj.hasGrenadeModes = 0; + //Phantom139: End } function EditGunImage::onFire(%data, %obj, %slot) { @@ -148,190 +156,29 @@ function EditGunImage::onFire(%data, %obj, %slot) { } } -function EditGunImage::onMount(%this, %obj, %slot) { - Parent::onMount(%this, %obj, %slot); - DispEditorToolInfo(%obj); - if(!isSet(%obj.EditPMode)) { - %obj.EditPMode = 0; - } - if(!isSet(%obj.EditSMode)) { - %obj.EditSMode = 0; - } - %obj.UsingEditTool = true; - -} - -function EditGunImage::onunmount(%this, %obj, %slot) { - Parent::onUnmount(%this, %obj, %slot); - %obj.UsingEditTool = false; -} - -function DispEditorToolInfo(%obj) { - switch(%obj.EditPMode) { - case 0: - %primary = "Pad Swapping"; - switch(%obj.EditSMode) { - case 0: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Blue Pad - [LSB] - MSB", 5, 3); - case 1: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: LSB - [MSB] - Walkway", 5, 3); - case 2: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: MSB - [Walkway] - Medium Floor ", 5, 3); - case 3: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Walkway - [Medium Floor] - Dark Pad", 5, 3); - case 4: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Medium Floor - [Dark Pad] - V-Pad", 5, 3); - case 5: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Dark Pad - [V-Pad] - C.1 Backpack", 5, 3); - case 6: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: V-Pad - [C.1 Backpack] - C.2 Small Containment", 5, 3); - case 7: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.1 Backpack - [C.2 Small Containment] - C.3 Large Containment", 5, 3); - case 8: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.2 Small Containment - [C.3 Large Containment] - C.4 Compressor", 5, 3); - case 9: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.3 Large Containment - [C.4 Compressor] - C.5 Tubes", 5, 3); - case 10: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.4 Compressor - [C.5 Tubes] - C.6 Quantium Bat.", 5, 3); - case 11: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.5 Tubes - [C.6 Quantium Bat.] - C.7 Proton Acc.", 5, 3); - case 12: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.6 Quantium Bat. - [C.7 Proton Acc.] - C.8 Cargo Crate", 5, 3); - case 13: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.7 Proton Acc. - [C.8 Cargo Crate] - C.9 Mag Cooler", 5, 3); - case 14: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.8 Cargo Crate - [C.9 Mag Cooler] - C.10 Recycle Unit", 5, 3); - case 15: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.9 Mag Cooler - [C.10 Recycle Unit] - C.11 Fuel Canister", 5, 3); - case 16: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.10 Recycle Unit - [C.11 Fuel Canister] - C.12 Wooden Box", 5, 3); - case 17: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.11 Fuel Canister - [C.12 Wooden Box] - C.13 Plasma Router", 5, 3); - case 18: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.12 Wooden Box - [C.13 Plasma Router] - Statue Base", 5, 3); - case 19: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: C.13 Plasma Router - [Statue Base] - Blue Pad", 5, 3); - case 20: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: [Pad Swap] - FF Swap - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Statue Base - [Blue Pad] - LSB", 5, 3); - } +function EditGunImage::changeMode(%this, %obj, %key) { + switch(%key) { case 1: - %primary = "Force-Field Swapping"; - switch(%obj.EditSMode) { - case 0: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Yellow - [Solid White] - Solid Red", 5, 3); - case 1: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid White - [Solid Red] - Solid Green", 5, 3); - case 2: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Red - [Solid Green] - Solid Blue", 5, 3); - case 3: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Green - [Solid Blue] - Solid Cyan", 5, 3); - case 4: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Blue - [Solid Cyan] - Solid Magenta", 5, 3); - case 5: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Cyan - [Solid Magenta] - Solid Yellow", 5, 3); - case 6: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Magenta - [Solid Yellow] - Team Pass White", 5, 3); - case 7: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Solid Yellow - [Team Pass White] - Team Pass Red", 5, 3); - case 8: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass White - [Team Pass Red] - Team Pass Green", 5, 3); - case 9: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Red - [Team Pass Green] - Team Pass Blue", 5, 3); - case 10: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Green - [Team Pass Blue] - Team Pass Cyan", 5, 3); - case 11: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Blue - [Team Pass Cyan] - Team Pass Magenta", 5, 3); - case 12: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Cyan - [Team Pass Magenta] - Team Pass Yellow", 5, 3); - case 13: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Magenta - [Team Pass Yellow] - All Pass White", 5, 3); - case 14: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: Team Pass Yellow - [All Pass White] - All Pass Red", 5, 3); - case 15: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass White - [All Pass Red] - All Pass Green", 5, 3); - case 16: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Red - [All Pass Green] - All Pass Blue", 5, 3); - case 17: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Green - [All Pass Blue] - All Pass Cyan", 5, 3); - case 18: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Blue - [All Pass Cyan] - All Pass Magenta", 5, 3); - case 19: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Cyan - [All Pass Magenta] - All Pass Yellow", 5, 3); - case 20: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - [FF Swap] - Barrel Swap - Cloak/Fade - Delete Objects \n Grenade: All Pass Magenta - [All Pass Yellow] - Solid White", 5, 3); - } + //Mine Modes + %obj.client.EditPMode++; + %obj.client.EditSMode = 0; + if (%obj.client.EditPMode >= 5) + %obj.client.EditPMode = 0; case 2: - %primary = "Turret Barrel Swapping"; - switch(%obj.EditSMode) { - case 0: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - [Barrel Swap] - Cloak/Fade - Delete Objects \n Grenade: Mortar - [Anti Air] - Missile", 5, 3); - case 1: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - [Barrel Swap] - Cloak/Fade - Delete Objects \n Grenade: Anti Air - [Missile] - Plasma", 5, 3); - case 2: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - [Barrel Swap] - Cloak/Fade - Delete Objects \n Grenade: Missile - [Plasma] - ELF", 5, 3); - case 3: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - [Barrel Swap] - Cloak/Fade - Delete Objects \n Grenade: Plasma - [ELF] - Mortar", 5, 3); - case 4: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - [Barrel Swap] - Cloak/Fade - Delete Objects \n Grenade: ELF - [Mortar] - Anti Air", 5, 3); - } - case 3: - switch(%obj.EditSMode) { - case 0: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - Barrel Swap - [Cloak/Fade] - Delete Objects \n Grenade: [Cloak] - UnCloak - Fade - UnFade ", 5, 3); - case 1: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - Barrel Swap - [Cloak/Fade] - Delete Objects \n Grenade: Cloak - [UnCloak] - Fade - UnFade ", 5, 3); - case 2: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - Barrel Swap - [Cloak/Fade] - Delete Objects \n Grenade: Cloak - UnCloak - [Fade] - UnFade ", 5, 3); - case 3: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - Barrel Swap - [Cloak/Fade] - Delete Objects \n Grenade: Cloak - UnCloak - Fade - [UnFade] ", 5, 3); - } - case 4: - switch(%obj.EditSMode) { - case 0: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - Barrel Swap - Cloak/Fade - [Delete Objects] \n Grenade: [Single] - Cascade ", 5, 3); - case 1: - commandToClient( %obj.client, 'BottomPrint', "[{Manipulator}] - Phantom139 \n Mine: Pad Swap - FF Swap - Barrel Swap - Cloak/Fade - [Delete Objects] \n Grenade: Single - [Cascade] ", 5, 3); - } - } -} - -function ChangeEditGunMode(%this, %data, %PriSec) { //This Is Easier To use - if(%PriSec == 1) { //Primary - if (!(getSimTime() > (%this.mineModeTime + 100))) - return; - %this.mineModeTime = getSimTime(); - %this.EditPMode++; - %this.EditSMode = 0; //Reset Secondary Mode TO Prevent Errors - if (%this.EditPMode > 4) { - %this.EditPMode = 0; - } - DispEditorToolInfo(%this); - return; - } - else { //Secondary - if (!(getSimTime() > (%this.grenadeModeTime + 100))) - return; - %this.grenadeModeTime = getSimTime(); - %this.EditSMode++; - //Check Primaries - if(%this.EditPMode == 0 && %this.EditSMode > 20) { - %this.EditSMode = 0; - } - else if(%this.EditPMode == 1 && %this.EditSMode > 20) { - %this.EditSMode = 0; - } - else if(%this.EditPMode == 2 && %this.EditSMode > 4) { - %this.EditSMode = 0; - } - else if(%this.EditPMode == 3 && %this.EditSMode > 3) { - %this.EditSMode = 0; - } - else if(%this.EditPMode == 4 && %this.EditSMode > 1) { - %this.EditSMode = 0; - } - DispEditorToolInfo(%this); - return; + //Grenade Modes + %obj.client.EditSMode++; + if (%obj.client.EditPMode == 0 && %obj.client.EditSMode == 21) + %obj.client.EditSMode = 0; + if (%obj.client.EditPMode == 1 && %obj.client.EditSMode == 21) + %obj.client.EditSMode = 0; + if (%obj.client.EditPMode == 2 && %obj.client.EditSMode == 5) + %obj.client.EditSMode = 0; + if (%obj.client.EditPMode == 3 && %obj.client.EditSMode == 4) + %obj.client.EditSMode = 0; + if (%obj.client.EditPMode == 4 && %obj.client.EditSMode == 2) + %obj.client.EditSMode = 0; } + displayWeaponInfo(%this, %obj, %obj.client.EditPMode, %obj.client.EditSMode); } //Editor Tool Functioning diff --git a/scripts/weapons/Construction/constructionTool.cs b/scripts/weapons/Construction/constructionTool.cs index cdcf6a1..ca8c448 100644 --- a/scripts/weapons/Construction/constructionTool.cs +++ b/scripts/weapons/Construction/constructionTool.cs @@ -126,6 +126,35 @@ datablock ShapeBaseImageData(ConstructionToolImage) { stateTransitionOnTimeout[5] = "ActivateReady"; }; +//Phantom139: Added Weapon Mode Code Here. +function ConstructionToolImage::changeMode(%this, %obj, %key) { + if(%obj.performing) { + commandToClient(%obj.client, 'bottomPrint', "Construction Tool\nCannot Change Modes While Performing.", 3, 3); + return; + } + switch(%key) { + case 1: + //Mine Modes + %obj.client.constructionToolMode++; + %obj.client.constructionToolMode2 = 0; + if (%obj.client.constructionToolMode >= 4) + %obj.client.constructionToolMode = 0; + case 2: + //Grenade Modes + %obj.client.constructionToolMode2++; + if (%obj.client.constructionToolMode == 0 && %obj.client.constructionToolMode2 == 2) + %obj.client.constructionToolMode2 = 0; + if (%obj.client.constructionToolMode == 1 && %obj.client.constructionToolMode2 == 2) + %obj.client.constructionToolMode2 = 0; + if (%obj.client.constructionToolMode == 2 && %obj.client.constructionToolMode2 == 6) + %obj.client.constructionToolMode2 = 0; + if (%obj.client.constructionToolMode == 3 && %obj.client.constructionToolMode2 == 4) + %obj.client.constructionToolMode2 = 0; + } + displayWeaponInfo(%this, %obj, %obj.client.constructionToolMode, %obj.client.constructionToolMode2, "[REPA] "@%obj.client.RotateAngle); +} +//Phantom139: End + function ConstructionToolImage::onActivate(%this,%obj,%slot) { } @@ -186,6 +215,9 @@ function ConstructionToolImage::onMount(%this,%obj,%slot) { %curWeap = ( %obj.getMountedImage($WeaponSlot) == 0 ) ? "" : %obj.getMountedImage($WeaponSlot).getName().item.pickUpName; BottomPrint(%obj.client, "Now using " @ %curWeap, 2, 1 ); } + if(%obj.client.RotateAngle $= "") { + %obj.client.RotateAngle = 22.5; + } %obj.errMsgSent = false; %obj.client.setWeaponsHudActive(%this.item); %obj.usingConstructionTool = true; @@ -193,6 +225,10 @@ function ConstructionToolImage::onMount(%this,%obj,%slot) { %obj.constructionToolMode = 0; if (!%obj.constructionToolMode2) %obj.constructionToolMode2 = 0; + //Phantom139: Added + %obj.hasMineModes = 1; + %obj.hasGrenadeModes = 1; + //Phantom139: End WeaponImage::onMount(%this,%obj,%slot); } @@ -203,6 +239,10 @@ function ConstructionToolImage::onUnmount(%data, %obj, %slot) { stopPerforming(%obj); messageClient(%player.client, 'msgClient', '\c2Construction Tool stopped.'); } + //Phantom139: Added + %obj.hasMineModes = 0; + %obj.hasGrenadeModes = 0; + //Phantom139: End %obj.errMsgSent = false; Parent::deconstruct(%data, %obj, %slot); WeaponImage::onUnmount(%data, %obj, %slot); diff --git a/scripts/weapons/Construction/modifiertool.cs b/scripts/weapons/Construction/modifiertool.cs index b9af81d..169ee4d 100644 --- a/scripts/weapons/Construction/modifiertool.cs +++ b/scripts/weapons/Construction/modifiertool.cs @@ -545,91 +545,56 @@ function MergeToolImage::onFire(%data,%obj,%slot) function MergeToolImage::onMount(%this,%obj,%slot) { + if(%obj.MTMode $= "") + %obj.MTMode = 0; + if(%obj.MTSubMode $= "") + %obj.MTSubMode = 0; %obj.usingMTelec = 1; + //Phantom139: Added + %obj.hasMineModes = 1; + %obj.hasGrenadeModes = 1; + //Phantom139: End Parent::onMount(%this, %obj, %slot); %obj.mountImage(MergeToolImage, 0); - MTShowStatus(%obj.client); + displayWeaponInfo(%this, %obj, %obj.client.MTMode, %obj.client.MTSubMode, "[REPA] "@%obj.client.MoveSetting); } function MergeToolImage::onUnmount(%this,%obj,%slot) { Parent::onUnmount(%this, %obj, %slot); %obj.usingMTelec = 0; + //Phantom139: Added + %obj.hasMineModes = 0; + %obj.hasGrenadeModes = 0; + //Phantom139: End } -function MTShowStatus(%client) -{ - if (%client.MTMode $= "") - %client.MTMode = 0; - if (%client.MTSubMode $= "") - %client.MTSubMode = 0; - - switch (%client.MTMode) - { - case 0: - switch (%client.MTSubMode) - { - case 0: - %status = "Mode: Merge. Fire the tool at two pieces. If possible, they will merge. Tolerance: " @ $ElecMod::MergeTool::Tolerance @ " meters."; - case 1: - %status = "Mode: Merge. Fire the tool at two pieces. If possible, they will merge. Tolerance: " @ $ElecMod::MergeTool::HighTolerance @ " meters."; - } - case 1: - switch (%client.MTSubMode) - { - case 0: - %status = "Mode: Isometric. Fire the tool at a piece to isometrically rotate them. Rotate: Default."; - case 1: - %status = "Mode: Isometric. Fire the tool at a piece to isometrically rotate them. Rotate: Z Axis."; - } - case 2: - switch (%client.MTSubMode) - { - case 0: - %status = "Mode: Split. Fire at a piece to split it in half. Axis: Automatic."; - case 1: - %status = "Mode: Split. Fire at a piece to split it on crosshair. Axis: Automatic."; - case 2: - %status = "Mode: Split. Fire at a piece to split it in half. Axis: X."; - case 3: - %status = "Mode: Split. Fire at a piece to split it in half. Axis: Y."; - case 4: - %status = "Mode: Split. Fire at a piece to split it in half. Axis: Z."; - case 5: - %status = "Mode: Split. Fire at a piece to split it on crosshair. Axis: X."; - case 6: - %status = "Mode: Split. Fire at a piece to split it on crosshair. Axis: Y."; - case 7: - %status = "Mode: Split. Fire at a piece to split it on crosshair. Axis: Z."; - } - case 3: - if(%client.MoveSetting $= "") { - %client.MoveSetting = 0.1; - } - switch (%client.MTSubMode) { - case 0: - %status = "Mode: Nudge. Fire at a piece to move it. Nudge "@%client.MoveSetting@"M +X Axis."; - case 1: - %status = "Mode: Nudge. Fire at a piece to move it. Nudge "@%client.MoveSetting@"M -X Axis."; - case 2: - %status = "Mode: Nudge. Fire at a piece to move it. Nudge "@%client.MoveSetting@"M +Y Axis."; - case 3: - %status = "Mode: Nudge. Fire at a piece to move it. Nudge "@%client.MoveSetting@"M -Y Axis."; - case 4: - %status = "Mode: Nudge. Fire at a piece to move it. Nudge "@%client.MoveSetting@"M +Z Axis."; - case 5: - %status = "Mode: Nudge. Fire at a piece to move it. Nudge "@%client.MoveSetting@"M -Z Axis."; - } - case 4: - switch (%client.MTSubMode) { - case 0: - %status = "Mode: Full Scale. Fire at a piece to scale it. Grow .01M."; - case 1: - %status = "Mode: Full Scale. Fire at a piece to scale it. Shrink .01M."; - } - } - CommandToClient(%client, 'BottomPrint', ">>>M/I/S Tool<<<\n" @ %status @ "\nCoded by Electricutioner.", 3, 3 ); +//Phantom139: Added Weapon Mode Code Here. +function MergeToolImage::changeMode(%this, %obj, %key) { + switch(%key) { + case 1: + //Mine Modes + %obj.client.MTMode++; + %obj.client.MTSubMode = 0; + if (%obj.client.MTMode >= 5) + %obj.client.MTMode = 0; + case 2: + //Grenade Modes + %obj.client.MTSubMode++; + if (%obj.client.MTMode == 0 && %obj.client.MTSubMode == 2) + %obj.client.MTSubMode = 0; + if (%obj.client.MTMode == 1 && %obj.client.MTSubMode == 2) + %obj.client.MTSubMode = 0; + if (%obj.client.MTMode == 2 && %obj.client.MTSubMode == 8) + %obj.client.MTSubMode = 0; + if (%obj.client.MTMode == 3 && %obj.client.MTSubMode == 6) + %obj.client.MTSubMode = 0; + if (%obj.client.MTMode == 4 && %obj.client.MTSubMode == 2) + %obj.client.MTSubMode = 0; + } + displayWeaponInfo(%this, %obj, %obj.client.MTMode, %obj.client.MTSubMode, "[REPA] "@%obj.client.MoveSetting); } +//Phantom139: End //Split code begins here. //The goal of this is to be a semi-inverse of the merge... diff --git a/scripts/weapons/Construction/superChaingun.cs b/scripts/weapons/Construction/superChaingun.cs index 38861e4..1bd991b 100644 --- a/scripts/weapons/Construction/superChaingun.cs +++ b/scripts/weapons/Construction/superChaingun.cs @@ -214,28 +214,32 @@ function SuperChaingunImage::onMount(%this,%obj,%slot) { %obj.superChaingunMode = 0; if (!%obj.superChaingunMode2) %obj.superChaingunMode2 = 0; - displaySCGStatus(%obj); + %obj.hasMineModes = 1; + %obj.hasGrenadeModes = 1; + displayWeaponInfo(%this, %obj, %obj.client.superChaingunMode, %obj.client.superChaingunMode2); WeaponImage::onMount(%this,%obj,%slot); } function SuperChaingunImage::onUnmount(%data, %obj, %slot) { %obj.usingSuperChaingun = false; + %obj.hasMineModes = 0; + %obj.hasGrenadeModes = 0; WeaponImage::onUnmount(%data, %obj, %slot); } -function displaySCGStatus(%obj) { - if (%obj.superChaingunMode == 1) - bottomPrint(%obj.client,">>>Super Chain Gun<<<\nIons. Progression: " @ ($Ion::StopIon ? "disabled" : "enabled") @ ".",2,2); - else if (%obj.superChaingunMode == 2) - bottomPrint(%obj.client,">>>Super Chain Gun<<<\nRepair Pulse.",2,2); - else if (%obj.superChaingunMode == 3) - bottomPrint(%obj.client,">>>Super Chain Gun<<<\nCloak Pulse.",2,2); - else if (%obj.superChaingunMode == 4) - bottomPrint(%obj.client,">>>Super Chain Gun<<<\nDeconstruction Pulse",2,2); - else if (%obj.superChaingunMode == 5) - bottomPrint(%obj.client,">>>Super Chain Gun<<<\nElectro-static Pulse.",2,2); - else if (%obj.superChaingunMode == 6) - bottomPrint(%obj.client,">>>Super Chain Gun<<<\nMorph Pulse.",2,2); - else - bottomPrint(%obj.client,">>>Super Chain Gun<<<\nRapid fire bullets.",2,2); +function SuperChaingunImage::changeMode(%this, %obj, %key) { + switch(%key) { + case 1: + //Mine Modes + %obj.client.superChaingunMode++; + %obj.client.superChaingunMode2 = 0; + if (%obj.client.superChaingunMode > 6 - (5 * $host::nopulseSCG)) + %obj.client.superChaingunMode = 0; + case 2: + //Grenade Modes + %obj.client.superChaingunMode2++; + if (%obj.client.superChaingunMode == 1 && %obj.client.superChaingunMode2 == 2) + %obj.client.superChaingunMode2 = 0; + } + displayWeaponInfo(%this, %obj, %obj.client.superChaingunMode, %obj.client.superChaingunMode2); } From f226c40a544f1648c4371ef1bad259cee9e8c9a5 Mon Sep 17 00:00:00 2001 From: Robert Fritzen Date: Sat, 2 Aug 2014 17:12:19 -0500 Subject: [PATCH 11/16] Killstreak System Update Nuked a ton of unnecessary code. Made a few minor adjustments. --- scripts/TWM2/CustomCamera.cs | 78 +- scripts/TWM2/LoadMod.cs | 1 + scripts/TWM2/Systems/Killstreak.cs | 161 +- scripts/TWM2/Systems/List.cs | 69 + scripts/weapons/Equipment/SWBeaconer.cs | 2308 ++++++----------------- 5 files changed, 795 insertions(+), 1822 deletions(-) create mode 100644 scripts/TWM2/Systems/List.cs diff --git a/scripts/TWM2/CustomCamera.cs b/scripts/TWM2/CustomCamera.cs index f00c51b..6731ec3 100644 --- a/scripts/TWM2/CustomCamera.cs +++ b/scripts/TWM2/CustomCamera.cs @@ -54,7 +54,7 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { //press JET if (%trigger == 3) { //Can we Call in this airstrike? - if(!%client.HasAirstrike && !%client.UnlimitedAS) { + if(%client.ksListInstance.find("Airstrike") == -1 && !%client.UnlimitedAS) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); @@ -79,7 +79,13 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); if(!%client.UnlimitedAS) { - %client.HasAirstrike = 0; + %newCt = getField(%client.ksListInstance.find("Airstrike"), 1) - 1; + if(%newCt == 0) { + %client.ksListInstance.removeElement(getField(%client.ksListInstance.find("Airstrike"), 1)); + } + else { + %client.ksListInstance.set(getField(%client.ksListInstance.find("Airstrike"), 1), "Airstrike" SPC %newCt); + } GainExperience(%client, 35, "Airstrike called in "); } bottomPrint(%client, "Coordinates Confirmed, Calling In Airstrike", 5, 2); @@ -95,7 +101,7 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { //press JET if (%trigger == 3) { //Can we Call in this airstrike? - if(!%client.HasHarrier) { + if(%client.ksListInstance.find("Harrier") == -1) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); @@ -117,7 +123,13 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); - %client.HasHarrier = 0; + %newCt = getField(%client.ksListInstance.find("Harrier"), 1) - 1; + if(%newCt == 0) { + %client.ksListInstance.removeElement(getField(%client.ksListInstance.find("Harrier"), 1)); + } + else { + %client.ksListInstance.set(getField(%client.ksListInstance.find("Harrier"), 1), "Harrier" SPC %newCt); + } GainExperience(%client, 150, "Harrier Airstrike called in "); messageTeam(%client.team, 'MsgAirstrike', "\c5TWM2: "@%client.namebase@"'s Harrier Airstrike is Approaching."); bottomPrint(%client, "Coordinates Confirmed, Calling In Harriers", 5, 2); @@ -132,7 +144,7 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { //press JET if (%trigger == 3) { //Can we Call in this airstrike? - if(!%client.HasNapalmHarrier) { + if(%client.ksListInstance.find("Napalm") == -1) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); @@ -154,7 +166,13 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); - %client.HasNapalmHarrier = 0; + %newCt = getField(%client.ksListInstance.find("Napalm"), 1) - 1; + if(%newCt == 0) { + %client.ksListInstance.removeElement(getField(%client.ksListInstance.find("Napalm"), 1)); + } + else { + %client.ksListInstance.set(getField(%client.ksListInstance.find("Napalm"), 1), "Napalm" SPC %newCt); + } GainExperience(%client, 350, "Napalm Airstrike called in "); messageTeam(%client.team, 'MsgAirstrike', "\c5TWM2: "@%client.namebase@"'s Napalm Airstrike is coming in hot."); bottomPrint(%client, "Coordinates Confirmed, Calling In Strike Fighters", 5, 2); @@ -169,7 +187,7 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { //press JET if (%trigger == 3) { //Can we Call in this airstrike? - if(!%client.HasOLS) { + if(%client.ksListInstance.find("OLS") == -1) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); @@ -183,7 +201,13 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); - %client.HasOLS = 0; + %newCt = getField(%client.ksListInstance.find("OLS"), 1) - 1; + if(%newCt == 0) { + %client.ksListInstance.removeElement(getField(%client.ksListInstance.find("OLS"), 1)); + } + else { + %client.ksListInstance.set(getField(%client.ksListInstance.find("OLS"), 1), "OLS" SPC %newCt); + } GainExperience(%client, 350, "Orbital Laser Strike Called In "); messageTeam(%client.team, 'MsgAirstrike', "\c5TWM2: "@%client.namebase@"'s Laser Strike is Incoming."); bottomPrint(%client, "Coordinates Confirmed, Spinning Laser Cannon", 5, 2); @@ -198,7 +222,7 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { //press JET if (%trigger == 3) { //Can we Call in this airstrike? - if(!%client.HasSlthAirstrike) { + if(%client.ksListInstance.find("Stealth") == -1) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); @@ -220,7 +244,13 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); - %client.HasSlthAirstrike = 0; + %newCt = getField(%client.ksListInstance.find("Stealth"), 1) - 1; + if(%newCt == 0) { + %client.ksListInstance.removeElement(getField(%client.ksListInstance.find("Stealth"), 1)); + } + else { + %client.ksListInstance.set(getField(%client.ksListInstance.find("Stealth"), 1), "Stealth" SPC %newCt); + } GainExperience(%client, 150, "Stealth Bomber Airstrike called in "); bottomPrint(%client, "Coordinates Confirmed, Calling In Stealth Bomber", 5, 2); StealthAirstrike(%client, %position, %direction); @@ -234,7 +264,7 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { //press JET if (%trigger == 3) { //Can we Call in this airstrike? - if(!%client.HasArtillery) { + if(%client.ksListInstance.find("Artillery") == -1) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); @@ -248,10 +278,14 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); - //if(!%client.UnlimitedAS) { - %client.HasArtillery = 0; - GainExperience(%client, 250, "Artillery called in "); - //} + %newCt = getField(%client.ksListInstance.find("Artillery"), 1) - 1; + if(%newCt == 0) { + %client.ksListInstance.removeElement(getField(%client.ksListInstance.find("Artillery"), 1)); + } + else { + %client.ksListInstance.set(getField(%client.ksListInstance.find("Artillery"), 1), "Artillery" SPC %newCt); + } + GainExperience(%client, 250, "Artillery called in "); bottomPrint(%client, "Coordinates Confirmed, Calling In Artillery", 5, 2); messageTeam(%client.team, 'MsgAirstrike', "\c5TWM2: Artillery Called In From "@%client.namebase@""); Artillery(%client, %position); @@ -265,7 +299,7 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { //press JET if (%trigger == 3) { //Can we Call in this airstrike? - if(!%client.HasNuke) { + if(%client.ksListInstance.find("NukeStrike") == -1) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); @@ -279,10 +313,14 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); - //if(!%client.UnlimitedAS) { - %client.HasNuke = 0; - GainExperience(%client, 500, "Nuclear Missile called in "); - //} + %newCt = getField(%client.ksListInstance.find("NukeStrike"), 1) - 1; + if(%newCt == 0) { + %client.ksListInstance.removeElement(getField(%client.ksListInstance.find("NukeStrike"), 1)); + } + else { + %client.ksListInstance.set(getField(%client.ksListInstance.find("NukeStrike"), 1), "NukeStrike" SPC %newCt); + } + GainExperience(%client, 500, "Nuclear Missile called in "); bottomPrint(%client, "Coordinates Confirmed, Launching Missile", 5, 2); messageAll('msgDanger', "\c5TWM2 ALERT: "@%client.namebase@" has activated a nuclear missile!!! ~wfx/misc/red_alert.wav"); Nuke(%client, %position); diff --git a/scripts/TWM2/LoadMod.cs b/scripts/TWM2/LoadMod.cs index 0f8aeb5..600e0a2 100644 --- a/scripts/TWM2/LoadMod.cs +++ b/scripts/TWM2/LoadMod.cs @@ -8,6 +8,7 @@ Error("********************************************"); //Mod Systems exec("serverControl.cs"); //Server Settings +exec("scripts/TWM2/Systems/List.cs"); //List Instance exec("scripts/TWM2/Systems/Directorate.cs"); //Client Container Objects exec("scripts/TWM2/Systems/AdvancedRankSystem.cs"); //Adv. Ranks exec("scripts/TWM2/Systems/MainControl.cs"); //TWM2 Core Functions diff --git a/scripts/TWM2/Systems/Killstreak.cs b/scripts/TWM2/Systems/Killstreak.cs index 9d8fd9b..f6c5345 100644 --- a/scripts/TWM2/Systems/Killstreak.cs +++ b/scripts/TWM2/Systems/Killstreak.cs @@ -295,62 +295,14 @@ function GameConnection::isActiveStreak(%client, %val) { } function GiveTWM2Weapons(%client) { - if(%client.HasUAV) { - %client.player.setInventory(UAVCaller, 1, true); - } - if(%client.HasAirstrike) { - %client.player.setInventory(AirstrikeCaller, 1, true); - } - if(%client.HasHeli) { - %client.player.setInventory(HeliCaller, 1, true); - } if(%client.HasAmmoDrop) { %client.player.setInventory(AmmoDropCaller, 1, true); } - if(%client.HasGM) { - %client.player.setInventory(GMCaller, 1, true); - } - if(%client.HasHarbinsWrath) { - %client.player.setInventory(HarbinsWrathCaller, 1, true); - } - if(%client.HasChopperGunner) { - %client.player.setInventory(ChopperGunnerCaller, 1, true); - } - if(%client.HasSlthAirstrike) { - %client.player.setInventory(StealthAirstrikeCaller, 1, true); - } - if(%client.HasArtillery) { - %client.player.setInventory(ArtilleryCaller, 1, true); - } - if(%client.HasAcGunner) { - %client.player.setInventory(AC130Caller, 1, true); - } - if(%client.HasNuke) { - %client.player.setInventory(NukeCaller, 1, true); - } - if(%client.HasOLS) { - %client.player.setInventory(OLSCaller, 1, true); - } - if(%client.HasZBomb) { - %client.player.setInventory(ZBombCaller, 1, true); - } - if(%client.HasGunshipHeli) { - %client.player.setInventory(GunshipHeliCaller, 1, true); - } - if(%client.HasHarrier) { - %client.player.setInventory(HarrierAirstrikeCaller, 1, true); - } - if(%client.HasFission) { - %client.player.setInventory(FissionBombCaller, 1, true); - } if(%client.HasFullTeamRespawn) { %client.player.setInventory(FullTeamRespawnCaller, 1, true); } - if(%client.HasMassEMP) { - %client.player.setInventory(MassEMPCaller, 1, true); - } - if(%client.HasNapalmHarrier) { - %client.player.setInventory(NapalmHarrierAirstrikeCaller, 1, true); + if(%client.ksListInstance.count() > 0) { + %client.player.setInventory(KillstreakBeacon, 1, true); } if(!%client.isconfiscated) { if (%client.isAdmin) { @@ -370,75 +322,114 @@ function GameConnection::AwardKillstreak(%client, %streakVal, %plz) { if(!%client.isActiveStreak(%streakVal) && ($Killstreak::Setting != 2) && !$TWM::PlayingHelljump) { return; } + if(!%client.ksListInstance) { + %client.ksListInstance = initList(); + } + %client.player.setInventory(KillstreakBeacon, 1, true); + %cAmt = 0; switch(%streakVal) { case 1: MessageClient(%client, 'MsgZKill', "\c5TWM2: UAV Recon at Your Disposal."); - %client.HasUAV = 1; //heh, now we can use it if we die - %client.player.setInventory(UAVCaller, 1, true); + if(%client.ksListInstance.find("UAV") != -1) { + %cAmt = getWord(getField(%client.ksListInstance.find("UAV"), 0), 1); + } + %client.ksListIntance.advancedAdd("UAV", "UAV "@%cAmt+1); case 2: MessageClient(%client, 'MsgZKill', "\c5TWM2: Airstrike Standing By."); - %client.HasAirstrike = 1; //heh, now we can use it if we die - %client.player.setInventory(AirstrikeCaller, 1, true); + if(%client.ksListInstance.find("Airstrike") != -1) { + %cAmt = getWord(getField(%client.ksListInstance.find("Airstrike"), 0), 1); + } + %client.ksListIntance.advancedAdd("Airstrike", "Airstrike "@%cAmt+1); case 3: MessageClient(%client, 'MsgZKill', "\c5TWM2: Guided Missile Strike Standing By."); - %client.HasGM = 1; //heh, now we can use it if we die - %client.player.setInventory(GMCaller, 1, true); + if(%client.ksListInstance.find("GM") != -1) { + %cAmt = getWord(getField(%client.ksListInstance.find("GM"), 0), 1); + } + %client.ksListIntance.advancedAdd("GM", "GM "@%cAmt+1); case 4: MessageClient(%client, 'MsgZKill', "\c5TWM2: Helicopter at your disposal."); - %client.HasHeli = 1; //heh, now we can use it if we die - %client.player.setInventory(HeliCaller, 1, true); + if(%client.ksListInstance.find("AIHeli") != -1) { + %cAmt = getWord(getField(%client.ksListInstance.find("AIHeli"), 0), 1); + } + %client.ksListIntance.advancedAdd("AIHeli", "AIHeli "@%cAmt+1); case 5: MessageClient(%client, 'MsgZKill', "\c5TWM2: Plasma Harrier Strike at your disposal."); - %client.HasHarrier = 1; //heh, now we can use it if we die - %client.player.setInventory(HarrierAirstrikeCaller, 1, true); + if(%client.ksListInstance.find("Harrier") != -1) { + %cAmt = getWord(getField(%client.ksListInstance.find("Harrier"), 0), 1); + } + %client.ksListIntance.advancedAdd("Harrier", "Harrier "@%cAmt+1); case 6: MessageClient(%client, 'MsgZKill', "\c5TWM2: Satellite Strike at your disposal."); - %client.HasOLS = 1; //heh, now we can use it if we die - %client.player.setInventory(OLSCaller, 1, true); + if(%client.ksListInstance.find("OLS") != -1) { + %cAmt = getWord(getField(%client.ksListInstance.find("OLS"), 0), 1); + } + %client.ksListIntance.advancedAdd("OLS", "OLS "@%cAmt+1); case 7: MessageClient(%client, 'MsgZKill', "\c5TWM2: Gunship Helicopter at your disposal."); - %client.HasGunshipHeli = 1; //heh, now we can use it if we die - %client.player.setInventory(GunshipHeliCaller, 1, true); + if(%client.ksListInstance.find("AIGunHeli") != -1) { + %cAmt = getWord(getField(%client.ksListInstance.find("AIGunHeli"), 0), 1); + } + %client.ksListIntance.advancedAdd("AIGunHeli", "AIGunHeli "@%cAmt+1); case 8: MessageClient(%client, 'MsgZKill', "\c5TWM2: Stealth Bomber at your disposal."); - %client.HasSlthAirstrike = 1; //heh, now we can use it if we die - %client.player.setInventory(StealthAirstrikeCaller, 1, true); + if(%client.ksListInstance.find("Stealth") != -1) { + %cAmt = getWord(getField(%client.ksListInstance.find("Stealth"), 0), 1); + } + %client.ksListIntance.advancedAdd("Stealth", "Stealth "@%cAmt+1); case 9: MessageClient(%client, 'MsgZKill', "\c5TWM2: Harbinger's Wrath Standing By."); - %client.HasHarbinsWrath = 1; //heh, now we can use it if we die - %client.player.setInventory(HarbinsWrathCaller, 1, true); + if(%client.ksListInstance.find("HarbWrath") != -1) { + %cAmt = getWord(getField(%client.ksListInstance.find("HarbWrath"), 0), 1); + } + %client.ksListIntance.advancedAdd("HarbWrath", "HarbWrath "@%cAmt+1); case 10: MessageClient(%client, 'MsgZKill', "\c5TWM2: Apache Gunner Standing By."); - %client.HasChopperGunner = 1; //heh, now we can use it if we die - %client.player.setInventory(ChopperGunnerCaller, 1, true); + if(%client.ksListInstance.find("Apache") != -1) { + %cAmt = getWord(getField(%client.ksListInstance.find("Apache"), 0), 1); + } + %client.ksListIntance.advancedAdd("Apache", "Apache "@%cAmt+1); case 11: MessageClient(%client, 'MsgZKill', "\c5TWM2: AC-130 Gunner Standing By."); - %client.HasAcGunner = 1; //heh, now we can use it if we die - %client.player.setInventory(AC130Caller, 1, true); + if(%client.ksListInstance.find("AC130") != -1) { + %cAmt = getWord(getField(%client.ksListInstance.find("AC130"), 0), 1); + } + %client.ksListIntance.advancedAdd("AC130", "AC130 "@%cAmt+1); case 12: MessageClient(%client, 'MsgZKill', "\c5TWM2: Centaur Bombardment Standing By."); - %client.HasArtillery = 1; //heh, now we can use it if we die - %client.player.setInventory(ArtilleryCaller, 1, true); + if(%client.ksListInstance.find("Artillery") != -1) { + %cAmt = getWord(getField(%client.ksListInstance.find("Artillery"), 0), 1); + } + %client.ksListIntance.advancedAdd("Artillery", "Artillery "@%cAmt+1); case 13: MessageClient(%client, 'MsgZKill', "\c5TWM2: Mass EMP Standing By."); - %client.HasMassEMP = 1; //heh, now we can use it if we die - %client.player.setInventory(MassEMPCaller, 1, true); + if(%client.ksListInstance.find("EMP") != -1) { + %cAmt = getWord(getField(%client.ksListInstance.find("EMP"), 0), 1); + } + %client.ksListIntance.advancedAdd("EMP", "EMP "@%cAmt+1); case 14: MessageClient(%client, 'MsgZKill', "\c5TWM2: Nuclear Strike Standing By."); - %client.HasNuke = 1; //heh, now we can use it if we die - %client.player.setInventory(NukeCaller, 1, true); + if(%client.ksListInstance.find("NukeStrike") != -1) { + %cAmt = getWord(getField(%client.ksListInstance.find("NukeStrike"), 0), 1); + } + %client.ksListIntance.advancedAdd("NukeStrike", "NukeStrike "@%cAmt+1); case 15: - MessageClient(%client, 'MsgZKill', "\c5TWM2: Zombie Bomb Standing By... wait... holy fuck, you got "@$Killstreak::Kills["ZBomb", 1]@" zombie kills without dying!?!?"); - %client.HasZBomb = 1; //heh, now we can use it if we die - %client.player.setInventory(ZBombCaller, 1, true); + MessageClient(%client, 'MsgZKill', "\c5TWM2: Zombie Bomb Standing By."); + if(%client.ksListInstance.find("ZBomb") != -1) { + %cAmt = getWord(getField(%client.ksListInstance.find("ZBomb"), 0), 1); + } + %client.ksListIntance.advancedAdd("ZBomb", "ZBomb "@%cAmt+1); case 16: MessageClient(%client, 'MsgZKill', "\c5TWM2: Fission Bomb Ready... Obliterate everyone!!!"); - %client.HasFission = 1; //heh, now we can use it if we die - %client.player.setInventory(FissionBombCaller, 1, true); + if(%client.ksListInstance.find("FBomb") != -1) { + %cAmt = getWord(getField(%client.ksListInstance.find("FBomb"), 0), 1); + } + %client.ksListIntance.advancedAdd("FBomb", "FBomb "@%cAmt+1); case 17: MessageClient(%client, 'MsgZKill', "\c5TWM2: Napalm Airstrike at your disposal."); - %client.HasNapalmHarrier = 1; //heh, now we can use it if we die - %client.player.setInventory(NapalmHarrierAirstrikeCaller, 1, true); + if(%client.ksListInstance.find("Napalm") != -1) { + %cAmt = getWord(getField(%client.ksListInstance.find("Napalm"), 0), 1); + } + %client.ksListIntance.advancedAdd("Napalm", "Napalm "@%cAmt+1); } if(%plz == 0) { if(%client.IsHighestPLStreak(%streakVal)) { diff --git a/scripts/TWM2/Systems/List.cs b/scripts/TWM2/Systems/List.cs new file mode 100644 index 0000000..ce72eda --- /dev/null +++ b/scripts/TWM2/Systems/List.cs @@ -0,0 +1,69 @@ +// List.cs +// Phantom139 +// TWM2 3.9 +// Declares a simple container system for list properties. + +function initList() { + %list = new ScriptObject() { + class = "ListInstance"; + numberOfElements = 0; + }; + return %list; +} + +function ListInstance::advancedAdd(%this, %elementTxt, %newValue) { + if(%this.find(%elementTxt) == -1) { + %this.addElement(%newValue); + } + else { + %indx = getField(%this.find(%elementTxt), 1); + %this.set(%indx, %newValue); + } +} + +function ListInstance::set(%this, %index, %new) { + %this.element[%index] = %new; +} + +function ListInstance::addElement(%this, %element) { + %this.element[%this.numberOfElements] = %element; + %this.numberOfElements++; +} + +function ListInstance::removeElement(%this, %index) { + if(%index > %this.count() || %index < 0) { + error("ListInstance::removeElements("@%index@"): Specified index is out of list bounds."); + return; + } + %this.element[%this.numberOfElements] = ""; + %this.compactList(); +} + +function ListInstance::element(%this, %index) { + return %this.element[%index]; +} + +function ListInstance::count(%this) { + return %this.numberOfElements; +} + +function ListInstance::find(%this, %key) { + for(%i = %this.count(); %i >= 0; %i--) { + if(strstr(%this.element[%i], %key) == 0) { + return %this.element[%i] TAB %i; + } + } + return -1; +} + +function ListInstance::compactList(%this) { + for(%i = %this.count(); %i >= 0; %i--) { + if(%this.element[%i] $= "") { + //Strip item, move others forward + for(%x = %i; %x < %this.count(); %x++) { + %this.element[%x] = %this.element[%x+1]; + } + %this.numberOfElements--; + } + } +} diff --git a/scripts/weapons/Equipment/SWBeaconer.cs b/scripts/weapons/Equipment/SWBeaconer.cs index 20be1af..c34b244 100644 --- a/scripts/weapons/Equipment/SWBeaconer.cs +++ b/scripts/weapons/Equipment/SWBeaconer.cs @@ -2,17 +2,17 @@ // SWs // System Core now moved to: scripts/TWM2/Systems/Killstreak.cs // Handles the Killstreak Datablocks +// +// 3.9: I've eliminated ~40 datablocks here by simply moving all killstreaks to a +// single weapon instance with mine/grenade modes to cycle through the earned +// streaks. This should prove to be a much more efficient system. //-------------------------------------------------------------------------- -//-------------------------------------- -// UAV -//-------------------------------------- -datablock ItemData(UAVCaller) -{ +datablock ItemData(KillstreakBeacon) { className = Weapon; catagory = "Spawn Items"; shapeFile = "weapon_targeting.dts"; - image = UAVCallerImage; + image = KillstreakBeaconImage; mass = 1; elasticity = 0.2; friction = 0.6; @@ -25,12 +25,11 @@ datablock ItemData(UAVCaller) }; -datablock ShapeBaseImageData(UAVCallerImage) -{ +datablock ShapeBaseImageData(KillstreakBeaconImage) { className = WeaponImage; shapeFile = "weapon_targeting.dts"; - item = UAVCaller; + item = KillstreakBeacon; offset = "0 0 0"; isKSSW = 1; @@ -73,45 +72,571 @@ datablock ShapeBaseImageData(UAVCallerImage) stateTransitionOnTimeout[5] = "Ready"; }; -function UAVCallerImage::OnFire(%data, %obj, %slot) { - %obj.client.HasUAV = 0; - GainExperience(%obj.client, 25, "UAV Called in "); - - $TWM2::UAVCalls[%obj.client.guid]++; - - %obj.client.TWM2Core.UAVCalls++; - UpdateSWBeaconFile(%obj.client, "UAV"); - - %obj.throwWeapon(1); - %obj.throwWeapon(0); - %obj.setInventory(UAVCaller, 0, true); - - %obj.client.OnUseKillstreak(1); - - %count = 0; - if(!$TWM2::FFAMode) { - %obj.team.UAVLoop = UAVLoop(%obj, %obj.client.team, %count); - for(%i = 0; %i < ClientGroup.getCount(); %i++) { - %cl = ClientGroup.getObject(%i); - if(%cl.team == %obj.team) { - messageClient(%cl, 'MsgUAVOnline' , "Our UAV is Online (30 Seconds)"); - } - else { - messageClient(%cl, 'MsgUAVOnline' , "Enemy UAV is Airborne (30 Seconds)"); - } - } +function KillstreakBeaconImage::onMount(%this, %obj, %slot) { + Parent::onMount(%this, %obj, %slot); + %obj.hasMineModes = 1; + %obj.hasGrenadeModes = 1; + DisplayKillstreakInfo(%obj); + if(!isSet(%obj.KSSetMode)) { + %obj.KSSetMode = 0; } - else { - %obj.client.UAVLoop = UAVLoop(%obj, "", 0); - for(%i = 0; %i < ClientGroup.getCount(); %i++) { - %cl = ClientGroup.getObject(%i); - if(%cl == %obj.client) { - messageClient(%cl, 'MsgUAVOnline' , "Your UAV is Online (30 Seconds)"); + %obj.usingKSBeacon = true; +} + +function KillstreakBeaconImage::onunmount(%this,%obj,%slot) { + Parent::onUnmount(%this, %obj, %slot); + %obj.hasMineModes = 0; + %obj.hasGrenadeModes = 0; + %obj.usingKSBeacon = false; +} + +function KillstreakBeaconImage::changeMode(%this, %obj, %key) { + switch(%key) { + case 1: + //Mine Modes + %obj.KSSetMode++; + if(%obj.KSSetMode >= %obj.client.ksListInstance.count()) { + %obj.KSSetMode = 0; + } + case 2: + //Grenade Modes + %obj.KSSetMode--; + if(%obj.KSSetMode < 0) { + %obj.KSSetMode = %obj.client.ksListInstance.count() - 1; + } + } + DisplayKillstreakInfo(%obj); +} + +function DisplayKillstreakInfo(%obj) { + %currentStreak = %obj.client.ksListInstance.element(%obj.KSSetMode); + %strkName = getWord(%currentStreak, 0); + %strkCnt = getWord(%currentStreak, 1); + + switch$(%strkName) { + case "UAV": + %msg = "UAV Recon"; + case "Airstrike": + %msg = "Thundersword Airstrike"; + case "GM": + %msg = "UAMS Assault Drone"; + case "AIHeli": + %msg = "Support Helicopter"; + case "Harrier": + %msg = "Plasma Harrier Airstrike"; + case "OLS": + %msg = "Orbital Laser Strike"; + case "AIGunHeli": + %msg = "Gunship Helicopter Support"; + case "Stealth": + %msg = "Stealth Bomber Airstrike"; + case "HarbWrath": + %msg = "Harbinger's Wrath"; + case "Apache": + %msg = "Apache Gunner"; + case "AC130": + %msg = "AC-130 Gunner"; + case "Artillery": + %msg = "Centaur Artillery Bombardment"; + case "EMP": + %msg = "EMP Strike"; + case "NukeStrike": + %msg = "Tactical Nuke Strike"; + case "ZBomb": + %msg = "Anti-Zombie Bomb"; + case "FBomb": + %msg = "Fission Bomb Strike"; + case "Napalm": + %msg = "Napalm Airstrike"; + } + + commandToClient(%obj.client, 'BottomPrint', ">>>Killstreak Beacon<<<\n"@%msg@" ["@%strkCnt@" Available]\nPress Mine to select next streak, Grenade to select previous streak.", 3, 3); +} + +function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { + %currentStreak = %obj.client.ksListInstance.element(%obj.KSSetMode); + %strkName = getWord(%currentStreak, 0); + %strkCnt = getWord(%currentStreak, 1); + %newCt = %strkCnt - 1; + if(%strkCnt <= 0) { + //Oops... + messageClient(%obj.client, 'msgError', "\c5TWM2: Nice Try..."); + %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); + if(%obj.client.ksListInstance.count() <= 0) { + //No more streaks in the list... + %obj.throwWeapon(1); + %obj.throwWeapon(0); + %obj.setInventory(KillstreakBeacon, 0, true); + } + return; + } + + switch$(%strkName) { + // + // + // UAV + // + // + case "UAV": + GainExperience(%obj.client, 25, "UAV Called in "); + %obj.client.TWM2Core.UAVCalls++; + UpdateSWBeaconFile(%obj.client, "UAV"); + + %obj.client.OnUseKillstreak(1); + if(%newCt == 0) { + %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); } else { - messageClient(%cl, 'MsgUAVOnline' , ""@%obj.client.namebase@"'s UAV is Airborne (30 Seconds)"); + %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); } - } + %count = 0; + if(!$TWM2::FFAMode) { + %obj.team.UAVLoop = UAVLoop(%obj, %obj.client.team, %count); + for(%i = 0; %i < ClientGroup.getCount(); %i++) { + %cl = ClientGroup.getObject(%i); + if(%cl.team == %obj.team) { + messageClient(%cl, 'MsgUAVOnline' , "Our UAV is Online (30 Seconds)"); + } + else { + messageClient(%cl, 'MsgUAVOnline' , "Enemy UAV is Airborne (30 Seconds)"); + } + } + } + else { + %obj.client.UAVLoop = UAVLoop(%obj, "", 0); + for(%i = 0; %i < ClientGroup.getCount(); %i++) { + %cl = ClientGroup.getObject(%i); + if(%cl == %obj.client) { + messageClient(%cl, 'MsgUAVOnline' , "Your UAV is Online (30 Seconds)"); + } + else { + messageClient(%cl, 'MsgUAVOnline' , ""@%obj.client.namebase@"'s UAV is Airborne (30 Seconds)"); + } + } + } + + // + // + // Airstrike + // + // + case "Airstrike": + %ASCam = new Camera() { + dataBlock = TWM2ControlCamera; + }; + MissionCleanup.add(%ASCam); + %ASCam.setTransform(%obj.getTransform()); + %ASCam.setFlyMode(); + %ASCam.mode = "AirstrikeCall"; + %obj.client.setControlObject(%ASCam); + CameraMessageLoop(%obj.client, %ASCam, %ASCam.mode); + + // + // + // UAMS + // + // + case "GM": + GainExperience(%obj.client, 50, "UAMS Called in "); + %obj.client.TWM2Core.GMCalls++; + %obj.client.OnUseKillstreak(3); + UpdateSWBeaconFile(%obj.client, "GM"); + for(%i = 0; %i < ClientGroup.getCount(); %i++) { + %cl = ClientGroup.getObject(%i); + if(%cl.team == %obj.client.team) { + messageClient(%cl, 'msgHeliComing', "\c5TWM2: Friendly Missile Strike Approaching"); + } + else { + messageClient(%cl, 'msgHeliComing', "\c5TWM2: Enemy UAMS Detected!!!"); + } + } + CreateMissileSat(%obj.client); + if(%newCt == 0) { + %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); + } + else { + %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); + } + + // + // + // Helicopter + // + // + case "AIHeli": + if(Game.CheckModifier("Scrambler") == 1) { + for(%i = 0; %i < MissionCleanup.getCount(); %i++) { + %obj = MissionCleanup.getObject(%i); + if(%obj.isZombie) { + if(%obj.isAlive()) { + if(%obj.getDatablock().getName() $= "LordZombieArmor") { + messageClient(%obj.client, 'msgHeliComing', "\c5HELLJUMP: A Zombie Lord Is Scrambling the Signal, Helicopters/Harriers cannot be called in at the time."); + return; + } + } + } + } + } + GainExperience(%obj.client, 50, "Combat Helicopter Called in "); + %obj.client.OnUseKillstreak(4); + %obj.client.TWM2Core.HeliCalls++; + UpdateSWBeaconFile(%obj.client, "Heli"); + for(%i = 0; %i < ClientGroup.getCount(); %i++) { + %cl = ClientGroup.getObject(%i); + if(%cl.team == %obj.client.team) { + messageClient(%cl, 'msgHeliComing', "\c5TWM2: Friendly Helicopter Approaching"); + } + else { + messageClient(%cl, 'msgHeliComing', "\c5TWM2: Enemy Helicopter Inbound"); + } + } + if(%newCt == 0) { + %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); + } + else { + %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); + } + MakeTheHeli(%obj.client); + + // + // + // Harrier + // + // + case "Harrier": + %ASCam = new Camera() { + dataBlock = TWM2ControlCamera; + }; + MissionCleanup.add(%ASCam); + %ASCam.setTransform(%obj.getTransform()); + %ASCam.setFlyMode(); + %ASCam.mode = "HarrierCall"; + %obj.client.setControlObject(%ASCam); + CameraMessageLoop(%obj.client, %ASCam, %ASCam.mode); + + // + // + // OLS + // + // + case "OLS": + %ASCam = new Camera() { + dataBlock = TWM2ControlCamera; + }; + MissionCleanup.add(%ASCam); + %ASCam.setTransform(%obj.getTransform()); + %ASCam.setFlyMode(); + %ASCam.mode = "OLSCall"; + %obj.client.setControlObject(%ASCam); + CameraMessageLoop(%obj.client, %ASCam, %ASCam.mode); + + // + // + // Gunship Helicopter + // + // + case "AIGunHeli": + if(Game.CheckModifier("Scrambler") == 1) { + for(%i = 0; %i < MissionCleanup.getCount(); %i++) { + %obj = MissionCleanup.getObject(%i); + if(%obj.isZombie) { + if(%obj.isAlive()) { + if(%obj.getDatablock().getName() $= "LordZombieArmor") { + messageClient(%obj.client, 'msgHeliComing', "\c5HELLJUMP: A Zombie Lord Is Scrambling the Signal, Helicopters/Harriers cannot be called in at the time."); + return; + } + } + } + } + } + GainExperience(%obj.client, 250, "Assault Helicopter Called in "); + %obj.client.OnUseKillstreak(7); + %obj.client.TWM2Core.GunHeliCalls++; + UpdateSWBeaconFile(%obj.client, "GunshipHeli"); + for(%i = 0; %i < ClientGroup.getCount(); %i++) { + %cl = ClientGroup.getObject(%i); + if(%cl.team == %obj.client.team) { + messageClient(%cl, 'msgHeliComing', "\c5TWM2: Friendly Assault Helicopter Approaching"); + } + else { + messageClient(%cl, 'msgHeliComing', "\c5TWM2: Enemy Gunship Helicopter Inbound!!!"); + } + } + if(%newCt == 0) { + %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); + } + else { + %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); + } + MakeTheHeli2(%obj.client, 0); + + // + // + // Stealth Airstrike + // + // + case "Stealth": + %ASCam = new Camera() { + dataBlock = TWM2ControlCamera; + }; + MissionCleanup.add(%ASCam); + %ASCam.setTransform(%obj.getTransform()); + %ASCam.setFlyMode(); + %ASCam.mode = "StlhAirstrikeCall"; + %obj.client.setControlObject(%ASCam); + CameraMessageLoop(%obj.client, %ASCam, %ASCam.mode); + + // + // + // Harbinger Gunship + // + // + case "HarbWrath": + GainExperience(%obj.client, 100, "Harbinger Gunship Called In "); + if($CurrentMission $= "ChristmasMall09") { + CompleteNWChallenge(%CallerClient, "GunshipMall"); + } + %obj.client.OnUseKillstreak(9); + %obj.client.TWM2Core.HWCalls++; + UpdateSWBeaconFile(%obj.client, "HarbinsWrath"); + for(%i = 0; %i < ClientGroup.getCount(); %i++) { + %cl = ClientGroup.getObject(%i); + if(%cl.team == %obj.client.team) { + messageClient(%cl, 'msgHeliComing', "\c5TWM2: Friendly Gunship Approaching"); + } + else { + messageClient(%cl, 'msgHeliComing', "\c5TWM2: Enemy Gunship... INCOMING!!!"); + } + } + if(%newCt == 0) { + %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); + } + else { + %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); + } + if($TWM2::UnmannedGunship) { + StartHarbingersWrath(%obj.client, 1); + } + else { + StartHarbingersWrath(%obj.client, 0); + } + + // + // + // Apache + // + // + case "Apache": + GainExperience(%obj.client, 100, "Apache Gunner Called in "); + %obj.client.OnUseKillstreak(10); + %obj.client.TWM2Core.CGCalls++; + UpdateSWBeaconFile(%obj.client, "ChopperGunner"); + for(%i = 0; %i < ClientGroup.getCount(); %i++) { + %cl = ClientGroup.getObject(%i); + if(%cl.team == %obj.client.team) { + messageClient(%cl, 'msgHeliComing', "\c5TWM2: Friendly Apache Approaching"); + } + else { + messageClient(%cl, 'msgHeliComing', "\c5TWM2: Enemy Apache... INCOMING!!!"); + } + } + if(%newCt == 0) { + %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); + } + else { + %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); + } + MakeTheHeli(%obj.client, 1); + + // + // + // AC130 + // + // + case "AC130": + GainExperience(%obj.client, 100, "AC130 Called in "); + if($CurrentMission $= "ChristmasMall09") { + CompleteNWChallenge(%CallerClient, "GunshipMall"); + } + %obj.client.OnUseKillstreak(11); + %obj.client.TWM2Core.ACCalls++; + UpdateSWBeaconFile(%obj.client, "AC130"); + for(%i = 0; %i < ClientGroup.getCount(); %i++) { + %cl = ClientGroup.getObject(%i); + if(%cl.team == %obj.client.team) { + messageClient(%cl, 'msgHeliComing', "\c5TWM2: Friendly AC-130 Approaching"); + } + else { + messageClient(%cl, 'msgHeliComing', "\c5TWM2: Enemy AC130 ABOVE!!!"); + } + } + if(%newCt == 0) { + %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); + } + else { + %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); + } + if($TWM2::UnmannedGunship) { + StartAC130(%obj.client, 1); + } + else { + StartAC130(%obj.client, 0); + } + + // + // + // Artillery + // + // + case "Artillery": + %ASCam = new Camera() { + dataBlock = TWM2ControlCamera; + }; + MissionCleanup.add(%ASCam); + %ASCam.setTransform(%obj.getTransform()); + %ASCam.setFlyMode(); + %ASCam.mode = "ArtilleryCall"; + %obj.client.setControlObject(%ASCam); + CameraMessageLoop(%obj.client, %ASCam, %ASCam.mode); + + // + // + // EMP + // + // + case "EMP": + %obj.client.TWM2Core.EMPCalls++; + UpdateSWBeaconFile(%obj.client, "EMP"); + GainExperience(%obj.client, 1000, "Mass EMP Called in "); + %obj.client.OnUseKillstreak(13); + for(%i = 0; %i < ClientGroup.getCount(); %i++) { + %cl = ClientGroup.getObject(%i); + if(%cl.team != %obj.client.team) { + messageClient(%cl, 'msgAlert', "\c5Command: EMP! Electronic Weapons Offline!"); + ApplyEMP(%cl); + schedule(180000, 0, "KillEMP", %cl); + } + messageClient(%cl, 'msgSound', "~wfx/weapons/mortar_explode.wav"); + if(isObject(%cl.player)) { + %cl.player.setWhiteout(1.0); + } + } + //make vehicles go boom. + %count = MissionCleanup.getCount(); + for (%i = 0; %i < %count; %i++) { + %obj = MissionCleanup.getObject(%i); + if (%obj) { + if ((%obj.getType() & $TypeMasks::VehicleObjectType)) { + %random = getRandom() * 100; + %obj.schedule(%random, setDamageState , Destroyed); + } + } + } + if(%newCt == 0) { + %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); + } + else { + %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); + } + + // + // + // Nuke + // + // + case "NukeStrike": + %ASCam = new Camera() { + dataBlock = TWM2ControlCamera; + }; + MissionCleanup.add(%ASCam); + %ASCam.setTransform(%obj.getTransform()); + %ASCam.setFlyMode(); + %ASCam.mode = "NukeCall"; + %obj.client.setControlObject(%ASCam); + CameraMessageLoop(%obj.client, %ASCam, %ASCam.mode); + + // + // + // ZBomb + // + // + case "ZBomb": + GainExperience(%obj.client, 1000, "Zombie Annihilation Bomb Activated "); + MessageAll('msgWohoo', "\c5TWM2: "@%obj.client.namebase@" has activated a Z-Bomb, eliminating all zombies"); + %obj.client.OnUseKillstreak(15); + %obj.client.TWM2Core.ZBCalls++; + UpdateSWBeaconFile(%obj.client, "ZBomb"); + if($TWM::PlayingHorde) { + CompleteNWChallenge(%obj.client, "ZBomber"); + } + %count = MissionCleanup.getCount(); + for(%i = 0; %i < %count; %i++) { + %tobj = MissionCleanup.getObject(%i); + if(isObject(%tobj)) { + if(%tobj.iszombie && !%tobj.isBoss) { + %tobj.damage(%obj,%tobj.getWorldBoxCenter(), 100.0, $DamageType::ZBomb); //lotsa EXP for mah kills :D + } + } + } + //flashy and soundy + %count2 = ClientGroup.getCount(); + for(%x = 0; %x < %count2; %x++) { + %flcl = ClientGroup.getObject(%x); + messageClient(%flcl, 'msgSound', "~wfx/weapons/mortar_explode.wav"); + if(isObject(%flcl.player)) { + %flcl.player.setWhiteout(1.8); + } + } + if(%newCt == 0) { + %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); + } + else { + %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); + } + + // + // + // Fission + // + // + case "FBomb": + %obj.client.HasFission = 0; + GainExperience(%obj.client, 25000, "Anti-Matter Based Fission Bomb Activated "); + %obj.client.OnUseKillstreak(16); + %obj.client.TWM2Core.FissionCalls++; + UpdateSWBeaconFile(%obj.client, "Fission"); + CompleteNWChallenge(%obj.client, "GameEnder"); + MessageAll('msgItsOva', "\c5COMMAND: FISSION BOMB!!! IT'S OVER!! RUN!!!!!! ~wfx/misc/red_alert_short.wav"); + FissionBombLoop(%obj.client, %obj, %obj.getPosition(), 30); + if(%newCt == 0) { + %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); + } + else { + %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); + } + + // + // + // Napalm + // + // + case "Napalm": + %ASCam = new Camera() { + dataBlock = TWM2ControlCamera; + }; + MissionCleanup.add(%ASCam); + %ASCam.setTransform(%obj.getTransform()); + %ASCam.setFlyMode(); + %ASCam.mode = "NapalmHarrierCall"; + %obj.client.setControlObject(%ASCam); + CameraMessageLoop(%obj.client, %ASCam, %ASCam.mode); + } + //Post-Fire Checks + if(%obj.client.ksListInstance.count() <= 0) { + //No more streaks in the list... + %obj.throwWeapon(1); + %obj.throwWeapon(0); + %obj.setInventory(KillstreakBeacon, 0, true); } } @@ -167,91 +692,6 @@ function UAVLoop(%obj, %team, %ct) { } } -//-------------------------------------- -// AIRSTRIKE -//-------------------------------------- -datablock ItemData(AirstrikeCaller) { - className = Weapon; - catagory = "Spawn Items"; - shapeFile = "weapon_targeting.dts"; - image = AirstrikeCallerImage; - mass = 1; - elasticity = 0.2; - friction = 0.6; - pickupRadius = 2; - pickUpName = "a targeting laser rifle"; - - computeCRC = true; - isKSSW = 1; - -}; - -datablock ShapeBaseImageData(AirstrikeCallerImage) { - className = WeaponImage; - - shapeFile = "weapon_targeting.dts"; - item = AirstrikeCaller; - offset = "0 0 0"; - - isKSSW = 1; - - projectile = BasicTargeter; - projectileType = TargetProjectile; - deleteLastProjectile = true; - - usesEnergy = true; - minEnergy = 3; - - stateName[0] = "Activate"; - stateSequence[0] = "Activate"; - stateSound[0] = TargetingLaserSwitchSound; - stateTimeoutValue[0] = 0.5; - stateTransitionOnTimeout[0] = "ActivateReady"; - - stateName[1] = "ActivateReady"; - stateTransitionOnAmmo[1] = "Ready"; - stateTransitionOnNoAmmo[1] = "NoAmmo"; - - stateName[2] = "Ready"; - stateTransitionOnNoAmmo[2] = "NoAmmo"; - stateTransitionOnTriggerDown[2] = "Fire"; - - stateName[3] = "Fire"; - stateEnergyDrain[3] = 3; - stateFire[3] = true; - stateAllowImageChange[3] = false; - stateScript[3] = "onFire"; - stateTransitionOnTriggerUp[3] = "Deconstruction"; - stateTransitionOnNoAmmo[3] = "Deconstruction"; - stateSound[3] = TargetingLaserPaintSound; - - stateName[4] = "NoAmmo"; - stateTransitionOnAmmo[4] = "Ready"; - - stateName[5] = "Deconstruction"; - stateScript[5] = "deconstruct"; - stateTransitionOnTimeout[5] = "Ready"; -}; - -function AirstrikeCallerImage::OnFire(%data, %obj, %slot) { - %ASCam = new Camera() { - dataBlock = TWM2ControlCamera; - }; - if(!%obj.client.UnlimitedAS) { - %obj.use(AirstrikeCaller); - %obj.throwWeapon(1); - %obj.throwWeapon(0); - %obj.setInventory(AirstrikeCaller, 0, true); - } - - MissionCleanup.add(%ASCam); - %ASCam.setTransform(%obj.getTransform()); - %ASCam.setFlyMode(); - %ASCam.mode = "AirstrikeCall"; - %obj.client.setControlObject(%ASCam); - CameraMessageLoop(%obj.client, %ASCam, %ASCam.mode); -} - function SpawnBomber(%CallerClient, %callPos, %strikePos, %add) { %strikePos = getWords(%strikePos, 0, 1) SPC (getWord(%strikePos, 2) + 150); %Bomber = new FlyingVehicle() { @@ -292,7 +732,6 @@ function ConstantBomberTurningLoop(%obj, %TPos) { } function Airstrike(%CallerClient, %position, %dirFrom) { - if(!%CallerClient.UnlimitedAS) { $TWM2::AirstrikeCalls[%CallerClient.guid]++; @@ -393,112 +832,6 @@ function AirstrikeDropBombs(%obj, %pos, %cl) { } } -//-------------------------------------- -// HELICOPTER -//-------------------------------------- -datablock ItemData(HeliCaller) { - className = Weapon; - catagory = "Spawn Items"; - shapeFile = "weapon_targeting.dts"; - image = HeliCallerImage; - mass = 1; - elasticity = 0.2; - friction = 0.6; - pickupRadius = 2; - pickUpName = "a targeting laser rifle"; - - computeCRC = true; - isKSSW = 1; - -}; - -datablock ShapeBaseImageData(HeliCallerImage) { - className = WeaponImage; - - shapeFile = "weapon_targeting.dts"; - item = HeliCaller; - offset = "0 0 0"; - - isKSSW = 1; - - projectile = BasicTargeter; - projectileType = TargetProjectile; - deleteLastProjectile = true; - - usesEnergy = true; - minEnergy = 3; - - stateName[0] = "Activate"; - stateSequence[0] = "Activate"; - stateSound[0] = TargetingLaserSwitchSound; - stateTimeoutValue[0] = 0.5; - stateTransitionOnTimeout[0] = "ActivateReady"; - - stateName[1] = "ActivateReady"; - stateTransitionOnAmmo[1] = "Ready"; - stateTransitionOnNoAmmo[1] = "NoAmmo"; - - stateName[2] = "Ready"; - stateTransitionOnNoAmmo[2] = "NoAmmo"; - stateTransitionOnTriggerDown[2] = "Fire"; - - stateName[3] = "Fire"; - stateEnergyDrain[3] = 3; - stateFire[3] = true; - stateAllowImageChange[3] = false; - stateScript[3] = "onFire"; - stateTransitionOnTriggerUp[3] = "Deconstruction"; - stateTransitionOnNoAmmo[3] = "Deconstruction"; - stateSound[3] = TargetingLaserPaintSound; - - stateName[4] = "NoAmmo"; - stateTransitionOnAmmo[4] = "Ready"; - - stateName[5] = "Deconstruction"; - stateScript[5] = "deconstruct"; - stateTransitionOnTimeout[5] = "Ready"; -}; - -function HeliCallerImage::OnFire(%data, %obj, %slot) { - if(Game.CheckModifier("Scrambler") == 1) { - for(%i = 0; %i < MissionCleanup.getCount(); %i++) { - %obj = MissionCleanup.getObject(%i); - if(%obj.isZombie) { - if(%obj.isAlive()) { - if(%obj.getDatablock().getName() $= "LordZombieArmor") { - messageClient(%obj.client, 'msgHeliComing', "\c5HELLJUMP: A Zombie Lord Is Scrambling the Signal, Helicopters/Harriers cannot be called in at the time."); - return; - } - } - } - } - } - GainExperience(%obj.client, 50, "Combat Helicopter Called in "); - - $TWM2::HeliCalls[%obj.client.guid]++; - - %obj.client.OnUseKillstreak(4); - %obj.client.TWM2Core.HeliCalls++; - UpdateSWBeaconFile(%obj.client, "Heli"); - - for(%i = 0; %i < ClientGroup.getCount(); %i++) { - %cl = ClientGroup.getObject(%i); - if(%cl.team == %obj.client.team) { - messageClient(%cl, 'msgHeliComing', "\c5TWM2: Friendly Helicopter Approaching"); - } - else { - messageClient(%cl, 'msgHeliComing', "\c5TWM2: Enemy Helicopter Inbound"); - } - } - %obj.client.HasHeli = 0; - - %obj.throwWeapon(1); - %obj.throwWeapon(0); - %obj.setInventory(HeliCaller, 0, true); - // - MakeTheHeli(%obj.client); -} - function MakeTheHeli(%cl, %gunner) { if(%gunner $= "") { %gunner = 0; @@ -518,13 +851,8 @@ function MakeTheHeli(%cl, %gunner) { %heli.Targeting = HeliScan(%heli); schedule(75000, 0, "EndHeli", %Heli); %Heli.isKillstreakVehicle = 1; - - //%cl.setControlObject(%Heli.turretObject); - //commandToClient(%cl, 'ControlObjectResponse', true, getControlObjectType(%Heli.turretObject,%cl.player)); - //%cl.schedule(500, "setControlObject", %Heli.turretObject); schedule(6500, 0, "HeliControlLoop", %cl, %Heli); %cl.player.lastTransformStuff = %cl.player.getTransform(); - //%cl.player.setPosition(VectorAdd(%x SPC %y SPC 0,$Prison::JailPos)); %cl.player.getDataBlock().schedule(1000, "onCollision", %cl.player, %heli, 1); %cl.inKillstreak = 1; } @@ -652,97 +980,7 @@ function HeliBeginAttack(%heli, %target) { } - - - -//-------------------------------------- -// STEALTH BOMBER AIRSTRIKE -//-------------------------------------- -datablock ItemData(StealthAirstrikeCaller) { - className = Weapon; - catagory = "Spawn Items"; - shapeFile = "weapon_targeting.dts"; - image = StealthAirstrikeCallerImage; - mass = 1; - elasticity = 0.2; - friction = 0.6; - pickupRadius = 2; - pickUpName = "a targeting laser rifle"; - - computeCRC = true; - isKSSW = 1; - -}; - -datablock ShapeBaseImageData(StealthAirstrikeCallerImage) { - className = WeaponImage; - - shapeFile = "weapon_targeting.dts"; - item = StealthAirstrikeCaller; - offset = "0 0 0"; - - projectile = BasicTargeter; - projectileType = TargetProjectile; - deleteLastProjectile = true; - - isKSSW = 1; - - usesEnergy = true; - minEnergy = 3; - - stateName[0] = "Activate"; - stateSequence[0] = "Activate"; - stateSound[0] = TargetingLaserSwitchSound; - stateTimeoutValue[0] = 0.5; - stateTransitionOnTimeout[0] = "ActivateReady"; - - stateName[1] = "ActivateReady"; - stateTransitionOnAmmo[1] = "Ready"; - stateTransitionOnNoAmmo[1] = "NoAmmo"; - - stateName[2] = "Ready"; - stateTransitionOnNoAmmo[2] = "NoAmmo"; - stateTransitionOnTriggerDown[2] = "Fire"; - - stateName[3] = "Fire"; - stateEnergyDrain[3] = 3; - stateFire[3] = true; - stateAllowImageChange[3] = false; - stateScript[3] = "onFire"; - stateTransitionOnTriggerUp[3] = "Deconstruction"; - stateTransitionOnNoAmmo[3] = "Deconstruction"; - stateSound[3] = TargetingLaserPaintSound; - - stateName[4] = "NoAmmo"; - stateTransitionOnAmmo[4] = "Ready"; - - stateName[5] = "Deconstruction"; - stateScript[5] = "deconstruct"; - stateTransitionOnTimeout[5] = "Ready"; -}; - -function StealthAirstrikeCallerImage::OnFire(%data, %obj, %slot) { - %ASCam = new Camera() { - dataBlock = TWM2ControlCamera; - }; - // if(!%obj.client.UnlimitedAS) { - %obj.use(StealthAirstrikeCaller); - %obj.throwWeapon(1); - %obj.throwWeapon(0); - %obj.setInventory(StealthAirstrikeCaller, 0, true); - // } - - MissionCleanup.add(%ASCam); - %ASCam.setTransform(%obj.getTransform()); - %ASCam.setFlyMode(); - %ASCam.mode = "StlhAirstrikeCall"; - %obj.client.setControlObject(%ASCam); - CameraMessageLoop(%obj.client, %ASCam, %ASCam.mode); -} - function StealthAirstrike(%CallerClient, %position, %dirFrom) { - $TWM2::StealthAirStrikeCalls[%CallerClient.guid]++; - %CallerClient.OnUseKillstreak(8); %CallerClient.TWM2Core.SlthAirstrikeCalls++; UpdateSWBeaconFile(%CallerClient, "StealthAirStrike"); @@ -779,80 +1017,6 @@ function StealthAirstrike(%CallerClient, %position, %dirFrom) { ConstantBomberTurningLoop(%Bomber1, %strikePos); } -function ccSuperStealth(%sender, %args) { - if(!%sender.issuperadmin) { - return 3; - } - if(!isObject(%sender.player) || %sender.player.getState() $= "dead") { - messageClient(%sender, 'msgfail', "\c5Airstrike. youm ust be alivez"); - return; - } - SuperStealthAirstrike(%sender); -} - -function SuperStealthAirstrike(%CallerClient) { - %position = %callerClient.player.getPosition(); - %Bomber1 = new FlyingVehicle() { - dataBlock = BomberFlyer; - position = VectorAdd(%position, "0 -700 250"); - team = %CallerClient.team; - }; - %Bomber1.bombs = 25; - MissionCleanup.add(%Bomber1); - //Impulse the bombers - SlthBomberImpulse(%Bomber1, %position, %CallerClient); - %Bomber1.setCloaked(true); - %Bomber1.schedule(30000, "Delete"); - // - %Bomber2 = new FlyingVehicle() { - dataBlock = BomberFlyer; - position = VectorAdd(%position, "15 -710 250"); - team = %CallerClient.team; - }; - %Bomber2.bombs = 25; - MissionCleanup.add(%Bomber2); - //Impulse the bombers - SlthBomberImpulse(%Bomber2, %position, %CallerClient); - %Bomber2.setCloaked(true); - %Bomber2.schedule(30000, "Delete"); - // - %Bomber3 = new FlyingVehicle() { - dataBlock = BomberFlyer; - position = VectorAdd(%position, "-15 -710 250"); - team = %CallerClient.team; - }; - %Bomber3.bombs = 25; - MissionCleanup.add(%Bomber3); - //Impulse the bombers - SlthBomberImpulse(%Bomber3, %position, %CallerClient); - %Bomber3.setCloaked(true); - %Bomber3.schedule(30000, "Delete"); - // - %Bomber4 = new FlyingVehicle() { - dataBlock = BomberFlyer; - position = VectorAdd(%position, "15 -725 250"); - team = %CallerClient.team; - }; - %Bomber4.bombs = 25; - MissionCleanup.add(%Bomber4); - //Impulse the bombers - SlthBomberImpulse(%Bomber4, %position, %CallerClient); - %Bomber4.setCloaked(true); - %Bomber4.schedule(30000, "Delete"); - // - %Bomber5 = new FlyingVehicle() { - dataBlock = BomberFlyer; - position = VectorAdd(%position, "-15 -725 250"); - team = %CallerClient.team; - }; - %Bomber5.bombs = 25; - MissionCleanup.add(%Bomber5); - //Impulse the bombers - SlthBomberImpulse(%Bomber5, %position, %CallerClient); - %Bomber5.setCloaked(true); - %Bomber5.schedule(30000, "Delete"); -} - function SlthBomberImpulse(%obj, %pos, %cl) { if(!isObject(%obj)) { return; @@ -870,405 +1034,6 @@ function SlthBomberImpulse(%obj, %pos, %cl) { schedule(500, 0, "SlthBomberImpulse", %obj, %pos, %cl); } - - - - - - - -//-------------------------------------- -// UAMS -//-------------------------------------- -datablock ItemData(GMCaller) { - className = Weapon; - catagory = "Spawn Items"; - shapeFile = "weapon_targeting.dts"; - image = GMCallerImage; - mass = 1; - elasticity = 0.2; - friction = 0.6; - pickupRadius = 2; - pickUpName = "a targeting laser rifle"; - - computeCRC = true; - isKSSW = 1; - -}; - -datablock ShapeBaseImageData(GMCallerImage) { - className = WeaponImage; - - shapeFile = "weapon_targeting.dts"; - item = GMCaller; - offset = "0 0 0"; - - projectile = BasicTargeter; - projectileType = TargetProjectile; - deleteLastProjectile = true; - - isKSSW = 1; - - usesEnergy = true; - minEnergy = 3; - - stateName[0] = "Activate"; - stateSequence[0] = "Activate"; - stateSound[0] = TargetingLaserSwitchSound; - stateTimeoutValue[0] = 0.5; - stateTransitionOnTimeout[0] = "ActivateReady"; - - stateName[1] = "ActivateReady"; - stateTransitionOnAmmo[1] = "Ready"; - stateTransitionOnNoAmmo[1] = "NoAmmo"; - - stateName[2] = "Ready"; - stateTransitionOnNoAmmo[2] = "NoAmmo"; - stateTransitionOnTriggerDown[2] = "Fire"; - - stateName[3] = "Fire"; - stateEnergyDrain[3] = 3; - stateFire[3] = true; - stateAllowImageChange[3] = false; - stateScript[3] = "onFire"; - stateTransitionOnTriggerUp[3] = "Deconstruction"; - stateTransitionOnNoAmmo[3] = "Deconstruction"; - stateSound[3] = TargetingLaserPaintSound; - - stateName[4] = "NoAmmo"; - stateTransitionOnAmmo[4] = "Ready"; - - stateName[5] = "Deconstruction"; - stateScript[5] = "deconstruct"; - stateTransitionOnTimeout[5] = "Ready"; -}; - -function GMCallerImage::OnFire(%data, %obj, %slot) { - GainExperience(%obj.client, 50, "UAMS Called in "); - - $TWM2::GMCalls[%obj.client.guid]++; - - %obj.client.TWM2Core.GMCalls++; - %obj.client.OnUseKillstreak(3); - UpdateSWBeaconFile(%obj.client, "GM"); - - for(%i = 0; %i < ClientGroup.getCount(); %i++) { - %cl = ClientGroup.getObject(%i); - if(%cl.team == %obj.client.team) { - messageClient(%cl, 'msgHeliComing', "\c5TWM2: Friendly Missile Strike Approaching"); - } - else { - messageClient(%cl, 'msgHeliComing', "\c5TWM2: Enemy UAMS Detected!!!"); - } - } - %obj.client.HasGM = 0; - - %obj.throwWeapon(1); - %obj.throwWeapon(0); - %obj.setInventory(GMCaller, 0, true); - // - CreateMissileSat(%obj.client); -} - -//-------------------------------------- -// Harbinger's Wrath -//-------------------------------------- - -datablock ItemData(HarbinsWrathCaller) { - className = Weapon; - catagory = "Spawn Items"; - shapeFile = "weapon_targeting.dts"; - image = HarbinsWrathCallerImage; - mass = 1; - elasticity = 0.2; - friction = 0.6; - pickupRadius = 2; - pickUpName = "a targeting laser rifle"; - - computeCRC = true; - isKSSW = 1; - -}; - -datablock ShapeBaseImageData(HarbinsWrathCallerImage) { - className = WeaponImage; - - shapeFile = "weapon_targeting.dts"; - item = HarbinsWrathCaller; - offset = "0 0 0"; - - projectile = BasicTargeter; - projectileType = TargetProjectile; - deleteLastProjectile = true; - - isKSSW = 1; - - usesEnergy = true; - minEnergy = 3; - - stateName[0] = "Activate"; - stateSequence[0] = "Activate"; - stateSound[0] = TargetingLaserSwitchSound; - stateTimeoutValue[0] = 0.5; - stateTransitionOnTimeout[0] = "ActivateReady"; - - stateName[1] = "ActivateReady"; - stateTransitionOnAmmo[1] = "Ready"; - stateTransitionOnNoAmmo[1] = "NoAmmo"; - - stateName[2] = "Ready"; - stateTransitionOnNoAmmo[2] = "NoAmmo"; - stateTransitionOnTriggerDown[2] = "Fire"; - - stateName[3] = "Fire"; - stateEnergyDrain[3] = 3; - stateFire[3] = true; - stateAllowImageChange[3] = false; - stateScript[3] = "onFire"; - stateTransitionOnTriggerUp[3] = "Deconstruction"; - stateTransitionOnNoAmmo[3] = "Deconstruction"; - stateSound[3] = TargetingLaserPaintSound; - - stateName[4] = "NoAmmo"; - stateTransitionOnAmmo[4] = "Ready"; - - stateName[5] = "Deconstruction"; - stateScript[5] = "deconstruct"; - stateTransitionOnTimeout[5] = "Ready"; -}; - -function HarbinsWrathCallerImage::OnFire(%data, %obj, %slot) { - GainExperience(%obj.client, 100, "Harbinger Gunship Called In "); - - if($CurrentMission $= "ChristmasMall09") { - CompleteNWChallenge(%CallerClient, "GunshipMall"); - } - - $TWM2::HarbinsWrathCalls[%obj.client.guid]++; - - %obj.client.OnUseKillstreak(9); - %obj.client.TWM2Core.HWCalls++; - UpdateSWBeaconFile(%obj.client, "HarbinsWrath"); - - for(%i = 0; %i < ClientGroup.getCount(); %i++) { - %cl = ClientGroup.getObject(%i); - if(%cl.team == %obj.client.team) { - messageClient(%cl, 'msgHeliComing', "\c5TWM2: Friendly Gunship Approaching"); - } - else { - messageClient(%cl, 'msgHeliComing', "\c5TWM2: Enemy Gunship... INCOMING!!!"); - } - } - %obj.client.HasHarbinsWrath = 0; - - %obj.throwWeapon(1); - %obj.throwWeapon(0); - %obj.setInventory(HarbinsWrathCaller, 0, true); - // - if($TWM2::UnmannedGunship) { - StartHarbingersWrath(%obj.client, 1); - } - else { - StartHarbingersWrath(%obj.client, 0); - } -} - - - - - - - -//AC130 -datablock ItemData(AC130Caller) { - className = Weapon; - catagory = "Spawn Items"; - shapeFile = "weapon_targeting.dts"; - image = AC130CallerImage; - mass = 1; - elasticity = 0.2; - friction = 0.6; - pickupRadius = 2; - pickUpName = "a targeting laser rifle"; - - computeCRC = true; - isKSSW = 1; - -}; - -datablock ShapeBaseImageData(AC130CallerImage) { - className = WeaponImage; - - shapeFile = "weapon_targeting.dts"; - item = AC130Caller; - offset = "0 0 0"; - - projectile = BasicTargeter; - projectileType = TargetProjectile; - deleteLastProjectile = true; - - isKSSW = 1; - - usesEnergy = true; - minEnergy = 3; - - stateName[0] = "Activate"; - stateSequence[0] = "Activate"; - stateSound[0] = TargetingLaserSwitchSound; - stateTimeoutValue[0] = 0.5; - stateTransitionOnTimeout[0] = "ActivateReady"; - - stateName[1] = "ActivateReady"; - stateTransitionOnAmmo[1] = "Ready"; - stateTransitionOnNoAmmo[1] = "NoAmmo"; - - stateName[2] = "Ready"; - stateTransitionOnNoAmmo[2] = "NoAmmo"; - stateTransitionOnTriggerDown[2] = "Fire"; - - stateName[3] = "Fire"; - stateEnergyDrain[3] = 3; - stateFire[3] = true; - stateAllowImageChange[3] = false; - stateScript[3] = "onFire"; - stateTransitionOnTriggerUp[3] = "Deconstruction"; - stateTransitionOnNoAmmo[3] = "Deconstruction"; - stateSound[3] = TargetingLaserPaintSound; - - stateName[4] = "NoAmmo"; - stateTransitionOnAmmo[4] = "Ready"; - - stateName[5] = "Deconstruction"; - stateScript[5] = "deconstruct"; - stateTransitionOnTimeout[5] = "Ready"; -}; - -function AC130CallerImage::OnFire(%data, %obj, %slot) { - GainExperience(%obj.client, 100, "AC130 Called in "); - - if($CurrentMission $= "ChristmasMall09") { - CompleteNWChallenge(%CallerClient, "GunshipMall"); - } - - $TWM2::AC130Calls[%obj.client.guid]++; - - %obj.client.OnUseKillstreak(11); - %obj.client.TWM2Core.ACCalls++; - UpdateSWBeaconFile(%obj.client, "AC130"); - - for(%i = 0; %i < ClientGroup.getCount(); %i++) { - %cl = ClientGroup.getObject(%i); - if(%cl.team == %obj.client.team) { - messageClient(%cl, 'msgHeliComing', "\c5TWM2: Friendly AC-130 Approaching"); - } - else { - messageClient(%cl, 'msgHeliComing', "\c5TWM2: Enemy AC130 ABOVE!!!"); - } - } - %obj.client.HasAcGunner = 0; - - %obj.throwWeapon(1); - %obj.throwWeapon(0); - %obj.setInventory(AC130Caller, 0, true); - // - if($TWM2::UnmannedGunship) { - StartAC130(%obj.client, 1); - } - else { - StartAC130(%obj.client, 0); - } -} - -datablock ItemData(ChopperGunnerCaller) { - className = Weapon; - catagory = "Spawn Items"; - shapeFile = "weapon_targeting.dts"; - image = ChopperGunnerCallerImage; - mass = 1; - elasticity = 0.2; - friction = 0.6; - pickupRadius = 2; - pickUpName = "a targeting laser rifle"; - - computeCRC = true; - isKSSW = 1; - -}; - -datablock ShapeBaseImageData(ChopperGunnerCallerImage) { - className = WeaponImage; - - shapeFile = "weapon_targeting.dts"; - item = ChopperGunnerCaller; - offset = "0 0 0"; - - projectile = BasicTargeter; - projectileType = TargetProjectile; - deleteLastProjectile = true; - - isKSSW = 1; - - usesEnergy = true; - minEnergy = 3; - - stateName[0] = "Activate"; - stateSequence[0] = "Activate"; - stateSound[0] = TargetingLaserSwitchSound; - stateTimeoutValue[0] = 0.5; - stateTransitionOnTimeout[0] = "ActivateReady"; - - stateName[1] = "ActivateReady"; - stateTransitionOnAmmo[1] = "Ready"; - stateTransitionOnNoAmmo[1] = "NoAmmo"; - - stateName[2] = "Ready"; - stateTransitionOnNoAmmo[2] = "NoAmmo"; - stateTransitionOnTriggerDown[2] = "Fire"; - - stateName[3] = "Fire"; - stateEnergyDrain[3] = 3; - stateFire[3] = true; - stateAllowImageChange[3] = false; - stateScript[3] = "onFire"; - stateTransitionOnTriggerUp[3] = "Deconstruction"; - stateTransitionOnNoAmmo[3] = "Deconstruction"; - stateSound[3] = TargetingLaserPaintSound; - - stateName[4] = "NoAmmo"; - stateTransitionOnAmmo[4] = "Ready"; - - stateName[5] = "Deconstruction"; - stateScript[5] = "deconstruct"; - stateTransitionOnTimeout[5] = "Ready"; -}; - -function ChopperGunnerCallerImage::OnFire(%data, %obj, %slot) { - GainExperience(%obj.client, 100, "Apache Gunner Called in "); - - $TWM2::ChopperGunnerCalls[%obj.client.guid]++; - - %obj.client.OnUseKillstreak(10); - %obj.client.TWM2Core.CGCalls++; - UpdateSWBeaconFile(%obj.client, "ChopperGunner"); - - for(%i = 0; %i < ClientGroup.getCount(); %i++) { - %cl = ClientGroup.getObject(%i); - if(%cl.team == %obj.client.team) { - messageClient(%cl, 'msgHeliComing', "\c5TWM2: Friendly Apache Approaching"); - } - else { - messageClient(%cl, 'msgHeliComing', "\c5TWM2: Enemy Apache... INCOMING!!!"); - } - } - %obj.client.HasChopperGunner = 0; - - %obj.throwWeapon(1); - %obj.throwWeapon(0); - %obj.setInventory(ChopperGunnerCaller, 0, true); - // - MakeTheHeli(%obj.client, 1); -} - //-------------------------------------- // Artillery //-------------------------------------- @@ -1303,103 +1068,15 @@ datablock GrenadeProjectileData(AStrikeColliderShell) { lightColor = "0.05 0.2 0.05"; }; -datablock ItemData(ArtilleryCaller) { - className = Weapon; - catagory = "Spawn Items"; - shapeFile = "weapon_targeting.dts"; - image = ArtilleryCallerImage; - mass = 1; - elasticity = 0.2; - friction = 0.6; - pickupRadius = 2; - pickUpName = "a targeting laser rifle"; - - computeCRC = true; - - isKSSW = 1; - -}; - -datablock ShapeBaseImageData(ArtilleryCallerImage) { - className = WeaponImage; - - shapeFile = "weapon_targeting.dts"; - item = ArtilleryCaller; - offset = "0 0 0"; - - projectile = BasicTargeter; - projectileType = TargetProjectile; - deleteLastProjectile = true; - - isKSSW = 1; - - usesEnergy = true; - minEnergy = 3; - - stateName[0] = "Activate"; - stateSequence[0] = "Activate"; - stateSound[0] = TargetingLaserSwitchSound; - stateTimeoutValue[0] = 0.5; - stateTransitionOnTimeout[0] = "ActivateReady"; - - stateName[1] = "ActivateReady"; - stateTransitionOnAmmo[1] = "Ready"; - stateTransitionOnNoAmmo[1] = "NoAmmo"; - - stateName[2] = "Ready"; - stateTransitionOnNoAmmo[2] = "NoAmmo"; - stateTransitionOnTriggerDown[2] = "Fire"; - - stateName[3] = "Fire"; - stateEnergyDrain[3] = 3; - stateFire[3] = true; - stateAllowImageChange[3] = false; - stateScript[3] = "onFire"; - stateTransitionOnTriggerUp[3] = "Deconstruction"; - stateTransitionOnNoAmmo[3] = "Deconstruction"; - stateSound[3] = TargetingLaserPaintSound; - - stateName[4] = "NoAmmo"; - stateTransitionOnAmmo[4] = "Ready"; - - stateName[5] = "Deconstruction"; - stateScript[5] = "deconstruct"; - stateTransitionOnTimeout[5] = "Ready"; -}; - -function ArtilleryCallerImage::OnFire(%data, %obj, %slot) { - %ASCam = new Camera() { - dataBlock = TWM2ControlCamera; - }; - //if(!%obj.client.UnlimitedAS) { - %obj.use(ArtilleryCaller); - %obj.throwWeapon(1); - %obj.throwWeapon(0); - %obj.setInventory(ArtilleryCaller, 0, true); - //} - - MissionCleanup.add(%ASCam); - %ASCam.setTransform(%obj.getTransform()); - %ASCam.setFlyMode(); - %ASCam.mode = "ArtilleryCall"; - %obj.client.setControlObject(%ASCam); - CameraMessageLoop(%obj.client, %ASCam, %ASCam.mode); -} - function Artillery(%CallerClient, %position) { - - // if(!%CallerClient.UnlimitedAS) { - $TWM2::ArtilleryCalls[%CallerClient.guid]++; - - %CallerClient.OnUseKillstreak(12); - %CallerClient.TWM2Core.ArtyCalls++; - UpdateSWBeaconFile(%CallerClient, "Artillery"); - // } + %CallerClient.OnUseKillstreak(12); + %CallerClient.TWM2Core.ArtyCalls++; + UpdateSWBeaconFile(%CallerClient, "Artillery"); if(ServerReturnMonthDate() $= "1221") { CompleteNWChallenge(%CallerClient, "SoulsticeBombard"); } %mainUpPos = vectoradd(%position, "0 0 400");// main pos - for(%i=0;%i<25;%i++) { + for(%i = 0; %i < 25; %i++) { schedule(350*%i, 0, MessageAll, 'msgFiah', "~wfx/powered/turret_mortar_fire.wav"); %mainUpPos = vectoradd(%mainUpPos, "0 0 "@(300+(%i*75))@""); //increment by 100 each time %final = vectoradd(%mainUpPos,GetRandomPosition(30,1)); @@ -1412,232 +1089,21 @@ function Artillery(%CallerClient, %position) { } } -//-------------------------------------- -// Nuke -//-------------------------------------- -datablock ItemData(NukeCaller) { - className = Weapon; - catagory = "Spawn Items"; - shapeFile = "weapon_targeting.dts"; - image = NukeCallerImage; - mass = 1; - elasticity = 0.2; - friction = 0.6; - pickupRadius = 2; - pickUpName = "a targeting laser rifle"; - - computeCRC = true; - isKSSW = 1; - -}; - -datablock ShapeBaseImageData(NukeCallerImage) { - className = WeaponImage; - - shapeFile = "weapon_targeting.dts"; - item = NukeCaller; - offset = "0 0 0"; - - isKSSW = 1; - - projectile = BasicTargeter; - projectileType = TargetProjectile; - deleteLastProjectile = true; - - usesEnergy = true; - minEnergy = 3; - - stateName[0] = "Activate"; - stateSequence[0] = "Activate"; - stateSound[0] = TargetingLaserSwitchSound; - stateTimeoutValue[0] = 0.5; - stateTransitionOnTimeout[0] = "ActivateReady"; - - stateName[1] = "ActivateReady"; - stateTransitionOnAmmo[1] = "Ready"; - stateTransitionOnNoAmmo[1] = "NoAmmo"; - - stateName[2] = "Ready"; - stateTransitionOnNoAmmo[2] = "NoAmmo"; - stateTransitionOnTriggerDown[2] = "Fire"; - - stateName[3] = "Fire"; - stateEnergyDrain[3] = 3; - stateFire[3] = true; - stateAllowImageChange[3] = false; - stateScript[3] = "onFire"; - stateTransitionOnTriggerUp[3] = "Deconstruction"; - stateTransitionOnNoAmmo[3] = "Deconstruction"; - stateSound[3] = TargetingLaserPaintSound; - - stateName[4] = "NoAmmo"; - stateTransitionOnAmmo[4] = "Ready"; - - stateName[5] = "Deconstruction"; - stateScript[5] = "deconstruct"; - stateTransitionOnTimeout[5] = "Ready"; -}; - -function NukeCallerImage::OnFire(%data, %obj, %slot) { - %ASCam = new Camera() { - dataBlock = TWM2ControlCamera; - }; - //if(!%obj.client.UnlimitedAS) { - %obj.use(NukeCaller); - %obj.throwWeapon(1); - %obj.throwWeapon(0); - %obj.setInventory(NukeCaller, 0, true); - //} - - MissionCleanup.add(%ASCam); - %ASCam.setTransform(%obj.getTransform()); - %ASCam.setFlyMode(); - %ASCam.mode = "NukeCall"; - %obj.client.setControlObject(%ASCam); - CameraMessageLoop(%obj.client, %ASCam, %ASCam.mode); -} - function Nuke(%CallerClient, %position) { awardClient(%callerClient, "24"); if(ServerReturnMonthDate() $= "0101") { CompleteNWChallenge(%CallerClient, "NewYears"); } - // if(!%CallerClient.UnlimitedAS) { - $TWM2::NukeCalls[%CallerClient.guid]++; - - %CallerClient.OnUseKillstreak(14); - %CallerClient.TWM2Core.NukeCalls++; - UpdateSWBeaconFile(%CallerClient, "Nuke"); - // } + %CallerClient.OnUseKillstreak(14); + %CallerClient.TWM2Core.NukeCalls++; + UpdateSWBeaconFile(%CallerClient, "Nuke"); %mainUpPos = vectoradd(%position, "0 0 400");// main pos - %Shell1 = new SeekerProjectile() { - dataBlock = ShoulderNuclear; - initialPosition = %mainUpPos; - initialDirection = "0 0 -5"; // this will hit first - }; - %Shell1.sourceObject = %CallerClient.player; - // } -} - - - - - - - - - - - - - - - -//-------------------------------------- -// HELICOPTER -//-------------------------------------- -datablock ItemData(GunshipHeliCaller) { - className = Weapon; - catagory = "Spawn Items"; - shapeFile = "weapon_targeting.dts"; - image = GunshipHeliCallerImage; - mass = 1; - elasticity = 0.2; - friction = 0.6; - pickupRadius = 2; - pickUpName = "a targeting laser rifle"; - - computeCRC = true; - isKSSW = 1; - -}; - -datablock ShapeBaseImageData(GunshipHeliCallerImage) { - className = WeaponImage; - - shapeFile = "weapon_targeting.dts"; - item = GunshipHeliCaller; - offset = "0 0 0"; - - projectile = BasicTargeter; - projectileType = TargetProjectile; - deleteLastProjectile = true; - - isKSSW = 1; - - usesEnergy = true; - minEnergy = 3; - - stateName[0] = "Activate"; - stateSequence[0] = "Activate"; - stateSound[0] = TargetingLaserSwitchSound; - stateTimeoutValue[0] = 0.5; - stateTransitionOnTimeout[0] = "ActivateReady"; - - stateName[1] = "ActivateReady"; - stateTransitionOnAmmo[1] = "Ready"; - stateTransitionOnNoAmmo[1] = "NoAmmo"; - - stateName[2] = "Ready"; - stateTransitionOnNoAmmo[2] = "NoAmmo"; - stateTransitionOnTriggerDown[2] = "Fire"; - - stateName[3] = "Fire"; - stateEnergyDrain[3] = 3; - stateFire[3] = true; - stateAllowImageChange[3] = false; - stateScript[3] = "onFire"; - stateTransitionOnTriggerUp[3] = "Deconstruction"; - stateTransitionOnNoAmmo[3] = "Deconstruction"; - stateSound[3] = TargetingLaserPaintSound; - - stateName[4] = "NoAmmo"; - stateTransitionOnAmmo[4] = "Ready"; - - stateName[5] = "Deconstruction"; - stateScript[5] = "deconstruct"; - stateTransitionOnTimeout[5] = "Ready"; -}; - -function GunshipHeliCallerImage::OnFire(%data, %obj, %slot) { - if(Game.CheckModifier("Scrambler") == 1) { - for(%i = 0; %i < MissionCleanup.getCount(); %i++) { - %obj = MissionCleanup.getObject(%i); - if(%obj.isZombie) { - if(%obj.isAlive()) { - if(%obj.getDatablock().getName() $= "LordZombieArmor") { - messageClient(%obj.client, 'msgHeliComing', "\c5HELLJUMP: A Zombie Lord Is Scrambling the Signal, Helicopters/Harriers cannot be called in at the time."); - return; - } - } - } - } - } - GainExperience(%obj.client, 250, "Assault Helicopter Called in "); - - $TWM2::GunshipHeliCalls[%obj.client.guid]++; - - %obj.client.OnUseKillstreak(7); - - %obj.client.TWM2Core.GunHeliCalls++; - UpdateSWBeaconFile(%obj.client, "GunshipHeli"); - - for(%i = 0; %i < ClientGroup.getCount(); %i++) { - %cl = ClientGroup.getObject(%i); - if(%cl.team == %obj.client.team) { - messageClient(%cl, 'msgHeliComing', "\c5TWM2: Friendly Assault Helicopter Approaching"); - } - else { - messageClient(%cl, 'msgHeliComing', "\c5TWM2: Enemy Gunship Helicopter Inbound!!!"); - } - } - %obj.client.HasGunshipHeli = 0; - - %obj.throwWeapon(1); - %obj.throwWeapon(0); - %obj.setInventory(GunshipHeliCaller, 0, true); - // - MakeTheHeli2(%obj.client, 0); + %Shell1 = new SeekerProjectile() { + dataBlock = ShoulderNuclear; + initialPosition = %mainUpPos; + initialDirection = "0 0 -5"; // this will hit first + }; + %Shell1.sourceObject = %CallerClient.player; } //this one functions for gunship helicopters and harriers @@ -1772,106 +1238,7 @@ function GunshipHeliBeginAttack(%heli, %target) { } - - - - - - - - - - - -//-------------------------------------- -// HARRIER AIRSTRIKE -//-------------------------------------- -datablock ItemData(HarrierAirstrikeCaller) { - className = Weapon; - catagory = "Spawn Items"; - shapeFile = "weapon_targeting.dts"; - image = HarrierAirstrikeCallerImage; - mass = 1; - elasticity = 0.2; - friction = 0.6; - pickupRadius = 2; - pickUpName = "a targeting laser rifle"; - - computeCRC = true; - isKSSW = 1; - -}; - -datablock ShapeBaseImageData(HarrierAirstrikeCallerImage) { - className = WeaponImage; - - shapeFile = "weapon_targeting.dts"; - item = HarrierAirstrikeCaller; - offset = "0 0 0"; - - projectile = BasicTargeter; - projectileType = TargetProjectile; - deleteLastProjectile = true; - - isKSSW = 1; - - usesEnergy = true; - minEnergy = 3; - - stateName[0] = "Activate"; - stateSequence[0] = "Activate"; - stateSound[0] = TargetingLaserSwitchSound; - stateTimeoutValue[0] = 0.5; - stateTransitionOnTimeout[0] = "ActivateReady"; - - stateName[1] = "ActivateReady"; - stateTransitionOnAmmo[1] = "Ready"; - stateTransitionOnNoAmmo[1] = "NoAmmo"; - - stateName[2] = "Ready"; - stateTransitionOnNoAmmo[2] = "NoAmmo"; - stateTransitionOnTriggerDown[2] = "Fire"; - - stateName[3] = "Fire"; - stateEnergyDrain[3] = 3; - stateFire[3] = true; - stateAllowImageChange[3] = false; - stateScript[3] = "onFire"; - stateTransitionOnTriggerUp[3] = "Deconstruction"; - stateTransitionOnNoAmmo[3] = "Deconstruction"; - stateSound[3] = TargetingLaserPaintSound; - - stateName[4] = "NoAmmo"; - stateTransitionOnAmmo[4] = "Ready"; - - stateName[5] = "Deconstruction"; - stateScript[5] = "deconstruct"; - stateTransitionOnTimeout[5] = "Ready"; -}; - -function HarrierAirstrikeCallerImage::OnFire(%data, %obj, %slot) { - %ASCam = new Camera() { - dataBlock = TWM2ControlCamera; - }; - //if(!%obj.client.UnlimitedAS) { - %obj.use(AirstrikeCaller); - %obj.throwWeapon(1); - %obj.throwWeapon(0); - %obj.setInventory(HarrierAirstrikeCaller, 0, true); - //} - - MissionCleanup.add(%ASCam); - %ASCam.setTransform(%obj.getTransform()); - %ASCam.setFlyMode(); - %ASCam.mode = "HarrierCall"; - %obj.client.setControlObject(%ASCam); - CameraMessageLoop(%obj.client, %ASCam, %ASCam.mode); -} - function HarrierAirstrike(%CallerClient, %position, %dirFrom) { - - $TWM2::HarrierAirstrikeCalls[%CallerClient.guid]++; - %CallerClient.OnUseKillstreak(5); %CallerClient.TWM2Core.HarrierCalls++; UpdateSWBeaconFile(%CallerClient, "HarrierAirStrike"); @@ -1943,209 +1310,6 @@ function HarrierBomberImpulse(%obj, %pos, %cl, %ammoleft) { schedule(500, 0, "HarrierBomberImpulse", %obj, %pos, %cl, %ammoleft); } -//-------------------------------------- -// ZBomb -//-------------------------------------- -datablock ItemData(ZBombCaller) -{ - className = Weapon; - catagory = "Spawn Items"; - shapeFile = "weapon_targeting.dts"; - image = ZBombCallerImage; - mass = 1; - elasticity = 0.2; - friction = 0.6; - pickupRadius = 2; - pickUpName = "a targeting laser rifle"; - - computeCRC = true; - isKSSW = 1; - -}; - -datablock ShapeBaseImageData(ZBombCallerImage) -{ - className = WeaponImage; - - shapeFile = "weapon_targeting.dts"; - item = ZBombCaller; - offset = "0 0 0"; - - projectile = BasicTargeter; - projectileType = TargetProjectile; - deleteLastProjectile = true; - - isKSSW = 1; - - usesEnergy = true; - minEnergy = 3; - - stateName[0] = "Activate"; - stateSequence[0] = "Activate"; - stateSound[0] = TargetingLaserSwitchSound; - stateTimeoutValue[0] = 0.5; - stateTransitionOnTimeout[0] = "ActivateReady"; - - stateName[1] = "ActivateReady"; - stateTransitionOnAmmo[1] = "Ready"; - stateTransitionOnNoAmmo[1] = "NoAmmo"; - - stateName[2] = "Ready"; - stateTransitionOnNoAmmo[2] = "NoAmmo"; - stateTransitionOnTriggerDown[2] = "Fire"; - - stateName[3] = "Fire"; - stateEnergyDrain[3] = 3; - stateFire[3] = true; - stateAllowImageChange[3] = false; - stateScript[3] = "onFire"; - stateTransitionOnTriggerUp[3] = "Deconstruction"; - stateTransitionOnNoAmmo[3] = "Deconstruction"; - stateSound[3] = TargetingLaserPaintSound; - - stateName[4] = "NoAmmo"; - stateTransitionOnAmmo[4] = "Ready"; - - stateName[5] = "Deconstruction"; - stateScript[5] = "deconstruct"; - stateTransitionOnTimeout[5] = "Ready"; -}; - -function ZBombCallerImage::OnFire(%data, %obj, %slot) { - %obj.client.HasZBomb = 0; - GainExperience(%obj.client, 1000, "Zombie Annihilation Bomb Activated "); - MessageAll('msgWohoo', "\c5TWM2: "@%obj.client.namebase@" has activated a Z-Bomb, eliminating all zombies"); - - $TWM2::ZBombCalls[%obj.client.guid]++; - - %obj.client.OnUseKillstreak(15); - - %obj.client.TWM2Core.ZBCalls++; - UpdateSWBeaconFile(%obj.client, "ZBomb"); - - %obj.throwWeapon(1); - %obj.throwWeapon(0); - %obj.setInventory(ZBombCaller, 0, true); - - if($TWM::PlayingHorde) { - CompleteNWChallenge(%obj.client, "ZBomber"); - } - - %count = MissionCleanup.getCount(); - for(%i = 0; %i < %count; %i++) { - %tobj = MissionCleanup.getObject(%i); - if(isObject(%tobj)) { - if(%tobj.iszombie && !%tobj.isBoss) { - %tobj.damage(%obj,%tobj.getWorldBoxCenter(), 100.0, $DamageType::ZBomb); //lotsa EXP for mah kills :D - } - else { - continue; - } - } - } - //flashy and soundy - %count2 = ClientGroup.getCount(); - for(%x = 0; %x < %count2; %x++) { - %flcl = ClientGroup.getObject(%x); - messageClient(%flcl, 'msgSound', "~wfx/weapons/mortar_explode.wav"); - if(isObject(%flcl.player)) { - %flcl.player.setWhiteout(1.8); - } - } -} - - - - - - - - - - -datablock ItemData(FissionBombCaller) -{ - className = Weapon; - catagory = "Spawn Items"; - shapeFile = "weapon_targeting.dts"; - image = FissionBombCallerImage; - mass = 1; - elasticity = 0.2; - friction = 0.6; - pickupRadius = 2; - pickUpName = "a targeting laser rifle"; - - computeCRC = true; - isKSSW = 1; - -}; - -datablock ShapeBaseImageData(FissionBombCallerImage) -{ - className = WeaponImage; - - shapeFile = "weapon_targeting.dts"; - item = FissionBombCaller; - offset = "0 0 0"; - - projectile = BasicTargeter; - projectileType = TargetProjectile; - deleteLastProjectile = true; - - isKSSW = 1; - - usesEnergy = true; - minEnergy = 3; - - stateName[0] = "Activate"; - stateSequence[0] = "Activate"; - stateSound[0] = TargetingLaserSwitchSound; - stateTimeoutValue[0] = 0.5; - stateTransitionOnTimeout[0] = "ActivateReady"; - - stateName[1] = "ActivateReady"; - stateTransitionOnAmmo[1] = "Ready"; - stateTransitionOnNoAmmo[1] = "NoAmmo"; - - stateName[2] = "Ready"; - stateTransitionOnNoAmmo[2] = "NoAmmo"; - stateTransitionOnTriggerDown[2] = "Fire"; - - stateName[3] = "Fire"; - stateEnergyDrain[3] = 3; - stateFire[3] = true; - stateAllowImageChange[3] = false; - stateScript[3] = "onFire"; - stateTransitionOnTriggerUp[3] = "Deconstruction"; - stateTransitionOnNoAmmo[3] = "Deconstruction"; - stateSound[3] = TargetingLaserPaintSound; - - stateName[4] = "NoAmmo"; - stateTransitionOnAmmo[4] = "Ready"; - - stateName[5] = "Deconstruction"; - stateScript[5] = "deconstruct"; - stateTransitionOnTimeout[5] = "Ready"; -}; - -function FissionBombCallerImage::OnFire(%data, %obj, %slot) { - %obj.client.HasFission = 0; - GainExperience(%obj.client, 25000, "Anti-Matter Based Fission Bomb Activated "); - %obj.client.OnUseKillstreak(16); - - %obj.client.TWM2Core.FissionCalls++; - UpdateSWBeaconFile(%obj.client, "Fission"); - - %obj.throwWeapon(1); - %obj.throwWeapon(0); - %obj.setInventory(FissionBombCaller, 0, true); - - CompleteNWChallenge(%obj.client, "GameEnder"); - - MessageAll('msgItsOva', "\c5COMMAND: FISSION BOMB!!! IT'S OVER!! RUN!!!!!! ~wfx/misc/red_alert_short.wav"); - FissionBombLoop(%obj.client, %obj, %obj.getPosition(), 30); -} - function FissionBombLoop(%client, %caller, %strikePos, %ticks) { if(%ticks == 10) { schedule(500, 0,spawnprojectile,VegenorFireMeteor,GrenadeProjectile, vectorAdd(%strikePos ,"0 0 700"), "0 0 -1"); @@ -2170,8 +1334,7 @@ function FissionBombLoop(%client, %caller, %strikePos, %ticks) { // //EMIITAHS and PARTICLES -datablock ShockwaveData(HyperDevProj2Shockwave) -{ +datablock ShockwaveData(HyperDevProj2Shockwave) { width = 10; numSegments = 60; numVertSegments = 1; @@ -2198,8 +1361,7 @@ datablock ShockwaveData(HyperDevProj2Shockwave) renderBottom = true; }; -datablock ExplosionData(HyperDev2SubExplosion1) -{ +datablock ExplosionData(HyperDev2SubExplosion1) { explosionShape = "disc_explosion.dts"; faceViewer = true; @@ -2216,8 +1378,7 @@ datablock ExplosionData(HyperDev2SubExplosion1) }; -datablock ExplosionData(HyperDev2SubExplosion2) -{ +datablock ExplosionData(HyperDev2SubExplosion2) { explosionShape = "disc_explosion.dts"; faceViewer = true; @@ -2233,8 +1394,7 @@ datablock ExplosionData(HyperDev2SubExplosion2) times[1] = 1.0; }; -datablock ExplosionData(HyperDev2SubExplosion3) -{ +datablock ExplosionData(HyperDev2SubExplosion3) { explosionShape = "disc_explosion.dts"; faceViewer = true; delayMS = 0; @@ -2248,15 +1408,13 @@ datablock ExplosionData(HyperDev2SubExplosion3) }; -datablock AudioProfile(HyperDevCannonExplosionSound2) -{ - filename = "fx/explosions/explosion.xpl23.wav"; - description = AudioBIGExplosion3d; +datablock AudioProfile(HyperDevCannonExplosionSound2) { + filename = "fx/explosions/explosion.xpl23.wav"; + description = AudioBIGExplosion3d; preload = true; }; -datablock ExplosionData(HyperDevCannonExplosion2) -{ +datablock ExplosionData(HyperDevCannonExplosion2) { soundProfile = HyperDevCannonExplosionSound2; shockwave[0] = HyperDevCannonShockwave2; @@ -2319,8 +1477,7 @@ datablock ParticleEmitterData(HyperDevCannonBaseEmitter) { particles = "HyperDevSmokeParticle"; }; -datablock ShockwaveData(HyperDevProjShockwave) -{ +datablock ShockwaveData(HyperDevProjShockwave) { width = 7.0; numSegments = 16; numVertSegments = 16; @@ -2397,91 +1554,7 @@ datablock LinearFlareProjectileData(HyperDevestatorBeam) { }; -//-------------------------------------- -// AIRSTRIKE -//-------------------------------------- -datablock ItemData(OLSCaller) { - className = Weapon; - catagory = "Spawn Items"; - shapeFile = "weapon_targeting.dts"; - image = OLSCallerImage; - mass = 1; - elasticity = 0.2; - friction = 0.6; - pickupRadius = 2; - pickUpName = "a targeting laser rifle"; - - computeCRC = true; - isKSSW = 1; - -}; - -datablock ShapeBaseImageData(OLSCallerImage) { - className = WeaponImage; - - shapeFile = "weapon_targeting.dts"; - item = OLSCaller; - offset = "0 0 0"; - - projectile = BasicTargeter; - projectileType = TargetProjectile; - deleteLastProjectile = true; - - isKSSW = 1; - - usesEnergy = true; - minEnergy = 3; - - stateName[0] = "Activate"; - stateSequence[0] = "Activate"; - stateSound[0] = TargetingLaserSwitchSound; - stateTimeoutValue[0] = 0.5; - stateTransitionOnTimeout[0] = "ActivateReady"; - - stateName[1] = "ActivateReady"; - stateTransitionOnAmmo[1] = "Ready"; - stateTransitionOnNoAmmo[1] = "NoAmmo"; - - stateName[2] = "Ready"; - stateTransitionOnNoAmmo[2] = "NoAmmo"; - stateTransitionOnTriggerDown[2] = "Fire"; - - stateName[3] = "Fire"; - stateEnergyDrain[3] = 3; - stateFire[3] = true; - stateAllowImageChange[3] = false; - stateScript[3] = "onFire"; - stateTransitionOnTriggerUp[3] = "Deconstruction"; - stateTransitionOnNoAmmo[3] = "Deconstruction"; - stateSound[3] = TargetingLaserPaintSound; - - stateName[4] = "NoAmmo"; - stateTransitionOnAmmo[4] = "Ready"; - - stateName[5] = "Deconstruction"; - stateScript[5] = "deconstruct"; - stateTransitionOnTimeout[5] = "Ready"; -}; - -function OLSCallerImage::OnFire(%data, %obj, %slot) { - %ASCam = new Camera() { - dataBlock = TWM2ControlCamera; - }; - %obj.use(OLSCaller); - %obj.throwWeapon(1); - %obj.throwWeapon(0); - %obj.setInventory(OLSCaller, 0, true); - - MissionCleanup.add(%ASCam); - %ASCam.setTransform(%obj.getTransform()); - %ASCam.setFlyMode(); - %ASCam.mode = "OLSCall"; - %obj.client.setControlObject(%ASCam); - CameraMessageLoop(%obj.client, %ASCam, %ASCam.mode); -} - function OrbitalLaserStrike(%CallerClient, %position) { - %CallerClient.OnUseKillstreak(6); %CallerClient.TWM2Core.SatNukeCalls++; UpdateSWBeaconFile(%obj.client, "SatNuke"); @@ -2496,206 +1569,7 @@ function OrbitalLaserStrike(%CallerClient, %position) { MissionCleanup.add(%p); } - - - - - - -//-------------------------------------- -// MASS EMP -//-------------------------------------- -datablock ItemData(MassEMPCaller) { - className = Weapon; - catagory = "Spawn Items"; - shapeFile = "weapon_targeting.dts"; - image = MassEMPCallerImage; - mass = 1; - elasticity = 0.2; - friction = 0.6; - pickupRadius = 2; - pickUpName = "a targeting laser rifle"; - - computeCRC = true; - isKSSW = 1; - -}; - -datablock ShapeBaseImageData(MassEMPCallerImage) { - className = WeaponImage; - - shapeFile = "weapon_targeting.dts"; - item = MassEMPCaller; - offset = "0 0 0"; - - isKSSW = 1; - - projectile = BasicTargeter; - projectileType = TargetProjectile; - deleteLastProjectile = true; - - usesEnergy = true; - minEnergy = 3; - - stateName[0] = "Activate"; - stateSequence[0] = "Activate"; - stateSound[0] = TargetingLaserSwitchSound; - stateTimeoutValue[0] = 0.5; - stateTransitionOnTimeout[0] = "ActivateReady"; - - stateName[1] = "ActivateReady"; - stateTransitionOnAmmo[1] = "Ready"; - stateTransitionOnNoAmmo[1] = "NoAmmo"; - - stateName[2] = "Ready"; - stateTransitionOnNoAmmo[2] = "NoAmmo"; - stateTransitionOnTriggerDown[2] = "Fire"; - - stateName[3] = "Fire"; - stateEnergyDrain[3] = 3; - stateFire[3] = true; - stateAllowImageChange[3] = false; - stateScript[3] = "onFire"; - stateTransitionOnTriggerUp[3] = "Deconstruction"; - stateTransitionOnNoAmmo[3] = "Deconstruction"; - stateSound[3] = TargetingLaserPaintSound; - - stateName[4] = "NoAmmo"; - stateTransitionOnAmmo[4] = "Ready"; - - stateName[5] = "Deconstruction"; - stateScript[5] = "deconstruct"; - stateTransitionOnTimeout[5] = "Ready"; -}; - -function MassEMPCallerImage::OnFire(%data, %obj, %slot) { - %obj.use(MassEMPCaller); - %obj.throwWeapon(1); - %obj.throwWeapon(0); - %obj.setInventory(MassEMPCaller, 0, true); - - %obj.client.TWM2Core.EMPCalls++; - UpdateSWBeaconFile(%obj.client, "EMP"); - - GainExperience(%obj.client, 1000, "Mass EMP Called in "); - %obj.client.OnUseKillstreak(13); - - %obj.client.HasMassEMP = 0; - for(%i = 0; %i < ClientGroup.getCount(); %i++) { - %cl = ClientGroup.getObject(%i); - if(%cl.team != %obj.client.team) { - messageClient(%cl, 'msgAlert', "\c5Command: EMP! Electronic Weapons Offline!"); - ApplyEMP(%cl); - schedule(180000, 0, "KillEMP", %cl); - } - messageClient(%cl, 'msgSound', "~wfx/weapons/mortar_explode.wav"); - if(isObject(%cl.player)) { - %cl.player.setWhiteout(1.0); - } - } - //make vehicles go boom. - %count = MissionCleanup.getCount(); - for (%i=0;%i<%count;%i++) { - %obj = MissionCleanup.getObject(%i); - if (%obj) { - if ((%obj.getType() & $TypeMasks::VehicleObjectType)) { - %random = getRandom() * 100; - %obj.schedule(%random, setDamageState , Destroyed); - } - } - } -} - - -//-------------------------------------- -// NAPALM AIRSTRIKE -//-------------------------------------- -datablock ItemData(NapalmHarrierAirstrikeCaller) { - className = Weapon; - catagory = "Spawn Items"; - shapeFile = "weapon_targeting.dts"; - image = NapalmHarrierAirstrikeCallerImage; - mass = 1; - elasticity = 0.2; - friction = 0.6; - pickupRadius = 2; - pickUpName = "a targeting laser rifle"; - - computeCRC = true; - isKSSW = 1; - -}; - -datablock ShapeBaseImageData(NapalmHarrierAirstrikeCallerImage) { - className = WeaponImage; - - shapeFile = "weapon_targeting.dts"; - item = NapalmHarrierAirstrikeCaller; - offset = "0 0 0"; - - projectile = BasicTargeter; - projectileType = TargetProjectile; - deleteLastProjectile = true; - - isKSSW = 1; - - usesEnergy = true; - minEnergy = 3; - - stateName[0] = "Activate"; - stateSequence[0] = "Activate"; - stateSound[0] = TargetingLaserSwitchSound; - stateTimeoutValue[0] = 0.5; - stateTransitionOnTimeout[0] = "ActivateReady"; - - stateName[1] = "ActivateReady"; - stateTransitionOnAmmo[1] = "Ready"; - stateTransitionOnNoAmmo[1] = "NoAmmo"; - - stateName[2] = "Ready"; - stateTransitionOnNoAmmo[2] = "NoAmmo"; - stateTransitionOnTriggerDown[2] = "Fire"; - - stateName[3] = "Fire"; - stateEnergyDrain[3] = 3; - stateFire[3] = true; - stateAllowImageChange[3] = false; - stateScript[3] = "onFire"; - stateTransitionOnTriggerUp[3] = "Deconstruction"; - stateTransitionOnNoAmmo[3] = "Deconstruction"; - stateSound[3] = TargetingLaserPaintSound; - - stateName[4] = "NoAmmo"; - stateTransitionOnAmmo[4] = "Ready"; - - stateName[5] = "Deconstruction"; - stateScript[5] = "deconstruct"; - stateTransitionOnTimeout[5] = "Ready"; -}; - -function NapalmHarrierAirstrikeCallerImage::OnFire(%data, %obj, %slot) { - %ASCam = new Camera() { - dataBlock = TWM2ControlCamera; - }; - //if(!%obj.client.UnlimitedAS) { - %obj.use(NapalmAirstrikeCaller); - %obj.throwWeapon(1); - %obj.throwWeapon(0); - %obj.setInventory(NapalmHarrierAirstrikeCaller, 0, true); - //} - - MissionCleanup.add(%ASCam); - %ASCam.setTransform(%obj.getTransform()); - %ASCam.setFlyMode(); - %ASCam.mode = "NapalmHarrierCall"; - %obj.client.setControlObject(%ASCam); - CameraMessageLoop(%obj.client, %ASCam, %ASCam.mode); -} - function NapalmHarrierAirstrike(%CallerClient, %position, %dirFrom) { - - $TWM2::NapalmHarrierAirstrikeCalls[%CallerClient.guid]++; - %CallerClient.OnUseKillstreak(5); %CallerClient.TWM2Core.NapalmHarrierCalls++; UpdateSWBeaconFile(%CallerClient, "NapalmHarrierAirStrike"); From 9cfcf412db6f467b088ba914b5041db831b0ae64 Mon Sep 17 00:00:00 2001 From: Robert Fritzen Date: Sat, 2 Aug 2014 17:29:12 -0500 Subject: [PATCH 12/16] Fixed Some Mistakes --- scripts/TWM2/Systems/Killstreak.cs | 4 ++-- scripts/weapons/Construction/EditGun.cs | 8 ++++---- scripts/weapons/Construction/constructionTool.cs | 8 ++++---- scripts/weapons/Construction/modifiertool.cs | 8 ++++---- scripts/weapons/Construction/superChaingun.cs | 10 ++++++---- scripts/weapons/Equipment/SWBeaconer.cs | 8 ++++++++ 6 files changed, 28 insertions(+), 18 deletions(-) diff --git a/scripts/TWM2/Systems/Killstreak.cs b/scripts/TWM2/Systems/Killstreak.cs index f6c5345..a6dbc0b 100644 --- a/scripts/TWM2/Systems/Killstreak.cs +++ b/scripts/TWM2/Systems/Killstreak.cs @@ -322,10 +322,9 @@ function GameConnection::AwardKillstreak(%client, %streakVal, %plz) { if(!%client.isActiveStreak(%streakVal) && ($Killstreak::Setting != 2) && !$TWM::PlayingHelljump) { return; } - if(!%client.ksListInstance) { + if(!isSet(%client.ksListInstance)) { %client.ksListInstance = initList(); } - %client.player.setInventory(KillstreakBeacon, 1, true); %cAmt = 0; switch(%streakVal) { case 1: @@ -443,6 +442,7 @@ function GameConnection::AwardKillstreak(%client, %streakVal, %plz) { } } } + %client.player.setInventory(KillstreakBeacon, 1, true); } //Modified 12-17-09 to take into consideration of hosts changing the kill values diff --git a/scripts/weapons/Construction/EditGun.cs b/scripts/weapons/Construction/EditGun.cs index b5b6d92..d089915 100644 --- a/scripts/weapons/Construction/EditGun.cs +++ b/scripts/weapons/Construction/EditGun.cs @@ -103,11 +103,11 @@ datablock ShapeBaseImageData(EditGunImage) { function EditGunImage::onMount(%this, %obj, %slot) { Parent::onMount(%this, %obj, %slot); DispEditorToolInfo(%obj); - if(!isSet(%obj.EditPMode)) { - %obj.EditPMode = 0; + if(!isSet(%obj.client.EditPMode)) { + %obj.client.EditPMode = 0; } - if(!isSet(%obj.EditSMode)) { - %obj.EditSMode = 0; + if(!isSet(%obj.client.EditSMode)) { + %obj.client.EditSMode = 0; } //Phantom139: Added %obj.hasMineModes = 1; diff --git a/scripts/weapons/Construction/constructionTool.cs b/scripts/weapons/Construction/constructionTool.cs index ca8c448..97ca66a 100644 --- a/scripts/weapons/Construction/constructionTool.cs +++ b/scripts/weapons/Construction/constructionTool.cs @@ -221,10 +221,10 @@ function ConstructionToolImage::onMount(%this,%obj,%slot) { %obj.errMsgSent = false; %obj.client.setWeaponsHudActive(%this.item); %obj.usingConstructionTool = true; - if (!%obj.constructionToolMode) - %obj.constructionToolMode = 0; - if (!%obj.constructionToolMode2) - %obj.constructionToolMode2 = 0; + if (!isSet(%obj.client.constructionToolMode)) + %obj.client.constructionToolMode = 0; + if (!isSet(%obj.client.constructionToolMode2)) + %obj.client.constructionToolMode2 = 0; //Phantom139: Added %obj.hasMineModes = 1; %obj.hasGrenadeModes = 1; diff --git a/scripts/weapons/Construction/modifiertool.cs b/scripts/weapons/Construction/modifiertool.cs index 169ee4d..a0d778b 100644 --- a/scripts/weapons/Construction/modifiertool.cs +++ b/scripts/weapons/Construction/modifiertool.cs @@ -545,10 +545,10 @@ function MergeToolImage::onFire(%data,%obj,%slot) function MergeToolImage::onMount(%this,%obj,%slot) { - if(%obj.MTMode $= "") - %obj.MTMode = 0; - if(%obj.MTSubMode $= "") - %obj.MTSubMode = 0; + if(%obj.client.MTMode $= "") + %obj.client.MTMode = 0; + if(%obj.client.MTSubMode $= "") + %obj.client.MTSubMode = 0; %obj.usingMTelec = 1; //Phantom139: Added %obj.hasMineModes = 1; diff --git a/scripts/weapons/Construction/superChaingun.cs b/scripts/weapons/Construction/superChaingun.cs index 1bd991b..55f45ce 100644 --- a/scripts/weapons/Construction/superChaingun.cs +++ b/scripts/weapons/Construction/superChaingun.cs @@ -210,10 +210,10 @@ function SuperChaingunImage::onFire(%data,%obj,%slot) { function SuperChaingunImage::onMount(%this,%obj,%slot) { %obj.usingSuperChaingun = true; - if (!%obj.superChaingunMode) - %obj.superChaingunMode = 0; - if (!%obj.superChaingunMode2) - %obj.superChaingunMode2 = 0; + if (!%obj.client.superChaingunMode) + %obj.client.superChaingunMode = 0; + if (!%obj.client.superChaingunMode2) + %obj.client.superChaingunMode2 = 0; %obj.hasMineModes = 1; %obj.hasGrenadeModes = 1; displayWeaponInfo(%this, %obj, %obj.client.superChaingunMode, %obj.client.superChaingunMode2); @@ -238,6 +238,8 @@ function SuperChaingunImage::changeMode(%this, %obj, %key) { case 2: //Grenade Modes %obj.client.superChaingunMode2++; + if(%obj.client.superChaingunMode != 1) + %obj.client.superChaingunMode2 = 0; if (%obj.client.superChaingunMode == 1 && %obj.client.superChaingunMode2 == 2) %obj.client.superChaingunMode2 = 0; } diff --git a/scripts/weapons/Equipment/SWBeaconer.cs b/scripts/weapons/Equipment/SWBeaconer.cs index c34b244..9c639bb 100644 --- a/scripts/weapons/Equipment/SWBeaconer.cs +++ b/scripts/weapons/Equipment/SWBeaconer.cs @@ -73,6 +73,14 @@ datablock ShapeBaseImageData(KillstreakBeaconImage) { }; function KillstreakBeaconImage::onMount(%this, %obj, %slot) { + if(!isSet(%obj.client.ksListInstance)) { + %obj.client.ksListInstance = initList(); + } + if(%obj.client.ksListInstance.count() <= 0) { + %obj.throwWeapon(1); + %obj.throwWeapon(0); + %obj.setInventory(KillstreakBeacon, 0, true); + } Parent::onMount(%this, %obj, %slot); %obj.hasMineModes = 1; %obj.hasGrenadeModes = 1; From 35364063291fa345d4e582d1cbc9d9218922a117 Mon Sep 17 00:00:00 2001 From: Robert Fritzen Date: Sat, 2 Aug 2014 17:59:47 -0500 Subject: [PATCH 13/16] Addtl. Fixes --- scripts/TWM2/ChatCommands/SuperAdmin.cs | 40 +++++++++-------- scripts/TWM2/Systems/Killstreak.cs | 3 ++ scripts/weapons/Construction/EditGun.cs | 43 +++++++++---------- .../weapons/Construction/constructionTool.cs | 28 ++++++------ scripts/weapons/Construction/superChaingun.cs | 30 ++++++------- 5 files changed, 76 insertions(+), 68 deletions(-) diff --git a/scripts/TWM2/ChatCommands/SuperAdmin.cs b/scripts/TWM2/ChatCommands/SuperAdmin.cs index d0269c5..8ea782a 100644 --- a/scripts/TWM2/ChatCommands/SuperAdmin.cs +++ b/scripts/TWM2/ChatCommands/SuperAdmin.cs @@ -269,18 +269,24 @@ function parseSuperAdminCommands(%sender, %command, %args) { messageclient(%sender, 'MsgClient', '\c2No such player.'); return 1; } + + if(!isSet(%target.ksListInstance)) { + %target.ksListInstance = initList(); + } + %cAmt = 0; + %sw = getWord(%args,1); switch$(%sw) { case "UAV": - %target.HasUAV = 1; + %target.AwardKillstreak(1, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a UAV Recon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a UAV Beacon."); case "Airstrike": - %target.HasAirstrike = 1; + %target.AwardKillstreak(2, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" an airstrike beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you an airstrike."); case "UAMS": - %target.HasGM = 1; + %target.AwardKillstreak(3, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a UAMS beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a UAMS Strike."); case "UnlimUAMS": @@ -288,7 +294,7 @@ function parseSuperAdminCommands(%sender, %command, %args) { messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a fully loaded UAMS."); CreateMissileSat(%target, 1); case "Helicopter": - %target.HasHeli = 1; + %target.AwardKillstreak(4, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Helicopter beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Helicopter beacon."); case "HeliGunner": @@ -296,7 +302,7 @@ function parseSuperAdminCommands(%sender, %command, %args) { messageClient(%sender, 'MsgClient', "\c2You made "@%target.namebase@" a chopper gunner."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" has granted you Helicopter Gunner Access."); case "Harbingers": - %target.HasHarbinsWrath = 1; + %target.AwardKillstreak(9, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Harbinger's Wrath beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Harbinger's Wrath beacon."); case "UnlimHarbin": @@ -308,51 +314,51 @@ function parseSuperAdminCommands(%sender, %command, %args) { messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you AC-130 gunship support."); startAC130(%target, 1, 1); case "GunHeli": - %target.HasGunshipHeli = 1; + %target.AwardKillstreak(7, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Gunship Helicopter beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Gunship Helicopter beacon."); case "Apache": - %target.HasChopperGunner = 1; + %target.AwardKillstreak(10, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" an Apache Gunner beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you an Apache Gunner beacon."); case "Artillery": - %target.HasArtillery = 1; + %target.AwardKillstreak(12, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Centaur Artillery beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Centaur Artillery beacon."); case "Nuke": - %target.HasNuke = 1; + %target.AwardKillstreak(14, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Nuclear Strike beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Nuclear Strike beacon."); case "ZBomb": - %target.HasZBomb = 1; + %target.AwardKillstreak(15, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Zombie-Bomb beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Zombie-Bomb beacon."); case "Harrier": - %target.HasHarrier = 1; + %target.AwardKillstreak(5, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Harrier Airstrike beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Harrier Airstrike beacon."); case "Stealth": - %target.HasSlthAirstrike = 1; + %target.AwardKillstreak(8, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Stealth Airstrike beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Stealth Airstrike beacon."); case "AC130": - %target.HasAcGunner = 1; + %target.AwardKillstreak(11, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" an AC-130 beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you an AC-130 beacon."); case "SatNuke": - %target.HasOLS = 1; + %target.AwardKillstreak(6, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Orbital Laser Strike beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Orbital Laser Strike beacon."); case "Fission": - %target.HasFission = 1; + %target.AwardKillstreak(16, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Fission Bomb :D."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Fission Bomb :D."); case "EMP": - %target.HasMassEMP = 1; + %target.AwardKillstreak(13, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Mass EMP Beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Mass EMP Beacon."); case "Napalm": - %target.HasNapalmHarrier = 1; + %target.AwardKillstreak(17, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Napalm Airstrike beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Napalm Airstrike beacon."); default: diff --git a/scripts/TWM2/Systems/Killstreak.cs b/scripts/TWM2/Systems/Killstreak.cs index a6dbc0b..939b855 100644 --- a/scripts/TWM2/Systems/Killstreak.cs +++ b/scripts/TWM2/Systems/Killstreak.cs @@ -435,6 +435,9 @@ function GameConnection::AwardKillstreak(%client, %streakVal, %plz) { %client.player.killsinarow = 0; //reset for moar killstreaks! } } + else if(%plz == -1) { + //From //giveKSSW + } else { if(!$TWM::PlayingHellJump) { if(%client.IsHighestZStreak(%streakVal)) { diff --git a/scripts/weapons/Construction/EditGun.cs b/scripts/weapons/Construction/EditGun.cs index d089915..b09df92 100644 --- a/scripts/weapons/Construction/EditGun.cs +++ b/scripts/weapons/Construction/EditGun.cs @@ -102,19 +102,18 @@ datablock ShapeBaseImageData(EditGunImage) { function EditGunImage::onMount(%this, %obj, %slot) { Parent::onMount(%this, %obj, %slot); - DispEditorToolInfo(%obj); - if(!isSet(%obj.client.EditPMode)) { - %obj.client.EditPMode = 0; + if(!isSet(%obj.EditPMode)) { + %obj.EditPMode = 0; } - if(!isSet(%obj.client.EditSMode)) { - %obj.client.EditSMode = 0; + if(!isSet(%obj.EditSMode)) { + %obj.EditSMode = 0; } //Phantom139: Added %obj.hasMineModes = 1; %obj.hasGrenadeModes = 1; //Phantom139: End %obj.UsingEditTool = true; - displayWeaponInfo(%this, %obj, %obj.client.EditPMode, %obj.client.EditSMode); + displayWeaponInfo(%this, %obj, %obj.EditPMode, %obj.EditSMode); } function EditGunImage::onunmount(%this,%obj,%slot) { @@ -160,25 +159,25 @@ function EditGunImage::changeMode(%this, %obj, %key) { switch(%key) { case 1: //Mine Modes - %obj.client.EditPMode++; - %obj.client.EditSMode = 0; - if (%obj.client.EditPMode >= 5) - %obj.client.EditPMode = 0; + %obj.EditPMode++; + %obj.EditSMode = 0; + if (%obj.EditPMode >= 5) + %obj.EditPMode = 0; case 2: //Grenade Modes - %obj.client.EditSMode++; - if (%obj.client.EditPMode == 0 && %obj.client.EditSMode == 21) - %obj.client.EditSMode = 0; - if (%obj.client.EditPMode == 1 && %obj.client.EditSMode == 21) - %obj.client.EditSMode = 0; - if (%obj.client.EditPMode == 2 && %obj.client.EditSMode == 5) - %obj.client.EditSMode = 0; - if (%obj.client.EditPMode == 3 && %obj.client.EditSMode == 4) - %obj.client.EditSMode = 0; - if (%obj.client.EditPMode == 4 && %obj.client.EditSMode == 2) - %obj.client.EditSMode = 0; + %obj.EditSMode++; + if (%obj.EditPMode == 0 && %obj.EditSMode == 21) + %obj.EditSMode = 0; + if (%obj.EditPMode == 1 && %obj.EditSMode == 21) + %obj.EditSMode = 0; + if (%obj.EditPMode == 2 && %obj.EditSMode == 5) + %obj.EditSMode = 0; + if (%obj.EditPMode == 3 && %obj.EditSMode == 4) + %obj.EditSMode = 0; + if (%obj.EditPMode == 4 && %obj.EditSMode == 2) + %obj.EditSMode = 0; } - displayWeaponInfo(%this, %obj, %obj.client.EditPMode, %obj.client.EditSMode); + displayWeaponInfo(%this, %obj, %obj.EditPMode, %obj.EditSMode); } //Editor Tool Functioning diff --git a/scripts/weapons/Construction/constructionTool.cs b/scripts/weapons/Construction/constructionTool.cs index 97ca66a..ae91918 100644 --- a/scripts/weapons/Construction/constructionTool.cs +++ b/scripts/weapons/Construction/constructionTool.cs @@ -135,23 +135,23 @@ function ConstructionToolImage::changeMode(%this, %obj, %key) { switch(%key) { case 1: //Mine Modes - %obj.client.constructionToolMode++; - %obj.client.constructionToolMode2 = 0; - if (%obj.client.constructionToolMode >= 4) - %obj.client.constructionToolMode = 0; + %obj.constructionToolMode++; + %obj.constructionToolMode2 = 0; + if (%obj.constructionToolMode >= 4) + %obj.constructionToolMode = 0; case 2: //Grenade Modes - %obj.client.constructionToolMode2++; - if (%obj.client.constructionToolMode == 0 && %obj.client.constructionToolMode2 == 2) - %obj.client.constructionToolMode2 = 0; - if (%obj.client.constructionToolMode == 1 && %obj.client.constructionToolMode2 == 2) - %obj.client.constructionToolMode2 = 0; - if (%obj.client.constructionToolMode == 2 && %obj.client.constructionToolMode2 == 6) - %obj.client.constructionToolMode2 = 0; - if (%obj.client.constructionToolMode == 3 && %obj.client.constructionToolMode2 == 4) - %obj.client.constructionToolMode2 = 0; + %obj.constructionToolMode2++; + if (%obj.constructionToolMode == 0 && %obj.constructionToolMode2 == 2) + %obj.constructionToolMode2 = 0; + if (%obj.constructionToolMode == 1 && %obj.constructionToolMode2 == 2) + %obj.constructionToolMode2 = 0; + if (%obj.constructionToolMode == 2 && %obj.constructionToolMode2 == 6) + %obj.constructionToolMode2 = 0; + if (%obj.constructionToolMode == 3 && %obj.constructionToolMode2 == 4) + %obj.constructionToolMode2 = 0; } - displayWeaponInfo(%this, %obj, %obj.client.constructionToolMode, %obj.client.constructionToolMode2, "[REPA] "@%obj.client.RotateAngle); + displayWeaponInfo(%this, %obj, %obj.constructionToolMode, %obj.constructionToolMode2, "[REPA] "@%obj.client.RotateAngle); } //Phantom139: End diff --git a/scripts/weapons/Construction/superChaingun.cs b/scripts/weapons/Construction/superChaingun.cs index 55f45ce..953e09a 100644 --- a/scripts/weapons/Construction/superChaingun.cs +++ b/scripts/weapons/Construction/superChaingun.cs @@ -210,13 +210,13 @@ function SuperChaingunImage::onFire(%data,%obj,%slot) { function SuperChaingunImage::onMount(%this,%obj,%slot) { %obj.usingSuperChaingun = true; - if (!%obj.client.superChaingunMode) - %obj.client.superChaingunMode = 0; - if (!%obj.client.superChaingunMode2) - %obj.client.superChaingunMode2 = 0; + if (!%obj.superChaingunMode) + %obj.superChaingunMode = 0; + if (!%obj.superChaingunMode2) + %obj.superChaingunMode2 = 0; %obj.hasMineModes = 1; %obj.hasGrenadeModes = 1; - displayWeaponInfo(%this, %obj, %obj.client.superChaingunMode, %obj.client.superChaingunMode2); + displayWeaponInfo(%this, %obj, %obj.superChaingunMode, %obj.superChaingunMode2); WeaponImage::onMount(%this,%obj,%slot); } @@ -231,17 +231,17 @@ function SuperChaingunImage::changeMode(%this, %obj, %key) { switch(%key) { case 1: //Mine Modes - %obj.client.superChaingunMode++; - %obj.client.superChaingunMode2 = 0; - if (%obj.client.superChaingunMode > 6 - (5 * $host::nopulseSCG)) - %obj.client.superChaingunMode = 0; + %obj.superChaingunMode++; + %obj.superChaingunMode2 = 0; + if (%obj.superChaingunMode > 6 - (5 * $host::nopulseSCG)) + %obj.superChaingunMode = 0; case 2: //Grenade Modes - %obj.client.superChaingunMode2++; - if(%obj.client.superChaingunMode != 1) - %obj.client.superChaingunMode2 = 0; - if (%obj.client.superChaingunMode == 1 && %obj.client.superChaingunMode2 == 2) - %obj.client.superChaingunMode2 = 0; + %obj.superChaingunMode2++; + if(%obj.superChaingunMode != 1) + %obj.superChaingunMode2 = 0; + if (%obj.superChaingunMode == 1 && %obj.superChaingunMode2 == 2) + %obj.superChaingunMode2 = 0; } - displayWeaponInfo(%this, %obj, %obj.client.superChaingunMode, %obj.client.superChaingunMode2); + displayWeaponInfo(%this, %obj, %obj.superChaingunMode, %obj.superChaingunMode2); } From 6541acbd7cc43dfc5e0a54423ef5a6d769987548 Mon Sep 17 00:00:00 2001 From: Robert Fritzen Date: Mon, 4 Aug 2014 19:43:00 -0500 Subject: [PATCH 14/16] Updates Adds missing Flatland files, some minor fixes. --- scripts/TWM2/Systems/Killstreak.cs | 34 ++++++++++++------------ scripts/weapons/Equipment/SWBeaconer.cs | 28 +++++++++---------- terrains/Flatland.nav | Bin 0 -> 540274 bytes terrains/Flatland.spn | Bin 0 -> 738 bytes terrains/Flatland.ter | 1 + 5 files changed, 32 insertions(+), 31 deletions(-) create mode 100644 terrains/Flatland.nav create mode 100644 terrains/Flatland.spn create mode 100644 terrains/Flatland.ter diff --git a/scripts/TWM2/Systems/Killstreak.cs b/scripts/TWM2/Systems/Killstreak.cs index 939b855..5580cb9 100644 --- a/scripts/TWM2/Systems/Killstreak.cs +++ b/scripts/TWM2/Systems/Killstreak.cs @@ -332,103 +332,103 @@ function GameConnection::AwardKillstreak(%client, %streakVal, %plz) { if(%client.ksListInstance.find("UAV") != -1) { %cAmt = getWord(getField(%client.ksListInstance.find("UAV"), 0), 1); } - %client.ksListIntance.advancedAdd("UAV", "UAV "@%cAmt+1); + %client.ksListInstance.advancedAdd("UAV", "UAV "@%cAmt+1); case 2: MessageClient(%client, 'MsgZKill', "\c5TWM2: Airstrike Standing By."); if(%client.ksListInstance.find("Airstrike") != -1) { %cAmt = getWord(getField(%client.ksListInstance.find("Airstrike"), 0), 1); } - %client.ksListIntance.advancedAdd("Airstrike", "Airstrike "@%cAmt+1); + %client.ksListInstance.advancedAdd("Airstrike", "Airstrike "@%cAmt+1); case 3: MessageClient(%client, 'MsgZKill', "\c5TWM2: Guided Missile Strike Standing By."); if(%client.ksListInstance.find("GM") != -1) { %cAmt = getWord(getField(%client.ksListInstance.find("GM"), 0), 1); } - %client.ksListIntance.advancedAdd("GM", "GM "@%cAmt+1); + %client.ksListInstance.advancedAdd("GM", "GM "@%cAmt+1); case 4: MessageClient(%client, 'MsgZKill', "\c5TWM2: Helicopter at your disposal."); if(%client.ksListInstance.find("AIHeli") != -1) { %cAmt = getWord(getField(%client.ksListInstance.find("AIHeli"), 0), 1); } - %client.ksListIntance.advancedAdd("AIHeli", "AIHeli "@%cAmt+1); + %client.ksListInstance.advancedAdd("AIHeli", "AIHeli "@%cAmt+1); case 5: MessageClient(%client, 'MsgZKill', "\c5TWM2: Plasma Harrier Strike at your disposal."); if(%client.ksListInstance.find("Harrier") != -1) { %cAmt = getWord(getField(%client.ksListInstance.find("Harrier"), 0), 1); } - %client.ksListIntance.advancedAdd("Harrier", "Harrier "@%cAmt+1); + %client.ksListInstance.advancedAdd("Harrier", "Harrier "@%cAmt+1); case 6: MessageClient(%client, 'MsgZKill', "\c5TWM2: Satellite Strike at your disposal."); if(%client.ksListInstance.find("OLS") != -1) { %cAmt = getWord(getField(%client.ksListInstance.find("OLS"), 0), 1); } - %client.ksListIntance.advancedAdd("OLS", "OLS "@%cAmt+1); + %client.ksListInstance.advancedAdd("OLS", "OLS "@%cAmt+1); case 7: MessageClient(%client, 'MsgZKill', "\c5TWM2: Gunship Helicopter at your disposal."); if(%client.ksListInstance.find("AIGunHeli") != -1) { %cAmt = getWord(getField(%client.ksListInstance.find("AIGunHeli"), 0), 1); } - %client.ksListIntance.advancedAdd("AIGunHeli", "AIGunHeli "@%cAmt+1); + %client.ksListInstance.advancedAdd("AIGunHeli", "AIGunHeli "@%cAmt+1); case 8: MessageClient(%client, 'MsgZKill', "\c5TWM2: Stealth Bomber at your disposal."); if(%client.ksListInstance.find("Stealth") != -1) { %cAmt = getWord(getField(%client.ksListInstance.find("Stealth"), 0), 1); } - %client.ksListIntance.advancedAdd("Stealth", "Stealth "@%cAmt+1); + %client.ksListInstance.advancedAdd("Stealth", "Stealth "@%cAmt+1); case 9: MessageClient(%client, 'MsgZKill', "\c5TWM2: Harbinger's Wrath Standing By."); if(%client.ksListInstance.find("HarbWrath") != -1) { %cAmt = getWord(getField(%client.ksListInstance.find("HarbWrath"), 0), 1); } - %client.ksListIntance.advancedAdd("HarbWrath", "HarbWrath "@%cAmt+1); + %client.ksListInstance.advancedAdd("HarbWrath", "HarbWrath "@%cAmt+1); case 10: MessageClient(%client, 'MsgZKill', "\c5TWM2: Apache Gunner Standing By."); if(%client.ksListInstance.find("Apache") != -1) { %cAmt = getWord(getField(%client.ksListInstance.find("Apache"), 0), 1); } - %client.ksListIntance.advancedAdd("Apache", "Apache "@%cAmt+1); + %client.ksListInstance.advancedAdd("Apache", "Apache "@%cAmt+1); case 11: MessageClient(%client, 'MsgZKill', "\c5TWM2: AC-130 Gunner Standing By."); if(%client.ksListInstance.find("AC130") != -1) { %cAmt = getWord(getField(%client.ksListInstance.find("AC130"), 0), 1); } - %client.ksListIntance.advancedAdd("AC130", "AC130 "@%cAmt+1); + %client.ksListInstance.advancedAdd("AC130", "AC130 "@%cAmt+1); case 12: MessageClient(%client, 'MsgZKill', "\c5TWM2: Centaur Bombardment Standing By."); if(%client.ksListInstance.find("Artillery") != -1) { %cAmt = getWord(getField(%client.ksListInstance.find("Artillery"), 0), 1); } - %client.ksListIntance.advancedAdd("Artillery", "Artillery "@%cAmt+1); + %client.ksListInstance.advancedAdd("Artillery", "Artillery "@%cAmt+1); case 13: MessageClient(%client, 'MsgZKill', "\c5TWM2: Mass EMP Standing By."); if(%client.ksListInstance.find("EMP") != -1) { %cAmt = getWord(getField(%client.ksListInstance.find("EMP"), 0), 1); } - %client.ksListIntance.advancedAdd("EMP", "EMP "@%cAmt+1); + %client.ksListInstance.advancedAdd("EMP", "EMP "@%cAmt+1); case 14: MessageClient(%client, 'MsgZKill', "\c5TWM2: Nuclear Strike Standing By."); if(%client.ksListInstance.find("NukeStrike") != -1) { %cAmt = getWord(getField(%client.ksListInstance.find("NukeStrike"), 0), 1); } - %client.ksListIntance.advancedAdd("NukeStrike", "NukeStrike "@%cAmt+1); + %client.ksListInstance.advancedAdd("NukeStrike", "NukeStrike "@%cAmt+1); case 15: MessageClient(%client, 'MsgZKill', "\c5TWM2: Zombie Bomb Standing By."); if(%client.ksListInstance.find("ZBomb") != -1) { %cAmt = getWord(getField(%client.ksListInstance.find("ZBomb"), 0), 1); } - %client.ksListIntance.advancedAdd("ZBomb", "ZBomb "@%cAmt+1); + %client.ksListInstance.advancedAdd("ZBomb", "ZBomb "@%cAmt+1); case 16: MessageClient(%client, 'MsgZKill', "\c5TWM2: Fission Bomb Ready... Obliterate everyone!!!"); if(%client.ksListInstance.find("FBomb") != -1) { %cAmt = getWord(getField(%client.ksListInstance.find("FBomb"), 0), 1); } - %client.ksListIntance.advancedAdd("FBomb", "FBomb "@%cAmt+1); + %client.ksListInstance.advancedAdd("FBomb", "FBomb "@%cAmt+1); case 17: MessageClient(%client, 'MsgZKill', "\c5TWM2: Napalm Airstrike at your disposal."); if(%client.ksListInstance.find("Napalm") != -1) { %cAmt = getWord(getField(%client.ksListInstance.find("Napalm"), 0), 1); } - %client.ksListIntance.advancedAdd("Napalm", "Napalm "@%cAmt+1); + %client.ksListInstance.advancedAdd("Napalm", "Napalm "@%cAmt+1); } if(%plz == 0) { if(%client.IsHighestPLStreak(%streakVal)) { diff --git a/scripts/weapons/Equipment/SWBeaconer.cs b/scripts/weapons/Equipment/SWBeaconer.cs index 9c639bb..467d232 100644 --- a/scripts/weapons/Equipment/SWBeaconer.cs +++ b/scripts/weapons/Equipment/SWBeaconer.cs @@ -18,7 +18,7 @@ datablock ItemData(KillstreakBeacon) { friction = 0.6; pickupRadius = 2; pickUpName = "a targeting laser rifle"; - + isKSSW = 1; computeCRC = true; @@ -31,7 +31,7 @@ datablock ShapeBaseImageData(KillstreakBeaconImage) { shapeFile = "weapon_targeting.dts"; item = KillstreakBeacon; offset = "0 0 0"; - + isKSSW = 1; projectile = BasicTargeter; @@ -120,7 +120,7 @@ function DisplayKillstreakInfo(%obj) { %currentStreak = %obj.client.ksListInstance.element(%obj.KSSetMode); %strkName = getWord(%currentStreak, 0); %strkCnt = getWord(%currentStreak, 1); - + switch$(%strkName) { case "UAV": %msg = "UAV Recon"; @@ -157,7 +157,7 @@ function DisplayKillstreakInfo(%obj) { case "Napalm": %msg = "Napalm Airstrike"; } - + commandToClient(%obj.client, 'BottomPrint', ">>>Killstreak Beacon<<<\n"@%msg@" ["@%strkCnt@" Available]\nPress Mine to select next streak, Grenade to select previous streak.", 3, 3); } @@ -178,7 +178,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { } return; } - + switch$(%strkName) { // // @@ -222,7 +222,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { } } } - + // // // Airstrike @@ -238,7 +238,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { %ASCam.mode = "AirstrikeCall"; %obj.client.setControlObject(%ASCam); CameraMessageLoop(%obj.client, %ASCam, %ASCam.mode); - + // // // UAMS @@ -265,7 +265,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { else { %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); } - + // // // Helicopter @@ -622,7 +622,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { else { %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); } - + // // // Napalm @@ -728,7 +728,7 @@ function ConstantBomberTurningLoop(%obj, %TPos) { %SwapA = -1 * getWord(%target, 0); %TVector = getWord(%target, 1)@" "@%SwapA@" 0"; %obj.setRotation(fullrot("0 0 0",%TVector)); - + %dist = vectorDist(%TPos, %BPos); if(%dist < 75) { %obj.ReachedDest = 1; @@ -747,7 +747,7 @@ function Airstrike(%CallerClient, %position, %dirFrom) { %CallerClient.TWM2Core.AirstrikeCalls++; UpdateSWBeaconFile(%CallerClient, "AirStrike"); } - + //new stuff TWM2 2.6 //%dirFrom = Spawn Position of Aircraft %THeight = getTerrainHeight(%dirFrom); @@ -844,7 +844,7 @@ function MakeTheHeli(%cl, %gunner) { if(%gunner $= "") { %gunner = 0; } - + if(%gunner) { %Heli = new FlyingVehicle() { dataBlock = ApacheHelicopter; @@ -961,7 +961,7 @@ function HeliBeginAttack(%heli, %target) { %heli.Targeting = schedule(500, 0, "HeliScan", %heli); return; } - + schedule(500, 0, "HeliBeginAttack", %heli, %target); %clpos = %target.getPosition(); if(vectorDist(%clpos, %pos) < 125) { @@ -1129,7 +1129,7 @@ function MakeTheHeli2(%cl, %harrier) { %Heli.doneAttack = 0; // %Heli.team = %cl.team; - + %heli.canFireMissiles = 1; %heli.Targeting = GunshipHeliScan(%heli); diff --git a/terrains/Flatland.nav b/terrains/Flatland.nav new file mode 100644 index 0000000000000000000000000000000000000000..80cef756b224282b370006b9df7ea11f19a3c930 GIT binary patch literal 540274 zcmeI43z!^LnfK33=Gt@X86#IE!-`y75F|m6m6;BNZ+Toc3c8}mWwDa0w25C7;qu7Fg+v^aglHf7eyIllb8?#Y!V2_GW(uOb=UM{x+bKa zCsx(3i$16N)H&}t=l}oJsjBWFb*lVpyg6K<2IS?{)cY0Y!xIk;4E$5y#sybRQ0j?? zl)Ao8W%a)I%62L>v~8tr+fl6lL`N~s(6*yok?yz3?Dymc2JY*$ef8v(YR?bXufJ`z zYg??pTH=h!tNvY&+4iN(+-q#xjIZBJF^)MXNpZgZwzaNpv3~h6+rDhSb*AlV>DL=) zPo@~h9F(NkZ@nwhTBXeXo%#24+n(v-%j0&w$LM|Uwd=MGg|-8|w(Xty3Uz;{-5=W4 z_GQQ1=-Lhp+~fN7kD+|qrb63Z-t2^W!sK+;j~sC zv~BYPy?uSEZHDl$k8giyzqY>ZcOS29_u@XwgS0K|4{f`zE7JY$XWPm+4|i?#eCyo) z(6*Kb+wcCiZGK?jB_A8IKMWhTzHRIJm9~?-etmI<_G^8yZ4WSqHCJ9=dd%J!hPFM> z6%C$mpC4l${Fp6ErER@A-kC2qU#qQc`(ZOI zy`KB$>+KI6v%l>@=CJO|tM899wCxyIq;+mL`^)o6ot;tl>h&$-+cyU#DXw(~yCU88 zFU)=>Q*683x9=+Y+S+TMo$p7?VgI#Hu8G~34tpK+w>?DKzBe%7t1s8J5w`uP=~rI| zy}o+#_ctvaQNM?}F%NX#=IZNyy?t{~lA>1jdOc{q9mR1z;k%BPZ+nuF^nto-?DfA`hZ($5W$Lw!w&q05EeeQeb)X=uJFWc`?cD~Zr3U8e( z+pq1*w*9zit9AC~=rlLF4ei(8)}H%Pzc5aJobqjpWA;2M->)5~9kcaFU%$LDm%o{cVr2{rc+r$1rrhwlCZ7C(Pm1wyhaw z`F?F*w(YTn`O0-ro@*K_Z|F7GLD~0u^{-;Z++_>=sa@RwcX#gFlJZZjJZr(*O%#coOJrmtks>qzRLFNZ+o0+dvV5VTM|dl zM_$Eiiq=QJ^n5>Q_C%jC&2EmOTVdZEl%&|!*0*g-`<>bOvCP2HA0AdK&p6%hsS@?X z1K${b$h((}fA#F%vBW!z`)bp;N|M{mQe=^X0 zW8c@WziNUho1!^7DnD@kd^28MX4mnijK55&rTKw@pX8OQ>s8Bb+kt_T`lPxrCS}5u ziT8u6CEg0DH!ttitCBj>HZw3#TWEXsWh?U!*WV(jNIlnfz*_Lax;N-fI2HE`oY`WmUnV#l{g>Rn^*)y?=W(c{x?*B099 z@kv?6--jOGz`)Nk{yx;K>8quWjK2^295uz(bNwE(ah*K6J|JbqKCWE%`Ci?NDRcGo zXQi&pzxUFbK2<-%>gUP^e)N+*^@5$p7rnB9Mdo^_=kbHw{=I*be=76B0Uzp9PuqHW z9!GZl>#=gjP^dR)!@hRD-E!_a{Z7m3fDg#?;m(2vg)w)ZR;Z_InR#>y8?LP_J5J6q zDf7)^VBi3`c1$ajebrQ)l2>Y`xfd?_A%3fq3T5hI?Z=dizn=AXo|O6OsYmk{b&OqJ zk(plLbYNh-@N$f>`}ix-x2-*M~G#tMh})v@W7)cU_;F9<2ul}_txKI>3uy0o$F^+o$LEAogd+8SH_4P^TpLY4lF8BJG=sthJ zy z`BN@`-sQh@`G2{5v&&z1`I|0(*X5NJR*yQDH@kea%MWmQyUP!C`H?O^*5xO-yu;-a zT>crCf6nD!bon_hztH8Ey8LpNf8FI*yFBaixh|jY@r!_-d-?${J^1!jvwHVmFm-}1x36qx z^*`$CpNVhUFF5(fgW6x1?#a93ow`l`I~Nb?|2J>2u4+ z_u5O_UBSJ&%Q*TF@xj#^e}o&FUHU6HooJ9_)ZkQ_@pT)e^^^FW?^hq+ z__I2m(?|AfpV!Iw^@m~kdFATWa(K}Aoxf)Mdj4K4iR1Uzj9>S^JL7+NM^EOH-#bg| zYubOK=&ug1I#TQMX2*^HP2uP3>ptK4n|*IzvEZSW-tV2?Jcyr}&%NV~-!#+hCBEj< zjK8~N{JMXsnDzSC<1ZWkM<%|GC2f@YtCyx`B+Gj3uNvK)_x7b+#{X~f*&H|h>+$Q) z1^s_C_%|Fo{$jif()UXH;`vk>@7j|2c;hJ_zsTRv`EM-gZ?OJ-JMPbv)u%*%Uwq&E zP5)WZ!T9U^(Yh$@zr^nyslPscOnjfeSsl;uBl}iE=Wjs#Qoo9N`SdsA_4#f3+YS9q z{nB{8^H)Z%`D)2XmX-g^{H)(W{1ka{`s)y;z4p)TOUzyAvvDN)>sYRRfp4S7NvQ%q zrN>SGx4zb!(QQY{=XI~vn)=ej#9#36+CFbz;tV;zrur1@Uj3kWzWxg1FT4KO_20zOvnXx<_*;jM_vWUL zm##ktU3Xbu+4#lrXLr@U^nS6l|Ng5l9$z+o$@tH_zr);5dSlk@-M;I8@cC`~5AwI@ zr*}UrF^y&mPM$kRe;;2)f7}1?@vrZmA?I%~{{MSuK(~{z+W3F<(w8&dzLbmp_vIza z%6}$)N9v!<=K`Pilw5ybE?nQGnO=W8GiIj{e~f&#ed+Sj_|r#UnwR1t|GSJ|I-cTu zeDRE4rStLT8!&#;R*%n(KkLokj&DeRddRLnJ-@*57wYd{b^RbeeSRCgOP^o7gv;*^>(ah*_y3n2ZJsX*`j_5+PkC_3p!n{2O!sfvy!Etvr{&kbR3GzvSM<+& zUh~@TH)r`Ey}av{H$U6I&)?Gc0s3z_;{-Q1r&o#oy+67*Uv~WV`LUo+>GNo*KGR1Z zqT|VHg!+`k_pSe(I*Pr%7WLEDPaWKguh%zOKZk$5FzctZaJ-a`w=~{hc zuU|5zq1TVnc%|#V9#8Q4UtE8D<9GcHUhhl$`+565c^Ou5ecR>pOHp6%eD^dcy?%M| zih9nL^CK{Rfgkt%f^K5`_1)h}S>gFxA2)6E{b{-LH|YC^()-)e^V|0C8~-lPucAJ_ z@fXJD#+oe|e_?*X&)2%8o$oAd3U-|2N4eUCuYJO_-|y7#oBDpeBwnw?dr0D_bEjXB|G@QA9{j@s+uy0{4;;*A zsXli7F|l>~A$rJsr2k&&zgHh$^yS;~I+y-UoBki9MiSq&)vZdO55G13emPe3vmHDm+xGX*Kxe@EttKwZ`^`uy*D2E4Ws|}KQdLv&B}i!{)XufjKAd% ziyyjVYQsI7Uc93BQ!jmOf^KbJ+0HfnSFb+0Vn*i&j~i#=FFNJ&ygO#buj3!Kc53gq ztFtEl-!>U;vi|rxuKZ5NS@i=a{_B7XIO&Jt_=3Pb~9ZTBi`7g^$mi5}(=T9?M zDO1XK{k8o+te;(U>-_EP5d*Dvh&?2@ZY{B_x< zGP-i{{%vslP2=?V^~+mtm*%~FU0TY^r(T+wk>e(|KJM{ci2rEG{dtkktghdYlE1}} z0A3&V`%T-ol*{wkof(~bedzoDOvT^zZryk3if2@F@8ngDgY~(6F#oQ7b{FxbtkA#g z**UoQox{dA&lkF-t>3p}Q^xIQb?KXj-_omdufKz;NQ{0`kL4hL*01BW03ZMWApa2S>01BW0 z3ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWA zpa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S> z01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>fM0KgkNff0Es2{fB?}PqG5=pJex0|KT70ldJ&zC)s`0fB1+0 zBr5>_Np_$0AO7J#$qK-KlHF(hhky7_vI6j*WcOMB;UE5!tN{Ec*?rc3_=o=_D**pV zcAxbh{^38#3c!Do-DmxWfA~+b0`Q+?_gVkpAO4f90Q@J}eb#^YhyNri0RKsLpYKgkNf zf0Es2{fB?}PqG5=pJex0|KT70ldJ&zC)s`0fB1+0Br5>_Np_$0AO7J#$qK-KlHF(h zhky7_vI6j*WcOMB;UE5!tN{Ec*?rc3_=o=_D**pVcAxbh{^38#3c!Do-DmxWfA~+b z0`Q+?_gVkpAO4f90Q@J}eb#^YhyNri0RKsLpYKgkNff0Es2{fGaA^Z&7<6aA`HszPO+ zIV$zJ9c^k)-dS~Y!=Aj`rybX@NAC%jH@7GF{rY=nH1Ekf(|1Gj-h6l6dRF_MyxVX2 zc*CB&)vv$OyeIEtMjh6$H{Y+X+^2zebT#OI<5Nw0^#01Y1N(WS!Cqou;ce~hywLy# zU;qYopMk78u$?y=M3sTe+n;Oa{r)xRzwC?6ywLy#U;qYSV0RhFszVOkoA3PbCmqNe z4PXEU-VX!IcOKQw8x3F}nhdo6_l@m)^SyBA;Ro|Z0~mk-7=Qs7fB_hQ0T_S*7=Qs7 zfB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ z0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S* z7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7 zfB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ z0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S* z7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7 zfB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ z0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S* z7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7 zfB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ z0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S* z7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7 zfB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*7=Qs7fB_hQ0T_S*82IyKpmTZG z1hw`2;=8?T0$%-jdWA3e5;g;BwVeC%zUKwE25|l#9Ja>96*<5EqjGFXQlL^+yutog<=B#mUVu3|7&w>aaN#4*7)-N*X7vasz9x*@4^1p=h)(?K%K1ZBlAC%V~d*t^|G#y z-2a9gTbvX~$(p`<{x{~>;-WxNXyzCj{j{rwx}u4D(iM={;Sb!QBpw8SNu;f zv-lsSvo-v&;(z#>MkylxN6D@5$BO^qYZ|49_#Y*=!XGRChp%arBI19P+zNlJ_#eKe zQHqHFQF1H%vEqODnno!i{zu8J@W+b(;cFVDi1;5Rx56JQ{)ew=lp^APl-vq`toR?k zrcsKB|50)){ITMH_?kv3BK}9ot?MkylxN6D@5$BO^qYZ|49_#Y*=!XGRChp%arBI19P+zNlJ z_#eKeQHqHFQF1H%vEqODnno!i{zu8J@W+b(;cFVDi1;5Rx56JQ{)ew=lp^APl-vq` ztoR?krcsKB|50)){ITMH_?kv3BK}9ot?MkylxN6D@5$BO^qYZ|49_#Y*=!XGRChp%arBI19P z+zNlJ_#eKeQHqHFQF1H%vEqODnno!i{zu8J@W+b(;cFVDi1;5Rx56JQ{)ew=lp^AP zl-vq`toR?krcsKB|50)){ITMH_?kv3BK`-vB^tRcxNg*H;Qy{2o7>jeR@Jty_1@N= z)?8uhk*`eEo$A= zdU^~P!2iMipDE}3MXm3O>u03X=@(n>YgycqD{PD9^NTHMIo6YYH+_+;1!qQ_0sJre zpOY1TYU_^lOmTjB%Q-Fkw)8izY+l@)D{PD9bAR)`a%{O!Ff+X)Jyos-xd=0W|DOL> zwykX)+uD=fH=S!atfjAca`Twx^-T{nEosUXwk7g;ebX2@*4KQPtP1?}e|ChAgE7$u;>0h;Uw5)8-G(Xccwdsha&5aK>E@{jawk7g;bK?)EtM;5x5?+7sZQacs&Q6hwOkiYko$o}LO@Ec0#UpVz<)Kms%@;S{ENl?!<(lz zJt61)(uRW@mZc`9RBBEA?e)3Bc6V908D{Mcmd#o-cU#(wXcSYSkbx+pb zQJX7lcho*vyN{HwuluU31Gl91uRU0vM`wTIL`UvpPYuCU!z^L))AwKvq($%=4d{igccWDOWA z_W{3cTG^aynJM20MeRGmr2D@~?)%f}!&)-U=gM8*Qd#*`>cskPIq%2T-c@sa&CAty zSLX`b-PJEwA1_3Vm35$72vBkrSlTd4o&_@UeLz~C12#o$1xU94bK4flwST#M+w+V( z@l`b*+;EDl{5f&|gSC@u)>cof-cq%!Dp%N+Rc)!7SiQD-a?J;YfSgohX*nZ(T5D&do&u8Xe^pzmHJ#qK zWlZxCa_#SIn3y`R{tCJ7-zDe1svcjJ8`U;yWo53gt*mSl7RCz!Ypd_7xuN!oy7THM z%J%_dt*$SL%!`%sZ{+wb%)d*Uo%n8{oJVM zD#ul>s>l_#RTbkZpR3Ht8Zc4r0}hdAft1_>>`cAUu(@%4Q-AY|EiXju86esI-`o1r z^nG&g|A0LA=NneZ>i?Kr`=6J)zAduyw~ZQC`L&8?Rj#l-tG*@#w8>RqOV!KO&(}Oz z`mp^&j9ze{8YXPj?yz=vi zURJe2R{mAu{wP&^jZ)95RTV2MSBzR#b+=pr?x_87-R<%exU^wOjal1<<>3Q(?C>h!y#}>3@-gSgC;jBRv1{ zKW10H-8}zgS_lWhO_{x{kF^ZQS-{pa`J zWc$zGeu2t#{TPn1A>45CE#!1V(q{FdjS6Z zr?P(o8FT;jm4JW$t<2xRCcuBq0RR5uFnJY%0Hz@$Wy! z?*Dx7JDlA8r2qb#T;~gG+sOYPsD!Tnab|?`KhEw3&kg^BHHvc${ExG{!E?j^V2$Ej z1OMafZt&djKUkwU*TDZcyBj<={14VB&Nc8q&h7@!4gZ5RigOM8kF&eMbHo2&jpAGb z|Ksd#@Z9h}Sfe=C!2dYA8$37s57sEoHSj;q?gq~d|ARG(a}E5Dv%A4_!~bB7;#>p& zV|2VrFJU9Fg)+o+3@ITJ(2G0%ugEfkC4g8O@yTNnA|6q;cTm%2( z>~8Sf@IP3iIM=}cIJ+A>H~bIQD9$zTKhEw3&kg^BHHvc${ExG{!E?j^V2$Ej1OMaf zZt&djKUkwU*TDZcyBj<={14VB&Nc8q&h7@!4gZ5RigOM8kF&eMbHo2&jpAGb|Ksd# z@Z9h}Sfe=C!2dYA8$37s57sEoHSj;q?gq~d|ARG(a}E5Dv%A4_!~bB7;#>p&V|2VrFJU9Fg)+o+3@ITJ(2G0%ugEfkC4g8O@yTNnA|6q;cTm%2(>~8Sf z@IP3iIM=}cIJ+A>H~bIQD9$zTKhEw3&kg^BHHvc${ExG{!E?j^V2$Ej1OMafZt&dj zKUkwU*TDZcyBj<={14VB&Nc8q&h7@!4gZ5RigOM8kF&eMbHo2&jpAGb|Ksd#@Z9h} zSfe=C!2dYA8$37s57sEoHSj;q?gq~d|ARG(a}E5Dv%A4_3)_E*#}+LGT65`KORhQB zlxxg2jZiVB2r{wlBn1F%J1f%kj=*C_XZY;jQF z{oMaI$TI+2Tol;d=f9LZ1G2?Qf!%rjub1xt*y5(ZNWcH7lkb4o;;6t#zW=M0?*Q52 zszA{9zcun5Fk74zDEIw;wfqLa7Iy`P`~9a%egk4lf&#nx{cn`~2FR8a1xkPat(4z@ z*^;Dy|M&k2`5OSXq$%M2{fGV=5Viy=U;rRVumUS&?ltnx%ck?JDO$RU*pQNF2BZ=XC>FVWkeaBYlXBG?Kea`u1^X1~N_0Q%D-SMo;7rNtF$u$T4s@?Hm^L{C_ zeAv9l9nZSF#~sf~u3z2Gmsu|FcD~G#T(S<#fzQZqK`nY1ifS%DB8sV%d1g)l=$&BG6mv0HrG4HtAdHLuOy6JI(%^ zCf%t%EG2K6^lg*AWzu#vMxq`oJt%dCq?PKkCOuXiEG1)2`UR8j&}qdP>Mx|uMf0urWYQ;1`jkmGn{>W9PU>7> z(i=^>P<_%w*6Ad(f1^5H_P=P-FPQW}w|{~u*XdhoqV)c@Nq3s`O}GD9DSuP6R2656 zu9fOdNwp(7Jy%Am)R#^AU6bzAsnpkLm-@UMJ;$W;O}ay;6|b57^VJvR=vgLRWYSC2 z-$}`hCY@x`Z_B9l>~wmrNq6W}BA+EC-!bV;Cf%XaiiPS+QhtL;7npR1PAk4EW7KNs zbb(2C=(OS@b+(jTVA2I9{f@Y#ue&;3VA5Ajy2YgD%WSkGI=#`Q=gR&<8J#ZI>8mDP zB%bRMoh~rxP2#pv-!kd9O}bFdCZ)b>(wj`W#g$xOYU*^pj83UPnskdvA2I2-WHw4I zl6bmzoqk8=t<+5>z0suKmDakBP8XQ;CK-{gsneUJol@U7>35|}@9XrBCVj-D+m+lY zRcuiANV?vne=zBGlWsHV@729>bfrn3HR*PfZZqiy_3v_Yok=&Ebel;xsFkK%ryI@w zHj{2v4@k+Q>OqxKn=o-i?=Fh`#- zF?IT+lgaTv zNq?hWko}j{uO<{$tJVES<)t%mrmEnRZiE` z>FXxlDru!0?Kd;(mpU8N?j!2}dcEFpo`Ku}kT_TVbw^G$(L*5ij5k*gC`TUxi|^Q@d9c{=(?O7UirZo*i|eXR zAa=(8xlZ?dE`ZIMIrr_s8C#};+3706hn!yS1e;?PBkp9gb~c#JDUy6}OZz0SIr`m( z2M%n}1haW3nL1sKHU+EMY$bf~N6&JwIi72_I)2L(0jtqGxAx#$g?unuEN|_BPv1U* z*?k7pPW<9rV7*IEw;x>MaCJY(Z6bFj9-Q`isRM}pV~Mn*&&>s3zeHT?JIL+58Lao! zmn#la?Pr47vd1SJobzAZ5v2Z`#~DX8!_#1Kv*T+I7Hgz}&EIx*x})^$RIqr`6K023 z(;$8cX1?G!!B!D${!Hna2c4=Wg4N8Di*xF#+5*;l`h$?e+MmzC;`?f}o&HQa;|Q|L zsbr^N>XBP`|zZCY-E+3J&KAJoq`0f&!5 z+MR=%OL`nZZdh=8g8lk7VX)q}C)AvR`L=@nHS7CAhxap9fz{i(m^j>x*9WU-Vn7Ec XoER8RI5D!Ii-Y+PNd_Yz2c!T1t!*48 literal 0 HcmV?d00001 diff --git a/terrains/Flatland.ter b/terrains/Flatland.ter new file mode 100644 index 0000000..d1eda4c --- /dev/null +++ b/terrains/Flatland.ter @@ -0,0 +1 @@ +€ € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € à € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € € DesertWorld.SandOrangeDesertWorld.RockSmoothÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ \ No newline at end of file From e80004bbd8e5569336e3aa163c1dca5ff7f96074 Mon Sep 17 00:00:00 2001 From: Robert Fritzen Date: Tue, 12 Aug 2014 16:16:58 -0500 Subject: [PATCH 15/16] Fixed up the killstreaks --- scripts/TWM2/ChatCommands/SuperAdmin.cs | 44 +++--- scripts/TWM2/CustomCamera.cs | 119 ++++++++-------- scripts/TWM2/LoadMod.cs | 3 + scripts/TWM2/Systems/Killstreak.cs | 117 ++++++---------- scripts/TWM2/Systems/List.cs | 14 +- scripts/weapons/Equipment/SWBeaconer.cs | 177 ++++++------------------ 6 files changed, 190 insertions(+), 284 deletions(-) diff --git a/scripts/TWM2/ChatCommands/SuperAdmin.cs b/scripts/TWM2/ChatCommands/SuperAdmin.cs index 8ea782a..553dfa6 100644 --- a/scripts/TWM2/ChatCommands/SuperAdmin.cs +++ b/scripts/TWM2/ChatCommands/SuperAdmin.cs @@ -275,89 +275,89 @@ function parseSuperAdminCommands(%sender, %command, %args) { } %cAmt = 0; - %sw = getWord(%args,1); + %sw = strlwr(getWord(%args,1)); switch$(%sw) { - case "UAV": + case "uav": %target.AwardKillstreak(1, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a UAV Recon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a UAV Beacon."); - case "Airstrike": + case "airstrike": %target.AwardKillstreak(2, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" an airstrike beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you an airstrike."); - case "UAMS": + case "uams": %target.AwardKillstreak(3, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a UAMS beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a UAMS Strike."); - case "UnlimUAMS": + case "unlimuams": messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a fully loaded UAMS."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a fully loaded UAMS."); CreateMissileSat(%target, 1); - case "Helicopter": + case "helicopter": %target.AwardKillstreak(4, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Helicopter beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Helicopter beacon."); - case "HeliGunner": + case "heligunner": MakeTheHeli(%target, 1); messageClient(%sender, 'MsgClient', "\c2You made "@%target.namebase@" a chopper gunner."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" has granted you Helicopter Gunner Access."); - case "Harbingers": + case "harbingers": %target.AwardKillstreak(9, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Harbinger's Wrath beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Harbinger's Wrath beacon."); - case "UnlimHarbin": + case "unlimharbin": messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" gunship support."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you gunship support."); startHarbingersWrath(%target, 1, 1); - case "UnlimAC130": + case "unlimac130": messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" AC-130 gunship support."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you AC-130 gunship support."); startAC130(%target, 1, 1); - case "GunHeli": + case "gunheli": %target.AwardKillstreak(7, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Gunship Helicopter beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Gunship Helicopter beacon."); - case "Apache": + case "apache": %target.AwardKillstreak(10, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" an Apache Gunner beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you an Apache Gunner beacon."); - case "Artillery": + case "artillery": %target.AwardKillstreak(12, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Centaur Artillery beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Centaur Artillery beacon."); - case "Nuke": + case "nuke": %target.AwardKillstreak(14, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Nuclear Strike beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Nuclear Strike beacon."); - case "ZBomb": + case "zbomb": %target.AwardKillstreak(15, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Zombie-Bomb beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Zombie-Bomb beacon."); - case "Harrier": + case "harrier": %target.AwardKillstreak(5, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Harrier Airstrike beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Harrier Airstrike beacon."); - case "Stealth": + case "stealth": %target.AwardKillstreak(8, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Stealth Airstrike beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Stealth Airstrike beacon."); - case "AC130": + case "ac130": %target.AwardKillstreak(11, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" an AC-130 beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you an AC-130 beacon."); - case "SatNuke": + case "satnuke": %target.AwardKillstreak(6, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Orbital Laser Strike beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Orbital Laser Strike beacon."); - case "Fission": + case "fission": %target.AwardKillstreak(16, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Fission Bomb :D."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Fission Bomb :D."); - case "EMP": + case "emp": %target.AwardKillstreak(13, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Mass EMP Beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Mass EMP Beacon."); - case "Napalm": + case "napalm": %target.AwardKillstreak(17, -1); messageClient(%sender, 'MsgClient', "\c2You gave "@%target.namebase@" a Napalm Airstrike beacon."); messageClient(%target, 'MsgClient', "\c2"@%sender.namebase@" gave you a Napalm Airstrike beacon."); diff --git a/scripts/TWM2/CustomCamera.cs b/scripts/TWM2/CustomCamera.cs index 6731ec3..50b09a9 100644 --- a/scripts/TWM2/CustomCamera.cs +++ b/scripts/TWM2/CustomCamera.cs @@ -54,7 +54,7 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { //press JET if (%trigger == 3) { //Can we Call in this airstrike? - if(%client.ksListInstance.find("Airstrike") == -1 && !%client.UnlimitedAS) { + if(%client.streakCount[2] <= 0 && !%client.UnlimitedAS) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); @@ -79,18 +79,19 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); if(!%client.UnlimitedAS) { - %newCt = getField(%client.ksListInstance.find("Airstrike"), 1) - 1; - if(%newCt == 0) { - %client.ksListInstance.removeElement(getField(%client.ksListInstance.find("Airstrike"), 1)); - } - else { - %client.ksListInstance.set(getField(%client.ksListInstance.find("Airstrike"), 1), "Airstrike" SPC %newCt); - } + %client.streakCount[2]--; GainExperience(%client, 35, "Airstrike called in "); } bottomPrint(%client, "Coordinates Confirmed, Calling In Airstrike", 5, 2); messageTeam(%client.team, 'MsgAirstrike', "\c5TWM2: Airstrike Called In From "@%client.namebase@""); Airstrike(%client, %position, %direction); + //Post-Fire Checks + if(getWordCount(%client.streakList()) == 0 && !%client.UnlimitedAS) { + //No more streaks in the list... + %obj.throwWeapon(1); + %obj.throwWeapon(0); + %obj.setInventory(KillstreakBeacon, 0, true); + } } else { bottomPrint(%client, "Player Object Required", 5, 2); @@ -101,7 +102,7 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { //press JET if (%trigger == 3) { //Can we Call in this airstrike? - if(%client.ksListInstance.find("Harrier") == -1) { + if(%client.streakCount[5] <= 0) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); @@ -123,17 +124,18 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); - %newCt = getField(%client.ksListInstance.find("Harrier"), 1) - 1; - if(%newCt == 0) { - %client.ksListInstance.removeElement(getField(%client.ksListInstance.find("Harrier"), 1)); - } - else { - %client.ksListInstance.set(getField(%client.ksListInstance.find("Harrier"), 1), "Harrier" SPC %newCt); - } + %client.streakCount[5]--; GainExperience(%client, 150, "Harrier Airstrike called in "); messageTeam(%client.team, 'MsgAirstrike', "\c5TWM2: "@%client.namebase@"'s Harrier Airstrike is Approaching."); bottomPrint(%client, "Coordinates Confirmed, Calling In Harriers", 5, 2); HarrierAirstrike(%client, %position, %direction); + //Post-Fire Checks + if(getWordCount(%client.streakList()) == 0) { + //No more streaks in the list... + %obj.throwWeapon(1); + %obj.throwWeapon(0); + %obj.setInventory(KillstreakBeacon, 0, true); + } } else { bottomPrint(%client, "Player Object Required", 5, 2); @@ -144,7 +146,7 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { //press JET if (%trigger == 3) { //Can we Call in this airstrike? - if(%client.ksListInstance.find("Napalm") == -1) { + if(%client.streakCount[17] <= 0) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); @@ -166,17 +168,18 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); - %newCt = getField(%client.ksListInstance.find("Napalm"), 1) - 1; - if(%newCt == 0) { - %client.ksListInstance.removeElement(getField(%client.ksListInstance.find("Napalm"), 1)); - } - else { - %client.ksListInstance.set(getField(%client.ksListInstance.find("Napalm"), 1), "Napalm" SPC %newCt); - } + %client.streakCount[17]--; GainExperience(%client, 350, "Napalm Airstrike called in "); messageTeam(%client.team, 'MsgAirstrike', "\c5TWM2: "@%client.namebase@"'s Napalm Airstrike is coming in hot."); bottomPrint(%client, "Coordinates Confirmed, Calling In Strike Fighters", 5, 2); NapalmHarrierAirstrike(%client, %position, %direction); + //Post-Fire Checks + if(getWordCount(%client.streakList()) == 0) { + //No more streaks in the list... + %obj.throwWeapon(1); + %obj.throwWeapon(0); + %obj.setInventory(KillstreakBeacon, 0, true); + } } else { bottomPrint(%client, "Player Object Required", 5, 2); @@ -187,7 +190,7 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { //press JET if (%trigger == 3) { //Can we Call in this airstrike? - if(%client.ksListInstance.find("OLS") == -1) { + if(%client.streakCount[6] <= 0) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); @@ -201,17 +204,18 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); - %newCt = getField(%client.ksListInstance.find("OLS"), 1) - 1; - if(%newCt == 0) { - %client.ksListInstance.removeElement(getField(%client.ksListInstance.find("OLS"), 1)); - } - else { - %client.ksListInstance.set(getField(%client.ksListInstance.find("OLS"), 1), "OLS" SPC %newCt); - } + %client.streakCount[6]--; GainExperience(%client, 350, "Orbital Laser Strike Called In "); messageTeam(%client.team, 'MsgAirstrike', "\c5TWM2: "@%client.namebase@"'s Laser Strike is Incoming."); bottomPrint(%client, "Coordinates Confirmed, Spinning Laser Cannon", 5, 2); OrbitalLaserStrike(%client, %position); + //Post-Fire Checks + if(getWordCount(%client.streakList()) == 0) { + //No more streaks in the list... + %obj.throwWeapon(1); + %obj.throwWeapon(0); + %obj.setInventory(KillstreakBeacon, 0, true); + } } else { bottomPrint(%client, "Player Object Required", 5, 2); @@ -222,7 +226,7 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { //press JET if (%trigger == 3) { //Can we Call in this airstrike? - if(%client.ksListInstance.find("Stealth") == -1) { + if(%client.streakCount[8] <= 0) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); @@ -244,16 +248,17 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); - %newCt = getField(%client.ksListInstance.find("Stealth"), 1) - 1; - if(%newCt == 0) { - %client.ksListInstance.removeElement(getField(%client.ksListInstance.find("Stealth"), 1)); - } - else { - %client.ksListInstance.set(getField(%client.ksListInstance.find("Stealth"), 1), "Stealth" SPC %newCt); - } + %client.streakCount[8]--; GainExperience(%client, 150, "Stealth Bomber Airstrike called in "); bottomPrint(%client, "Coordinates Confirmed, Calling In Stealth Bomber", 5, 2); StealthAirstrike(%client, %position, %direction); + //Post-Fire Checks + if(getWordCount(%client.streakList()) == 0) { + //No more streaks in the list... + %obj.throwWeapon(1); + %obj.throwWeapon(0); + %obj.setInventory(KillstreakBeacon, 0, true); + } } else { bottomPrint(%client, "Player Object Required", 5, 2); @@ -264,7 +269,7 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { //press JET if (%trigger == 3) { //Can we Call in this airstrike? - if(%client.ksListInstance.find("Artillery") == -1) { + if(%client.streakCount[12] <= 0) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); @@ -278,17 +283,18 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); - %newCt = getField(%client.ksListInstance.find("Artillery"), 1) - 1; - if(%newCt == 0) { - %client.ksListInstance.removeElement(getField(%client.ksListInstance.find("Artillery"), 1)); - } - else { - %client.ksListInstance.set(getField(%client.ksListInstance.find("Artillery"), 1), "Artillery" SPC %newCt); - } + %client.streakCount[12]--; GainExperience(%client, 250, "Artillery called in "); bottomPrint(%client, "Coordinates Confirmed, Calling In Artillery", 5, 2); messageTeam(%client.team, 'MsgAirstrike', "\c5TWM2: Artillery Called In From "@%client.namebase@""); Artillery(%client, %position); + //Post-Fire Checks + if(getWordCount(%client.streakList()) == 0) { + //No more streaks in the list... + %obj.throwWeapon(1); + %obj.throwWeapon(0); + %obj.setInventory(KillstreakBeacon, 0, true); + } } else { bottomPrint(%client, "Player Object Required", 5, 2); @@ -299,7 +305,7 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { //press JET if (%trigger == 3) { //Can we Call in this airstrike? - if(%client.ksListInstance.find("NukeStrike") == -1) { + if(%client.streakCount[14] <= 0) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); @@ -313,17 +319,18 @@ function TWM2ControlCamera::onTrigger(%data,%obj,%trigger,%state) { if(isObject(%client.player)) { %obj.schedule(1000, "delete"); %client.setControlObject(%client.player); - %newCt = getField(%client.ksListInstance.find("NukeStrike"), 1) - 1; - if(%newCt == 0) { - %client.ksListInstance.removeElement(getField(%client.ksListInstance.find("NukeStrike"), 1)); - } - else { - %client.ksListInstance.set(getField(%client.ksListInstance.find("NukeStrike"), 1), "NukeStrike" SPC %newCt); - } + %client.streakCount[14]--; GainExperience(%client, 500, "Nuclear Missile called in "); bottomPrint(%client, "Coordinates Confirmed, Launching Missile", 5, 2); messageAll('msgDanger', "\c5TWM2 ALERT: "@%client.namebase@" has activated a nuclear missile!!! ~wfx/misc/red_alert.wav"); Nuke(%client, %position); + //Post-Fire Checks + if(getWordCount(%client.streakList()) == 0) { + //No more streaks in the list... + %obj.throwWeapon(1); + %obj.throwWeapon(0); + %obj.setInventory(KillstreakBeacon, 0, true); + } } else { bottomPrint(%client, "Player Object Required", 5, 2); diff --git a/scripts/TWM2/LoadMod.cs b/scripts/TWM2/LoadMod.cs index 600e0a2..0877332 100644 --- a/scripts/TWM2/LoadMod.cs +++ b/scripts/TWM2/LoadMod.cs @@ -155,3 +155,6 @@ Error("********************************************"); Error("************* EXECUTE COMPLETE *************"); Error("********************************************"); Error("********************************************"); + +//POST LOAD TASKS..... +//OrderStreaks(); diff --git a/scripts/TWM2/Systems/Killstreak.cs b/scripts/TWM2/Systems/Killstreak.cs index 5580cb9..0b81e57 100644 --- a/scripts/TWM2/Systems/Killstreak.cs +++ b/scripts/TWM2/Systems/Killstreak.cs @@ -18,6 +18,31 @@ $Killstreak[15] = "Z-Bomb\t-1\t"@$Killstreak::Kills["ZBomb", 1]@"\tWipe out all $Killstreak[16] = "Fission Bomb\t"@$Killstreak::Kills["Fission", 0]@"\t-1\t(Matches) End the game with an explosive bang."; $Killstreak[17] = "Napalm Airstrike\t"@$Killstreak::Kills["Napalm", 0]@"\t"@$Killstreak::Kills["Napalm", 1]@"\tQuick destructive airstrike with remaining fire."; +//Phantom: V3.9: Order the streaks based on killcounts... +function OrderStreaks() { + echo("Ordering Killstreak List..."); + for(%i = 1; %i <= $KillstreakCount; %i++) { + %cur = getField($Killstreak[%i], 1); + + %temp = $Killstreak[%i]; + $OrderedKillstreak[%i] = $Killstreak[%i]; + + for(%x = 1; %x <= %i; %x++) { + %mine = getField($Killstreak[%x], 1); + //This streak has a lower count, sift it down + if(%mine < %cur) { + $OrderedKillstreak[%i] = $Killstreak[%x]; + $OrderedKillstreak_CONVINDX[%i] = %x; + $OrderedKillstreak[%x] = %temp; + $OrderedKillstreak_CONVINDX[%x] = %i; + } + } + } + echo("Complete..."); + for(%r = 1; %r <= $KillstreakCount; %r++) { + echo(""@%r@": "@$OrderedKillstreak[%r]@" => "@$OrderedKillstreak_CONVINDX[%r]); + } +} function GetStreakDescrip(%val) { %desc = getField($Killstreak[%val], 3); @@ -301,7 +326,7 @@ function GiveTWM2Weapons(%client) { if(%client.HasFullTeamRespawn) { %client.player.setInventory(FullTeamRespawnCaller, 1, true); } - if(%client.ksListInstance.count() > 0) { + if(getWordCount(%client.streakList()) > 0) { %client.player.setInventory(KillstreakBeacon, 1, true); } if(!%client.isconfiscated) { @@ -311,6 +336,21 @@ function GiveTWM2Weapons(%client) { } } +function GameConnection::streakList(%client) { + %total = ""; + for(%i = 1; %i <= $KillstreakCount; %i++) { + if(%client.streakCount[%i] > 0) { + if(%total $= "") { + %total = %i; + } + else { + %total = %total @ " " @ %i; + } + } + } + return %total; +} + function GameConnection::AwardKillstreak(%client, %streakVal, %plz) { if(%plz $= "") { %plz = 1; @@ -319,117 +359,46 @@ function GameConnection::AwardKillstreak(%client, %streakVal, %plz) { if($Killstreak::Setting == 4) { return; } - if(!%client.isActiveStreak(%streakVal) && ($Killstreak::Setting != 2) && !$TWM::PlayingHelljump) { + if(%plz != -1 && (!%client.isActiveStreak(%streakVal) && ($Killstreak::Setting != 2) && !$TWM::PlayingHelljump)) { return; } - if(!isSet(%client.ksListInstance)) { - %client.ksListInstance = initList(); - } - %cAmt = 0; switch(%streakVal) { case 1: MessageClient(%client, 'MsgZKill', "\c5TWM2: UAV Recon at Your Disposal."); - if(%client.ksListInstance.find("UAV") != -1) { - %cAmt = getWord(getField(%client.ksListInstance.find("UAV"), 0), 1); - } - %client.ksListInstance.advancedAdd("UAV", "UAV "@%cAmt+1); case 2: MessageClient(%client, 'MsgZKill', "\c5TWM2: Airstrike Standing By."); - if(%client.ksListInstance.find("Airstrike") != -1) { - %cAmt = getWord(getField(%client.ksListInstance.find("Airstrike"), 0), 1); - } - %client.ksListInstance.advancedAdd("Airstrike", "Airstrike "@%cAmt+1); case 3: MessageClient(%client, 'MsgZKill', "\c5TWM2: Guided Missile Strike Standing By."); - if(%client.ksListInstance.find("GM") != -1) { - %cAmt = getWord(getField(%client.ksListInstance.find("GM"), 0), 1); - } - %client.ksListInstance.advancedAdd("GM", "GM "@%cAmt+1); case 4: MessageClient(%client, 'MsgZKill', "\c5TWM2: Helicopter at your disposal."); - if(%client.ksListInstance.find("AIHeli") != -1) { - %cAmt = getWord(getField(%client.ksListInstance.find("AIHeli"), 0), 1); - } - %client.ksListInstance.advancedAdd("AIHeli", "AIHeli "@%cAmt+1); case 5: MessageClient(%client, 'MsgZKill', "\c5TWM2: Plasma Harrier Strike at your disposal."); - if(%client.ksListInstance.find("Harrier") != -1) { - %cAmt = getWord(getField(%client.ksListInstance.find("Harrier"), 0), 1); - } - %client.ksListInstance.advancedAdd("Harrier", "Harrier "@%cAmt+1); case 6: MessageClient(%client, 'MsgZKill', "\c5TWM2: Satellite Strike at your disposal."); - if(%client.ksListInstance.find("OLS") != -1) { - %cAmt = getWord(getField(%client.ksListInstance.find("OLS"), 0), 1); - } - %client.ksListInstance.advancedAdd("OLS", "OLS "@%cAmt+1); case 7: MessageClient(%client, 'MsgZKill', "\c5TWM2: Gunship Helicopter at your disposal."); - if(%client.ksListInstance.find("AIGunHeli") != -1) { - %cAmt = getWord(getField(%client.ksListInstance.find("AIGunHeli"), 0), 1); - } - %client.ksListInstance.advancedAdd("AIGunHeli", "AIGunHeli "@%cAmt+1); case 8: MessageClient(%client, 'MsgZKill', "\c5TWM2: Stealth Bomber at your disposal."); - if(%client.ksListInstance.find("Stealth") != -1) { - %cAmt = getWord(getField(%client.ksListInstance.find("Stealth"), 0), 1); - } - %client.ksListInstance.advancedAdd("Stealth", "Stealth "@%cAmt+1); case 9: MessageClient(%client, 'MsgZKill', "\c5TWM2: Harbinger's Wrath Standing By."); - if(%client.ksListInstance.find("HarbWrath") != -1) { - %cAmt = getWord(getField(%client.ksListInstance.find("HarbWrath"), 0), 1); - } - %client.ksListInstance.advancedAdd("HarbWrath", "HarbWrath "@%cAmt+1); case 10: MessageClient(%client, 'MsgZKill', "\c5TWM2: Apache Gunner Standing By."); - if(%client.ksListInstance.find("Apache") != -1) { - %cAmt = getWord(getField(%client.ksListInstance.find("Apache"), 0), 1); - } - %client.ksListInstance.advancedAdd("Apache", "Apache "@%cAmt+1); case 11: MessageClient(%client, 'MsgZKill', "\c5TWM2: AC-130 Gunner Standing By."); - if(%client.ksListInstance.find("AC130") != -1) { - %cAmt = getWord(getField(%client.ksListInstance.find("AC130"), 0), 1); - } - %client.ksListInstance.advancedAdd("AC130", "AC130 "@%cAmt+1); case 12: MessageClient(%client, 'MsgZKill', "\c5TWM2: Centaur Bombardment Standing By."); - if(%client.ksListInstance.find("Artillery") != -1) { - %cAmt = getWord(getField(%client.ksListInstance.find("Artillery"), 0), 1); - } - %client.ksListInstance.advancedAdd("Artillery", "Artillery "@%cAmt+1); case 13: MessageClient(%client, 'MsgZKill', "\c5TWM2: Mass EMP Standing By."); - if(%client.ksListInstance.find("EMP") != -1) { - %cAmt = getWord(getField(%client.ksListInstance.find("EMP"), 0), 1); - } - %client.ksListInstance.advancedAdd("EMP", "EMP "@%cAmt+1); case 14: MessageClient(%client, 'MsgZKill', "\c5TWM2: Nuclear Strike Standing By."); - if(%client.ksListInstance.find("NukeStrike") != -1) { - %cAmt = getWord(getField(%client.ksListInstance.find("NukeStrike"), 0), 1); - } - %client.ksListInstance.advancedAdd("NukeStrike", "NukeStrike "@%cAmt+1); case 15: MessageClient(%client, 'MsgZKill', "\c5TWM2: Zombie Bomb Standing By."); - if(%client.ksListInstance.find("ZBomb") != -1) { - %cAmt = getWord(getField(%client.ksListInstance.find("ZBomb"), 0), 1); - } - %client.ksListInstance.advancedAdd("ZBomb", "ZBomb "@%cAmt+1); case 16: MessageClient(%client, 'MsgZKill', "\c5TWM2: Fission Bomb Ready... Obliterate everyone!!!"); - if(%client.ksListInstance.find("FBomb") != -1) { - %cAmt = getWord(getField(%client.ksListInstance.find("FBomb"), 0), 1); - } - %client.ksListInstance.advancedAdd("FBomb", "FBomb "@%cAmt+1); case 17: MessageClient(%client, 'MsgZKill', "\c5TWM2: Napalm Airstrike at your disposal."); - if(%client.ksListInstance.find("Napalm") != -1) { - %cAmt = getWord(getField(%client.ksListInstance.find("Napalm"), 0), 1); - } - %client.ksListInstance.advancedAdd("Napalm", "Napalm "@%cAmt+1); } + %client.streakCount[%streakVal]++; if(%plz == 0) { if(%client.IsHighestPLStreak(%streakVal)) { %client.player.killsinarow = 0; //reset for moar killstreaks! diff --git a/scripts/TWM2/Systems/List.cs b/scripts/TWM2/Systems/List.cs index ce72eda..3c324cf 100644 --- a/scripts/TWM2/Systems/List.cs +++ b/scripts/TWM2/Systems/List.cs @@ -12,10 +12,13 @@ function initList() { } function ListInstance::advancedAdd(%this, %elementTxt, %newValue) { + echo("AdvancedAdd("@%this@", "@%elementTxt@", "@%newValue@")"); if(%this.find(%elementTxt) == -1) { + echo("AdvancedAdd: Add New"); %this.addElement(%newValue); } else { + echo("AdvancedAdd: Replace Old"); %indx = getField(%this.find(%elementTxt), 1); %this.set(%indx, %newValue); } @@ -26,6 +29,7 @@ function ListInstance::set(%this, %index, %new) { } function ListInstance::addElement(%this, %element) { + echo("Add "@%element@" => "@%this.numberOfElements); %this.element[%this.numberOfElements] = %element; %this.numberOfElements++; } @@ -35,7 +39,8 @@ function ListInstance::removeElement(%this, %index) { error("ListInstance::removeElements("@%index@"): Specified index is out of list bounds."); return; } - %this.element[%this.numberOfElements] = ""; + echo(%this@".removeElement("@%index@"): Strip "@%this.element[%index]); + %this.element[%index] = ""; %this.compactList(); } @@ -57,12 +62,19 @@ function ListInstance::find(%this, %key) { } function ListInstance::compactList(%this) { + echo("Compact "@%this@", "@%this.count()); for(%i = %this.count(); %i >= 0; %i--) { + echo("Test "@%i@": "@%this.element[%i]); if(%this.element[%i] $= "") { + echo("Remove Element "@%i); //Strip item, move others forward for(%x = %i; %x < %this.count(); %x++) { + echo(%x@" Is Now: "@%this.element[%x+1]); %this.element[%x] = %this.element[%x+1]; } + //Remove the last item.... + %this.element[%this.numberOfElements] = ""; + echo("Subduct "@%this.numberOfElements); %this.numberOfElements--; } } diff --git a/scripts/weapons/Equipment/SWBeaconer.cs b/scripts/weapons/Equipment/SWBeaconer.cs index 467d232..e2c56a9 100644 --- a/scripts/weapons/Equipment/SWBeaconer.cs +++ b/scripts/weapons/Equipment/SWBeaconer.cs @@ -73,10 +73,7 @@ datablock ShapeBaseImageData(KillstreakBeaconImage) { }; function KillstreakBeaconImage::onMount(%this, %obj, %slot) { - if(!isSet(%obj.client.ksListInstance)) { - %obj.client.ksListInstance = initList(); - } - if(%obj.client.ksListInstance.count() <= 0) { + if(getWordCount(%obj.client.streakList()) == 0) { %obj.throwWeapon(1); %obj.throwWeapon(0); %obj.setInventory(KillstreakBeacon, 0, true); @@ -103,74 +100,41 @@ function KillstreakBeaconImage::changeMode(%this, %obj, %key) { case 1: //Mine Modes %obj.KSSetMode++; - if(%obj.KSSetMode >= %obj.client.ksListInstance.count()) { + if(%obj.KSSetMode >= getWordCount(%obj.client.streakList())) { %obj.KSSetMode = 0; } case 2: //Grenade Modes %obj.KSSetMode--; if(%obj.KSSetMode < 0) { - %obj.KSSetMode = %obj.client.ksListInstance.count() - 1; + %obj.KSSetMode = getWordCount(%obj.client.streakList()); } } DisplayKillstreakInfo(%obj); } function DisplayKillstreakInfo(%obj) { - %currentStreak = %obj.client.ksListInstance.element(%obj.KSSetMode); - %strkName = getWord(%currentStreak, 0); - %strkCnt = getWord(%currentStreak, 1); + %streakList = %obj.client.streakList(); + %currentStreak = getWord(%streakList, %obj.KSSetMode); + %strkName = getField($Killstreak[%currentStreak], 0); + %strkCnt = %obj.client.streakCount[%currentStreak]; - switch$(%strkName) { - case "UAV": - %msg = "UAV Recon"; - case "Airstrike": - %msg = "Thundersword Airstrike"; - case "GM": - %msg = "UAMS Assault Drone"; - case "AIHeli": - %msg = "Support Helicopter"; - case "Harrier": - %msg = "Plasma Harrier Airstrike"; - case "OLS": - %msg = "Orbital Laser Strike"; - case "AIGunHeli": - %msg = "Gunship Helicopter Support"; - case "Stealth": - %msg = "Stealth Bomber Airstrike"; - case "HarbWrath": - %msg = "Harbinger's Wrath"; - case "Apache": - %msg = "Apache Gunner"; - case "AC130": - %msg = "AC-130 Gunner"; - case "Artillery": - %msg = "Centaur Artillery Bombardment"; - case "EMP": - %msg = "EMP Strike"; - case "NukeStrike": - %msg = "Tactical Nuke Strike"; - case "ZBomb": - %msg = "Anti-Zombie Bomb"; - case "FBomb": - %msg = "Fission Bomb Strike"; - case "Napalm": - %msg = "Napalm Airstrike"; - } - - commandToClient(%obj.client, 'BottomPrint', ">>>Killstreak Beacon<<<\n"@%msg@" ["@%strkCnt@" Available]\nPress Mine to select next streak, Grenade to select previous streak.", 3, 3); + commandToClient(%obj.client, 'BottomPrint', ">>>Killstreak Beacon<<<\n"@%strkName@" ["@%strkCnt@" Available]\nPress Mine to select next streak, Grenade to select previous streak.", 3, 3); } function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { - %currentStreak = %obj.client.ksListInstance.element(%obj.KSSetMode); - %strkName = getWord(%currentStreak, 0); - %strkCnt = getWord(%currentStreak, 1); + %streakList = %obj.client.streakList(); + %currentStreak = getWord(%streakList, %obj.KSSetMode); + %strkName = getField($Killstreak[%currentStreak], 0); + %strkCnt = %obj.client.streakCount[%currentStreak]; %newCt = %strkCnt - 1; + + echo("KSBeacon::Fire("@%data@", "@%obj@", "@%slot@"): "@%strkName@" "@%strkCnt@" => "@%newCt); if(%strkCnt <= 0) { //Oops... messageClient(%obj.client, 'msgError', "\c5TWM2: Nice Try..."); - %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); - if(%obj.client.ksListInstance.count() <= 0) { + //%obj.client.streakCount[%currentStreak]--; + if(getWordCount(%obj.client.streakList()) == 0) { //No more streaks in the list... %obj.throwWeapon(1); %obj.throwWeapon(0); @@ -179,24 +143,19 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { return; } - switch$(%strkName) { + switch(%currentStreak) { // // // UAV // // - case "UAV": + case 1: GainExperience(%obj.client, 25, "UAV Called in "); %obj.client.TWM2Core.UAVCalls++; UpdateSWBeaconFile(%obj.client, "UAV"); %obj.client.OnUseKillstreak(1); - if(%newCt == 0) { - %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); - } - else { - %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); - } + %obj.client.streakCount[%currentStreak]--; %count = 0; if(!$TWM2::FFAMode) { %obj.team.UAVLoop = UAVLoop(%obj, %obj.client.team, %count); @@ -228,7 +187,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { // Airstrike // // - case "Airstrike": + case 2: %ASCam = new Camera() { dataBlock = TWM2ControlCamera; }; @@ -244,7 +203,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { // UAMS // // - case "GM": + case 3: GainExperience(%obj.client, 50, "UAMS Called in "); %obj.client.TWM2Core.GMCalls++; %obj.client.OnUseKillstreak(3); @@ -259,19 +218,15 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { } } CreateMissileSat(%obj.client); - if(%newCt == 0) { - %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); - } - else { - %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); - } + %obj.client.streakCount[%currentStreak]--; + // // // Helicopter // // - case "AIHeli": + case 4: if(Game.CheckModifier("Scrambler") == 1) { for(%i = 0; %i < MissionCleanup.getCount(); %i++) { %obj = MissionCleanup.getObject(%i); @@ -298,12 +253,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { messageClient(%cl, 'msgHeliComing', "\c5TWM2: Enemy Helicopter Inbound"); } } - if(%newCt == 0) { - %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); - } - else { - %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); - } + %obj.client.streakCount[%currentStreak]--; MakeTheHeli(%obj.client); // @@ -311,7 +261,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { // Harrier // // - case "Harrier": + case 5: %ASCam = new Camera() { dataBlock = TWM2ControlCamera; }; @@ -327,7 +277,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { // OLS // // - case "OLS": + case 6: %ASCam = new Camera() { dataBlock = TWM2ControlCamera; }; @@ -343,7 +293,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { // Gunship Helicopter // // - case "AIGunHeli": + case 7: if(Game.CheckModifier("Scrambler") == 1) { for(%i = 0; %i < MissionCleanup.getCount(); %i++) { %obj = MissionCleanup.getObject(%i); @@ -370,12 +320,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { messageClient(%cl, 'msgHeliComing', "\c5TWM2: Enemy Gunship Helicopter Inbound!!!"); } } - if(%newCt == 0) { - %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); - } - else { - %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); - } + %obj.client.streakCount[%currentStreak]--; MakeTheHeli2(%obj.client, 0); // @@ -383,7 +328,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { // Stealth Airstrike // // - case "Stealth": + case 8: %ASCam = new Camera() { dataBlock = TWM2ControlCamera; }; @@ -399,7 +344,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { // Harbinger Gunship // // - case "HarbWrath": + case 9: GainExperience(%obj.client, 100, "Harbinger Gunship Called In "); if($CurrentMission $= "ChristmasMall09") { CompleteNWChallenge(%CallerClient, "GunshipMall"); @@ -416,12 +361,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { messageClient(%cl, 'msgHeliComing', "\c5TWM2: Enemy Gunship... INCOMING!!!"); } } - if(%newCt == 0) { - %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); - } - else { - %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); - } + %obj.client.streakCount[%currentStreak]--; if($TWM2::UnmannedGunship) { StartHarbingersWrath(%obj.client, 1); } @@ -434,7 +374,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { // Apache // // - case "Apache": + case 10: GainExperience(%obj.client, 100, "Apache Gunner Called in "); %obj.client.OnUseKillstreak(10); %obj.client.TWM2Core.CGCalls++; @@ -448,12 +388,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { messageClient(%cl, 'msgHeliComing', "\c5TWM2: Enemy Apache... INCOMING!!!"); } } - if(%newCt == 0) { - %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); - } - else { - %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); - } + %obj.client.streakCount[%currentStreak]--; MakeTheHeli(%obj.client, 1); // @@ -461,7 +396,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { // AC130 // // - case "AC130": + case 11: GainExperience(%obj.client, 100, "AC130 Called in "); if($CurrentMission $= "ChristmasMall09") { CompleteNWChallenge(%CallerClient, "GunshipMall"); @@ -478,12 +413,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { messageClient(%cl, 'msgHeliComing', "\c5TWM2: Enemy AC130 ABOVE!!!"); } } - if(%newCt == 0) { - %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); - } - else { - %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); - } + %obj.client.streakCount[%currentStreak]--; if($TWM2::UnmannedGunship) { StartAC130(%obj.client, 1); } @@ -496,7 +426,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { // Artillery // // - case "Artillery": + case 12: %ASCam = new Camera() { dataBlock = TWM2ControlCamera; }; @@ -512,7 +442,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { // EMP // // - case "EMP": + case 13: %obj.client.TWM2Core.EMPCalls++; UpdateSWBeaconFile(%obj.client, "EMP"); GainExperience(%obj.client, 1000, "Mass EMP Called in "); @@ -540,19 +470,14 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { } } } - if(%newCt == 0) { - %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); - } - else { - %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); - } + %obj.client.streakCount[%currentStreak]--; // // // Nuke // // - case "NukeStrike": + case 14: %ASCam = new Camera() { dataBlock = TWM2ControlCamera; }; @@ -568,7 +493,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { // ZBomb // // - case "ZBomb": + case 15: GainExperience(%obj.client, 1000, "Zombie Annihilation Bomb Activated "); MessageAll('msgWohoo', "\c5TWM2: "@%obj.client.namebase@" has activated a Z-Bomb, eliminating all zombies"); %obj.client.OnUseKillstreak(15); @@ -595,19 +520,14 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { %flcl.player.setWhiteout(1.8); } } - if(%newCt == 0) { - %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); - } - else { - %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); - } + %obj.client.streakCount[%currentStreak]--; // // // Fission // // - case "FBomb": + case 16: %obj.client.HasFission = 0; GainExperience(%obj.client, 25000, "Anti-Matter Based Fission Bomb Activated "); %obj.client.OnUseKillstreak(16); @@ -616,19 +536,14 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { CompleteNWChallenge(%obj.client, "GameEnder"); MessageAll('msgItsOva', "\c5COMMAND: FISSION BOMB!!! IT'S OVER!! RUN!!!!!! ~wfx/misc/red_alert_short.wav"); FissionBombLoop(%obj.client, %obj, %obj.getPosition(), 30); - if(%newCt == 0) { - %obj.client.ksListInstance.removeElement(getField(%obj.client.ksListInstance.find(%strkName), 1)); - } - else { - %obj.client.ksListInstance.set(getField(%obj.client.ksListInstance.find(%strkName), 1), %strkName SPC %newCt); - } + %obj.client.streakCount[%currentStreak]--; // // // Napalm // // - case "Napalm": + case 17: %ASCam = new Camera() { dataBlock = TWM2ControlCamera; }; @@ -640,7 +555,7 @@ function KillstreakBeaconImage::OnFire(%data, %obj, %slot) { CameraMessageLoop(%obj.client, %ASCam, %ASCam.mode); } //Post-Fire Checks - if(%obj.client.ksListInstance.count() <= 0) { + if(getWordCount(%obj.client.streakList()) == 0) { //No more streaks in the list... %obj.throwWeapon(1); %obj.throwWeapon(0); From 5ebf31e057677952d84f702effd27373beeb3e48 Mon Sep 17 00:00:00 2001 From: Robert Fritzen Date: Thu, 12 Feb 2015 19:45:18 -0600 Subject: [PATCH 16/16] 3.9.1 Update Patched up some TWM2 bugs, re-did the Vardison Boss. --- scripts/TWM2/Bosses/LordVardison.cs | 3041 +++++++++++----------- scripts/TWM2/ChatCommands/Public.cs | 2 +- scripts/TWM2/ChatCommands/SuperAdmin.cs | 6 +- scripts/TWM2/Systems/BossSystem.cs | 104 +- scripts/TWM2/Systems/NWChallengeIndex.cs | 4 + scripts/TWM2/Zombie/ZombieCreation.cs | 4 +- scripts/chatCommands.cs | 4 - scripts/packs/Medpack.cs | 8 +- scripts/packs/ZSpawnpack.cs | 45 +- scripts/player.cs | 11 + scripts/weapons/Other/ShadowRifle.cs | 43 - 11 files changed, 1697 insertions(+), 1575 deletions(-) diff --git a/scripts/TWM2/Bosses/LordVardison.cs b/scripts/TWM2/Bosses/LordVardison.cs index d60a120..54c93da 100644 --- a/scripts/TWM2/Bosses/LordVardison.cs +++ b/scripts/TWM2/Bosses/LordVardison.cs @@ -1,6 +1,238 @@ -//LORD \/ARDISON & Dark Archmage Vardison -//THIS BOSS WILL MURDER OCCULTBADBOY -//Yeah, he really will +//Lord Vardison +//Version 2.0 +//Revised And Reimagined... The Pure Evil of TWM2 Has Been Reborn, Now With Less Crashing xD +// Now with difficulty levels :P +// 1, Easy: Standard Vardison Battle +// - Limited Mobs +// - Attacks On Normal +// - Has Timed Grab Kills +// 2, Normal: Tougher Vardison Battle +// - Enhanced Mob Spawns +// - Slightly Faster Attacks +// - Phase 3 Insta-Kills +// - Shadow Orb Mechanic: Deaths to phase 3 initiate Shadow Orb, which is a 20 second to kill all mechanic. +// 3, Hard: The True Experience +// - Minions A Plenty +// - Quick Attacks +// - Phases 2 & 3 Insta-Kill +// - Shadow Orb at Phase 2 & 3 +// 4, WTF!?!?! Why God... Why.... +// - The Army Comith... +// - Attacks Are So Rapid.... +// - All Phases Insta-Kill, Phase 3 does the spawn camp thingy :D +// - Shadow Orb at all Phases +// - Shadow Orb regenerates Vardison's HP + +$TWM2::VardisonDifficulty = 1; +$TWM2::Vardison_DMsg[1] = "Lord Vardison Fight [EASY]: The Standard Battle... Work Togther and Be Victorious."; +$TWM2::Vardison_DMsg[2] = "Lord Vardison Fight [NORMAL]: Vardison Has Enhanced His Skills, Will you prove stronger?"; +$TWM2::Vardison_DMsg[3] = "Lord Vardison Fight [HARD]: The True Vardison Experience... Only The True Will Be Victorious..."; +$TWM2::Vardison_DMsg[4] = "Lord Vardison Fight [WTF]: All Prayers Will Be Accepted Before You Painfully Die... Over And Over And Over...."; +//Difficulty Variables, Don't Touch +$TWM2::Vardison_OrbKillTime = 12500; +$TWM2::Vardison1_AttSpeed[1] = 20000; +$TWM2::Vardison1_AttSpeed[2] = 17500; +$TWM2::Vardison1_AttSpeed[3] = 13500; +$TWM2::Vardison1_AttSpeed[4] = 7500; +$TWM2::Vardison2_AttSpeed[1] = 20000; +$TWM2::Vardison2_AttSpeed[2] = 17500; +$TWM2::Vardison2_AttSpeed[3] = 12500; +$TWM2::Vardison2_AttSpeed[4] = 7000; +$TWM2::Vardison3_AttSpeed[1] = 17500; +$TWM2::Vardison3_AttSpeed[2] = 15000; +$TWM2::Vardison3_AttSpeed[3] = 11500; +$TWM2::Vardison3_AttSpeed[4] = 6500; +$TWM2::Vardison1_CanOrb[1] = false; +$TWM2::Vardison1_CanOrb[2] = false; +$TWM2::Vardison1_CanOrb[3] = false; +$TWM2::Vardison1_CanOrb[4] = true; +$TWM2::Vardison2_CanOrb[1] = false; +$TWM2::Vardison2_CanOrb[2] = false; +$TWM2::Vardison2_CanOrb[3] = true; +$TWM2::Vardison2_CanOrb[4] = true; +$TWM2::Vardison3_CanOrb[1] = false; +$TWM2::Vardison3_CanOrb[2] = true; +$TWM2::Vardison3_CanOrb[3] = true; +$TWM2::Vardison3_CanOrb[4] = true; +$TWM2::Vardison_OrbRegenHP[1] = false; +$TWM2::Vardison_OrbRegenHP[2] = false; +$TWM2::Vardison_OrbRegenHP[3] = false; +$TWM2::Vardison_OrbRegenHP[4] = true; +$TWM2::Vardison1_MaxMinions[1] = 5; +$TWM2::Vardison1_MaxMinions[2] = 10; +$TWM2::Vardison1_MaxMinions[3] = 12; +$TWM2::Vardison1_MaxMinions[4] = 15; +$TWM2::Vardison2_MaxMinions[1] = 7; +$TWM2::Vardison2_MaxMinions[2] = 9; +$TWM2::Vardison2_MaxMinions[3] = 12; +$TWM2::Vardison2_MaxMinions[4] = 15; +$TWM2::Vardison3_MaxMinions[1] = 10; +$TWM2::Vardison3_MaxMinions[2] = 13; +$TWM2::Vardison3_MaxMinions[3] = 17; +$TWM2::Vardison3_MaxMinions[4] = 25; +$TWM2::Vardison_MinionCooldown[1] = 20; +$TWM2::Vardison_MinionCooldown[2] = 17; +$TWM2::Vardison_MinionCooldown[3] = 15; +$TWM2::Vardison_MinionCooldown[4] = 10; + +//Particles & Emitters +datablock ParticleData(SummoningPierParticle) { + dragCoeffiecient = 0.0; + gravityCoefficient = -0.1; + inheritedVelFactor = 0.1; + + lifetimeMS = 1500; + lifetimeVarianceMS = 50; + + textureName = "special/cloudflash"; + + spinRandomMin = -10.0; + spinRandomMax = 10.0; + + colors[0] = "1 0.18 0.03 0.4"; + colors[1] = "0 134 139 0.3"; + colors[2] = "1 0.18 0.03 0.0"; + sizes[0] = 10.0; + sizes[1] = 7.5; + sizes[2] = 5.0; + times[0] = 0.0; + times[1] = 0.6; + times[2] = 1.0; +}; + +datablock ParticleEmitterData(SummoningPierEmitter) { + ejectionPeriodMS = 3; + periodVarianceMS = 0; + + ejectionOffset = 0.2; + ejectionVelocity = 10.0; + velocityVariance = 0.0; + + thetaMin = 0.0; + thetaMax = 10.0; + + particles = "SummoningPierParticle"; +}; + +datablock ParticleData(ShadowOrbParticle) { + dragCoefficient = 5; + gravityCoefficient = 0.0; + inheritedVelFactor = 0.0; + constantAcceleration = -1.3; + lifetimeMS = 1000; + lifetimeVarianceMS = 150; + textureName = "special/cloudflash"; + useInvAlpha = false; + colors[0] = "0.5 0.1 0.9 1.0"; + colors[1] = "0.5 0.1 0.9 1.0"; + colors[2] = "0.5 0.1 0.9 1.0"; + sizes[0] = 20.501; + sizes[1] = 25.001; + sizes[2] = 30.001; + times[0] = 0.0; + times[1] = 0.2; + times[2] = 1.0; +}; + +datablock ParticleEmitterData(ShadowOrbEmitter) { + ejectionPeriodMS = 15; + periodVarianceMS = 5; + + ejectionVelocity = 42.7; // A little oomph at the back end + velocityVariance = 0.0; + ejectionoffset = 0; + thetaMin = 0.0; + thetaMax = 180.0; + phiReferenceVel = 0; + phiVariance = "360"; + particles = "ShadowOrbParticle"; + overrideAdvances = true; + orientParticles = true; +}; + +datablock ParticleData(ShadowOrbDetonationParticle) { + dragCoefficient = 1.0; + gravityCoefficient = 0.00; + windcoefficient = 0.0; + inheritedVelFactor = 0.0; + constantAcceleration = 10.0; + lifetimeMS = 1000; + lifetimeVarianceMS = 100; + useInvAlpha = true; + spinRandomMin = -90.0; + spinRandomMax = 90.0; + textureName = "special/cloudFlash"; + + colors[0] = "0.5 0.1 0.9 1.0"; + colors[1] = "156 0 0 0.5"; + colors[2] = "0.5 0.1 0.9 1.0"; + sizes[0] = 500; + sizes[1] = 500; + sizes[2] = 2; + times[0] = 0.0; + times[1] = 0.5; + times[2] = 1.0; +}; + +datablock ParticleEmitterData(ShadowOrbDetonationEmitter) { + ejectionPeriodMS = 1; + periodVarianceMS = 0; + ejectionVelocity = 400.0; + velocityVariance = 150.0; + ejectionOffset = 0.0; + thetaMin = 85; + thetaMax = 85; + phiReferenceVel = 0; + phiVariance = 360; + overrideAdvances = false; + particles = "ShadowOrbDetonationParticle"; +}; + +datablock ParticleData(ShadowBaseParticle) { + dragCoeffiecient = 0.0; + gravityCoefficient = -0.2; + inheritedVelFactor = 0.0; + + lifetimeMS = 800; + lifetimeVarianceMS = 500; + + useInvAlpha = false; + spinRandomMin = -160.0; + spinRandomMax = 160.0; + + animateTexture = true; + framesPerSec = 15; + + textureName = "special/cloudflash"; + + colors[0] = "0.5 0.1 0.9 1.0"; + colors[1] = "0.5 0.1 0.9 1.0"; + colors[2] = "0.5 0.1 0.9 1.0"; + + sizes[0] = 2.5; + sizes[1] = 2.7; + sizes[2] = 3.0; + + times[0] = 0.0; + times[1] = 0.7; + times[2] = 1.0; +}; + +datablock ParticleEmitterData(ShadowBaseEmitter) { + ejectionPeriodMS = 10; + periodVarianceMS = 0; + + ejectionVelocity = 1.5; + velocityVariance = 0.3; + + thetaMin = 0.0; + thetaMax = 30.0; + + particles = "ShadowBaseParticle"; +}; + +//Projectile Datablocks: +//Ultimate Laser Projectile datablock LinearFlareProjectileData(SuperlaserProjectile) { scale = "15.0 15.0 15.0"; faceViewer = false; @@ -51,1621 +283,1440 @@ datablock LinearFlareProjectileData(SuperlaserProjectile) { }; -// -datablock ParticleData(ShadowBaseParticle) { - dragCoeffiecient = 0.0; - gravityCoefficient = -0.2; - inheritedVelFactor = 0.0; +datablock LinearFlareProjectileData(ShadowBladeSlam) { + scale = "0.1 0.1 0.1"; + faceViewer = false; + directDamage = 1.0; + hasDamageRadius = true; + indirectDamage = 5.0; + damageRadius = 15.0; + kickBackStrength = 1000.0; + radiusDamageType = $DamageType::BladeOfVengance; - lifetimeMS = 800; - lifetimeVarianceMS = 500; + explosion[0] = "SatchelMainExplosion"; + splash = PlasmaSplash; - useInvAlpha = true; - spinRandomMin = -160.0; - spinRandomMax = 160.0; - animateTexture = true; - framesPerSec = 15; + dryVelocity = 200.0; + wetVelocity = 200; + velInheritFactor = 0.5; + fizzleTimeMS = 10000; + lifetimeMS = 10000; + explodeOnDeath = false; + reflectOnWaterImpactAngle = 0.0; + explodeOnWaterImpact = true; + deflectionOnWaterImpact = 0.0; + fizzleUnderwaterMS = -1; - textureName = "special/cloudflash"; + //activateDelayMS = 100; + activateDelayMS = -1; - colors[0] = "0.1 0.1 0.1 1.0";// //////////////////// - colors[1] = "0.1 0.1 0.1 1.0";// //////////////////// - colors[2] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ + size[0] = "0.1"; + size[1] = "0.1"; + size[2] = "0.1"; - sizes[0] = 2.5; - sizes[1] = 2.7; - sizes[2] = 3.0; - times[0] = 0.0; - times[1] = 0.7; - times[2] = 1.0; + numFlares = 1; + flareColor = "0.0 1.0 0"; + flareModTexture = "flaremod"; + flareBaseTexture = "flarebase"; + + sound = MissileProjectileSound; + fireSound = PlasmaFireSound; + wetFireSound = PlasmaFireWetSound; + + hasLight = true; + lightRadius = 3.0; + lightColor = "0 0.75 0.25"; + }; -datablock ParticleEmitterData(ShadowBaseEmitter) { - ejectionPeriodMS = 10; - periodVarianceMS = 0; +datablock LinearFlareProjectileData(ShadowBlastBolt) { + projectileShapeName = "turret_muzzlepoint.dts"; + scale = "1.0 1.0 1.0"; + faceViewer = true; + directDamage = 0.9; + hasDamageRadius = true; + indirectDamage = 0.9; + damageRadius = 15.0; + kickBackStrength = 0.0; + radiusDamageType = $DamageType::Vardison; - ejectionVelocity = 1.5; - velocityVariance = 0.3; + explosion = "MortarExplosion"; + splash = PlasmaSplash; - thetaMin = 0.0; - thetaMax = 30.0; - - particles = "ShadowBaseParticle"; -}; - -datablock ParticleData(SmallShadowBaseParticle) { - dragCoeffiecient = 0.0; - gravityCoefficient = -0.2; - inheritedVelFactor = 0.0; - - lifetimeMS = 9999999999999; - lifetimeVarianceMS = 9999999999999; - - useInvAlpha = true; - spinRandomMin = -160.0; - spinRandomMax = 160.0; - - animateTexture = true; - framesPerSec = 15; - - textureName = "special/cloudflash"; - - colors[0] = "0.1 0.1 0.1 1.0";// //////////////////// - colors[1] = "0.1 0.1 0.1 1.0";// //////////////////// - colors[2] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ - - sizes[0] = 0.5; - sizes[1] = 0.7; - sizes[2] = 1.0; - - times[0] = 0.0; - times[1] = 0.7; - times[2] = 1.0; -}; - -datablock ParticleEmitterData(SmallShadowBaseEmitter) { - ejectionPeriodMS = 10; - periodVarianceMS = 0; - - ejectionVelocity = 1.5; - velocityVariance = 0.3; - - thetaMin = 0.0; - thetaMax = 30.0; - - particles = "SmallShadowBaseParticle"; -}; - -datablock ParticleData(JetShadowParticle) { - dragCoeffiecient = 0.0; - gravityCoefficient = 0; - inheritedVelFactor = 0.0; - - lifetimeMS = 2500; - lifetimeVarianceMS = 0; - - textureName = "particleTest"; - - useInvAlpha = true; - spinRandomMin = -160.0; - spinRandomMax = 160.0; - - animateTexture = true; - framesPerSec = 15; - - animTexName[0] = "special/Explosion/exp_0016"; - animTexName[1] = "special/Explosion/exp_0018"; - animTexName[2] = "special/Explosion/exp_0020"; - animTexName[3] = "special/Explosion/exp_0022"; - animTexName[4] = "special/Explosion/exp_0024"; - animTexName[5] = "special/Explosion/exp_0026"; - animTexName[6] = "special/Explosion/exp_0028"; - animTexName[7] = "special/Explosion/exp_0030"; - animTexName[8] = "special/Explosion/exp_0032"; - - colors[0] = "0.1 0.1 0.1 1.0";// //////////////////// - colors[1] = "0.1 0.1 0.1 1.0";// //////////////////// - colors[2] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ - sizes[0] = 2.5; - sizes[1] = 1.25; - sizes[2] = 0.625; - times[0] = 0.0; - times[1] = 0.7; - times[2] = 1.0; -}; - -datablock ParticleEmitterData(JetShadowEmitter) { - ejectionPeriodMS = 2; - periodVarianceMS = 0; - - ejectionVelocity = 0; - velocityVariance = 0; - ejectionOffset = 5; - thetaMin = 22.5; - thetaMax = 45; - phiReferenceVel = 0; - phiVariance = 360; - spinRandomMin = "200"; - spinRandomMax = "-200"; - overrideAdvances = false; - particles = "JetShadowParticle"; -}; - -datablock ParticleData(LaserBallGlobeSmoke) { - dragCoefficient = 50;/////////----------------------- - gravityCoefficient = 0.0; - inheritedVelFactor = 1.0; - constantAcceleration = 0.0; - lifetimeMS = 1000; - lifetimeVarianceMS = 0; - useInvAlpha = true; - spinRandomMin = -360.0; - spinRandomMax = 360.0; - textureName = "particleTest"; - colors[0] = "0.1 0.1 0.1 1.0";// //////////////////// - colors[1] = "0.1 0.1 0.1 1.0";// //////////////////// - colors[2] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ - colors[3] = "0.1 0.1 0.1 1.0";// \\\\\\\\\\\\\\\\\\\\ - sizes[0] = 1.0; - sizes[1] = 1.0; - sizes[2] = 1.0; - sizes[3] = 1.0; - times[0] = 0.0; - times[1] = 0.33; - times[2] = 0.66; - times[3] = 1.0; - mass = 0.7; - elasticity = 0.2; - friction = 1; - computeCRC = true; - haslight = true; - lightType = "PulsingLight"; - lightColor = "0.2 0.0 0.5 1.0"; - lightTime = "200"; - lightRadius = "2.0"; -}; - -datablock ParticleEmitterData(MiniShadowBallEmitter) { - ejectionPeriodMS = 0.3; - periodVarianceMS = 0; - ejectionVelocity = 0.0; - velocityVariance = 0.0; - ejectionOffset = 2; - thetaMin = 0; - thetaMax = 180; - overrideAdvances = false; - particles = "LaserBallGlobeSmoke"; -}; - -datablock LinearFlareProjectileData(ShadowBomb) : FlamethrowerBolt { baseEmitter = ShadowBaseEmitter; - fizzleTimeMS = 14000; - lifetimeMS = 10000; // z0dd - ZOD, 4/25/02. Was 6000 -}; -datablock SeekerProjectileData(VardisonLaserBallMissile) : YvexNightmareMissile { - baseEmitter = ShadowBaseEmitter; -}; - -function VardisonLaserBallMissile::OnExplode(%data, %proj, %pos, %mod) { - //LaserBall - %ball = CreateEmitter(%pos, "MiniShadowBallEmitter", "0 0 0 0"); - %ball.schedule(10000, "Delete"); - LaserBallStrike(vectorAdd(%pos, "0 0 3"), 0); -} - -function LaserBallStrike(%position, %count) { - %count++; - if(%count > 100) { - %p = new LinearFlareProjectile() { - dataBlock = VardisonSubShadowBomb; - initialDirection = "0 0 -1"; - initialPosition = %position; - }; - return; //stop here - } - else { - if(%count % 3 == 0) { //multiples of 3 == strike - %p = new TracerProjectile() { - dataBlock = PlasmaCannonMainProj; - initialDirection = vectorAdd(%postition, getRandomPosition(25,0)); - initialPosition = %position; - }; - } - } - schedule(100, 0, "LaserBallStrike", %position, %count); -} - -datablock LinearFlareProjectileData(VardisonSubShadowBomb) : DMPlasma { - explosion = MortarExplosion; - dryVelocity = 500.0; // z0dd - ZOD, 4/25/02. Was 50. Velocity of projectile out of water + dryVelocity = 50.0; // z0dd - ZOD, 7/20/02. Faster plasma projectile. was 55 wetVelocity = -1; - velInheritFactor = 1.0; - fizzleTimeMS = 14000; - lifetimeMS = 10000; // z0dd - ZOD, 4/25/02. Was 6000 + velInheritFactor = 0.3; + fizzleTimeMS = 29500; + lifetimeMS = 30000; + explodeOnDeath = false; + reflectOnWaterImpactAngle = 0.0; + explodeOnWaterImpact = true; + deflectionOnWaterImpact = 0.0; + fizzleUnderwaterMS = -1; + + //activateDelayMS = 100; + activateDelayMS = -1; + + size[0] = 0.2; + size[1] = 0.5; + size[2] = 0.1; + + + numFlares = 35; + flareColor = "1 0.18 0.03"; + flareModTexture = "flaremod"; + flareBaseTexture = "flarebase"; + + sound = PlasmaProjectileSound; + fireSound = FlamethrowerFireSound; + wetFireSound = PlasmaFireWetSound; + + hasLight = true; + lightRadius = 10.0; + lightColor = "0.94 0.03 0.12"; }; -//ARMOR DBs -datablock PlayerData(VardisonStage1Armor) : LightMaleHumanArmor { - runForce = 60.20 * 90; - runEnergyDrain = 0.0; - minRunEnergy = 10; - maxForwardSpeed = 9; - maxBackwardSpeed = 7; - maxSideSpeed = 7; - - jumpForce = 14.0 * 90; +//Armor Datablocks +datablock StaticShapeData(InitialVaridionHoloArmor) : StaticShapeDamageProfile { + className = "player"; + shapeFile = "TR2Heavy_male.dts"; // dmiscf.dts, alternate + mass = 1; + elasticity = 0.1; + friction = 0.9; + collideable = 0; + isInvincible = true; +}; +function InitialVaridionHoloArmor::shouldApplyImpulse(%targetObject) { + return false; +} +datablock PlayerData(VardisonStageOneArmor) : LightMaleHumanArmor { + boundingBox = "1.63 1.63 2.6"; maxDamage = 300.0; minImpactSpeed = 35; - shapeFile = "light_male.dts"; - jetEmitter = BiodermArmorJetEmitter; - jetEffect = BiodermArmorJetEffect; + shapeFile = "medium_male.dts"; debrisShapeName = "bio_player_debris.dts"; //Foot Prints - decalData = LightBiodermFootprint; - decalOffset = 0.3; + decalData = HeavyBiodermFootprint; + decalOffset = 0.4; waterBreathSound = WaterBreathBiodermSound; - damageScale[$DamageType::M1700] = 3.0; - damageScale[$DamageType::Missile] = 0.0000000000000001; - damageScale[$DamageType::Nuclear] = 0.0000000000000001; - damageScale[$DamageType::EMP] = 0.0000000000000001; + damageScale[$DamageType::W1700] = 3.0; damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs + damageScale[$DamageType::BladeOfVengance] = 0.001; +}; + +datablock PlayerData(VardisonStageTwoArmor) : LightMaleHumanArmor { + shapefile = "TR2medium_male.dts"; + mass = 500; + maxDamage = 350.0; + minImpactSpeed = 50; + speedDamageScale = 0.015; + boundingBox = "2.9 2.9 4.8"; + + underwaterJetForce = 10; + + LFootSoftSound = ZLordFootSound; + RFootSoftSound = ZLordFootSound; + LFootHardSound = HZLordFootSound; + RFootHardSound = HZLordFootSound; + LFootMetalSound = ZLordFootSound; + RFootMetalSound = ZLordFootSound; + LFootSnowSound = ZLordFootSound; + RFootSnowSound = ZLordFootSound; + + damageScale[$DamageType::M1700] = 1.5; + damageScale[$DamageType::BladeOfVengance] = 0.001; max[RepairKit] = 0; max[Mine] = 0; max[Grenade] = 0; }; -datablock PlayerData(DarkArchmageVardisonArmor) : VardisonStage1Armor { - maxDamage = 1000.0; - minImpactSpeed = 35; - shapeFile = "light_male.dts"; - jetEmitter = BiodermArmorJetEmitter; - jetEffect = BiodermArmorJetEffect; - - damageScale[$DamageType::M1700] = 3.0; - damageScale[$DamageType::Missile] = 0.0000000000000001; - damageScale[$DamageType::Nuclear] = 0.0000000000000001; - damageScale[$DamageType::EMP] = 0.0000000000000001; - damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs - - max[RepairKit] = 0; - max[Mine] = 0; - max[Grenade] = 0; -}; - -datablock FlyingVehicleData(VardisonStage2Flyer) : ShrikeDamageProfile { - spawnOffset = "0 0 2"; - canControl = false; - catagory = "Vehicles"; - shapeFile = "vehicle_air_bomber.dts"; - multipassenger = false; - computeCRC = true; - - debrisShapeName = "vehicle_air_bomber.dts"; - debris = MeShapeDebris; - renderWhenDestroyed = false; - - drag = 0.15; - density = 1.0; - - mountPose[0] = sitting; - numMountPoints = 1; - isProtectedMountPoint[0] = false; - cameraMaxDist = 15; - cameraOffset = 2.5; - cameraLag = 0.9; - explosion = MeVehicleExplosion; - explosionDamage = 1.0; - explosionRadius = 10.0; - - maxDamage = 50.0; - destroyedLevel = 50.0; - - HDAddMassLevel = 49.9; - HDMassImage = LflyerHDMassImage; - - isShielded = false; - energyPerDamagePoint = 0; - maxEnergy = 5000; // Afterburner and any energy weapon pool - rechargeRate = 4; - - minDrag = 22; // Linear Drag (eventually slows you down when not thrusting...constant drag) - rotationalDrag = 900; // Anguler Drag (dampens the drift after you stop moving the mouse...also tumble drag) - - maxAutoSpeed = 50; // Autostabilizer kicks in when less than this speed. (meters/second) - autoAngularForce = 400; // Angular stabilizer force (this force levels you out when autostabilizer kicks in) - autoLinearForce = 1; // Linear stabilzer force (this slows you down when autostabilizer kicks in) - autoInputDamping = 0.8; // Dampen control input so you don't` whack out at very slow speeds - - - // Maneuvering - maxSteeringAngle = 4.5; // Max radiens you can rotate the wheel. Smaller number is more maneuverable. - horizontalSurfaceForce = 6; // Horizontal center "wing" (provides "bite" into the wind for climbing/diving and turning) - verticalSurfaceForce = 4; // Vertical center "wing" (controls side slip. lower numbers make MORE slide.) - maneuveringForce = 5250; // Horizontal jets (W,S,D,A key thrust) - steeringForce = 675; // Steering jets (force applied when you move the mouse) - steeringRollForce = 3000; // Steering jets (how much you heel over when you turn) - rollForce = 1; // Auto-roll (self-correction to right you after you roll/invert) - hoverHeight = 2.5; // Height off the ground at rest - createHoverHeight = 1; // Height off the ground when created - maxForwardSpeed = 165; // speed in which forward thrust force is no longer applied (meters/second) - - // Turbo Jet - jetForce = 2500; // Afterburner thrust (this is in addition to normal thrust) - minJetEnergy = 40; // Afterburner can't be used if below this threshhold. - jetEnergyDrain = 10; // Energy use of the afterburners (low number is less drain...can be fractional) // Auto stabilize speed - vertThrustMultiple = 1.25; - - // Rigid body - mass = 150; // Mass of the vehicle - bodyFriction = 0; // Don't mess with this. - bodyRestitution = 0.5; // When you hit the ground, how much you rebound. (between 0 and 1) - minRollSpeed = 0; // Don't mess with this. - softImpactSpeed = 14; // Sound hooks. This is the soft hit. - hardImpactSpeed = 25; // Sound hooks. This is the hard hit. - - // Ground Impact Damage (uses DamageType::Ground) - minImpactSpeed = 20; // If hit ground at speed above this then it's an impact. Meters/second - speedDamageScale = 0.06; - - // Object Impact Damage (uses DamageType::Impact) - collDamageThresholdVel = 23.0; - collDamageMultiplier = 0.02; - - // - minTrailSpeed = 70; // The speed your contrail shows up at. - trailEmitter = JetShadowEmitter; - forwardJetEmitter = JetShadowEmitter; - downJetEmitter = JetShadowEmitter; - - // - jetSound = ScoutFlyerThrustSound; - engineSound = ScoutFlyerEngineSound; - softImpactSound = SoftImpactSound; - hardImpactSound = HardImpactSound; - //wheelImpactSound = WheelImpactSound; - - // - softSplashSoundVelocity = 10.0; - mediumSplashSoundVelocity = 15.0; - hardSplashSoundVelocity = 20.0; - exitSplashSoundVelocity = 10.0; - - exitingWater = VehicleExitWaterMediumSound; - impactWaterEasy = VehicleImpactWaterSoftSound; - impactWaterMedium = VehicleImpactWaterMediumSound; - impactWaterHard = VehicleImpactWaterMediumSound; - waterWakeSound = VehicleWakeMediumSplashSound; - - dustEmitter = VehicleLiftoffDustEmitter; - triggerDustHeight = 4.0; - dustHeight = 1.0; - - damageEmitter[0] = MeLightDamageSmoke; - damageEmitter[1] = MeHeavyDamageSmoke; - damageEmitter[2] = MeDamageBubbles; - damageEmitterOffset[0] = "0.0 -3.0 0.0 "; - damageLevelTolerance[0] = 0.4; - damageLevelTolerance[1] = 0.75; - numDmgEmitterAreas = 1; - - // - max[chaingunAmmo] = 2000; - max[MissileLauncherAmmo] = 200; - max[MortarAmmo] = 200; - - damageScale[$DamageType::Nuclear] = 0.0000000000000001; - damageScale[$DamageType::EMP] = 0.0000000000000001; - damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs - ShieldDamageScale[$DamageType::Bullet] = 0.01; //I deny you shrike n0bs - - minMountDist = 7; - - splashEmitter[0] = VehicleFoamDropletsEmitter; - splashEmitter[1] = VehicleFoamEmitter; - - shieldImpact = VehicleShieldImpact; - - cmdCategory = "Tactical"; - cmdIcon = CMDFlyingScoutIcon; - cmdMiniIconName = "commander/MiniIcons/com_scout_grey"; - targetNameTag = 'Lord Vardison'; - targetTypeTag = ''; - sensorData = SSTurretBaseSensorObj; - sensorRadius = SSTurretBaseSensorObj.detectRadius; - sensorColor = "9 9 255"; - - checkRadius = 5.5; - observeParameters = "1 10 10"; - - runningLight[0] = ShrikeLight1; -// runningLight[1] = ShrikeLight2; - - shieldEffectScale = "0.937 1.125 0.60"; - - numWeapons = 3; - - replaceTime = 90; -}; - -datablock PlayerData(VardisonStage3Armor) : LightMaleHumanArmor { - runForce = 60.20 * 90; - runEnergyDrain = 0.0; - minRunEnergy = 10; - maxForwardSpeed = 9; - maxBackwardSpeed = 7; - maxSideSpeed = 7; - - jumpForce = 14.0 * 90; - +datablock PlayerData(VardisonStageThreeArmor) : LightMaleHumanArmor { + shapefile = "TR2Heavy_male.dts"; + mass = 500; maxDamage = 500.0; - minImpactSpeed = 35; - shapeFile = "TR2Heavy_Male.dts"; - jetEmitter = BiodermArmorJetEmitter; - jetEffect = BiodermArmorJetEffect; + minImpactSpeed = 50; + speedDamageScale = 0.015; + boundingBox = "2.9 2.9 4.8"; - debrisShapeName = "bio_player_debris.dts"; + underwaterJetForce = 10; - //Foot Prints - decalData = LightBiodermFootprint; - decalOffset = 0.3; - - boundingBox = "5 5 10"; + LFootSoftSound = ZLordFootSound; + RFootSoftSound = ZLordFootSound; + LFootHardSound = HZLordFootSound; + RFootHardSound = HZLordFootSound; + LFootMetalSound = ZLordFootSound; + RFootMetalSound = ZLordFootSound; + LFootSnowSound = ZLordFootSound; + RFootSnowSound = ZLordFootSound; - waterBreathSound = WaterBreathBiodermSound; - - damageScale[$DamageType::M1700] = 3.0; - damageScale[$DamageType::PlasmaCannon] = 0.001; - damageScale[$DamageType::Missile] = 0.0000000000000001; - damageScale[$DamageType::Nuclear] = 0.0000000000000001; - damageScale[$DamageType::EMP] = 0.0000000000000001; - damageScale[$DamageType::Bullet] = 0.10; //I deny you shrike n0bs + damageScale[$DamageType::M1700] = 1.5; + damageScale[$DamageType::BladeOfVengance] = 0.001; max[RepairKit] = 0; max[Mine] = 0; max[Grenade] = 0; }; -function StartDAVardison(%pos) { - %Vardison = new player() { - Datablock = "DarkArchmageVardisonArmor"; - }; - %Cpos = vectorAdd(%pos, "0 0 5"); - MessageAll('MsgVardison', "\c4"@$TWM2::BossName["DAVardison"]@": Rise forces of darkness, as our enemies shall face their demise"); +datablock StaticShapeData(ShadowOrb) : StaticShapeDamageProfile { + className = "logoprojector"; + shapeFile = "pack_deploy_sensor_motion.dts"; - %command = "DAVardisonmovetotarget"; - %Vardison.ticks = 0; - InitiateBoss(%Vardison, "DAVardison"); + maxDamage = 10.0; + destroyedLevel = 10.0; + disabledLevel = 0.3; - %Vardison.team = 30; - %zname = CollapseEscape("\c7"@$TWM2::BossName["DAVardison"]@""); // <- To Hosts, Enjoy, You can - //Change the Demon Names now!!! - %Vardison.target = createTarget(%Vardison, %zname, "", "Derm3", '', %Vardison.team, PlayerSensor); - setTargetSensorData(%Vardison.target, PlayerSensor); - setTargetSensorGroup(%Vardison.target, 30); - setTargetName(%Vardison.target, addtaggedstring(%zname)); - setTargetSkin(%Vardison.target, 'Inferno'); - // - %Vardison.setPosition(%cpos); - %Vardison.canjump = 1; - %Vardison.hastarget = 1; - MissionCleanup.add(%Vardison); - schedule(1000, %Vardison, %command, %Vardison); + isShielded = false; + energyPerDamagePoint = 240; + maxEnergy = 50; + rechargeRate = 0.25; - DAVardisonAttacks(%Vardison); -} + explosion = HandGrenadeExplosion; + expDmgRadius = 1.0; + expDamage = 0.05; + expImpulse = 200; + + boundingBox = "5.0 5.0 5.0"; + dynamicType = $TypeMasks::StaticShapeObjectType; + deployedObject = true; + cmdCategory = "DSupport"; + cmdIcon = CMDSensorIcon; + cmdMiniIconName = "commander/MiniIcons/com_deploymotionsensor"; + targetNameTag = 'Shadow Rift'; + deployAmbientThread = true; + debrisShapeName = "debris_generic_small.dts"; + debris = DeployableDebris; + heatSignature = 0; + needsPower = true; +}; -function StartVardison1(%pos) { - - %Vardison = new player(){ - Datablock = "VardisonStage1Armor"; - }; - %Cpos = vectorAdd(%pos, "0 0 5"); - MessageAll('MsgVardison', "\c4"@$TWM2::BossName["Vardison"]@": "@$TWM2::BossName["Vardison"]@", Checking into duty, and about to slaughter some fuckin' enemies!!!"); - - %command = "Vardison1movetotarget"; - %Vardison.ticks = 0; - InitiateBoss(%Vardison, "Vardison1"); - - %Vardison.team = 30; - %zname = CollapseEscape("\c7"@$TWM2::BossName["Vardison"]@""); // <- To Hosts, Enjoy, You can - //Change the Demon Names now!!! - %Vardison.target = createTarget(%Vardison, %zname, "", "Derm3", '', %Vardison.team, PlayerSensor); - setTargetSensorData(%Vardison.target, PlayerSensor); - setTargetSensorGroup(%Vardison.target, 30); - setTargetName(%Vardison.target, addtaggedstring(%zname)); - setTargetSkin(%Vardison.target, 'Inferno'); - // - %Vardison.setPosition(%cpos); - %Vardison.canjump = 1; - %Vardison.hastarget = 1; - MissionCleanup.add(%Vardison); - schedule(1000, %Vardison, %command, %Vardison); - - VardisonAttacks(%Vardison); -} - -function StartVardison2(%pos) { - %StartPos = VectorAdd(%pos, "0 0 100"); - %team = 30; - %rotation = "1 0 0 0"; - %skill = 10; - - %Drone = new FlyingVehicle() { - dataBlock = VardisonStage2Flyer; - position = %StartPos; - rotation = %rotation; - team = %team; - }; - MissionCleanUp.add(%Drone); - - MessageAll('MsgVardison', "\c4"@$TWM2::BossName["Vardison"]@": HA! I'm nowhere near finished with you, Lets take this to the skies.. shall we."); - - setTargetSensorGroup(%Drone.getTarget(), %team); - - %Drone.isdrone = 1; - %drone.dodgeGround = 0; - - %drone.isace = 1; - - %drone.skill = 0.2 + (%skill / 12.5); - - schedule(100, 0, "DroneForwardImpulse", %drone); //special impulse - schedule(101, 0, "DronefindTarget", %drone); - schedule(102, 0, "DroneScanGround", %drone); - - InitiateBoss(%drone, "Vardison2"); - VardisonDroneAttacks(%drone); -} - -function StartVardison3(%pos) { - %Vardison = new player(){ - Datablock = "VardisonStage3Armor"; - }; - %Cpos = vectorAdd(%pos, "0 0 5"); - MessageAll('MsgVardison', "\c4"@$TWM2::BossName["Vardison"]@": Now you will see the full power of a shadow demon!!!"); - - %command = "Vardison3movetotarget"; - %Vardison.ticks = 0; - InitiateBoss(%Vardison, "Vardison3"); - - %Vardison.team = 30; - %zname = CollapseEscape("\c7"@$TWM2::BossName["Vardison"]@""); // <- To Hosts, Enjoy, You can - //Change the Demon Names now!!! - %Vardison.target = createTarget(%Vardison, %zname, "", "Derm3", '', %Vardison.team, PlayerSensor); - setTargetSensorData(%Vardison.target, PlayerSensor); - setTargetSensorGroup(%Vardison.target, 30); - setTargetName(%Vardison.target, addtaggedstring(%zname)); - setTargetSkin(%Vardison.target, 'Inferno'); - // - %Vardison.setTransform(%cpos); - %Vardison.canjump = 1; - %Vardison.hastarget = 1; - MissionCleanup.add(%Vardison); - schedule(1000, %Vardison, %command, %Vardison); - - VardisonDemonAttacks(%Vardison); - - //SpawnVardHelper(%Vardison, vectorAdd(%Vardison.getPosition(), "15 0 100")); - -} - -function DAVardisonmovetotarget(%Demon){ - if(!isobject(%Demon)) - return; - if(%Demon.getState() $= "dead") - return; - %pos = %Demon.getworldboxcenter(); - %closestClient = ZombieLookForTarget(%Demon); - %z = getWord(%pos, 2); - if(%z < -300) { - %Demon.startFade(400, 0, true); - %Demon.startFade(1000, 0, false); - %Demon.setPosition(vectorAdd(vectoradd(%closestclient.player.getPosition(), "0 0 20"), getRandomPosition(25, 1))); - %Demon.setVelocity("0 0 0"); - MessageAll('MsgVardison', "\c4"@$TWM2::BossName["DAVardison"]@": I'm back...."); - } - %closestDistance = getWord(%closestClient,1); - %closestClient = getWord(%closestClient,0).Player; - if(%closestDistance <= $Zombie::detectDist){ - if(%closestDistance < 15) { - if(!%closestClient.vardKilling) { - %closestClient.vardKilling = 1; - DoVardisonSuperCloseKill(%Demon, %closestClient, 0); - MessageAll('MsgVardison', "\c4"@$TWM2::BossName["DAVardison"]@": Die.... Human...."); - } - } - if(%Demon.hastarget != 1){ - //LZDoYell(%Demon); - %Demon.hastarget = 1; - } - - %vector = ZgetFacingDirection(%Demon,%closestClient,%pos); - - %vector = vectorscale(%vector, $Zombie::DForwardSpeed); - %upvec = "150"; - %x = Getword(%vector,0); - %y = Getword(%vector,1); - %z = Getword(%vector,2); - if(%z >= ($Zombie::DForwardSpeed)) - %upvec = (%upvec * 5); - %vector = %x@" "@%y@" "@%upvec; - %Demon.applyImpulse(%pos, %vector); - } - else if(%Demon.hastarget == 1){ - %Demon.hastarget = 0; - %Demon.DemonRmove = schedule(100, %Demon, "ZSetRandomMove", %Demon); - } - %Demon.moveloop = schedule(500, %Demon, "DAVardisonmovetotarget", %Demon); -} - -function Vardison1movetotarget(%Demon){ - if(!isobject(%Demon)) - return; - if(%Demon.getState() $= "dead") - return; - %pos = %Demon.getworldboxcenter(); - %closestClient = ZombieLookForTarget(%Demon); - %z = getWord(%pos, 2); - if(%z < -300) { - %Demon.startFade(400, 0, true); - %Demon.startFade(1000, 0, false); - %Demon.setPosition(vectorAdd(vectoradd(%closestclient.player.getPosition(), "0 0 20"), getRandomPosition(25, 1))); - %Demon.setVelocity("0 0 0"); - MessageAll('MsgVardison', "\c4"@$TWM2::BossName["Vardison"]@": I'm back...."); - } - %closestDistance = getWord(%closestClient,1); - %closestClient = getWord(%closestClient,0).Player; - if(%closestDistance <= $Zombie::detectDist){ - if(%closestDistance < 15) { - if(!%closestClient.vardKilling) { - %closestClient.vardKilling = 1; - DoVardisonSuperCloseKill(%Demon, %closestClient, 0); - MessageAll('MsgVardison', "\c4"@$TWM2::BossName["Vardison"]@": Die.... Human...."); - } - } - if(%Demon.hastarget != 1){ - //LZDoYell(%Demon); - %Demon.hastarget = 1; - } - - %vector = ZgetFacingDirection(%Demon,%closestClient,%pos); - - %vector = vectorscale(%vector, $Zombie::DForwardSpeed); - %upvec = "150"; - %x = Getword(%vector,0); - %y = Getword(%vector,1); - %z = Getword(%vector,2); - if(%z >= ($Zombie::DForwardSpeed)) - %upvec = (%upvec * 5); - %vector = %x@" "@%y@" "@%upvec; - %Demon.applyImpulse(%pos, %vector); - } - else if(%Demon.hastarget == 1){ - %Demon.hastarget = 0; - %Demon.DemonRmove = schedule(100, %Demon, "ZSetRandomMove", %Demon); - } - %Demon.moveloop = schedule(500, %Demon, "Vardison1movetotarget", %Demon); -} - -function Vardison3movetotarget(%Demon){ - if(!isobject(%Demon)) - return; - if(%Demon.getState() $= "dead") - return; - %pos = %Demon.getworldboxcenter(); - %closestClient = ZombieLookForTarget(%Demon); - %z = getWord(%pos, 2); - if(%z < -300) { - %Demon.startFade(400, 0, true); - %Demon.startFade(1000, 0, false); - %Demon.setPosition(vectorAdd(vectoradd(%closestclient.getPosition(), "0 0 20"), getRandomPosition(25, 1))); - %Demon.setVelocity("0 0 0"); - MessageAll('MsgVardison', "\c4"@$TWM2::BossName["Vardison"]@": I'm back...."); - } - %closestDistance = getWord(%closestClient,1); - %closestClient = getWord(%closestClient,0).Player; - if(%closestDistance <= $Zombie::detectDist){ - if(%closestDistance < 10) { - %closestClient.scriptKill(0); - MessageAll('MsgVardison', "\c4"@$TWM2::BossName["Vardison"]@": DIE!!!!!!"); - } - if(%Demon.hastarget != 1){ - %Demon.hastarget = 1; - } - - %vector = ZgetFacingDirection(%Demon,%closestClient,%pos); - - %vector = vectorscale(%vector, $Zombie::DForwardSpeed*1.8); - %upvec = "150"; - %x = Getword(%vector,0); - %y = Getword(%vector,1); - %z = Getword(%vector,2); - if(%z >= ($Zombie::DForwardSpeed)) - %upvec = (%upvec * 5); - %vector = %x@" "@%y@" "@%upvec; - %Demon.applyImpulse(%pos, %vector); - } - else if(%Demon.hastarget == 1){ - %Demon.hastarget = 0; - %Demon.DemonRmove = schedule(100, %Demon, "ZSetRandomMove", %Demon); - } - %Demon.moveloop = schedule(500, %Demon, "Vardison3movetotarget", %Demon); -} - -//ATTACKS - -function DoVardisonSuperCloseKill(%source, %target, %count) { - %count++; - if(!isObject(%source) || %source.getState() $= "dead") { - %target.setMoveState(false); +function ShadowOrb::onDestroyed(%this, %obj, %prevState) { + if (%obj.isRemoved) { return; } - %source.setMoveState(true); - %target.setMoveState(true); - %target.clearInventory(); //ha, no guns for You! - //lift - if(%count <= 15) { - %ZPos = %count * 0.025; - %newpos = vectoradd(%target.getPosition(),"0 0 "@%ZPos@""); - %target.setTransform(%newpos); - %target.setvelocity("0 0 0"); + %obj.isRemoved = true; + Parent::onDestroyed(%this, %obj, %prevState); + if(isObject(%orb.sfx)) { + %obj.sfx.schedule(500, "delete"); } - else if(%count == 16) { - //MessageAll('MsgDIE', "\c4"@%source.client.namebase@": You're so.... weak..."); - %newpos = vectoradd(%target.getPosition(),"0 0 "@%ZPos * -1@""); - %target.setTransform(%newpos); - %target.setvelocity("0 0 0"); - } - else if(%count == 17) { - %target.setvelocity("1000 1000 1000"); - %target.blowup();//BAM! - ServerPlay3d(BOVHitSound, %target.getPosition()); - ServerPlay3d(BOVHitSound, %target.getPosition()); - ServerPlay3d(BOVHitSound, %target.getPosition()); - %target.damage(%source, %target.getposition(), 9999, $DamageType::BladeOfVengance); - %source.setMoveState(false); - return; - } - schedule(100, 0, "DoVardisonSuperCloseKill", %source, %target, %count); + %obj.schedule(500, "delete"); + $TWM2::VardisonManager.orbDestroyed(); } -function ShadowBomb::onExplode(%data, %proj, %pos, %mod) { - %vec = %proj.spdvec; - %vec = getword(%vec, 0)@" "@getword(%vec, 1)@" 0"; - %vec = vectorNormalize(%vec); - %vec = vectorscale(%vec, 30); - %result = containerRayCast(vectoradd(%pos,"0 0 10"), vectoradd(%pos,%vec), $TypeMasks::StaticShapeObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::TerrainObjectType, %proj); - for(%i = 0; %i < 3; %i++) { - if(%result) - schedule((5 * %i), 0, "Napalm2FindNewDir", %pos, %vec, %proj.sourceobject, 0, 0); - else { - %rndvec = (getRandom(1, 15) - 7.5)@" "@(getRandom(1, 15) - 7.5)@" "@((getRandom() * 5) + 5); - %newvec = vectoradd(%vec,%rndvec); - %newvec = vectoradd(%pos,%newvec); - %p = new LinearFlareProjectile() { - dataBlock = VardisonSubShadowBomb; - initialDirection = "0 0 -1"; - initialPosition = %newvec; - sourceObject = %proj.sourceobject; - SourceSlot = 5; - }; - %p.sourceobject = %proj.sourceobject; - %p.vector = %vec; - %p.count = 1; - if(%proj.maxExplode $= "") { - %p.maxExplode = 15; +//Boss Functions +function CheckVardisonManager() { + if($TWM2::VardisonDifficulty < 1 || $TWM2::VardisonDifficulty > 4) { + //Are the odds in your favor now, or will Vardison rek you endlessly? + $TWM2::VardisonDifficulty = getRandom(1, 4); + } + if(!isObject($TWM2::VardisonManager)) { + $TWM2::VardisonManager = new ScriptObject() { + class = "VardisonManager"; + }; + } + //Setup default params + $TWM2::VardisonManager.lastAttackTime = getRealTime(); + $TWM2::VardisonManager.minionCount = 0; + $TWM2::VardisonManager.orbObject = -1; +} + +function StartVardison1(%position) { + CheckVardisonManager(); + //Trip the boss manager so nothing else fires up in the initial 10 seconds. + $TWM2::BossGoing = 1; + //Erupt a firestorm in his coming.... + // They shall know fear xD + MessageAll('msgAdminForce', "\c5"@$TWM2::Vardison_DMsg[$TWM2::VardisonDifficulty]); + //Adjust Position + %spawnPos = getWord(%position, 0) SPC getWord(%position, 1) SPC getTerrainHeight(%position); + //First Spawn The Firestorm & Sound FX + MessageAll('msgSound', "~wfx/environment/wind_sandstorm.wav"); + MessageAll('msgSound', "~wfx/environment/snowstorm1.wav"); + schedule(1500, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav"); + schedule(2500, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav"); + schedule(3500, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav"); + schedule(5000, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav"); + schedule(5500, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav"); + schedule(7500, 0, MessageAll, 'msgSound', "~wfx/armor/breath_bio_uw.wav"); + schedule(10000, 0, MessageAll, 'msgSound', "~wfx/explosions/explosion.xpl03.wav"); + schedule(10000, 0, MessageAll, 'msgSound', "~wfx/explosions/explosion.xpl03.wav"); + schedule(10000, 0, MessageAll, 'msgSound', "~wfx/explosions/explosion.xpl03.wav"); + %fire = new ParticleEmissionDummy(){ + position = vectoradd(%spawnPos, "0 0 0.5"); + dataBlock = "defaultEmissionDummy"; + emitter = "SummoningPierEmitter"; + }; + MissionCleanup.add(%fire); + %fire.schedule(10000, "delete"); + //Spawn the fake hologram vardison. + %fakeHolo = new StaticShape(){ + Datablock = "InitialVaridionHoloArmor"; + }; + %fakeHolo.setTransform(vectorAdd(%spawnPos, "0 0 0.25")); + %fakeHolo.startfade(0, 0, true); + %fakeHolo.schedule(1000, startfade, 2500, 0, false); + %fakeHolo.schedule(7500, startfade, 2500, 0, true); + %fakeHolo.schedule(10000, "Delete"); + //And then start the real one... + schedule(10000, 0, SpawnVardison, %spawnPos); +} + +function SpawnVardison(%position) { + %Boss = new player(){ + Datablock = "VardisonStageOneArmor"; + }; + %Cpos = vectorAdd(%position, "0 0 5"); + InitiateBoss(%Boss, "Vardison1"); + + %Boss.team = 30; + %Boss.target = createTarget(%Boss, "\c7Lord Vardison", "", "Derm3", '', %Boss.team, PlayerSensor); + setTargetSensorData(%Boss.target, PlayerSensor); + setTargetSensorGroup(%Boss.target, 30); + setTargetName(%Boss.target, addtaggedstring("\c7Lord Vardison")); + setTargetSkin(%Boss.target, 'Horde'); + + %Boss.setTransform(%Cpos); + %Boss.phase = 1; + MissionCleanup.add(%Boss); + + %Boss.lastKillCount = $TWM2::BossManager.bossKills; + %Boss.canSummonMinions = true; + $TWM2::VardisonManager.Vardison = %Boss; + + %Boss.thinkSched = schedule(2500, 0, VardisonThink, %Boss); +} + +function SpawnVardison2(%position) { + schedule(250, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav"); + schedule(500, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav"); + schedule(750, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav"); + schedule(1000, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav"); + schedule(1100, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav"); + + %Boss = new player(){ + Datablock = "VardisonStageTwoArmor"; + }; + %Cpos = vectorAdd(%position, "0 0 5"); + InitiateBoss(%Boss, "Vardison2"); + + %Boss.team = 30; + %Boss.target = createTarget(%Boss, "\c7Lord Vardison", "", "Derm3", '', %Boss.team, PlayerSensor); + setTargetSensorData(%Boss.target, PlayerSensor); + setTargetSensorGroup(%Boss.target, 30); + setTargetName(%Boss.target, addtaggedstring("\c7Lord Vardison")); + setTargetSkin(%Boss.target, 'Horde'); + + %Boss.setTransform(%Cpos); + %Boss.phase = 2; + MissionCleanup.add(%Boss); + + %Boss.lastKillCount = $TWM2::BossManager.bossKills; + %Boss.canSummonMinions = true; + $TWM2::VardisonManager.Vardison = %Boss; + + //If we're on difficulty level 4, summon an orb :P + if($TWM2::VardisonDifficulty >= 4) { + VardisonSummonOrb(%Boss); + } + + %Boss.thinkSched = schedule(1000, 0, VardisonThink, %Boss); +} + +function SpawnVardison3(%position) { + schedule(250, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav"); + schedule(500, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav"); + schedule(750, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav"); + schedule(1000, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav"); + schedule(1100, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav"); + schedule(1250, 0, MessageAll, 'msgSound', "~wfx/armor/breath_bio_uw.wav"); + schedule(1250, 0, MessageAll, 'msgSound', "~wfx/explosions/explosion.xpl03.wav"); + schedule(1250, 0, MessageAll, 'msgSound', "~wfx/explosions/explosion.xpl03.wav"); + schedule(1250, 0, MessageAll, 'msgSound', "~wfx/explosions/explosion.xpl03.wav"); + + %Boss = new player(){ + Datablock = "VardisonStageThreeArmor"; + }; + %Cpos = vectorAdd(%position, "0 0 5"); + InitiateBoss(%Boss, "Vardison3"); + + %Boss.team = 30; + %Boss.target = createTarget(%Boss, "\c7Lord Vardison", "", "Derm3", '', %Boss.team, PlayerSensor); + setTargetSensorData(%Boss.target, PlayerSensor); + setTargetSensorGroup(%Boss.target, 30); + setTargetName(%Boss.target, addtaggedstring("\c7Lord Vardison")); + setTargetSkin(%Boss.target, 'Horde'); + + %Boss.setTransform(%Cpos); + %Boss.phase = 3; + MissionCleanup.add(%Boss); + + %Boss.lastKillCount = $TWM2::BossManager.bossKills; + %Boss.canSummonMinions = true; + $TWM2::VardisonManager.Vardison = %Boss; + + //If we're on level 3 or 4, instantly summon the Shadow Orb to kick things off + if($TWM2::VardisonDifficulty >= 3) { + VardisonSummonOrb(%Boss); + } + + %Boss.thinkSched = schedule(1000, 0, VardisonThink, %Boss); +} + +function VardisonThink(%Boss) { + if(!isObject(%Boss) || %Boss.getState() $= "Dead") { + //Kill this think instance, let the next one take over. + return; + } + if(%Boss.busy) { + //I'm currently doing something, check back soon. + %Boss.thinkSched = schedule(200, 0, VardisonThink, %Boss); + return; + } + %dLevel = $TWM2::VardisonDifficulty; + %lastAtt = $TWM2::VardisonManager.lastAttackTime; //<--- Note: This value is from the time the last attack ENDED + %cTime = getRealTime(); + %lastKC = %Boss.lastKillCount; + %nowKC = $TWM2::BossManager.bossKills; + %Boss.lastKillCount = $TWM2::BossManager.bossKills; + //Possible Outcomes... + %needAttack = false; + %needMinions = false; + %needOrbSummon = false; + %needMove = false; + //Check for anti-fall.... + if(getWord(%Boss.getPosition(), 2) < (getTerrainHeight(%Boss.getPosition()) - 250)) { + if(getWord(%Boss.getVelocity(), 2) < -1) { + //Block the fall... bring us back up... + echo("VardisonThink(): Anti-Fall Countermeasures activated."); + %Boss.setPosition(getWord(%Boss.getPosition(), 0) SPC getWord(%Boss.getPosition(), 1) SPC getTerrainHeight(%Boss.getPosition()) + 15); + %Boss.setVelocity("0 0 1"); + %Boss.startfade(0, 0, true); + %Boss.schedule(250, startfade, 1000, 0, false); + } + } + //Determine the correct action. + switch(%Boss.phase) { + case 1: + //Did I just get a kill? + if(%nowKC > %lastKC) { + //Do I need to summon a shadow orb? + if($TWM2::Vardison1_CanOrb[%dLevel]) { + //Is there already an active orb? + if(!isObject($TWM2::VardisonManager.orbObject)) { + //Yep, I need to summon it. + %needOrbSummon = true; + } + } + } + if((%cTime - %lastAtt) >= $TWM2::Vardison1_AttSpeed[%dLevel]) { + //Time for an attack + %needAttack = true; } else { - %p.maxExplode = %proj.maxExplode; + //If we're not ready to dish out an attack, let's check what else we need to do... + // Are we low on minions? + if($TWM2::VardisonManager.minionCount < $TWM2::Vardison1_MaxMinions[%dLevel]) { + //How many players am I up against? + %pCount = $HostGamePlayerCount; + //How low is my health? + %percentage = mCeil((mFloor(%boss.getDamageLeft()*100) / mFloor(%boss.getMaxDamage()*100)) * 100); + %BackwardsHP = 100 - %percentage; + %chance = %BackwardsHP * %pCount * (%Boss.canSummonMinions ? 1 : 0); + //Using our test factor, determine if I need minions. + if(%chance <= getRandom(1, 100)) { + %needMinions = true; + } + } + //Do I need to be moving towards the enemy? + %needMove = true; //Phase 1 is always doing this... + } + case 2: + //Did I just get a kill? + if(%nowKC > %lastKC) { + //Do I need to summon a shadow orb? + if($TWM2::Vardison2_CanOrb[%dLevel]) { + //Is there already an active orb? + if(!isObject($TWM2::VardisonManager.orbObject)) { + //Yep, I need to summon it. + %needOrbSummon = true; + } + } + } + if((%cTime - %lastAtt) >= $TWM2::Vardison2_AttSpeed[%dLevel]) { + //Time for an attack + %needAttack = true; + } + else { + //If we're not ready to dish out an attack, let's check what else we need to do... + // Are we low on minions? + if($TWM2::VardisonManager.minionCount < $TWM2::Vardison2_MaxMinions[%dLevel]) { + //How many players am I up against? + %pCount = $HostGamePlayerCount; + //How low is my health? + %percentage = mCeil((mFloor(%boss.getDamageLeft()*100) / mFloor(%boss.getMaxDamage()*100)) * 100); + %BackwardsHP = 100 - %percentage; + %chance = %BackwardsHP * %pCount * (%Boss.canSummonMinions ? 1 : 0); + //Using our test factor, determine if I need minions. + if(%chance <= getRandom(1, 100)) { + %needMinions = true; + } + } + //Phase 2 is stationary unless you're on Hard or WTF mode + if(%dLevel >= 3) { + %needMove = true; + } + else { + //Phase Two only Super-Lunges if you get too close + if(getWord(VardisonGetClosest(%Boss), 1) <= 50) { + %needMove = true; + } + } + } + case 3: + //Did I just get a kill? + if(%nowKC > %lastKC) { + //Do I need to summon a shadow orb? + if($TWM2::Vardison3_CanOrb[%dLevel]) { + //Is there already an active orb? + if(!isObject($TWM2::VardisonManager.orbObject)) { + //Yep, I need to summon it. + %needOrbSummon = true; + } + } + } + if((%cTime - %lastAtt) >= $TWM2::Vardison3_AttSpeed[%dLevel]) { + //Time for an attack + %needAttack = true; + } + else { + //If we're not ready to dish out an attack, let's check what else we need to do... + // Are we low on minions? + if($TWM2::VardisonManager.minionCount < $TWM2::Vardison3_MaxMinions[%dLevel]) { + //How many players am I up against? + %pCount = $HostGamePlayerCount; + //How low is my health? + %percentage = mCeil((mFloor(%boss.getDamageLeft()*100) / mFloor(%boss.getMaxDamage()*100)) * 100); + %BackwardsHP = 100 - %percentage; + %chance = %BackwardsHP * %pCount * (%Boss.canSummonMinions ? 1 : 0); + //Using our test factor, determine if I need minions. + if(%chance <= getRandom(1, 100)) { + %needMinions = true; + } + } + //Do I need to be moving towards the enemy? + %needMove = true; //Phase 3 is always doing this... } - } } - if (%data.hasDamageRadius) - RadiusExplosion(%proj, %pos, %data.damageRadius, %data.indirectDamage, %data.kickBackStrength, %proj.sourceObject, %data.radiusDamageType); -} - -function VardisonSubShadowBomb::onExplode(%data, %proj, %pos, %mod) { - if(%proj.count < %proj.maxExplode) { //holy... christ - %vec = vectorscale(vectornormalize(%proj.vector), 24); - %result = containerRayCast(vectoradd(%pos,"0 0 10"), vectoradd(%pos,%vec), $TypeMasks::StaticShapeObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::TerrainObjectType, %proj); - if(%result) - schedule(5, 0, "Napalm2FindNewDir", %pos, %vec, %proj.sourceobject, %proj.count, 0); - else { - %rndvec = (getRandom(1, 10) - 5)@" "@(getRandom(1, 10) - 5)@" "@((getRandom() * 5) + 5); - %newvec = vectoradd(%vec,%rndvec); - %newvec = vectoradd(%pos,%newvec); - %p = new LinearFlareProjectile() { - dataBlock = VardisonSubShadowBomb; - initialDirection = "0 0 -1"; - initialPosition = %newvec; - sourceObject = %proj.sourceobject; - sourceSlot = 5; - }; - %p.sourceobject = %proj.sourceobject; - %p.vector = %vec; - %p.count = %proj.count + 1; - } + //Call the correct function... + if(%needOrbSummon) { + VardisonSummonOrb(%Boss); } - if (%data.hasDamageRadius) - RadiusExplosion(%proj, %pos, %data.damageRadius, %data.indirectDamage, %data.kickBackStrength, %proj.sourceObject, %data.radiusDamageType); -} - -function Napalm2FindNewDir(%pos, %vec, %source, %count, %count2) { - if(%count2 == 2) { - %rndvec = getRandom(1, 10)@" "@getRandom(1, 10)@" "@((getRandom() * 5) + 4); - %newvec = vectoradd(%pos,%rndvec); - %p = new LinearFlareProjectile() { - dataBlock = VardisonSubShadowBomb; - initialDirection = "0 0 -1"; - initialPosition = %newvec; - sourceObject = %source; - sourceSlot = 5; - }; - %p.sourceobject = %source; - %p.vector = %vec; - %p.count = %count+1; - return; - } - if(%count2 == 1) { - %vec = vectorscale(%vec,-1); - %result = containerRayCast(vectoradd(%pos,"0 0 10"), vectoradd(%pos,%vec), $TypeMasks::StaticShapeObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::TerrainObjectType, 0); - if(!(%result)){ - %rndvec = getRandom(1, 10)@" "@getRandom(1, 10)@" "@((getRandom() * 5) + 4); - %newvec = vectoradd(%vec,%rndvec); - %newvec = vectoradd(%pos,%newvec); - %p = new LinearFlareProjectile() { - dataBlock = VardisonSubShadowBomb; - initialDirection = "0 0 -1"; - initialPosition = %newvec; - sourceObject = %source; - sourceSlot = 5; - }; - %p.sourceobject = %source; - %p.vector = %vec; - %p.count = %count+1; - return; - } + else if(%needAttack) { + VardisonPerformAttack(%Boss); } else { - %chance = getrandom(1,4); - if(%chance <= 2){ - %nv2 = (getword(%vec, 0) * -1); - %nv1 = getword(%vec, 1); - %vec = %nv1@" "@%nv2@" 0"; - } - else { - %nv2 = getword(%vec, 0); - %nv1 = (getword(%vec, 1) * -1); - %vec = %nv1@" "@%nv2@" 0"; - } - %result = containerRayCast(vectoradd(%pos,"0 0 10"), vectoradd(%pos,%vec), $TypeMasks::StaticShapeObjectType | $TypeMasks::InteriorObjectType | $TypeMasks::ForceFieldObjectType | $TypeMasks::TerrainObjectType, 0); - if(!(%result)){ - %rndvec = getRandom(1, 10)@" "@getRandom(1, 10)@" "@((getRandom() * 5) + 4); - %newvec = vectoradd(%vec,%rndvec); - %newvec = vectoradd(%pos,%newvec); - %p = new LinearFlareProjectile() { - dataBlock = VardisonSubShadowBomb; - initialDirection = "0 0 -1"; - initialPosition = %newvec; - sourceObject = %source; - sourceSlot = 5; - }; - %p.sourceobject = %source; - %p.vector = %vec; - %p.count = %count+1; - return; + if(%needMinions) { + VardisonSummonMinions(%Boss); + } + if(%needMove) { + VardisonDoMove(%Boss); } } - %count2++; - schedule(2, 0, "Napalm2FindNewDir", %pos, %vec, %source, %count, %count2); + %Boss.thinkSched = schedule(500, 0, VardisonThink, %Boss); } -function GOVDoFlameCano(%g, %target) { - if(!isObject(%g) || %g.getState() $= "dead") { +function VardisonDoMove(%Boss) { + if(!isObject(%Boss) || %Boss.getState() $= "Dead") { return; } - %g.setPosition(VectorAdd(%target.getPosition(), "0 0 70")); - %Pad = new StaticShape() { - dataBlock = DeployedSpine; - scale = ".1 .1 1"; - position = VectorAdd(%target.getPosition(), "0 0 69"); + %pos = %Boss.getworldboxcenter(); + switch(%Boss.phase) { + case 1: + %closest = VardisonGetClosest(%Boss); + %clDst = getWord(%closest, 1); + %clPlayer = getWord(%closest, 0).Player; + if(%clDst < 12) { + //Perform a sword slam + VardisonDoSlam(%Boss, %clPlayer); + return; + } + if(%Boss.hastarget != 1){ + %Boss.hastarget = 1; + } + %vector = ZgetFacingDirection(%Boss, %clPlayer, %pos); + %vector = vectorscale(%vector, $Zombie::DForwardSpeed); + %upvec = "150"; + %x = Getword(%vector,0); + %y = Getword(%vector,1); + %z = Getword(%vector,2); + if(%z >= ($Zombie::DForwardSpeed)) { + %upvec = (%upvec * 5); + } + %vector = %x@" "@%y@" "@%upvec; + %Boss.applyImpulse(%pos, %vector); + + case 2: + %closest = VardisonGetClosest(%Boss); + %clDst = getWord(%closest, 1); + %clPlayer = getWord(%closest, 0).Player; + if(%clDst < 15) { + //Perform a sword slam + VardisonDoSlam(%Boss, %clPlayer); + return; + } + if(%Boss.hastarget != 1){ + %Boss.hastarget = 1; + } + %vector = ZgetFacingDirection(%Boss, %clPlayer, %pos); + %vector = vectorscale(%vector, $Zombie::DForwardSpeed*2); + %upvec = "150"; + %x = Getword(%vector,0); + %y = Getword(%vector,1); + %z = Getword(%vector,2); + if(%z >= ($Zombie::DForwardSpeed)) { + %upvec = (%upvec * 5); + } + %vector = %x@" "@%y@" "@%upvec; + %Boss.applyImpulse(%pos, %vector); + + case 3: + %closest = VardisonGetClosest(%Boss); + %clDst = getWord(%closest, 1); + %clPlayer = getWord(%closest, 0).Player; + if(%clDst < 6) { + //Insta-Kill xD + %clPlayer.setInvincible(false); + MessageAll('msgDie', "\c4Lord Vardision: DIE "@getWord(%closest, 0).namebase@"!!!"); + %clPlayer.damage(%boss, %clPlayer.getPosition(), 10000, $DamageType::Idiocy); + return; + } + if(%Boss.hastarget != 1){ + %Boss.hastarget = 1; + } + %vector = ZgetFacingDirection(%Boss, %clPlayer, %pos); + %vector = vectorscale(%vector, $Zombie::DForwardSpeed*1.8); + %upvec = "150"; + %x = Getword(%vector,0); + %y = Getword(%vector,1); + %z = Getword(%vector,2); + if(%z >= ($Zombie::DForwardSpeed)) { + %upvec = (%upvec * 5); + } + %vector = %x@" "@%y@" "@%upvec; + %Boss.applyImpulse(%pos, %vector); + } +} + +function VardisonDoSlam(%Boss, %ToDie) { + %Boss.busy = true; + %vector = ZgetFacingDirection(%Boss, %ToDie, %Boss.getWorldBoxCenter()); + %vector = vectorscale(%vector, $Zombie::DForwardSpeed * 7.5); + %upvec = "150"; + %x = Getword(%vector,0); + %y = Getword(%vector,1); + %z = Getword(%vector,2); + if(%z >= ($Zombie::DForwardSpeed)) { + %upvec = (%upvec * 5); + } + %vector = %x@" "@%y@" "@%upvec; + %Boss.applyImpulse(%pos, %vector); + schedule(750, 0, "VardisonFinishSlam", %Boss, %ToDie); +} + +function VardisonFinishSlam(%Boss, %ToDie) { + //Summon the invis-projectile + %Boss.setMoveState(true); + %p = new LinearFlareProjectile() { + dataBlock = ShadowBladeSlam; + initialDirection = "0 0 -10"; + initialPosition = vectorAdd(%ToDie.getPosition(), "0 0 1"); + sourceSlot = 0; }; - %g.setMoveState(true); - %Pad.setCloaked(true); - %Pad.schedule(3000, "setPosition", vectorSub(%Pad.getPosition(), "0 0 10")); - %Pad.schedule(4000, "setPosition", vectorSub(%Pad.getPosition(), "0 0 20")); - %Pad.schedule(5000, "setPosition", vectorSub(%Pad.getPosition(), "0 0 30")); - %Pad.schedule(6000, "setPosition", vectorSub(%Pad.getPosition(), "0 0 40")); - %g.schedule(6500, "SetMoveState", false); - %pad.schedule(6500, "Delete"); - //The Vector Crap - schedule(2500,0,"DropFlameCano2", %g, %target); + %p.sourceObject = %Boss; + MissionCleanup.add(%p); + %Boss.schedule(1000, "setMoveState", false); + ServerPlay3d(BOVHitSound, %ToDie.getPosition()); + ServerPlay3d(BOVHitSound, %ToDie.getPosition()); + ServerPlay3d(BOVHitSound, %ToDie.getPosition()); + $TWM2::VardisonManager.schedule(1000, cooldownOff, %Boss, "busy"); } -function DropFlameCano2(%g, %target) { - if(!isObject(%g) || %g.getState() $= "dead") { +function VardisonSummonOrb(%Boss) { + if(isObject($TWM2::VardisonManager.orbObject)) { + //Stop, we already have an orb. return; } - //First, Specify All Directions - %vec[1] = vectorscale(vectornormalize("1 0 0"), 24); // +X 0Y - %vec[2] = vectorscale(vectornormalize("1 1 0"), 24); // +X +Y - %vec[3] = vectorscale(vectornormalize("1 -1 0"), 24); // +X -Y - %vec[4] = vectorscale(vectornormalize("-1 0 0"), 24); // -X 0Y - %vec[5] = vectorscale(vectornormalize("-1 1 0"), 24); // -X +Y - %vec[6] = vectorscale(vectornormalize("-1 -1 0"), 24); //-X -Y - %vec[7] = vectorscale(vectornormalize("0 1 0"), 24); // 0X +Y - %vec[8] = vectorscale(vectornormalize("0 -1 0"), 24); // 0X -Y - //Oh.. long crap - for(%i = 1; %i <= 8; %i++) { - %p = new LinearFlareProjectile() { - dataBlock = ShadowBomb; - initialDirection = "0 0 -30"; - initialPosition = vectorAdd(%g.getPosition(), "0 0 -3"); - sourceObject = %g; - sourceSlot = 5; - }; - %p.vector = %vec[%i]; - %p.count = 1; - %p.MaxExplode = 15; - } + //Shadow Orb Time... + MessageAll('msgAttack', "\c5Alert: Lord Vardison Opens The Shadow Rift..."); + schedule(250, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav"); + schedule(700, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav"); + schedule(1250, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav"); + schedule(1350, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav"); + schedule(1500, 0, MessageAll, 'msgSound', "~wfx/environment/ctmelody4.wav"); + schedule(2000, 0, MessageAll, 'msgSound', "~wfx/explosions/explosion.xpl03.wav"); + schedule(2000, 0, MessageAll, 'msgSound', "~wfx/explosions/explosion.xpl03.wav"); + schedule(2000, 0, MessageAll, 'msgSound', "~wfx/explosions/explosion.xpl03.wav"); + %Boss.busy = true; + %Boss.rapierShield = true; + %Boss.setMoveState(true); + //Fire SFX + $TWM2::VardisonManager.orbFire = new ParticleEmissionDummy(){ + position = vectoradd(%Boss.getPosition(), "0 0 0.5"); + dataBlock = "defaultEmissionDummy"; + emitter = "SummoningPierEmitter"; + }; + MissionCleanup.add($TWM2::VardisonManager.orbFire); + //Create the Orb Object + $TWM2::VardisonManager.schedule(2000, summonOrb, %Boss); } -//The evilness Begins Here -function DAVardisonAttacks(%boss) { - if(!isObject(%boss) || %boss.getState() $= "dead") { - return; - } - schedule(23500, 0, "DAVardisonAttacks", %boss); - %attack = getRandom(1, 10); - switch(%attack) { +function VardisonSummonMinions(%Boss) { + %currentCount = $TWM2::VardisonManager.minionCount; + %dLevel = $TWM2::VardisonDifficulty; + %max = 0; + switch(%Boss.phase) { case 1: - %target = FindValidTarget(%boss); - if(isObject(%target.player)) { - %target = %target.player; - VardisonAttack(%boss, "NMM", %target); - } + %max = $TWM2::Vardison1_MaxMinions[%dLevel]; case 2: - %target = FindValidTarget(%boss); - if(isObject(%target.player)) { - %target = %target.player; - VardisonAttack(%boss, "LBM", %target); - } + %max = $TWM2::Vardison2_MaxMinions[%dLevel]; case 3: - %target = FindValidTarget(%boss); - if(isObject(%target.player)) { - %target = %target.player; - VardisonAttack(%boss, "ShadowBombDirect", %target SPC 2); - } - case 4: - %target = FindValidTarget(%boss); - if(isObject(%target.player)) { - %target = %target.player; - GOVDoFlameCano(%boss, %target); - } - case 5: - %target = FindValidTarget(%boss); - if(isObject(%target.player)) { - %target = %target.player; - VardisonAttack(%boss, "ShadowBombDirect", %target SPC 4); - } - case 6: - %target = FindValidTarget(%boss); - if(isObject(%target.player)) { - %target = %target.player; - for(%i = 0; %i < 10; %i++) { - %timeInt = %i * 200; - schedule(%timeInt, 0, VardisonAttack, %boss, "ShadowBombLaunchAbove", %target SPC 4); - } - } - case 7: - %boss.setMoveState(true); - %vS[0] = "10 10 0"; - %vS[1] = "-10 10 0"; - %vS[2] = "10 -10 0"; - %vS[3] = "-10 -10 0"; - for(%i = 0; %i < 4; %i++) { - CreateDemon(vectorAdd(%boss.getPosition(), %vS[%i])); - } - %boss.schedule(5000, setMoveState, false); - case 8: - %boss.setMoveState(true); - //four charge-up beams - createLifeEmitter(%boss.getPosition(), PrebeamEmitter, 5000); - createLifeEmitter(%boss.getPosition(), PrebeamEmitter, 5000); - createLifeEmitter(%boss.getPosition(), PrebeamEmitter, 5000); - createLifeEmitter(%boss.getPosition(), PrebeamEmitter, 5000); - //the actual attack - for(%i = 0; %i < 50; %i++) { - %timeAtt = 5000 + (%i *150); - //-------------------------- - %vec = %boss.GetMuzzleVector(4); - %pos = %boss.GetMuzzlePoint(4); - schedule(%timeAtt, 0, VardisonAttack, %boss, "HyperspeedPlasmaBolt", %pos TAB %vec); - } - %boss.schedule(12500, setMoveState, false); - case 9: - VardisonAttack(%boss, "LinearFlameWall"); - case 10: - VardisonAttack(%boss, "SeekingRapiers", %target); + %max = $TWM2::Vardison3_MaxMinions[%dLevel]; + } + %Low = 1; + %High = %max - %currentCount; + for(%i = 0; %i < getRandom(%Low, %High); %i++) { + VardisonDoMinionSummon(%Boss); + } + %Boss.canSummonMinions = false; + $TWM2::VardisonManager.schedule($TWM2::Vardison_MinionCooldown[%dLevel] * 1000, cooldownOff, %Boss, "minions"); +} + +function VardisonDoMinionSummon(%Boss) { + %posSpawn = vectorAdd(%Boss.getPosition(), getRandomposition(50, 1)); + %spawnFire = new ParticleEmissionDummy(){ + position = vectoradd(%posSpawn, "0 0 0.5"); + dataBlock = "defaultEmissionDummy"; + emitter = "SummoningPierEmitter"; + }; + MissionCleanup.add(%spawnFire); + %spawnFire.schedule(500, "delete"); + schedule(650, 0, SpawnVMinion, %posSpawn); +} + +function SpawnVMinion(%position) { + %minion = StartAZombie(%position, 17); + if(isObject(%minion)) { + //Apply minion settings & increase count + $TWM2::VardisonManager.minionCount++; + %minion.isBossMinion = true; + %minion.isVardisonMinion = true; } } -function VardisonAttacks(%boss) { - if(!isObject(%boss) || %boss.getState() $= "dead") { - return; - } - schedule(23500, 0, "VardisonAttacks", %boss); - %attack = getRandom(1, 8); - switch(%attack) { - case 1: - %target = FindValidTarget(%boss); - if(isObject(%target.player)) { - %target = %target.player; - VardisonAttack(%boss, "NMM", %target); - } - case 2: - %target = FindValidTarget(%boss); - if(isObject(%target.player)) { - %target = %target.player; - VardisonAttack(%boss, "LBM", %target); - } - case 3: - %target = FindValidTarget(%boss); - if(isObject(%target.player)) { - %target = %target.player; - VardisonAttack(%boss, "ShadowBombDirect", %target SPC 2); - } - case 4: - %target = FindValidTarget(%boss); - if(isObject(%target.player)) { - %target = %target.player; - GOVDoFlameCano(%boss, %target); - } - case 5: - %target = FindValidTarget(%boss); - if(isObject(%target.player)) { - %target = %target.player; - VardisonAttack(%boss, "ShadowBombDirect", %target SPC 4); - } - case 6: - %target = FindValidTarget(%boss); - if(isObject(%target.player)) { - %target = %target.player; - for(%i = 0; %i < 10; %i++) { - %timeInt = %i * 200; - schedule(%timeInt, 0, VardisonAttack, %boss, "ShadowBombLaunchAbove", %target SPC 4); - } - } - case 7: - %boss.setMoveState(true); - %vS[0] = "10 10 0"; - %vS[1] = "-10 10 0"; - %vS[2] = "10 -10 0"; - %vS[3] = "-10 -10 0"; - for(%i = 0; %i < 4; %i++) { - CreateDemon(vectorAdd(%boss.getPosition(), %vS[%i])); - } - %boss.schedule(5000, setMoveState, false); - case 8: - %boss.setMoveState(true); - //four charge-up beams - createLifeEmitter(%boss.getPosition(), PrebeamEmitter, 5000); - createLifeEmitter(%boss.getPosition(), PrebeamEmitter, 5000); - createLifeEmitter(%boss.getPosition(), PrebeamEmitter, 5000); - createLifeEmitter(%boss.getPosition(), PrebeamEmitter, 5000); - //the actual attack - for(%i = 0; %i < 50; %i++) { - %timeAtt = 5000 + (%i *150); - //-------------------------- - %vec = %boss.GetMuzzleVector(4); - %pos = %boss.GetMuzzlePoint(4); - schedule(%timeAtt, 0, VardisonAttack, %boss, "HyperspeedPlasmaBolt", %pos TAB %vec); - } - %boss.schedule(12500, setMoveState, false); +function VardisonGetClosest(%Boss) { + %wbpos = %Boss.getworldboxcenter(); + %count = ClientGroup.getCount(); + %closestClient = -1; + %closestDistance = 32767; + for(%i = 0; %i < %count; %i++) { + %cl = ClientGroup.getObject(%i); + if(isObject(%cl.player)){ + %testPos = %cl.player.getWorldBoxCenter(); + %distance = vectorDist(%wbpos, %testPos); + if (%distance > 0 && %distance < %closestDistance) { + %closestClient = %cl; + %closestDistance = %distance; + } + } } + return %closestClient SPC %closestDistance; } -function VardisonDroneAttacks(%boss) { - if(!isObject(%boss)) { - return; - } - schedule(10000, 0, "VardisonDroneAttacks", %boss); - %attack = getRandom(1,3); - switch(%attack) { +function VardisonPerformAttack(%Boss) { + //The do-all opening function for Vardison's attacks + //Start by halting the think() method + %Boss.busy = true; + switch(%Boss.phase) { case 1: - %target = FindValidTarget(%boss); - if(isObject(%target.player)) { - VardisonAttack(%boss, "NMM", %target.player); - } - case 2: - %target = FindValidTarget(%boss); - if(isObject(%target.player)) { - %target = %target.player; - VardisonAttack(%boss, "LBM", %target); - } - case 3: - %target = FindValidTarget(%boss); - if(isObject(%target.player)) { - %target = %target.player; - VardisonAttack(%boss, "SuperLaser", %target); - } - } -} - -function VardisonDemonAttacks(%boss) { - if(!isObject(%boss) || %boss.getState() $= "dead") { - return; - } - //create a mini-demon - CreateDemon(vectorAdd(%boss.getPosition(), getRandomPosition(10, 1))); - // - %boss.setMoveState(true); - schedule(15000, 0, "VardisonDemonAttacks", %boss); - %attack = getRandom(1,8); - switch(%attack) { - case 1: - %target = FindValidTarget(%boss); - if(isObject(%target.player)) { - %target = %target.player; - VardisonAttack(%boss, "LBM", %target); - schedule(2500, 0, VardisonAttack, %boss, "LBM", %target); - schedule(3500, 0, VardisonAttack, %boss, "LBM", %target); - schedule(5000, 0, VardisonAttack, %boss, "LBM", %target); - schedule(5100, 0, VardisonAttack, %boss, "LBM", %target); - %boss.schedule(5100, "SetMoveState", false); - MessageAll('MsgVardison', "\c4"@$TWM2::BossName["Vardison"]@": I've got some missiles for you "@getTaggedString(%target.client.name)@"."); - return; - } - %boss.schedule(1, "SetMoveState", false); - case 2: - %target = FindValidTarget(%boss); - if(isObject(%target.player)) { - VardisonAttack(%boss, "NMM", %target.player); - MessageAll('MsgVardison', "\c4"@$TWM2::BossName["Vardison"]@": It's time to invoke darkness upon "@getTaggedString(%target.name)@"."); - %boss.schedule(1000, "SetMoveState", false); - return; - } - %boss.schedule(1, "SetMoveState", false); - case 3: - setgravity(-1000); - MessageAll('MsgVardison', "\c4"@$TWM2::BossName["Vardison"]@": I'll disorient you all!"); - schedule(3000, 0, "SetGravity", 1000); - schedule(7500, 0, "SetGravity", -20); - %boss.schedule(7500, "SetMoveState", false); - //%boss.InvokeLoop = InvokeStillwallLoop(%boss); - schedule(7500, 0, "Cancel", %boss.InvokeLoop); - case 4: - %target = FindValidTarget(%boss); - if(isObject(%target.player)) { - %target = %target.player; - VardisonAttack(%boss, "LaserDrop", %target); - %boss.schedule(3000, "SetMoveState", false); - MessageAll('MsgVardison', "\c4"@$TWM2::BossName["Vardison"]@": Your time has come "@getTaggedString(%target.client.name)@"."); - return; - } - %boss.schedule(1, "SetMoveState", false); - case 5: - %target = FindValidTarget(%boss); - if(isObject(%target.player)) { - %target = %target.player; - for(%i = 0; %i < 25; %i++) { - schedule(50+(%i*150), 0, VardisonAttack, %boss, "SuperLaser", %target); - } - %boss.schedule(10000, "SetMoveState", false); - MessageAll('MsgVardison', "\c4"@$TWM2::BossName["Vardison"]@": BLAAAAHAAHAHAHAAHA!!!"); - return; - } - %boss.schedule(1, "SetMoveState", false); - case 6: - for(%i = 0; %i < ClientGroup.getCount(); %i++) { - %target = ClientGroup.getObject(%i); - if(isObject(%target.player)) { - VardisonAttack(%boss, "NMM", %target.player); - } - } - MessageAll('MsgVardison', "\c4"@$TWM2::BossName["Vardison"]@": All must suffer!!!"); - %boss.schedule(1000, "SetMoveState", false); - return; - case 7: - for(%i = 0; %i < ClientGroup.getCount(); %i++) { - %target = ClientGroup.getObject(%i); - if(isObject(%target.player)) { - %target = %target.player; - for(%l = 0; %l < 25; %l++) { - schedule(50+(%l*150), 0, VardisonAttack, %boss, "SuperLaser", %target); + %attackSelect = getRandom(1, 5); + switch(%attackSelect) { + case 1: + //Shadow Bomb Strike + %Boss.setMoveState(true); + %target = FindValidTarget(%Boss); + if(isObject(%target)) { + %tPl = %target.player; + VardisonNamedAttack(%Boss, "ShadowBombStrike", %tPl); + $TWM2::VardisonManager.schedule(4000, cooldownOff, %Boss, "attackFinished"); } - } - } - MessageAll('MsgVardison', "\c4"@$TWM2::BossName["Vardison"]@": Everyone DIES NOW!!!!"); - %boss.schedule(10000, "SetMoveState", false); - return; - case 8: - %target = FindValidTarget(%boss); - if(isObject(%target.player)) { - for(%i = 0; %i < 15; %i++) { - %time = %i * 150; - %mType = getRandom(0, 1); - switch(%mType) { - case 0: - schedule(%time, 0, VardisonAttack, %boss, "NMM", %target.player); - case 1: - schedule(%time, 0, VardisonAttack, %boss, "LBM", %target.player); - default: - schedule(%time, 0, VardisonAttack, %boss, "NMM", %target.player); + else { + %Boss.setMoveState(false); + %Boss.busy = false; + } + + case 2: + //Nightmare Missile + %Boss.setMoveState(true); + %target = FindValidTarget(%Boss); + if(isObject(%target)) { + %tPl = %target.player; + VardisonNamedAttack(%Boss, "NightmareMissile", %tPl); + $TWM2::VardisonManager.schedule(4500, cooldownOff, %Boss, "attackFinished"); + } + else { + %Boss.setMoveState(false); + %Boss.busy = false; + } + + case 3: + //Shadow Fissure + %Boss.setMoveState(true); + %target = FindValidTarget(%Boss); + if(isObject(%target)) { + %tPl = %target.player; + %tPos = %tPl.getPosition(); + %bPos = %Boss.getPosition(); + %fVec = vectorNormalize(vectorSub(%tPos, %bPos)); + //Phase Vardison Out To Safety + %fire = new ParticleEmissionDummy(){ + position = vectoradd(%spawnPos, "0 0 0.5"); + dataBlock = "defaultEmissionDummy"; + emitter = "SummoningPierEmitter"; + }; + MissionCleanup.add(%fire); + %fire.schedule(6500, "delete"); + //Fades & Teleports + %Boss.startfade(1500, 0, true); + %Boss.schedule(2000, setPosition, vectorAdd(%bPos, "9999 9999 10")); + schedule(3000, 0, "VardisonNamedAttack", %Boss, "ShadowFissure", %bPos TAB %fVec); + %Boss.schedule(6000, setPosition, %bPos); + %Boss.schedule(6000, startFade, 1000, 0, false); + // + $TWM2::VardisonManager.schedule(7000, cooldownOff, %Boss, "attackFinished"); + } + else { + %Boss.setMoveState(false); + %Boss.busy = false; + } + + case 4: + //4x Seeker Photon + %Boss.setMoveState(true); + %target = FindValidTarget(%Boss); + if(isObject(%target)) { + %tPl = %target.player; + schedule(1000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl); + schedule(2000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl); + schedule(3000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl); + schedule(4000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl); + $TWM2::VardisonManager.schedule(5000, cooldownOff, %Boss, "attackFinished"); + } + else { + %Boss.setMoveState(false); + %Boss.busy = false; + } + + case 5: + //Fire Missile + %Boss.setMoveState(true); + %target = FindValidTarget(%Boss); + if(isObject(%target)) { + %tPl = %target.player; + VardisonNamedAttack(%Boss, "FireSeeker", %tPl); + $TWM2::VardisonManager.schedule(4500, cooldownOff, %Boss, "attackFinished"); + } + else { + %Boss.setMoveState(false); + %Boss.busy = false; } - } - MessageAll('MsgVardison', "\c4"@$TWM2::BossName["Vardison"]@": "@getTaggedString(%target.name)@" Will Feel the Power of My Missiles."); - %boss.schedule(1000, "SetMoveState", false); - return; } - %boss.schedule(1, "SetMoveState", false); + + case 2: + %attackSelect = getRandom(1, 8); + switch(%attackSelect) { + case 1: + //Shadow Bomb Strike + %Boss.setMoveState(true); + %target = FindValidTarget(%Boss); + if(isObject(%target)) { + %tPl = %target.player; + VardisonNamedAttack(%Boss, "ShadowBombStrike", %tPl); + $TWM2::VardisonManager.schedule(4000, cooldownOff, %Boss, "attackFinished"); + } + else { + %Boss.setMoveState(false); + %Boss.busy = false; + } + + case 2: + //Nightmare Missile + %Boss.setMoveState(true); + %target = FindValidTarget(%Boss); + if(isObject(%target)) { + %tPl = %target.player; + VardisonNamedAttack(%Boss, "NightmareMissile", %tPl); + $TWM2::VardisonManager.schedule(4500, cooldownOff, %Boss, "attackFinished"); + } + else { + %Boss.setMoveState(false); + %Boss.busy = false; + } + + case 3: + //Shadow Fissure + %Boss.setMoveState(true); + %target = FindValidTarget(%Boss); + if(isObject(%target)) { + %tPl = %target.player; + %tPos = %tPl.getPosition(); + %bPos = %Boss.getPosition(); + %fVec = vectorNormalize(vectorSub(%tPos, %bPos)); + //Phase Vardison Out To Safety + %fire = new ParticleEmissionDummy(){ + position = vectoradd(%spawnPos, "0 0 0.5"); + dataBlock = "defaultEmissionDummy"; + emitter = "SummoningPierEmitter"; + }; + MissionCleanup.add(%fire); + %fire.schedule(6500, "delete"); + //Fades & Teleports + %Boss.startfade(1500, 0, true); + %Boss.schedule(2000, setPosition, vectorAdd(%bPos, "9999 9999 10")); + schedule(3000, 0, "VardisonNamedAttack", %Boss, "ShadowFissure", %bPos TAB %fVec); + %Boss.schedule(6000, setPosition, %bPos); + %Boss.schedule(6000, startFade, 1000, 0, false); + // + $TWM2::VardisonManager.schedule(7000, cooldownOff, %Boss, "attackFinished"); + } + else { + %Boss.setMoveState(false); + %Boss.busy = false; + } + + case 4: + //4x Seeker Photon + %Boss.setMoveState(true); + %target = FindValidTarget(%Boss); + if(isObject(%target)) { + %tPl = %target.player; + schedule(1000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl); + schedule(2000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl); + schedule(3000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl); + schedule(4000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl); + $TWM2::VardisonManager.schedule(5000, cooldownOff, %Boss, "attackFinished"); + } + else { + %Boss.setMoveState(false); + %Boss.busy = false; + } + + case 5: + //Minion Army + VardisonNamedAttack(%Boss, "MinionFlood", ""); + + case 6: + //Stasis Gate + %Boss.setMoveState(true); + %target = FindValidTarget(%Boss); + if(isObject(%target)) { + %tPl = %target.player.getPosition(); + VardisonNamedAttack(%Boss, "StasisGate", %tPl); + $TWM2::VardisonManager.schedule(10000, cooldownOff, %Boss, "attackFinished"); + } + else { + %Boss.setMoveState(false); + %Boss.busy = false; + } + + case 7: + //Rift Gate + %Boss.setMoveState(true); + %target = FindValidTarget(%Boss); + if(isObject(%target)) { + %tPl = %target.player.getPosition(); + VardisonNamedAttack(%Boss, "RiftGate", %tPl); + $TWM2::VardisonManager.schedule(10000, cooldownOff, %Boss, "attackFinished"); + } + else { + %Boss.setMoveState(false); + %Boss.busy = false; + } + + case 8: + //SGF + %Boss.setMoveState(true); + %target = FindValidTarget(%Boss); + if(isObject(%target)) { + %tPl = %target.player; + VardisonNamedAttack(%Boss, "SolomentaryGravityFlux", %tPl TAB 0); + $TWM2::VardisonManager.schedule(5000, cooldownOff, %Boss, "attackFinished"); + } + else { + %Boss.setMoveState(false); + %Boss.busy = false; + } + } + + case 3: + %attackSelect = getRandom(1, 7); + switch(%attackSelect) { + case 1: + //Shadow Bomb Strike + %Boss.setMoveState(true); + %target = FindValidTarget(%Boss); + if(isObject(%target)) { + %tPl = %target.player; + VardisonNamedAttack(%Boss, "ShadowBombStrike", %tPl); + $TWM2::VardisonManager.schedule(4000, cooldownOff, %Boss, "attackFinished"); + } + else { + %Boss.setMoveState(false); + %Boss.busy = false; + } + + case 2: + //Nightmare Missile + %Boss.setMoveState(true); + %target = FindValidTarget(%Boss); + if(isObject(%target)) { + %tPl = %target.player; + VardisonNamedAttack(%Boss, "NightmareMissile", %tPl); + $TWM2::VardisonManager.schedule(4500, cooldownOff, %Boss, "attackFinished"); + } + else { + %Boss.setMoveState(false); + %Boss.busy = false; + } + + case 3: + //Shadow Fissure + %Boss.setMoveState(true); + %target = FindValidTarget(%Boss); + if(isObject(%target)) { + %tPl = %target.player; + %tPos = %tPl.getPosition(); + %bPos = %Boss.getPosition(); + %fVec = vectorNormalize(vectorSub(%tPos, %bPos)); + //Phase Vardison Out To Safety + %fire = new ParticleEmissionDummy(){ + position = vectoradd(%spawnPos, "0 0 0.5"); + dataBlock = "defaultEmissionDummy"; + emitter = "SummoningPierEmitter"; + }; + MissionCleanup.add(%fire); + %fire.schedule(6500, "delete"); + //Fades & Teleports + %Boss.startfade(1500, 0, true); + %Boss.schedule(2000, setPosition, vectorAdd(%bPos, "9999 9999 10")); + schedule(3000, 0, "VardisonNamedAttack", %Boss, "ShadowFissure", %bPos TAB %fVec); + %Boss.schedule(6000, setPosition, %bPos); + %Boss.schedule(6000, startFade, 1000, 0, false); + // + $TWM2::VardisonManager.schedule(7000, cooldownOff, %Boss, "attackFinished"); + } + else { + %Boss.setMoveState(false); + %Boss.busy = false; + } + + case 4: + //4x Seeker Photon + %Boss.setMoveState(true); + %target = FindValidTarget(%Boss); + if(isObject(%target)) { + %tPl = %target.player; + schedule(1000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl); + schedule(2000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl); + schedule(3000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl); + schedule(4000, 0, "VardisonNamedAttack", %Boss, "SeekerPhoton", %tPl); + $TWM2::VardisonManager.schedule(5000, cooldownOff, %Boss, "attackFinished"); + } + else { + %Boss.setMoveState(false); + %Boss.busy = false; + } + + case 5: + //Laser Drop + %Boss.setMoveState(true); + %target = FindValidTarget(%Boss); + if(isObject(%target)) { + %tPl = %target.player; + VardisonNamedAttack(%Boss, "LaserDrop", %tPl); + $TWM2::VardisonManager.schedule(5000, cooldownOff, %Boss, "attackFinished"); + } + else { + %Boss.setMoveState(false); + %Boss.busy = false; + } + + case 6: + //Laser Wall + %Boss.setMoveState(true); + %target = FindValidTarget(%Boss); + if(isObject(%target)) { + %tPl = %target.player; + for(%i = 0; %i < 25; %i++) { + schedule(50+(%i*150), 0, VardisonNamedAttack, %Boss, "LaserWall", %tPl); + } + $TWM2::VardisonManager.schedule(10000, cooldownOff, %Boss, "attackFinished"); + } + else { + %Boss.setMoveState(false); + %Boss.busy = false; + } + + case 7: + //Gravity Well + %Boss.setMoveState(true); + VardisonNamedAttack(%Boss, "GravityWell", 0); + $TWM2::VardisonManager.schedule(5000, cooldownOff, %Boss, "attackFinished"); + } + } } -function VardisonAttack(%boss, %att, %arg) { - if(!isObject(%boss) || %boss.getState() $= "dead") { +function VardisonNamedAttack(%Boss, %attack, %args) { + if(!isObject(%Boss) || %Boss.getState() $= "Dead") { return; } - switch$(%att) { - case "ShadowBombDirect": - %target = getWord(%arg, 0); - %detCt = getWord(%arg, 1); - if(!isObject(%target) || %target.getState() $= "dead") { + %bPos = %Boss.getPosition(); + + switch$(%attack) { + case "ShadowBombStrike": + //Spawn 4 Pulses Above Vardison Fired at a guy + %target = getField(%args, 0); + %sPos = vectorAdd(%bPos, "0 0 25"); + %vec = vectorNormalize(vectorSub(%target.getPosition(), %sPos)); + for(%i = 0; %i < 4; %i++) { + %p = new LinearFlareProjectile() { + dataBlock = ShadowBlastBolt; + initialDirection = vectorScale(%vec, 10); + initialPosition = %sPos; + sourceSlot = 4; + }; + %p.sourceObject = %Boss; + MissionCleanup.add(%p); + } + + case "NightmareMissile": + %target = getField(%args, 0); + %sPos = vectorAdd(%bPos, "0 0 25"); + %vec = vectorNormalize(vectorSub(%target.getPosition(), %sPos)); + %p = new SeekerProjectile() { + dataBlock = YvexNightmareMissile; + initialDirection = %vec; + initialPosition = %sPos; + sourceSlot = 4; + }; + %p.sourceObject = %Boss; + %beacon = new BeaconObject() { + dataBlock = "SubBeacon"; + beaconType = "vehicle"; + position = %target.getWorldBoxCenter(); + }; + %beacon.team = 0; + %beacon.setTarget(0); + MissionCleanup.add(%beacon); + %p.setObjectTarget(%beacon); + DemonMotherMissileFollow(%target, %beacon, %p); + + case "ShadowFissure": + %sPos = getField(%args, 0); + %fVec = getField(%args, 1); + for(%i = 1; %i < 20; %i++) { + %sPos = vectorAdd(%sPos, "0 0 0.5"); + %sPos = vectorAdd(%sPos, vectorScale(%fVec, %i*3)); + %p = new LinearFlareProjectile() { + dataBlock = ShadowBlastBolt; + initialDirection = "0 0 -15"; + initialPosition = %sPos; + sourceSlot = 4; + }; + %p.sourceObject = %Boss; + MissionCleanup.add(%p); + } + + case "SeekerPhoton": + %target = getField(%args, 0); + FireSeekerPhotons(%Boss, %target); + + case "FireSeeker": + %target = getField(%args, 0); + %sPos = vectorAdd(%bPos, "0 0 25"); + %vec = vectorNormalize(vectorSub(%target.getPosition(), %sPos)); + %p = new SeekerProjectile() { + dataBlock = VegenorFireMissile; + initialDirection = %vec; + initialPosition = %sPos; + sourceSlot = 4; + }; + %p.sourceObject = %Boss; + %beacon = new BeaconObject() { + dataBlock = "SubBeacon"; + beaconType = "vehicle"; + position = %target.getWorldBoxCenter(); + }; + %beacon.team = 0; + %beacon.setTarget(0); + MissionCleanup.add(%beacon); + %p.setObjectTarget(%beacon); + DemonMotherMissileFollow(%target, %beacon, %p); + + case "MinionFlood": + //Summon Maximum Minions & then Phase out until the team drops them + %max = $TWM2::Vardison2_MaxMinions[$TWM2::VardisonDifficulty]; + %lowEnd = mFloor(%max * 0.25); + %retPos = %bPos; + %current = $TWM2::VardisonManager.minionCount; + %need = %max - %current; + for(%i = 0; %i < %need; %i++) { + VardisonDoMinionSummon(%Boss); + } + //Meanwhile, I take my leave :) + %Boss.startfade(1500, 0, true); + %Boss.rapierShield = true; + %Boss.schedule(2000, setPosition, vectorAdd(%bPos, "9999 9999 10")); + %Boss.vmcountLoop = schedule(1000, 0, VardisonMinionCountCheckup, %Boss, %retPos, %lowEnd); + + case "StasisGate": + %pos = getField(%args, 0); + %TargetSearchMask = $TypeMasks::PlayerObjectType; + %c = createEmitter(%pos, FlashLEmitter, "1 0 0"); //Rotate it + %c.schedule(1000, delete); + InitContainerRadiusSearch(%pos, 25, %TargetSearchMask); + while ((%potentialTarget = ContainerSearchNext()) != 0){ + if (!%potentialTarget.isZombie && !%potentialTarget.isBoss && !%potentialTarget.isVardisonMinion) { + VardisonNamedAttack(%Boss, "StasisLoop", %potentialTarget TAB 0); + } + } + + case "StasisLoop": + %pl = getField(%args, 0); + if(!isObject(%pl) || %pl.getState() $= "dead") { return; } - %vec = vectorNormalize(vectorSub(%target.getPosition(),%boss.getPosition())); - %p = new LinearFlareProjectile() { - dataBlock = ShadowBomb; - initialDirection = vectorScale(%vec, 10); - initialPosition = %boss.getPosition(); - sourceObject = %boss; - sourceSlot = 4; - }; - %p.maxExplode = %detCt; - MissionCleanup.add(%p); - - case "ShadowBombLaunchAbove": - %target = getWord(%arg, 0); - %detCt = getWord(%arg, 1); - if(!isObject(%target) || %target.getState() $= "dead") { + %counter = getField(%args, 1); + %counter++; + if(%counter > 10) { + %pl.setMoveState(false); return; } - %vec = vectorNormalize(vectorSub(%target.getPosition(), vectorAdd(%boss.getPosition(), "0 0 35"))); - %p = new LinearFlareProjectile() { - dataBlock = ShadowBomb; - initialDirection = vectorScale(%vec, 10); - initialPosition = vectorAdd(%boss.getPosition(), "0 0 35"); - sourceSlot = 4; - }; - %p.maxExplode = %detCt; - %p.sourceObject = %boss; - MissionCleanup.add(%p); - - case "HyperspeedPlasmaBolt": - %boss.playShieldEffect("1 1 1"); - %pos = getField(%arg, 0); - %dir = getField(%arg, 1); - %p = new TracerProjectile() { - dataBlock = PlasmaCannonMainProj; - initialDirection = %dir; - initialPosition = %pos; - sourceObject = %boss; - sourceSlot = 4; - }; - MissionCleanup.add(%p); - + %c = createEmitter(%pl.getPosition(), PBCExpEmitter, "1 0 0"); //Rotate it + %c.schedule(1000, delete); + %pl.setMoveState(true); + schedule(1000, 0, VardisonNamedAttack, %Boss, %attack, %pl TAB %counter); + + case "RiftGate": + %pos = getField(%args, 0); + %goPos = RMPG(); + %TargetSearchMask = $TypeMasks::PlayerObjectType; + %c = createEmitter(%pos, FlashLEmitter, "1 0 0"); //Rotate it + %c.schedule(1000, delete); + %c2 = createEmitter(%goPos, FlashLEmitter, "1 0 0"); //Rotate it + %c2.schedule(1000, delete); + InitContainerRadiusSearch(%pos, 25, %TargetSearchMask); + while ((%potentialTarget = ContainerSearchNext()) != 0){ + if (!%potentialTarget.isZombie && !%potentialTarget.isBoss && !%potentialTarget.isVardisonMinion) { + %PosAdd = vectorNormalize(vectorSub(%pos, %potentialTarget.getPosition())); + %PosDst = vectorDist(%pos, %potentialTarget.getPosition()); + %newPos = vectorAdd(%goPos, vectorScale(%PosAdd, %PosDst)); + %potentialTarget.setPosition(%newPos); + } + } + case "LaserDrop": - %toDie = %arg; + %toDie = getField(%args, 0); if(!isObject(%toDie) || %toDie.getState() $= "dead") { return; } %p = new LinearFlareProjectile() { dataBlock = HyperDevestatorBeam; initialDirection = "0 0 -10"; - initialPosition = vectoradd(%target.getPosition(), "0 0 500"); - sourceObject = %boss; + initialPosition = vectoradd(%toDie.getPosition(), "0 0 500"); sourceSlot = 4; }; + %p.sourceObject = %boss; MissionCleanup.add(%p); - - case "SuperLaser": - %toDie = %arg; + + case "LaserWall": + %toDie = getField(%args, 0); if(!isObject(%toDie) || %toDie.getState() $= "dead") { return; } - %vec = vectorNormalize(vectorSub(%toDie.getPosition(), %boss.getPosition())); + %vec = vectorNormalize(vectorSub(%toDie.getPosition(), %bPos)); %p = new LinearFlareProjectile() { dataBlock = SuperlaserProjectile; initialDirection = %vec; - initialPosition = %boss.getPosition(); + initialPosition = %bPos; sourceObject = %boss; sourceSlot = 4; }; MissionCleanup.add(%p); - - case "NMM": - %target = %arg; - %vec = vectorNormalize(vectorSub(%target.getPosition(), %boss.getPosition())); - %p = new SeekerProjectile() { - dataBlock = YvexNightmareMissile; - initialDirection = %vec; - initialPosition = %boss.getPosition(); - sourceObject = %boss; - sourceSlot = 4; - }; - %beacon = new BeaconObject() { - dataBlock = "SubBeacon"; - beaconType = "vehicle"; - position = %target.getWorldBoxCenter(); - }; - %beacon.team = 0; - %beacon.setTarget(0); - MissionCleanup.add(%p); - MissionCleanup.add(%beacon); - %p.setObjectTarget(%beacon); - DemonMotherMissileFollow(%target,%beacon,%p); - - case "LBM": - %target = %arg; - %vec = vectorNormalize(vectorSub(%target.getPosition(), %boss.getPosition())); - %p = new SeekerProjectile() { - dataBlock = VardisonLaserBallMissile; - initialDirection = %vec; - initialPosition = %boss.getPosition(); - sourceObject = %boss; - sourceSlot = 4; - }; - %beacon = new BeaconObject() { - dataBlock = "SubBeacon"; - beaconType = "vehicle"; - position = %target.getWorldBoxCenter(); - }; - %beacon.team = 0; - %beacon.setTarget(0); - MissionCleanup.add(%p); - MissionCleanup.add(%beacon); - %p.setObjectTarget(%beacon); - DemonMotherMissileFollow(%target,%beacon,%p); - - case "LinearFlameWall": - %fVec = %boss.getEyeVector(); - %fPos = %boss.getEyePosition(); - %lPos = vectorAdd(%fPos, vectorScale(%fVec, 10)); - %vec = vectorScale(%fVec, 24); - //drop a line fire hire - %p = new TracerProjectile() { - dataBlock = napalmSubExplosion; - initialDirection = "0 0 -30"; - initialPosition = vectorAdd(%lPos, "0 0 3"); - sourceSlot = 5; - maxCount = 15; - }; - %p.sourceObject = %g; - %p.vector = %vec; - %p.count = 1; - - case "SeekingRapiers": - %target = %arg; - %iVec[0] = "1 0 0"; - %iVec[1] = "0 1 0"; - %iVec[2] = "-1 0 0"; - %iVec[3] = "0 -1 0"; - for(%i = 0; %i < 4; %i++) { - createSeekingProjectile("RapierShieldForwardProjectile", "LinearFlareProjectile", %boss.getPosition(), %iVec[%i], %boss, %target, 3000); + + case "SolomentaryGravityFlux": + %target = getField(%args, 0); + if(!isObject(%target) || %target.getState() $= "dead") { + return; } + %counter = getField(%args, 1); + %counter++; + if(%counter < 15) { + %target.setVelocity("0 0 300"); + } + else if(%counter > 25) { + //Stop... + return; + } + else { + %target.setVelocity("0 0 -300"); + } + schedule(150, 0, VardisonNamedAttack, %Boss, %attack, %target TAB %counter); + + case "GravityWell": + %counter = getField(%args, 0); + %counter++; + if(%counter < 15) { + for(%i = 0; %i < ClientGroup.getCount(); %i++) { + %cl = ClientGroup.getObject(%i); + if(isObject(%cl.player) || %cl.player.getState() !$= "dead") { + %cl.player.setVelocity("0 0 300"); + } + } + } + else if(%counter > 25) { + //Stop... + return; + } + else { + for(%i = 0; %i < ClientGroup.getCount(); %i++) { + %cl = ClientGroup.getObject(%i); + if(isObject(%cl.player) || %cl.player.getState() !$= "dead") { + %cl.player.setVelocity("0 0 -300"); + } + } + } + schedule(150, 0, VardisonNamedAttack, %Boss, %attack, %counter); + + default: + error("Invalid vardison attack..."); } } -function InvokeStillwallLoop(%boss) { - if(!isObject(%boss) || %boss.getState() $= "dead") { +function VardisonMinionCountCheckup(%boss, %retPos, %lowEnd) { + if($TWM2::VardisonManager.minionCount < %lowEnd) { + //Return to the arena + %Boss.schedule(1500, setPosition, %retPos); + %Boss.schedule(1500, startFade, 1000, 0, false); + %Boss.rapierShield = false; + $TWM2::VardisonManager.schedule(7000, cooldownOff, %Boss, "attackFinished"); return; } - %boss.setVelocity("0 0 0"); - %boss.InvokeLoop = schedule(100, 0, "InvokeStillwallLoop", %boss); + %boss.vmcountLoop = schedule(1000, 0, VardisonMinionCountCheckup, %boss, %retPos, %lowEnd); } - - - - - - - -//============================================================================== -datablock SeekerProjectileData(VardisonMiniDemonSpawner) : VardisonNightmareMissile { - baseEmitter = ShadowBaseEmitter; -}; - -function VardisonMiniDemonSpawner::OnExplode(%data, %proj, %pos, %mod) { - //LaserBall - %ball = CreateEmitter(%pos, "MiniShadowBallEmitter", "0 0 0 0"); - %ball.schedule(1000, "Delete"); - %Fire = CreateEmitter(%pos, "burnEmitter", "0 0 0 0"); - %Fire.schedule(2500, "Delete"); - CreateDemonAT(vectorAdd(%pos, "0 0 3")); -} - -datablock PlayerData(MiniDemonArmor) : LightMaleHumanArmor { - runForce = 60.20 * 90; - runEnergyDrain = 0.0; - minRunEnergy = 10; - maxForwardSpeed = 9; - maxBackwardSpeed = 7; - maxSideSpeed = 7; - - jumpForce = 14.0 * 90; - - maxDamage = 2.8; - minImpactSpeed = 1000; - shapeFile = "bioderm_medium.dts"; - jetEmitter = BiodermArmorJetEmitter; - jetEffect = BiodermArmorJetEffect; - - debrisShapeName = "bio_player_debris.dts"; - - //Foot Prints - decalData = LightBiodermFootprint; - decalOffset = 0.3; - - waterBreathSound = WaterBreathBiodermSound; - - damageScale[$DamageType::M1700] = 3.0; - damageScale[$DamageType::PlasmaCannon] = 0.001; - damageScale[$DamageType::Missile] = 0.0000000000000001; - damageScale[$DamageType::Nuclear] = 0.0000000000000001; - damageScale[$DamageType::EMP] = 0.0000000000000001; - - max[RepairKit] = 0; - max[Mine] = 0; - max[Grenade] = 0; -}; - -datablock GrenadeProjectileData(MiniDemonBlaster) { - projectileShapeName = "plasmabolt.dts"; - emitterDelay = -1; - directDamage = 0.0; - hasDamageRadius = true; - indirectDamage = 0.45; - damageRadius = 5.0; // z0dd - ZOD, 8/13/02. Was 20.0 - radiusDamageType = $DamageType::Demon; - kickBackStrength = 1500; - - explosion = "MortarExplosion"; - underwaterExplosion = "MortarExplosion"; - velInheritFactor = 0; - splash = PlasmaSplash; - depthTolerance = 100.0; - - baseEmitter = DemonFBSmokeEmitter; - bubbleEmitter = DemonFBSmokeEmitter; - - grenadeElasticity = 0; - grenadeFriction = 0.4; - armingDelayMS = -1; // z0dd - ZOD, 4/14/02. Was 2000 - - gravityMod = 0.4; // z0dd - ZOD, 5/18/02. Make mortar projectile heavier, less floaty - muzzleVelocity = 125.0; // z0dd - ZOD, 8/13/02. More velocity to compensate for higher gravity. Was 63.7 - drag = 0; - sound = PlasmaProjectileSound; - - hasLight = true; - lightRadius = 10; - lightColor = "1 0.75 0.25"; - - hasLightUnderwaterColor = true; - underWaterLightColor = "1 0.75 0.25"; -}; - -function CreateDemon(%pos) { - %p = new SeekerProjectile() { - dataBlock = VardisonMiniDemonSpawner; - initialDirection = "0 0 -10"; - initialPosition = vectorAdd(%pos, "0 0 500"); - //sourceObject = %boss; - //sourceSlot = 4; +//Vardison Manager Functions +//SummonOrb() +function VardisonManager::summonOrb(%this, %boss) { + %summonPos = vectorAdd(%boss.getPosition(), "0 0 35"); + %orb = new (StaticShape)() { + dataBlock = ShadowOrb; }; -} + %orb.setTransform(%summonPos SPC "0 0 0 1"); + %orb.team = %boss.Team; + %orb.setOwner(%boss); -function CreateDemonAT(%Pos) { - %Demon = new player(){ - Datablock = "MiniDemonArmor"; - }; - %Demon.setTransform(%Pos); - %Demon.type = 1; - %Demon.canjump = 1; - %Demon.hastarget = 1; - %Demon.isBoss = 1; //grant boss-like ability - - %Demon.team = 30; - - %Demon.target = createTarget(%Demon, "Shadow Warrior", "", "Derm3", '', %Demon.team, PlayerSensor); - setTargetSensorData(%Demon.target, PlayerSensor); - setTargetSensorGroup(%Demon.target, 30); - setTargetName(%Demon.target, addtaggedstring("Shadow Warrior")); - setTargetSkin(%Demon.target, 'Horde'); - - MissionCleanup.add(%Demon); - schedule(1000, %Demon, "MiniDemonMoveToTarget", %Demon); -} - -function MiniDemonMoveToTarget(%Demon){ - if(!isobject(%Demon)) - return; - if(%Demon.getState() $= "dead") - return; - %pos = %Demon.getworldboxcenter(); - %closestClient = ZombieLookForTarget(%Demon); - %closestDistance = getWord(%closestClient,1); - %closestClient = getWord(%closestClient,0).Player; - %Demon.counter++; - if(%Demon.counter >= 5) { - %Demon.counter = 0; - %Demon.canFire = 1; - } - if(%closestDistance <= $Zombie::detectDist) { - if(%Demon.hastarget != 1){ - %Demon.hastarget = 1; - } - %upvec = "250"; - %fmultiplier = $Zombie::FForwardSpeed; - - %vector = ZgetFacingDirection(%Demon,%closestClient,%pos); - - %vector = vectorscale(%vector, %Fmultiplier); - %x = Getword(%vector,0); - %y = Getword(%vector,1); - %z = Getword(%vector,2); - if(%z >= "1200" && %Demon.canjump == 1){ - %Demon.setvelocity("0 0 0"); - %upvec = (%upvec * 8); - %x = (%x * 0.5); - %y = (%y * 0.5); - %Demon.canjump = 0; - schedule(2500, %Demon, "Zsetjump", %Demon); - } - - if(%Demon.canFire) { - MiniDemonFire(%Demon, %closestclient); - } - - %vector = %x@" "@%y@" "@%upvec; - %Demon.applyImpulse(%pos, %vector); - } - else if(%Demon.hastarget == 1) { - %Demon.hastarget = 0; - %Demon.DemonRmove = schedule(100, %Demon, "ZSetRandomMove", %Demon); - } - %Demon.moveloop = schedule(500, %Demon, "MiniDemonMoveToTarget", %Demon); -} - -function MiniDemonFire(%demon, %closestclient){ - %pos = %demon.getMuzzlePoint(4); - %tpos = %closestclient.getWorldBoxCenter(); - %tvel = %closestclient.getvelocity(); - %vec = vectorsub(%tpos,%pos); - %dist = vectorlen(%vec); - %velpredict = vectorscale(%tvel,(%dist / 125)); - %vector = vectoradd(%vec,%velpredict); - %ndist = vectorlen(%vector); - %upvec = "0 0 "@((%ndist / 125) * (%ndist / 125) * 2); - %vector = vectornormalize(vectoradd(%vector,%upvec)); + %orb.team = 30; + %orb.target = createTarget(%orb, "\c7Shadow Rift", "", "Derm3", '', %orb.team, PlayerSensor); + setTargetSensorData(%orb.target, PlayerSensor); + setTargetSensorGroup(%orb.target, 30); + setTargetName(%orb.target, addtaggedstring("\c7Shadow Rift")); - %p = new GrenadeProjectile() { - dataBlock = MiniDemonBlaster; - initialDirection = %vector; - initialPosition = %pos; - sourceObject = %demon; - sourceSlot = 4; - }; - - %demon.canFire = 0; + //SFX + %orb.sfx = new ParticleEmissionDummy(){ + position = %orb.getPosition(); + dataBlock = "defaultEmissionDummy"; + emitter = "ShadowOrbEmitter"; + }; + MissionCleanup.add(%orb.sfx); + // + %this.orbKillSched = %this.schedule($TWM2::Vardison_OrbKillTime, orbKill, %boss, %orb); +} + +function VardisonManager::orbKill(%this, %boss, %orb) { + for(%i = 0; %i < ClientGroup.getCount(); %i++) { + %cl = ClientGroup.getObject(%i); + if(isObject(%cl.player) && %cl.player.getState() !$= "dead") { + //Bye Bye :) + %cl.player.setInvincible(false); + %cl.player.damage(%boss, %cl.player.getPosition(), 10000, $DamageType::ShadowOrb); + %cl.player.blowup(); + MessageAll('msgDeath', "\c2"@%cl.player.namebase@" has been annihilated by the Shadow Rift."); + //If Vardison Restores HP from rift kills, do that now :P + if($TWM2::Vardison_OrbRegenHP[$TWM2::VardisonDifficulty]) { + %boss.setDamageLevel(%boss.getDamageLevel() - 0.35); + } + } + } + %wipeEmit = new ParticleEmissionDummy(){ + position = %orb.getPosition(); + dataBlock = "defaultEmissionDummy"; + emitter = "ShadowOrbDetonationEmitter"; + }; + %wipeEmit.schedule(500, "delete"); + //Delete the orb & it's effects + if(isObject(%orb.sfx)) { + %obj.sfx.schedule(500, "delete"); + } + %orb.schedule(500, "delete"); + if(isObject(%this.orbFire)) { + %this.orbFire.schedule(500, "delete"); + } + %this.orbObject = -1; + %boss.rapierShield = false; + %boss.busy = false; //<-- let think() resume... +} + +function VardisonManager::orbDestroyed(%this) { + if(isObject(%this.orbFire)) { + %this.orbFire.schedule(500, "delete"); + } + cancel(%this.orbKillSched); + %this.orbObject = -1; + %boss = %this.Vardison; + %boss.rapierShield = false; + %boss.busy = false; //<-- let think() resume... +} + +function VardisonManager::cooldownOff(%this, %Boss, %type) { + if(!isObject(%this)) { + error("VardisonManager::cooldownOff(): Missing instance of VM."); + return; + } + if(!isObject(%Boss) || %Boss.getState() $= "dead") { + error("VardisonManager::cooldownOff(): Vardison Dead."); + return; + } + switch$(%type) { + case "minions": + %Boss.canSummonMinions = true; + + case "busy": + %Boss.busy = false; + + case "attackFinished": + //Unlock the boss & update LAT + %Boss.setMoveState(false); + %this.lastAttackTime = getRealTime(); + %Boss.busy = false; + } } diff --git a/scripts/TWM2/ChatCommands/Public.cs b/scripts/TWM2/ChatCommands/Public.cs index 80c1f71..f8511f3 100644 --- a/scripts/TWM2/ChatCommands/Public.cs +++ b/scripts/TWM2/ChatCommands/Public.cs @@ -831,7 +831,7 @@ function parsePublicCommands(%sender, %command, %args) { } else if (!isBoss(strlwr(%Boss))) { messageclient(%sender, 'MsgClient', '\c2Invalid Boss Name.'); - messageclient(%sender, 'MsgClient', '\c2Bosses: Yvex, CnlWindshear, GOL, GOF, Stormrider, DAVardison.'); + messageclient(%sender, 'MsgClient', '\c2Bosses: Yvex, CnlWindshear, GOL, GOF, Stormrider.'); messageclient(%sender, 'MsgClient', '\c2GenVeg, LordRog, Insignia, Trebor, Vardison, ShadeLord.'); return 1; } diff --git a/scripts/TWM2/ChatCommands/SuperAdmin.cs b/scripts/TWM2/ChatCommands/SuperAdmin.cs index 553dfa6..796f23e 100644 --- a/scripts/TWM2/ChatCommands/SuperAdmin.cs +++ b/scripts/TWM2/ChatCommands/SuperAdmin.cs @@ -143,10 +143,6 @@ function parseSuperAdminCommands(%sender, %command, %args) { %pos = VectorAdd(%sender.player.getPosition(), "0 0 5"); StartVardison1(%pos); MessageAll('MsgAdminForce', "\c3"@%sender.namebase@"\c2 spawned Lord Vardison, go hide noobs."); - case "DAVardison": - %pos = VectorAdd(%sender.player.getPosition(), "0 0 5"); - StartDAVardison(%pos); - MessageAll('MsgAdminForce', "\c3"@%sender.namebase@"\c2 spawned Dark Archmage Vardison, run in fear n0bs."); case "ShadeLord": %pos = VectorAdd(%sender.player.getPosition(), "0 0 5"); SpawnShadeLord(%pos); @@ -155,7 +151,7 @@ function parseSuperAdminCommands(%sender, %command, %args) { messageclient(%sender, 'MsgClient', '\c2Invalid Boss Name.'); messageclient(%sender, 'MsgClient', '\c2Bosses: Yvex, CnlWindshear, GhostOfLightning.'); messageclient(%sender, 'MsgClient', '\c2GenVegenor, LordRog, Insignia, Trebor, Vardison.'); - messageclient(%sender, 'MsgClient', '\c2Stormrider, GhostOfFire, ShadeLord, DAVardison.'); + messageclient(%sender, 'MsgClient', '\c2Stormrider, GhostOfFire, ShadeLord.'); } return 1; diff --git a/scripts/TWM2/Systems/BossSystem.cs b/scripts/TWM2/Systems/BossSystem.cs index c455401..33bef7f 100644 --- a/scripts/TWM2/Systems/BossSystem.cs +++ b/scripts/TWM2/Systems/BossSystem.cs @@ -3,6 +3,15 @@ function InitiateBoss(%Boss, %name) { error("SERVER: Cannot initiate boss, in horde/helljump"); return; } + + if(!isObject($TWM2::BossManager)) { + $TWM2::BossManager = new scriptObject() { + class = "BossManager"; + }; + } + $TWM2::BossManager.bossKills = 0; + $TWM2::BossManager.bossObject = %Boss; + $TWM2::BossManager.activeBoss = %name; $TWM2::BossGoing = 1; switch$(%name) { @@ -21,9 +30,9 @@ function InitiateBoss(%Boss, %name) { case "Vardison1": %print = "BOSS BATTLE \n LORD VARDISON"; case "Vardison2": - %print = "!DANGER! \n VARDISON HAS TRANSFORMED \n AIR FORM"; + %print = "BOSS ALERT \n LORD VARDISON HAS ENTERED HIS SECOND FORM"; case "Vardison3": - %print = "!DANGER! \n VARDISON HAS TRANSFORMED AGAIN \n DEMON FORM"; + %print = "BOSS ALERT \n LORD VARDISON HAS ENTERED HIS FINAL FORM"; case "Trebor": %print = "BOSS BATTLE \n LORDRANIUS TREVOR"; case "Stormrider": @@ -49,11 +58,11 @@ function InitiateBoss(%Boss, %name) { } function BossCheckUp(%boss, %name) { + %percentage = (mFloor(%boss.getDamageLeft()*100) / mFloor(%boss.getMaxDamage()*100)) * 100; + MessageAll('MsgSPCurrentObjective1', "", "Boss Battle: "@$TWM2::BossName[%name]@" [Boss Kill Count: "@$TWM2::BossManager.bossKills@"]"); + MessageAll('MsgSPCurrentObjective2', "", "Boss HP: "@mFloor(%boss.getDamageLeft()*100)@"/"@mFloor(%boss.getMaxDamage()*100)@" ("@%percentage@"%)"); - MessageAll('MsgSPCurrentObjective1', "", "Boss Battle: "@$TWM2::BossName[%name]@""); - MessageAll('MsgSPCurrentObjective2', "", "Boss HP: "@mFloor(%boss.getDamageLeft()*100)@"/"@mFloor(%boss.getMaxDamage()*100)@""); - - if(%name !$= "CnlWindshear" && %name !$= "Vardison2" && %name !$= "Trebor" && %name !$= "Stormrider") { + if(%name !$= "CnlWindshear" && %name !$= "Trebor" && %name !$= "Stormrider") { if(!isObject(%boss) || %boss.getState() $= "dead") { if(%name $= "Vardison1") { %count = ClientGroup.getCount(); @@ -61,7 +70,16 @@ function BossCheckUp(%boss, %name) { %cl = ClientGroup.getObject(%i); recordAction(%cl, "BOSS", "Vardison1"); } - StartVardison2(%boss.getPosition()); + SpawnVardison2(%boss.getPosition()); + return; + } + if(%name $= "Vardison2") { + %count = ClientGroup.getCount(); + for(%i = 0; %i < %count; %i++) { + %cl = ClientGroup.getObject(%i); + recordAction(%cl, "BOSS", "Vardison2"); + } + SpawnVardison3(%boss.getPosition()); return; } //the boss has been defeated, horrah!!! @@ -81,17 +99,6 @@ function BossCheckUp(%boss, %name) { } else { if(!isObject(%boss)) { - //the boss has been defeated, horrah!!! - if(%name $= "Vardison2") { - //but not quite so xD - %count = ClientGroup.getCount(); - for(%i = 0; %i < %count; %i++) { - %cl = ClientGroup.getObject(%i); - recordAction(%cl, "BOSS", "Vardison2"); - } - StartVardison3("0 0 200"); - return; - } %count = ClientGroup.getCount(); for(%i = 0; %i < %count; %i++) { %cl = ClientGroup.getObject(%i); @@ -167,11 +174,27 @@ function GameConnection::GiveBossAward(%client, %bossName) { } function FindValidTarget(%boss, %counter) { //This is usefull - %client = ClientGroup.getObject(GetRandom()*ClientGroup.getCount()); - if(!isObject(%client.player) || %client.player.getState() $= "dead" || %boss == %client.player) { - return schedule(500,0,"FindValidTarget", %boss, %counter++); //Keep Looking; + if(%counter $= "") { + %counter = 10; //10 attempts } - return %client; //target is good + for(%i = 0; %i < %counter; %i++) { + %test = ClientGroup.getObject(getRandom(0, ClientGroup.getCount())); + if(isObject(%test)) { + %tPL = %test.getControlObject(); + if(isObject(%tPL)) { + if(isPlayer(%tPL)) { + if(%tPL.getState() !$= "dead") { + //Got one! + return %test; + } + } + else { + return %test; + } + } + } + } + return -1; //Found nothing. } function CheckBossChallenge(%client, %boss) { @@ -430,9 +453,46 @@ function GenerateBossChallengeMenu(%client, %tag, %index) { %index++; } // + if(%client.CheckNWChallengeCompletion("VardEasy")) { + messageClient( %client, 'SetLineHud', "", %tag, %index, "The Standard Experience - Done"); + %index++; + } + else { + messageClient( %client, 'SetLineHud', "", %tag, %index, "The Standard Experience - Defeat Lord Vardison on Easy Difficulty"); + %index++; + } + if(%client.CheckNWChallengeCompletion("VardNorm")) { + messageClient( %client, 'SetLineHud', "", %tag, %index, "Demon Hunter - Done"); + %index++; + } + else { + messageClient( %client, 'SetLineHud', "", %tag, %index, "Demon Hunter - Defeat Lord Vardison on Normal Difficulty"); + %index++; + } + if(%client.CheckNWChallengeCompletion("VardHard")) { + messageClient( %client, 'SetLineHud', "", %tag, %index, "Master Demon Slayer - Done"); + %index++; + } + else { + messageClient( %client, 'SetLineHud', "", %tag, %index, "Master Demon Slayer - Defeat Lord Vardison on Hard Difficulty"); + %index++; + } + if(%client.CheckNWChallengeCompletion("VardWtf")) { + messageClient( %client, 'SetLineHud', "", %tag, %index, "God of the Shadow Realm - Done [You are a freaking boss master]"); + %index++; + } + else { + messageClient( %client, 'SetLineHud', "", %tag, %index, "God of the Shadow Realm - Against all odds, emerge victorious against WTF difficulty Lord Vardison"); + %index++; + } + // return %index; } +function BossManager::addKill(%this, %tObj) { + %this.bossKills++; +} + //Load The Boss Files exec("scripts/TWM2/Bosses/LordYvex.cs"); exec("scripts/TWM2/Bosses/ColonelWindshear.cs"); diff --git a/scripts/TWM2/Systems/NWChallengeIndex.cs b/scripts/TWM2/Systems/NWChallengeIndex.cs index 9e0b266..c19c53e 100644 --- a/scripts/TWM2/Systems/NWChallengeIndex.cs +++ b/scripts/TWM2/Systems/NWChallengeIndex.cs @@ -80,6 +80,10 @@ $Challenge::Info["Treb3"] = "Tank Halter\t2\t10000\tNone"; $Challenge::Info["Vard1"] = "Shining Star\t2\t3500\tNone"; $Challenge::Info["Vard2"] = "Glare The Dark\t2\t7000\tNone"; $Challenge::Info["Vard3"] = "Outevil The Wicked\t2\t12500\tLord Vardison Recruitable Ally"; +$Challenge::Info["VardEasy"] = "The Standard Experience\t2\t7000\tNone"; +$Challenge::Info["VardNorm"] = "Demon Hunter\t2\t1500\tNone"; +$Challenge::Info["VardHard"] = "Master Demon Slayer\t2\t25000\tNone"; +$Challenge::Info["VardWtf"] = "God of the Shadow Realm\t2\t50000\tNone"; //Blacklist $Challenge::Info["Acceptance"] = "Acceptance\t3\t1000\tNone"; $Challenge::Info["ListHit"] = "Hitlister of The List\t3\t2500\tNone"; diff --git a/scripts/TWM2/Zombie/ZombieCreation.cs b/scripts/TWM2/Zombie/ZombieCreation.cs index be42947..1e682be 100644 --- a/scripts/TWM2/Zombie/ZombieCreation.cs +++ b/scripts/TWM2/Zombie/ZombieCreation.cs @@ -182,10 +182,10 @@ function ZPCreateZombie(%obj){ function StartAZombie(%pos, %type){ if(!isObject(Game)) { error("UE Blocked..."); - return; + return -1; } if($Game::ZombieCount > $TWM2::MaxZombies || !$TWM2::CanSpawnZ) { - return; + return -1; } // if(%type $= "") { diff --git a/scripts/chatCommands.cs b/scripts/chatCommands.cs index ba5c5d2..2a30a72 100644 --- a/scripts/chatCommands.cs +++ b/scripts/chatCommands.cs @@ -286,8 +286,6 @@ function BossFullname(%BossAbbr) return "Ghost of Fire"; case "vardison": return "Lord Vardison"; - case "davardison": - return "Dark Archmage Vardison"; case "shadelord": return "The Shade Lord"; } @@ -317,8 +315,6 @@ function isBoss(%Boss) return 1; case "vardison": return 1; - case "davardison": - return 1; case "shadelord": return 1; } diff --git a/scripts/packs/Medpack.cs b/scripts/packs/Medpack.cs index 21230b7..633ab51 100644 --- a/scripts/packs/Medpack.cs +++ b/scripts/packs/Medpack.cs @@ -235,7 +235,7 @@ function Medrepair(%obj, %targets){ if(%obj.isreping == 0) return; if(%targets !$= ""){ - %numtrgs = getNumberOfWords(%targets); + %numtrgs = getWordCount(%targets); for(%i = 0; %i < %numtrgs; %i++){ %target = getWord(%targets, %i); if(vectorDist(%obj.getWorldBoxCenter(), %target.getWorldBoxCenter()) <= 10 && %target.getDamageLevel() > 0.0){ @@ -267,7 +267,7 @@ function Medrepair(%obj, %targets){ function MedstopRepair(%obj){ %obj.isreping = 0; if(%obj.reptargets !$= ""){ - %numtrgs = getNumberOfWords(%obj.reptargets); + %numtrgs = getWordCount(%obj.reptargets); for(%i = 0; %i < %numtrgs; %i++){ %target = getWord(%obj.reptargets, %i); if(%target.reping == 1){ @@ -305,6 +305,10 @@ function checkrevive(%obj){ messageclient(%obj.client, 'MsgClient', "\c2This body is destroyed."); return; } + if(%Tobj.isBoss == 1){ + messageclient(%obj.client, 'MsgClient', "\c2ARE YOU INSANE!?!??! YEAH... LETS JUST REVIVE THE DAMNED BOSS THAT JUST REKT YOU ABOUT 100 TIMES!!!!"); + return; + } if(%Tobj.infected || %Tobj.isZombie) { messageclient(%obj.client, 'MsgClient', "\c2WHOA!!! We don't want to make the Undead.... UnDead AGAIN."); return; diff --git a/scripts/packs/ZSpawnpack.cs b/scripts/packs/ZSpawnpack.cs index e2e10ce..6ac77ed 100644 --- a/scripts/packs/ZSpawnpack.cs +++ b/scripts/packs/ZSpawnpack.cs @@ -26,8 +26,51 @@ datablock AudioProfile(ZombieHOWL) preload = true; }; -//USED IN FLAMETHROWER +//USED IN FLAMETHROWER / NMM //DO NOT REMOVE: NEEDED HERE +datablock ParticleData(NMMissileBaseParticle) { + dragCoeffiecient = 0.0; + gravityCoefficient = -0.2; + inheritedVelFactor = 0.0; + + lifetimeMS = 800; + lifetimeVarianceMS = 500; + + useInvAlpha = false; + spinRandomMin = -160.0; + spinRandomMax = 160.0; + + animateTexture = true; + framesPerSec = 15; + + textureName = "special/cloudflash"; + + colors[0] = "0.5 0.1 0.9 1.0"; + colors[1] = "0.5 0.1 0.9 1.0"; + colors[2] = "0.5 0.1 0.9 1.0"; + + sizes[0] = 2.5; + sizes[1] = 2.7; + sizes[2] = 3.0; + + times[0] = 0.0; + times[1] = 0.7; + times[2] = 1.0; +}; + +datablock ParticleEmitterData(NMMissileBaseEmitter) { + ejectionPeriodMS = 10; + periodVarianceMS = 0; + + ejectionVelocity = 1.5; + velocityVariance = 0.3; + + thetaMin = 0.0; + thetaMax = 30.0; + + particles = "NMMissileBaseParticle"; +}; + datablock ParticleData(ThrowerBaseParticle) { dragCoeffiecient = 0.0; gravityCoefficient = -0.2; diff --git a/scripts/player.cs b/scripts/player.cs index 7920a9e..a6c8b89 100644 --- a/scripts/player.cs +++ b/scripts/player.cs @@ -3585,6 +3585,17 @@ function Armor::damageObject(%data, %targetObject, %sourceObject, %position, %am //now call the "onKilled" function if the client was... you know... if(%targetObject.getState() $= "Dead") { + //Is there a boss going? + if(!%targetObject.isZombie && !%targetObject.isBossMinion) { + if($TWM2::BossGoing) { + //Chalk up the kill count :P + $TWM2::BossManager.addKill(%targetObject); + } + } + if(%targetObject.isVardisonMinion) { + $TWM2::VardisonManager.minionCount--; + } + if($TWM2::PlayingSabo) { if(Game.Bomb.Carrier == %targetObject) { if(%damageType == $DamageType::FellOff) { diff --git a/scripts/weapons/Other/ShadowRifle.cs b/scripts/weapons/Other/ShadowRifle.cs index 84825f1..19bac80 100644 --- a/scripts/weapons/Other/ShadowRifle.cs +++ b/scripts/weapons/Other/ShadowRifle.cs @@ -1,46 +1,3 @@ -datablock ParticleData(NMMissileBaseParticle) { - dragCoeffiecient = 0.0; - gravityCoefficient = -0.2; - inheritedVelFactor = 0.0; - - lifetimeMS = 800; - lifetimeVarianceMS = 500; - - useInvAlpha = false; - spinRandomMin = -160.0; - spinRandomMax = 160.0; - - animateTexture = true; - framesPerSec = 15; - - textureName = "special/cloudflash"; - - colors[0] = "0.5 0.1 0.9 1.0"; - colors[1] = "0.5 0.1 0.9 1.0"; - colors[2] = "0.5 0.1 0.9 1.0"; - - sizes[0] = 2.5; - sizes[1] = 2.7; - sizes[2] = 3.0; - - times[0] = 0.0; - times[1] = 0.7; - times[2] = 1.0; -}; - -datablock ParticleEmitterData(NMMissileBaseEmitter) { - ejectionPeriodMS = 10; - periodVarianceMS = 0; - - ejectionVelocity = 1.5; - velocityVariance = 0.3; - - thetaMin = 0.0; - thetaMax = 30.0; - - particles = "NMMissileBaseParticle"; -}; - datablock LinearFlareProjectileData(ShadowRifleBolt) { projectileShapeName = "turret_muzzlepoint.dts"; scale = "1.0 1.0 1.0";