Full Version : xmlsocket question
xmlspawner >>Q&A >>xmlsocket question
<< Prev | Next >>
slida- 05-15-2006
So here is the scenario I've envisioned. Players on the quest will eventually acquire 4 socketed demon statuettes of different colors(not four each, four in total). The backstory is that a very powerful demon is imprisoned in one of these four, and when the sockets on this particular demon statuette are filled correctly it will summon an incredibly powerful demon blah blah blah I guess thats not pertinent to the question.
The players have really no idea this is going to happen, and but they have to summon this demon in order to finish this part of the story and be able to leave the dungeon, thus the other statuettes. The other statuettes are traps, diversions with the intention of killing the curious and preventing this demon from being released. So what I'm looking at is four sockets, if they are not filled with the right four jewels, nothing happens. If they are filled in correctly(order is not important) they will explode, poison etc.or in the case of the correct one, summon the demon.
XmlSockets doesn't seem to be designed with this sort of thing in mind, but I'd like to use it in this way, it seems like a nifty idea. This seems like it might be pretty complex, but if you could point me in the right direction I'll try to figure it out(things are starting to make a lot more sense lately). I haven't got to the point where I am working on this yet but I see it as a significant hurdle in the not-so-distant future. I've read your information on the socket system, so I know how to make the statuettes socketable but thats about it, as far as my particular question.
As a little addon to this, I am thinking of 'blessing' all the players items while they are in the dungeon, which I believe I can accomplish with an attachment. However, especially with the statuettes, I would like some items to not be blessed, and actually have creatures specifically loot them(the npc's in the dungeon do not want players to have those statues, because they want this demon to remain imprisoned, for very good reasons, the players will find), is that possible, or will the playermob properties override any added properties of the statuettes. Would the attachment be modifiable to not work with certain items, or do I modify the item itself? TIA!
ArteGordon- 05-16-2006
yes, you could fairly easily do something like that with the socket system. All of the functionality would actually be in the augments. If you take a look at keyaugment.cs for example, it is an augment that can be used to unlock doors that have sockets on them.
What you would do would be to add a check in the OnAugment method of the augment to test for a full set of augments, and then perform the action that you want.
You would add something like this to the scripts for your special augments.

CODE
public override bool OnAugment(Mobile from, object target) { if (target is YourStatuette) { // look for the other augments in the target sockets
XmlSockets s = (XmlSockets)XmlAttach.FindAttachment(target, typeof(XmlSockets));
if(s != null && s.SocketOccupants != null)
{
bool hasaugment1 = false;
bool hasaugment2 = false;
bool hasaugment3 = false;
bool hasaugment4 = false;
foreach (SocketOccupant so in s.SocketOccupants)
{
if (so.OccupantType is YourSpecialAugment1)
hasaugment1 = true;
if (so.OccupantType is YourSpecialAugment2)
hasaugment2 = true;
if (so.OccupantType is YourSpecialAugment3)
hasaugment3 = true;
if (so.OccupantType is YourSpecialAugment4)
hasaugment4 = true;
}
if (hasaugment1 && hasaugment2 && hasaugment3 && hasaugment4)
{
// spawn your creature
}
}
}
return false;
}
public override bool CanAugment(Mobile from, object target)
{
if (target is YourStatuette)
{
return true;
}
return false;
}

ArteGordon- 05-16-2006
to add an attachment to players that would prevent items from being dropped to the corpse, you could add this modification to the GetParentMoveResultFor and GetInventoryMoveResultFor methods in PlayerMobile.cs

QUOTE
public override DeathMoveResult GetParentMoveResultFor(Item item) { if (CheckInsuranceOnDeath(item)) return DeathMoveResult.MoveToBackpack; DeathMoveResult res = base.GetParentMoveResultFor(item);
XmlData a = (XmlData)XmlAttach.FindAttachment(this, typeof(XmlData), "NoDrop");
if (res == (DeathMoveResult.MoveToCorpse && item.Movable && this.Young) || (a != null && !(item is YourSpecialStatuette)))
res = DeathMoveResult.MoveToBackpack;
return res;
}

QUOTE
public override DeathMoveResult GetInventoryMoveResultFor(Item item) { if (CheckInsuranceOnDeath(item)) return DeathMoveResult.MoveToBackpack; DeathMoveResult res = base.GetInventoryMoveResultFor(item);
XmlData a = (XmlData)XmlAttach.FindAttachment(this, typeof(XmlData), "NoDrop");
if (res == (DeathMoveResult.MoveToCorpse && item.Movable && this.Young) || (a != null && !(item is YourSpecialStatuette)))
res = DeathMoveResult.MoveToBackpack;
return res;
}

Then, as long as the player has the xmldata attachment named "NoDrop", then any items they are carrying will not drop to the corpse with the exception of items of the type YourSpecialStatuette. You could add that attachment with something like
SETONTRIGMOB/ATTACH/xmldata,NoDrop
You might also want to add a region check or an expiration time for the attachment so that they dont get permanent NoDrop status.
slida- 05-16-2006
Thanks again Arte, I seem to have a knack for coming up with ideas that require scripting, which is good because by the time I'm done I should be able to do some coding. I'm sure I'll have many questions as I try to figure this out but hopefully I'll learn how to do most of it. I've got a couple of questions right now.

QUOTE
if (res == (DeathMoveResult.MoveToCorpse && item.Movable && this.Young) || (a != null && !(item is YourSpecialStatuette))) res = DeathMoveResult.MoveToBackpack;

The way I'm interpreting this code is that, if you have the statuette, all of your items will be dropped on your corpse, instead of just the statuette, because the check would fail if you had the statue, I need more insight on what's happening here I guess. This isn't neccesarily a bad thing because I am thinking about adding some sort of penalty to those carrying the statues anyway.
Second question involves the region check, this is definitely what I want to do with the attachment but I wanted to limit my questions for one post, I wasn't sure if it was possible. So you can add an If region/goto sort of loop to the attachment? I don't know anything about regions, is this done by name or coordinates? This is all being done in the dungeon Despise so this is probably pretty easy?
ArteGordon- 05-17-2006
that code would result in all items except for statuettes being moved to the backpack instead of to the corpse on death (essentially behaving as though they were all blessed except for the statuette).
I think that a better general solution is to create a new attachment that will allow you to do this but also allow you to do things like check the region and add specific item exemptions in the attachment instead of hardcoding them into those playermobile methods.
Adding new attachments is pretty easy. I have attached an example that would do it.
It would involve making a similar mod to playermobile.cs only using an attachment designed for this purpose. It calls the ProtectItem method on the attachment that can check regions, excluded items, etc. Basically any condition that you want to apply.

QUOTE
public override DeathMoveResult GetParentMoveResultFor(Item item) { if (CheckInsuranceOnDeath(item)) return DeathMoveResult.MoveToBackpack; DeathMoveResult res = base.GetParentMoveResultFor(item);
XmlProtectItems a = (XmlProtectItems)XmlAttach.FindAttachment(this, typeof(XmlProtectItems));
if (res == DeathMoveResult.MoveToCorpse && ((item.Movable && this.Young) || (a != null && a.ProtectItem(item))))
res = DeathMoveResult.MoveToBackpack;
return res;
}
public override DeathMoveResult GetInventoryMoveResultFor(Item item)
{
if (CheckInsuranceOnDeath(item))
return DeathMoveResult.MoveToBackpack;
DeathMoveResult res = base.GetInventoryMoveResultFor(item);
XmlProtectItems a = (XmlProtectItems)XmlAttach.FindAttachment(this, typeof(XmlProtectItems));
if (res == DeathMoveResult.MoveToCorpse && ((item.Movable && this.Young) || (a != null && a.ProtectItem(item))))
res = DeathMoveResult.MoveToBackpack;
return res;
}

With the attachment below, you can also specify a region name that it will apply to, like
[addatt xmlprotectitems "Deceit"
or
SETONTRIGMOB/ATTACH/xmlprotectitems,Deceit
would prevent items from dropping to the corpse in Deceit.
I also added constructors that accept an expiration time so that you can make them time limited.
SETONTRIGMOB/ATTACH/xmlprotectitems,Deceit,20
would give 20 mins of protection in Deceit
I added in some example exclusions in the ProtectItem method, but you could put in whatever you wanted.

QUOTE
public bool ProtectItem(Item item) { // check to see whether this item should be moved to the backpack on death // check the region Mobile from = AttachedTo as Mobile;
if (from != null)
{
Region r = Region.Find(from.Location, from.Map);
// if it is in the wrong region then dont protect the item
if (from != null && RegionName != null && RegionName != String.Empty)
return false;
}
// add whatever item exemptions that you want here
if (item is BaseClothing || item is BaseArmor)
{
// dont protect them
return false;
}
// by default protect all items
return true;
}

You could easily mod this attachment to handle multiple regions, or commandline specification of items to be excluded etc.
slida- 05-20-2006
Well I was hoping to sit down and figure out all this stuff today, but I was done in right at the start. The item identification skill is not functional for me. It either says you can't identify it or it does nothing. I looked at the script for the skill and it appears to be incomplete, with no action defined for successful identification:

CODE
using System; using Server; using Server.Targeting; using Server.Mobiles; namespace Server.Items
{
public class ItemIdentification
{
public static void Initialize()
{
SkillInfo.Table[(int)SkillName.ItemID].Callback = new SkillUseCallback( OnUse );
}
public static TimeSpan OnUse( Mobile from )
{
from.SendLocalizedMessage( 500343 ); // What do you wish to appraise and identify?
from.Target = new InternalTarget();
return TimeSpan.FromSeconds( 1.0 );
}
[PlayerVendorTarget]
private class InternalTarget : Target
{
public InternalTarget() : base ( 8, false, TargetFlags.None )
{
AllowNonlocal = true;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Item )
{
if ( from.CheckTargetSkill( SkillName.ItemID, o, 0, 100 ) )
{
if ( o is BaseWeapon )
((BaseWeapon)o).Identified = true;
else if ( o is BaseArmor )
((BaseArmor)o).Identified = true;
if ( !Core.AOS )
((Item)o).OnSingleClick( from );
}
else
{
from.SendLocalizedMessage( 500353 ); // You are not certain...
}
}
else if ( o is Mobile )
{
((Mobile)o).OnSingleClick( from );
}
else
{
from.SendLocalizedMessage( 500353 ); // You are not certain...
}
}
}
}
}

This is pretty strange, and it really sucks because I don't know enough to be able to tell what's wrong. I haven't found much about this over at runuo, except for the fact that AOS has something to do with it maybe. Since no one else has reported a problem, I am mystified. I'm gonna try a couple of things but I'm not too optimistic.AAAAAURGH!
ArteGordon- 05-20-2006
you need to perform xmlspawner installation step 8

QUOTE
STEP 8: (recommended but not required) To allow the ItemIdentification skill to be used to reveal attachments on items/mobs, one line must be added to ItemIdentification.cs (Scripts/Skills/ItemIdentification.cs) as described below. (note, you dont have to make this mod if you dont want to, the spawner and other items will work just fine without it, players just wont be able to see what attachments are on an item/mob using this skill).
around line 50 of ItemIdentification.cs change
else if ( o is Mobile )
{
((Mobile)o).OnSingleClick( from );
}
else
{
from.SendLocalizedMessage( 500353 ); // You are not certain...
}
to
else if ( o is Mobile )
{
((Mobile)o).OnSingleClick( from );
}
else
{
from.SendLocalizedMessage( 500353 ); // You are not certain...
}
//allows the identify skill to reveal attachments
Server.Engines.XmlSpawner2.XmlAttach.RevealAttachments(from,o);

and installation step is suggested but not required

QUOTE
STEP 11: (recommended but not required) To allow attachment properties on weapons/armor to be automatically displayed in the properties list on mouseover/click, these changes must be made to BaseWeapon.cs (Scripts/Items/Weapons/BaseWeapon.cs), BaseArmor.cs (Scripts/Items/Armor/BaseArmor.cs) and BaseJewel.cs (Scripts/Items/Jewels/BaseJewel.cs) described below. (note, you dont have to make this mod if you dont want to, the spawner and other items will work just fine without it, players just wont automatically see attachment properties on items with attachments).
at the end of the GetProperties method around line 2823 of BaseWeapon.cs change
if ( m_Hits > 0 && m_MaxHits > 0 )
list.Add( 1060639, "{0}\t{1}", m_Hits, m_MaxHits ); // durability ~1_val~ / ~2_val~
to
if ( m_Hits > 0 && m_MaxHits > 0 )
list.Add( 1060639, "{0}\t{1}", m_Hits, m_MaxHits ); // durability ~1_val~ / ~2_val~
// mod to display attachment properties
Server.Engines.XmlSpawner2.XmlAttach.AddAttachmentProperties(this, list);
at the end of the GetProperties method around line 1488 of BaseArmor.cs change
if ( m_HitPoints > 0 && m_MaxHitPoints > 0 )
list.Add( 1060639, "{0}\t{1}", m_HitPoints, m_MaxHitPoints ); // durability ~1_val~ / ~2_val~
to
if ( m_HitPoints > 0 && m_MaxHitPoints > 0 )
list.Add( 1060639, "{0}\t{1}", m_HitPoints, m_MaxHitPoints ); // durability ~1_val~ / ~2_val~
// mod to display attachment properties
Server.Engines.XmlSpawner2.XmlAttach.AddAttachmentProperties(this, list);
at the end of the GetProperties method around line 226 of BaseJewel.cs change
base.AddResistanceProperties( list );
to
base.AddResistanceProperties( list );
// mod to display attachment properties
Server.Engines.XmlSpawner2.XmlAttach.AddAttachmentProperties(this, list);

slida- 05-20-2006
Aha, I was looking in the wrong place, I knew it must be something like that. That was easy enough, now on to the real hard part... Thanks again.
slida- 05-20-2006
HeHe, I knew I was a bit over my head here but I thought I'd get a little farther than this . So the following script doesn't really do much of anything(actually it does nothing at all right now) but my first goal was to take an augment script, change it and get it to compile. I'm just deleting the things I'm doing wrong as I go with the idea of slowly adding onto it. Unfortunatley I got stuck a little higher up than I wanted, because I pretty much knew what I didn't know how to do from the get go.

CODE
using System; using Server; using Server.Mobiles; using Server.Engines.XmlSpawner2; namespace Server.Items
{
public class JimsRuby : BaseSocketAugmentation, IMythicAugment
{
[Constructable]
public JimsRuby() : base(0xF13)
{
Name = "Mythic Ruby";
Hue = 32;
}
public JimsRuby( Serial serial ) : base( serial )
{
}
public override int SocketsRequired {get { return 4; } }
public override int Icon {get { return 0x9a8; } }
public override bool UseGumpArt {get { return true; } }
public override int IconXOffset { get { return 15;} }
public override int IconYOffset { get { return 15;} }
public override string OnIdentify(Mobile from)
{
return "You can feel this jewels power.";
}
public override bool OnAugment(Mobile from, object target)
{
if (target is Artifact)
{
// look for the other augments in the target sockets
XmlSockets s = (XmlSockets)XmlAttach.FindAttachment(target, typeof(XmlSockets));
if(s != null && s.SocketOccupants != null)
{
bool hasaugment1 = false;
bool hasaugment2 = false;
bool hasaugment3 = false;
bool hasaugment4 = false;
foreach (SocketOccupant so in s.SocketOccupants)
{
if (so.OccupantType is YourSpecialAugment1)
hasaugment1 = true;
if (so.OccupantType is YourSpecialAugment2)
hasaugment2 = true;
if (so.OccupantType is YourSpecialAugment3)
hasaugment3 = true;
if (so.OccupantType is YourSpecialAugment4)
hasaugment4 = true;
}
if (hasaugment1 && hasaugment2 && hasaugment3 && hasaugment4)
{
// spawn your creature
}
}
}
return false;
}
public override bool CanAugment(Mobile from, object target)
{
if (target is Artifact)
{return true;
}
return false;
}
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();
}
}
}

