RunUO Community

This is a sample guest message. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

Consume via Targeting

Erevan

Sorceror
edit: i apologize to anyone who read this prior to my edit.. posted the wrong code.. this flu is not conducive to posting on a forum! :)

for something so simple, i'm (shamefully) baffled that i can't seem to figure this out..

i'm attempting to create an altar, that when double-clicked, will present a target cursor, and players will have to target a treasure map in their pack (the tmap has no requirements.. it can be used/unused, any facet, any level). if not, the player will be prompted to target a tmap. once they target the tmap, they will have 30 seconds (haven't added the timer yet) to target a world map. once they target the world map, both maps should have been consumed, the player's hits set to 1, and a new map (CorgulMap) added to their pack. this is a jerry-rigged version of the system outlined here:http://uo2.stratics.com/monsters/corgul-the-soulbinder

for whatever reason, i have completely boggled the targeting portion of this and can't seem to figure it out. shouldn't come as any surprise, as this is one of the more complicated scripts i've tried my own hand at. certainly looks as though i'll have to walk through this step by step.

what it does CURRENTLY:
  • Db-clicking works fine
  • Targeting the Treasure Map returns (the first else statement that sends the message "You must target a treasure map first.")
  • Targeting any other map gives me the same message.. so it's not recognizing the Treasure Map
what i'd like it to do:
  • recognize the treasure map.. then 'continue' (allowing the player to dbl-click the altar once more for another targeting cursor, and then they can target the WORLD map)

Code:
using System;
using Server;
using Server.Items;
using System.Collections;
using System.Collections.Generic;
using Server.Gumps;
using Server.Mobiles;
using Server.ContextMenus;
using Server.Prompts;
using Server.Targeting;
using Server.Network;
 
namespace Server.Items
{
    public class CorgulAltar : Item
    {
        [Constructable]
        public CorgulAltar()
            : base(0x35EF)
        {
            this.Name = "Sacrificial Altar";
            this.Hue = 2075;
            this.Movable = false;
        }
 
        public override void OnDoubleClick(Mobile from)
        {
            from.SendMessage("Your offering will be consumed by the altar if the sacrifice is accepted. You will then have 30 seconds to re-use the shrine to collect your new map and pay the blood cost.");
            from.Target = new InternalTarget(this);
        }
 
        private class InternalTarget : Target
        {
            private CorgulAltar m_Item;
 
            public InternalTarget(CorgulAltar item)
                : base(2, false, TargetFlags.None)
            {
                m_Item = item;
            }
 
            protected override void OnTarget(Mobile from, object targeted)
            {
                PlayerMobile pm = from as PlayerMobile;
 
                if (m_Item.Deleted)
                    return;
 
                WorldMap wmap = targeted as WorldMap;
                TreasureMap tmap = targeted as TreasureMap;
 
                if (null == wmap || null == tmap)
                {
                    from.SendMessage("You may only target a world map or treasure map...");
                    return;
                }
                if (targeted is TreasureMap)
                {
                    from.SendMessage("Your offering has been accepted. The price of blood will be taken when you sacrifice your “world map”.");
                    tmap.Delete();
                }
                else
                {
                    from.SendMessage("You must target a treasure map first.");
                        return;
                }
                
                if (targeted is WorldMap)
                {
                    from.SendMessage("Your final offering has been accepted and the blood cost has been collected.");
                    from.Hits = 1;
                    from.AddToBackpack(new CorgulMap());
                    wmap.Delete();
                }
                else
                {
                    from.SendMessage("You must target a world map.");
                        return;
                }
            }
        }
 
        public CorgulAltar(Serial serial)
            : base(serial)
        {
        }
 
        public override void Serialize(GenericWriter writer)
        {
            base.Serialize(writer);
 
            writer.Write((int) 0); // version
        }
 
        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);
 
            int version = reader.ReadInt();
        }
    }
}
 

_Epila_

Sorceror
Now, you are opening else statement with "()" instead of "{}"

Seems that you are using notepad or another text editor to code. If yes, Look at my signature and you will find two links that lead to a tutorial of how to use Visual Studio in order to make scripting easier and avoid those errors
 

Erevan

Sorceror
thanks for the advice, but i was never overly fond of vs.. for someone who is accustomed to using it, i'm sure it's the best. but it seems like an awful lot of work to learn something i can do with notepadd++. i'm a little off my game thanks to this flu.. so those brackets were an oversight. ;)

Code:
 + Custom Systems/- Publish 15 -/CorgulAltar2.cs:
    CS1061: Line 60: 'Server.Items.TreasureMap' does not contain a definition fo
r 'delete' and no extension method 'delete' accepting a first argument of type '
Server.Items.TreasureMap' could be found (are you missing a using directive or a
n assembly reference?)
 

Erevan

Sorceror
oh yeah.. fixed that.. but that's not the issue it seems. this is all very basic stuff, but my head is so clouded i'm missing the obvious.. i sincerely appreciate your patience.

Code:
    CS1061: Line 60: 'Server.Items.TreasureMap' does not contain a definition fo
r 'delete' and no extension method 'delete' accepting a first argument of type '
Server.Items.TreasureMap' could be found (are you missing a using directive or a
n assembly reference?)
    CS1061: Line 73: 'Server.Items.WorldMap' does not contain a definition for '
delete' and no extension method 'delete' accepting a first argument of type 'Ser
ver.Items.WorldMap' could be found (are you missing a using directive or an asse
mbly reference?)
 

Erevan

