Poisonous swamps
Update: 02-14-2006: Added two more null checks, in the testing for swampboots and GetItemsInRange. Please post if you experience any crashes with this! Script in post and attached file have both been updated. Documentation also updated.
Update: 02-13-2006: Updated to include an internal map check. If the character is on the internal map, the swamp check ends. Updated included code and attached file.
Update: 01-30-2006: Updated for an apparently rare problem where the playermobile is or becomes null. Updated attached files and included code, as well as the file on my script archive site. I put the null check in two places, both before calling SwampCheck and as the first sanity check inside SwampCheck.
Update: 07-26-2005: Updated to verify the player height. (Players walking in structures in Papua will no longer be poisoned) Download and code attached updated.
Update: 07-25-2005: Detects Land/Terrain (ie: swamp east of Britain) Static (ie: 'static' dungeon decoration) and Added (ie: Pandora's Box or '[add static ####') swamps! Yay!
How this script works:
This script runs each time a character moves, examining the ground beneath them for 'swampy' tiles. Light swamp tiles (generally light green, such as found on the edges of swamps or in small islands around trees and such) have a 0.05% chance of giving the character a Lesser poisoning, while Deep swamp tiles (darker green, sometimes bubbling) have a 0.15% chance of giving the character a Regular poisoning.
I tested the values carefully, although they may seem low, from my experience a player has a reasonable chance of 'dashing across' a small patch of light swampy ground without becoming poisoned, while even short forays into deeper swamp areas will almost certainly poison the character after a few steps. Of course you can adjust the chance of poisoning to your own taste.
This script was inspired by the original Ultima series, where swampy ground would poison the characters.
Currently three forms of tile data are examined:
Land Terrain - These tiles are actual ground tiles, such as the kind of ground that can slope up or downhill. They are written to the map file as 'ground level' data, though of course objects can exist below ground level. (Not necessarily located at 0z, most of the default Britannia is above 0z.)
Static Terrain - These tiles are 'ground tile' pieces that have been added and frozen, or are included in the existing map, such as certain types of ground inside dungeons. These tiles cannot slope, they are objects that look like ground and have been frozen to the map.
Added Terrain - These tiles are 'added' by GMs using tools such as Pandora's Box, or by directly adding a static. They are also the type of tiles that make up character houses. Yes, this means that if you use this script and don't disable that check, swamp tiles in houses can poison characters.
Installation:
This script modifies PlayerMobile.cs! Please please PLEASE make a FULL backup of your shard and a spare copy of your PlayerMobile.cs before installing this. Though there are no changes to serialization/deserialization (which, when done incorrectly, could cause the loss of all characters on the shard) - it's better to be safe than sorry. ^.^;
In this post you will find two forms of the code necessary to modify your PlayerMobile.cs.
The easiest way to install this: (Only if you have not modified your PlayerMobile.cs!) In the zip file attached to this post is a distro PlayerMobile.cs modified appropriately. Rename your PlayerMobile.cs to PlayerMobile.cs.bak, and extract the PlayerMobile.cs to wherever you like in your Scripts directory.
If you have modified your PlayerMobile.cs, you can use either the code in the quote box below, or from the archive attached to this post there is a file called
"Poisonous Swamps - Modification to PlayerMobile.txt"
Both include the same code.
The code begins with the full Move override, to show you where to add the call to SwampCheck. Please note that only two lines actually need to be added to the Move override, they are clearly marked. Add those lines to the appropriate place in the Move override. Now from the point where it says "// begin poisonous swamps" to the end of the code box or file, select that code and place it below the closing brace of your Move override.
(Conversely, if you have not modified the Move override, you can select ALL the text from the code box or modification file, and replace the entire PlayerMobile.cs Move override with that.)
Things you should know: (and some things that you can change, by editing the code. =)
Staff members WILL be poisoned. There is a section of code commented out at the beginning of SwampCheck which will keep staff from being poisoned. Remove the comment marks and adjust the access level to your taste. (Or have staff wear swamp boots. =)
This script ONLY affects characters. Mounts and pets will not be poisoned. Mounted characters will be poisoned regardless of wearing Swamp Boots. (The mount walking through the swamp stirs up poisonous gasses, or some such like that. =)
ALL swamps will be poisonous after this is installed, including homes with swamp tiles.
Proximity to swamps doesn't matter, only the tile directly below the character is checked.
Please report any new slowdowns or crashes that this script may cause. So far I haven't found any in my testing, but it has been rather limited. If you encounter a crash and you can repeat it, a crash report from the server running in debug mode would be exteremly helpful.
And thank you to everyone. ^.^
-----------------------------
PlayerMobile.cs modifications:
Oh yeah you might need these.
I suggest you sell the swamp boots on vendors and make them craftable by players.
Update: 02-14-2006: Added two more null checks, in the testing for swampboots and GetItemsInRange. Please post if you experience any crashes with this! Script in post and attached file have both been updated. Documentation also updated.
Update: 02-13-2006: Updated to include an internal map check. If the character is on the internal map, the swamp check ends. Updated included code and attached file.
Update: 01-30-2006: Updated for an apparently rare problem where the playermobile is or becomes null. Updated attached files and included code, as well as the file on my script archive site. I put the null check in two places, both before calling SwampCheck and as the first sanity check inside SwampCheck.
Update: 07-26-2005: Updated to verify the player height. (Players walking in structures in Papua will no longer be poisoned) Download and code attached updated.
Update: 07-25-2005: Detects Land/Terrain (ie: swamp east of Britain) Static (ie: 'static' dungeon decoration) and Added (ie: Pandora's Box or '[add static ####') swamps! Yay!
How this script works:
This script runs each time a character moves, examining the ground beneath them for 'swampy' tiles. Light swamp tiles (generally light green, such as found on the edges of swamps or in small islands around trees and such) have a 0.05% chance of giving the character a Lesser poisoning, while Deep swamp tiles (darker green, sometimes bubbling) have a 0.15% chance of giving the character a Regular poisoning.
I tested the values carefully, although they may seem low, from my experience a player has a reasonable chance of 'dashing across' a small patch of light swampy ground without becoming poisoned, while even short forays into deeper swamp areas will almost certainly poison the character after a few steps. Of course you can adjust the chance of poisoning to your own taste.
This script was inspired by the original Ultima series, where swampy ground would poison the characters.
Currently three forms of tile data are examined:
Land Terrain - These tiles are actual ground tiles, such as the kind of ground that can slope up or downhill. They are written to the map file as 'ground level' data, though of course objects can exist below ground level. (Not necessarily located at 0z, most of the default Britannia is above 0z.)
Static Terrain - These tiles are 'ground tile' pieces that have been added and frozen, or are included in the existing map, such as certain types of ground inside dungeons. These tiles cannot slope, they are objects that look like ground and have been frozen to the map.
Added Terrain - These tiles are 'added' by GMs using tools such as Pandora's Box, or by directly adding a static. They are also the type of tiles that make up character houses. Yes, this means that if you use this script and don't disable that check, swamp tiles in houses can poison characters.
Installation:
This script modifies PlayerMobile.cs! Please please PLEASE make a FULL backup of your shard and a spare copy of your PlayerMobile.cs before installing this. Though there are no changes to serialization/deserialization (which, when done incorrectly, could cause the loss of all characters on the shard) - it's better to be safe than sorry. ^.^;
In this post you will find two forms of the code necessary to modify your PlayerMobile.cs.
The easiest way to install this: (Only if you have not modified your PlayerMobile.cs!) In the zip file attached to this post is a distro PlayerMobile.cs modified appropriately. Rename your PlayerMobile.cs to PlayerMobile.cs.bak, and extract the PlayerMobile.cs to wherever you like in your Scripts directory.
If you have modified your PlayerMobile.cs, you can use either the code in the quote box below, or from the archive attached to this post there is a file called
"Poisonous Swamps - Modification to PlayerMobile.txt"
Both include the same code.
The code begins with the full Move override, to show you where to add the call to SwampCheck. Please note that only two lines actually need to be added to the Move override, they are clearly marked. Add those lines to the appropriate place in the Move override. Now from the point where it says "// begin poisonous swamps" to the end of the code box or file, select that code and place it below the closing brace of your Move override.
(Conversely, if you have not modified the Move override, you can select ALL the text from the code box or modification file, and replace the entire PlayerMobile.cs Move override with that.)
Things you should know: (and some things that you can change, by editing the code. =)
Staff members WILL be poisoned. There is a section of code commented out at the beginning of SwampCheck which will keep staff from being poisoned. Remove the comment marks and adjust the access level to your taste. (Or have staff wear swamp boots. =)
This script ONLY affects characters. Mounts and pets will not be poisoned. Mounted characters will be poisoned regardless of wearing Swamp Boots. (The mount walking through the swamp stirs up poisonous gasses, or some such like that. =)
ALL swamps will be poisonous after this is installed, including homes with swamp tiles.
Proximity to swamps doesn't matter, only the tile directly below the character is checked.
Please report any new slowdowns or crashes that this script may cause. So far I haven't found any in my testing, but it has been rather limited. If you encounter a crash and you can repeat it, a crash report from the server running in debug mode would be exteremly helpful.
And thank you to everyone. ^.^
-----------------------------
PlayerMobile.cs modifications:
Code:
// for poisonous swamps.
// code given is for Move override in PlayerMobile. Code changes start at the "SwampCheck( this )" line.
// Please note that the code given closes the move override, just selecting all the code and pasting it
// at the given line will not work. You need to select the entire Move override to be replaced, or selectively
// replace the code starting at that point.
public override bool Move( Direction d )
{
NetState ns = this.NetState;
if ( ns != null )
{
GumpCollection gumps = ns.Gumps;
for ( int i = 0; i < gumps.Count; ++i )
{
if ( gumps[i] is ResurrectGump )
{
if ( Alive )
{
CloseGump( typeof( ResurrectGump ) );
}
else
{
SendLocalizedMessage( 500111 ); // You are frozen and cannot move.
return false;
}
}
}
}
TimeSpan speed = ComputeMovementSpeed( d );
if ( !base.Move( d ) )
return false;
m_NextMovementTime += speed;
/////////////////////// begin playermobile Move addition
// 'Move( Direction d )' seems to be called when the player moves.
if ( this != null )
SwampCheck( this ); // for poisonous swamps
/////////////////////// end playermobile Move addition
return true;
}
// begin poisonous swamps
private static void SwampCheck( PlayerMobile from )
{
// poisonous swamps... Mostly.
// basic sanity checks
if ( from == null )
return; // wtf? O.o;
// don't poison staff
// if ( from.AccessLevel >= AccessLevel.GameMaster )
// return;
// if the player is dead, don't poison them. Thanks GrayStar! :>
if ( !from.Alive )
return;
// don't poison a poisoned player.
if ( from.Poisoned )
return;
// no swamps on the internal map.
if ( from.Map == Map.Internal )
return;
// is the player wearing swamp boots and not mounted?
Item shoes = from.FindItemOnLayer( Layer.Shoes );
if ( shoes != null && shoes is SwampBoots && !( from.Mounted ) )
return;
// find out if the player is moving over a land/terrain (ground), static/frozen (dungeon) swamp, or static/unfrozen/added swamp.
// initialize common variables.
Map map = from.Map;
// is it a land/terrain swamp?
Tile lt = map.Tiles.GetLandTile( from.X, from.Y );
if ( IsDeepLandSwamp( lt.ID ) && lt.Z == from.Z )
{
if ( Utility.RandomDouble() < 0.15 )
{
// poison player
from.Poison = Poison.Regular;
from.SendMessage( "You were poisoned by the swamp!" );
return;
}
}
else if ( IsLightLandSwamp( lt.ID ) && lt.Z == from.Z )
{
if ( Utility.RandomDouble() < 0.05 )
{
// poison player
from.Poison = Poison.Lesser;
from.SendMessage( "You were poisoned by the swamp!" );
return;
}
}
// is it a static swamp?
Tile[] tiles = map.Tiles.GetStaticTiles( from.X, from.Y );
for ( int i = 0; i < tiles.Length; ++i )
{
Tile t = tiles[i];
ItemData id = TileData.ItemTable[t.ID & 0x3FFF];
int tand = t.ID & 0x3FFF;
if ( t.Z != from.Z )
{
continue;
}
else if ( IsDeepStaticSwamp( tand ) )
{
if ( Utility.RandomDouble() < 0.15 ) // 0.15% chance
{
// poison player
from.Poison = Poison.Regular;
from.SendMessage( "You were poisoned by the swamp!" );
return;
}
}
else if ( IsLightStaticSwamp( tand ) )
{
if ( Utility.RandomDouble() < 0.05 ) // 0.05% chance
{
// poison player
from.Poison = Poison.Lesser;
from.SendMessage( "You were poisoned by the swamp!" );
return;
}
}
}
// is it an added swamp?
IPooledEnumerable eable = map.GetItemsInRange( new Point3D( from.X, from.Y, from.Z ), 0 );
foreach ( Item item in eable )
{
if ( item == null || item.Z != from.Z )
{
continue;
}
else if ( IsDeepStaticSwamp( item.ItemID ) )
{
if ( Utility.RandomDouble() < 0.15 ) // 0.15% chance
{
// poison player
from.Poison = Poison.Regular;
from.SendMessage( "You were poisoned by the swamp!" );
return;
}
}
else if ( IsLightStaticSwamp( item.ItemID ) )
{
if ( Utility.RandomDouble() < 0.05 ) // 0.05% chance
{
// poison player
from.Poison = Poison.Lesser;
from.SendMessage( "You were poisoned by the swamp!" );
return;
}
}
}
eable.Free();
}
private static bool IsLightLandSwamp( int itemID )
{
if ( itemID >= 15808 && itemID <= 15833 )
return true;
if ( itemID >= 15835 && itemID <= 15836 )
return true;
if ( itemID >= 15838 && itemID <= 15848 )
return true;
if ( itemID >= 15853 && itemID <= 15857 )
return true;
return false;
}
private static bool IsDeepLandSwamp( int itemID )
{
if ( itemID >= 15849 && itemID <= 15852 )
return true;
return false;
}
private static bool IsLightStaticSwamp( int itemID )
{
if ( itemID >= 12809 && itemID <= 12810 )
return true;
if ( itemID >= 12882 && itemID <= 12905 )
return true;
if ( itemID >= 12912 && itemID <= 12933 )
return true;
return false;
}
private static bool IsDeepStaticSwamp( int itemID )
{
if ( itemID >= 12813 && itemID <= 12881 )
return true;
if ( itemID >= 12906 && itemID <= 12911 )
return true;
return false;
}
// end poisonous swamps
Code:
namespace Server.Items
{
public class SwampBoots : ThighBoots
{
[Constructable]
public SwampBoots() : base()
{
Name = "swamp boots";
Hue = Utility.RandomGreenHue();
}
public SwampBoots(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int) 0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}