So I was hoping to get as far in as YourSpecialAugment before having problems, I don't really know how to refer to the augment here and wanted to see if I could figure it out by looking at other scripts. However I got stuck on SocketOccupant, it could not find it. I did a search and found SocketOccupant in the XmlSockets.cs, but I haven't figured out how to use it. Is it the namespace or the class you have to refer to here? Either way I'm doing it wrong which is no surprise at all .
I haven't gained to much insight into these two questions today so I'll just give up and ask.
1. How do I refer to any specific statue?(The other scripts just dealt with BaseWeapon etc. as the target). I tried using if (target is Base(0x40000058)) but the compiler didn't care for that idea. I have 4 statues which are the same with the exception of the hue and their serial no. Addtionally I don't know how to refer to the augments(YourSpecialAugment) but I haven't gotten far enough to experiment with that.
2.I haven't actually scripted my creature yet, but I wasn't able to come up with any compiler-satisfying code to spawn an existing creature. Is it a return something; or an add.something?
I'm going to go browse runuo's custom scripts and see if I can figure out the answers to these questions tonight, but the SocketOccupant is the real stumper right now.TIA!
ArteGordon- 05-20-2006
in this case YourSpecialAugment would correspond to the new augment class you are making JimsRuby.
SocketOccupant is just the class used to keep track of the current contents of a socket. You dont really need to worry about it, since all you are going to do is to look through the list of occupants and check the type against your custom augment class (JimsRuby) pretty much exactly the way you currently have it.
If you wanted to actually test an item by its serialno, you would do something like
if(((Item)target).Serial == 0xblahblah)
{
}
but that is pretty specific. Why not just give the statues unique names and check that?
if(((Item)target).Name == "Special Statue 1")
{
}
To spawn a creature, you would just create an instance of it and place it into the world, like
Mobile m = new Horse();
m.MoveToWorld(from.Location, from.Map);
slida- 05-20-2006
allright, cool.
The reason I was wanting to use serialnos is that all the statues have the same name, and only one of the statues is the real, demon-summoning statue, the rest will explode or do other nasty things when socketed properly(more questions coming about that probably), its a story issue more than a mechanical issue. Would changing the captilization of certain letters in a name work? Otherwise I'll just go with the serialnos.
My problem with SocketOccupant is that the compiler says that it isn't there when I try to compile the script in my previous post.(are you missing a using directive or an assembly reference?) which makes me think I have to refer to XmlSockets somehow but I haven't been able to do it right, I can't figure out the tree. I guess my previous post was a bit too vague about this problem, sorry about that. THanks for you help!
ArteGordon- 05-20-2006
ah, yes. That is my fault. SocketOccupant is a class within the XmlSockets class so you have to refer to it as
XmlSockets.SocketOccupant
and yes, the string test would be sensitive to capitalization, even though the name property display will always be capitalized, so you could have different names, but they would appear to be the same to players.
slida- 05-22-2006
Allright I've gotten where I thought I'd get stuck.