Sorceror
updated the main post with some more info (just above the code). the script compiles, but the targeting needs some work.
 

Erevan

Sorceror
Have done some additional testing.. still running into the same issue with it not recognizing Treasure Maps, and it doesn't "continue" after targeting the first item.
 

Vorspire

Knight
Code:
                WorldMap wmap = targeted as WorldMap;
                TreasureMap tmap = targeted as TreasureMap;
 
                if (null == wmap || null == tmap)
                {
                    from.SendMessage("You may only target a world map or treasure map...");
                    return;
                }

One of these 2 values is definitely going to be null and therefore your if-statement will always evaluate to true, meaning you will always get that message.

A more efficient way to do what you want would be:

Rich (BB code):
protected override void OnTarget(Mobile from, object targeted)
{ 
	if (from == null || m_Item.Deleted)
		return;

	if (targeted is WorldMap)
	{
		from.SendMessage("Your final offering has been accepted and the blood cost has been collected.");
		((WorldMap)targeted).Delete();
		from.Hits = 1;
		from.AddToBackpack(new CorgulMap());
		return;
	}

	if (targeted is TreasureMap)
	{
		from.SendMessage("Your offering has been accepted. The price of blood will be taken when you sacrifice your “world map”.");
		((TreasureMap)targeted).Delete();
		return;
	}

	from.SendMessage("You may only target a world map or treasure map...");
}
 

Erevan

Sorceror
Appreciate the response Vorspire. Your suggestion is certainly much better, but unfortunately it doesn't solve the dilemma of needing to target a specific map first (the TMap). Basically, I need to have players target the tmap, then be prompted to "continue" and then target the world map.

Currently, players can target either or.. if they target the world map first, they skip right over the treasure map.
 

Murzin

Knight
what you have to do is setup a method that stores temp object values for both world and tmaps, as long as one of them is empty, it will send a new target, when both are filled with "valid" maps, it will delete them, and then spawn the new map in their pack.

also, make sure that the double click on the altar is a revealing option, and you will want to make that method instanced not global on the altar to prevent others from hiding near the altar and waiting for someone else to "add" a map and jacking their additions. and then probably a simple timer check that will empty all values within say 5 minutes to prevent someone from coming by, adding a map, and then walking away preventing anyone else from using it.
 

Khaz

Knight
Erevan, would something like this work for you?
Code:
public class CorgulAltar : Item
{
    public override void OnDoubleClick(Mobile from)
    {
        from.SendMessage("Select a treasure map");
        from.BeginTarget(2, false, TargetFlags.None, new TargetCallback( OnTargetTMap ));
    }
    
    private void OnTargetTMap(Mobile from, object targeted)
    {
        if(targeted is TreasureMap)
        {
            from.SendMessage("Great, now pick a world map");
            from.BeginTarget(2, false, TargetFlags.None, new TargetCallback( OnTargetWMap ));
        }
        else
        {
            from.SendMessage("Pick a treasure map");
            from.BeginTarget(2, false, TargetFlags.None, new TargetCallback( OnTargetTMap ));
        }   
    }
    
    private void OnTargetWMap(Mobile from, object targeted)
    {
        if(targeted is WorldMap)
        {
            from.SendMessage("Great job!");
        }
        else
        {
            from.SendMessage("Pick a world map");
            from.BeginTarget(2, false, TargetFlags.None, new TargetCallback( OnTargetWMap ));
        }   
    }
}
 

Murzin

Knight
here is what i would do:

please note, this is to show logic and flow, not actually compile

Code:
ondoublclick( mobile from )
{
check range 5 tiles
revealing action
 
if ( from is PlayerMobile && from.Alive ) 
call method pickmaps passing ( PlayerMobile player )
 
else
return 
}
 
pickmaps( PlayerMobile player )
{
private TreasureMap tmap;
private WorldMap wmap;
 
player.sendmessage( please select both a worldmap and treasuremap)
 
while ( tmap = null && wmap = null )
{
player.sendtarget( player, target );
if ( target is WorldMap )
{
wmap = target
}
else if ( target is TreasureMap )
{
tmap = target
}
}
 
if ( tmap != null && wmap != null )
{
try
{
tmap.Delete();
wmap.Delete();
from.AddToBackpack( new CorgulMap() ) 
}
catch
{
player.sendmessage( there was a problem combining the maps into the new map!  try again. )
}
}
 
targeting code here

see what i mean?

yes, using a while loop can cause problems if you players really want to, you could include a way to exit out of the loop or maybe use a different method for repeatedly sending the target option to the player.

the key is to NOT store the reference holders for the maps on the stone, they need to be instanced so as to allow multiple people to use the stone at once.
 

Khaz

Knight
Appreciate the response Vorspire. Your suggestion is certainly much better, but unfortunately it doesn't solve the dilemma of needing to target a specific map first (the TMap). Basically, I need to have players target the tmap, then be prompted to "continue" and then target the world map.

Murzin, your solution seems overly complex. There shouldn't be a need to store the maps because the proposed design is to pick them sequentially, not either/or, then delete it and continue.

$0.02
 

Erevan

Sorceror
I'm not at home at the moment, but will certainly give this a try as soon as I get there in the next hour or so. But Khaz is correct.. the selection would be sequential. The accuracy sake the tmap has to be picked first, then the world map. Although Murzin has a point with the timer, as someone could basically ninja the altar selection. In fact, accuracy requires a 30s timer. Problem is adding such a complex method to it.
 
Top