CODE
if (so.OccupantType is JimsRuby) hasaugment1 = true;

This made it by the compiler somehow but it crashes the server when I try to attach the augment(my first server crash, I'm so proud!) I didn't think that would work and I've tried a few other things but I can't figure it out. Also when I hashed out these offending lines, I was not able to augment the statue at all(kept saying the augment failed). I had to hash out the entire OnAugment method to get it to work. You have any insight into that? TIA!
ArteGordon- 05-22-2006
Sorry, I didnt give you the correct example. The way to compare types is like this

CODE
if (so.OccupantType == typeof(JimsRuby)) hasaugment1 = true;

The crash is probably unrelated to this and has to do with code later on. If you post the whole thing I can take a look.
slida- 05-22-2006
Well you were right, I guess the crash wasn't related to this. It's something right around there though. Heres the code:

CODE
using System; using Server; using Server.Mobiles; using Server.Engines.XmlSpawner2; namespace Server.Items
{
public class JimsRuby : BaseSocketAugmentation, IMythicAugment
{
[Constructable]
public JimsRuby() : base(0xF13)
{
Name = "Mythic Ruby";
Hue = 32;
}
public JimsRuby( Serial serial ) : base( serial )
{
}
public override int SocketsRequired {get { return 1; } }
public override int Icon {get { return 0x9a8; } }
public override bool UseGumpArt {get { return true; } }
public override int IconXOffset { get { return 15;} }
public override int IconYOffset { get { return 15;} }
public override string OnIdentify(Mobile from)
{
return "You can feel this jewels power";
}
public override bool OnAugment(Mobile from, object target)
{
if(((SimpleArtifact)target).Name == "DEMISE")
{
// look for the other augments in the target sockets
XmlSockets s = (XmlSockets)XmlAttach.FindAttachment(target, typeof(XmlSockets));
if(s != null && s.SocketOccupants != null)
{
bool hasaugment1 = false;
bool hasaugment2 = false;
bool hasaugment3 = false;
bool hasaugment4 = false;
foreach (XmlSockets.SocketOccupant so in s.SocketOccupants)
{
if (so.OccupantType == typeof(JimsRuby))
hasaugment1 = true;
if (so.OccupantType == typeof(JimsRuby))
hasaugment2 = true;
if (so.OccupantType == typeof(JimsRuby))
hasaugment3 = true;
if (so.OccupantType == typeof(JimsRuby))
hasaugment4 = true;
}
if (hasaugment1 && hasaugment2 && hasaugment3 && hasaugment4)
{
//spawn your creature
}
}
}
return false;
}
public override bool CanAugment(Mobile from, object target)
{
if(((SimpleArtifact)target).Name == "DEMISE")
{return true;
}
return false;
}
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();
}
}
}

And here is the crash log

CODE
Exception: System.NullReferenceException: Object reference not set to an instance of an object. at Server.Items.JimsRuby.OnAugment(Mobile from, Object target) at Server.Engines.XmlSpawner2.XmlSockets.Augment(Mobile from, Object parent, XmlSockets sock, Int32 socketnum, IXmlSocketAugmentation a)
at Server.Engines.XmlSpawner2.AddAugmentationToSocket.OnTarget(Mobile from, Object targeted)
at Server.Targeting.Target.Invoke(Mobile from, Object targeted)
at Server.Network.PacketHandlers.TargetResponse(NetState state, PacketReader pvSrc)
at Server.Network.MessagePump.HandleReceive(NetState ns)
at Server.Network.MessagePump.Slice()
at Server.Core.Main(String[] args)