UOGamers 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!

  • To obtain new Razor updates, please reinstall Razor from our new website.

[SVN514][Copern] Missing Necromancy Potions

Status
Not open for further replies.
[SVN514][Copern] Missing Necromancy Potions

Type: Missing Feature

Basic Description: Conflagration and Confusion Blast potions (both normal and greater) are missing.

Way to experience: You can't create them in the Alchemy gump

Detailed Description: As above. This is a SE feature (Publish 32). The Conflagration power depends by the Alchemy skill and by the Enhance Potions mod. (info on Stratics).
Note: only alchemy skill is required. Necromancy is not required.

Links: announcement: http://update.uo.com/design_513.html
details and formulas: http://uo.stratics.com/content/skills/alchemy.php

Code: see below
I'm a Ultima VIII fan so... :)

Seriously, it's a missing feature. What else?
 

psz

Administrator
Re: Missing Necromancy Potions

osd_daedalus;559691 said:
** checking if MalGanis' ML already thought about this **


Since it's an SE feature, probably not. This isn't to say someone else hadn't thought of it already, though.
 
Re: Missing Necromancy Potions

psz;559715 said:
Since it's an SE feature, probably not. This isn't to say someone else hadn't thought of it already, though.

instead they are in Malganis' ML :)

I have only to localize them and merge.

I could also add others, because ML's Earthen Mixtures "needs a recipe" so it won't be affect the gameplay now.

EDIT: better to proceed one step at time, as we are coding for RunUO we have to specify expansions for each code and looks like this it's not always specified in MalGanis' ML.

At the end, it's not different than this: http://www.runuo.com/forums/custom-script-releases/83264-2-0-rc1-potions.html

The only thing that concerns me is that "mask of death" potion I can't reach to find any documentation about. Do it exist in OSI?
 
Re: Missing Necromancy Potions

I found something about "Mask of Death" potion:

It was meant to be in Publish 32:
http://www.uo.com/cgi-bin/newstools.pl?Article=8876

but at the end, it was removed.
http://update.uo.com/design_513.html

So, we have to exclude that potion.

(pity, that was another nice U8 necro spell...)


** merging, coding... **

err... I have a problem...

Who helps me to make the proper changes in Scripts\Items\Skill Items\Magical\Potions\BasePotion.cs in the field "public enum PotionEffect:" as they can be read only in Core.SE? Or another way not to let options in gump menu appear in pre-SE shards?
 

psz

Administrator
Re: Missing Necromancy Potions

From Stratics: http://uo.stratics.com/content/basics/reagenttome.shtml
Dead Wood (rare)
History
Preservation and binding were probably the keywords for the necromancers when they used this reagent, since trees can be nearly immortal in the eyes of a human. Currently spider's silk will do the trick. Magical Uses: Mask of death (Gives the caster the appearance of death), Quake, Rock flesh (a long-lost wisdom, in some ways recreated in the spells Strenght and Bless), Summon dead, Golem and Withstand death.
Alchemical Uses:
The alchemical properties of Dead Wood remain to be discovered.

Magery Uses:
Although no known spell makes use of Dead Wood, it is possible that other, uninvented, spells may.

Necromantic Uses:
- unknown -

Location:
Reapers carry Dead Wood


Note: Dead Wood was part of the *UNUSED* Necro system. So it is not a valid item.
 
Re: Missing Necromancy Potions

psz;559756 said:
From Stratics: http://uo.stratics.com/content/basics/reagenttome.shtml

Note: Dead Wood was part of the *UNUSED* Necro system. So it is not a valid item.

That part says what was their role in their magical history (in that case, in Ultima 8), but in UO reagents are different. Otherwise, both Conflagration and Confusion Blast would require Brimstone and other regs (instead they use Grave Dust and Pig Iron) :p

P.S. In U8 neither of those two are necromantic spells. They are respectively Sorcery (Fire) and Thaumaturgy (Ethereal) spells :p
 

gilgamash

Knight
Re: Missing Necromancy Potions

psz;559756 said:
Note: Dead Wood was part of the *UNUSED* Necro system. So it is not a valid item.

Hoi, I know one of my guildmates got Dead Wood from a wind vortex, so at least it exists on this shard.

G.
 

psz

Administrator
Re: Missing Necromancy Potions

I didn't say there wasn't dead wood, I said it wasn't a valid item (for necro regs)
 
Re: Missing Necromancy Potions

OK, I have also adapted that code for RC2/SVN, and this is my fix submitted:

- download and extract those two folders from "potions.zip" in \Scripts\Items\Skill Items\Magical\Potions\

- then apply the patch.

Requesting testing, to assess:

- if it works only in ML and SE
- if it has the effect researched

- if it is possible, to verify if it works like OSI

I have seen some minor glitches, like "you should have both hands free to drink a potion"... with a Conflagration one :D
Anyway, looks like it works.

P.S. The only place where I reached to add an expansion statement was in DefAlchemy.cs. That means, before SE a player should not to be able to create one of those potions.
But a nice GM can always use [add conflagrationpotion and start creating the hell in a pre-AoS shard. Hehehehehehe...
I just ask that nice GM to shout "At this very moment, BRITANNIA BURNS!!!" ;)

edit: removed the attachment. See the attachment in post below.
 
Re: Missing Necromancy Potions

Ignore that patch above, it has plenty of bugs.

I am working on MalGanis' one that is more accurate... now I'm trying to let the damage boost by Alchemy and Enhance Potions.

EDIT: Patch is below.

Who helps me? Thank you :)
 

Muggz

Sorceror
Re: Missing Necromancy Potions

Off Topic bug wise but just wanted to say Holy hell did making the necro icons in U8 piss me off alot with that stupid bag and key.
 
Re: Missing Necromancy Potions

Muggz;561621 said:
Off Topic bug wise but just wanted to say Holy hell did making the necro icons in U8 piss me off alot with that stupid bag and key.

LOL, yes I remember that:

"AH yeah, stupid damned skeleton! It's time to give you eternal rest, prepare to... uh... wait... where the hell I have placed the Grant Peace talisman... not here... not under the scroll... ufff... where is it??"

Not to mention the reagents you lose if you wrong the formula :p

What pissed me off the most instead was to make sorcery spells on the pentagram. Everytime "Something is not right"... at the end you had to place the reagent *over* the candle
 
Re: Missing Necromancy Potions

osd_daedalus;561381 said:
- if you pour Confusion Blast potions in a keg, it will be displayed as "A keg of [greater] Mask of Death potions" (this is NOT reproducible in Malganis' ML)

Ok, I fixed that. Only 1 bug remaining...
 

Hilde

Page
Re: Missing Necromancy Potions

gilgamash;560204 said:
Hoi, I know one of my guildmates got Dead Wood from a wind vortex, so at least it exists on this shard.

G.

Aye, I got one piece of Dead Wood at home :)
 
Re: Missing Necromancy Potions

hmmm... no. I can't reach to resolve this one.

I am attempting to give to conflagration damage a bonus depending by Alchemy skill, that is, according to Stratics, 1 damage every 13 skill points, all rounded down (so, 12 skillpoints will return 0; 25 skillpoints will return 1...)

The Math.Floor function should return me an integer, no? Why I have complains in compiling because it's a double?
I have already tried to declare it as double, then declare a new int with Math.Floor, but looks like to the compiler I'm attempting to sum an integer with a double :(

That's the code. Someone helps me? Thank you :)

NOTE: The last goal is to have also Enhance Potions to enhance the damage, but I don't figure how to implement this, looking at the Explosion potion scripts. If you can help me also in this, I'll give you a big thank you and signal this as ready for commit.

edit: I have added a Convert.ToInt16 and now it compiles, but still no effect. Should I use ToInt32 or 64? It's only a bonus that goes not over +8!

In the meanwhile, I am adding a new archive with a new patch: now there is something about "balanced" archery weapons so I had to insert some variables in BaseRanged.cs. Looks like little changed, but I think it will turn useful later ;)

My Scripts\Items\Skill Items\Magical\Potions\Conflagration Potions\BaseConflagrationPotion.cs. In red is what I have added. Modifies are either in OnMoveOver and in OnTick:
Code:
using System;
using System.Collections;
using System.Collections.Generic;
using Server;
using Server.Network;
using Server.Targeting;
using Server.Spells;

namespace Server.Items
{
    public abstract class BaseConflagrationPotion : BasePotion
    {
        public abstract int MinDamage{ get; }
        public abstract int MaxDamage{ get; }

        public override bool RequireFreeHand{ get{ return false; } }

        public BaseConflagrationPotion( PotionEffect effect ) : base( 0xF06, effect )
        {
            Hue = 0x489;
        }

        public BaseConflagrationPotion( Serial serial ) : base( serial )
        {
        }
        
        public override void Drink( Mobile from )
        {
            if ( Core.AOS && (from.Paralyzed || from.Frozen || (from.Spell != null && from.Spell.IsCasting)) )
            {
                from.SendLocalizedMessage( 1062725 ); // You can not use that potion while paralyzed.
                return;
            }
            
            int delay = GetDelay( from );
        
            if ( delay > 0 )
            {
                from.SendLocalizedMessage( 1072529, String.Format( "{0}\t{1}", delay, delay > 1 ? "seconds." : "second." ) ); // You cannot use that for another ~1_NUM~ ~2_TIMEUNITS~
                return;
            }

            ThrowTarget targ = from.Target as ThrowTarget;

            if ( targ != null && targ.Potion == this )
                return;

            from.RevealingAction();

            if ( !m_Users.Contains( from ) )
                m_Users.Add( from );

            from.Target = new ThrowTarget( this );
        }

        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();
        }
        
        private List<Mobile> m_Users = new List<Mobile>();
        
        public void Explode_Callback( object state )
        {
            object[] states = (object[]) state;
            
            Explode( (Mobile) states[ 0 ], (Point3D) states[ 1 ], (Map) states[ 2 ] );
        }
        
        public virtual void Explode( Mobile from, Point3D loc, Map map )
        {
            if ( Deleted || map == null )
                return;

            Consume();
            
            // Check if any other players are using this potion
            for ( int i = 0; i < m_Users.Count; i ++ )
            {
                ThrowTarget targ = m_Users[ i ].Target as ThrowTarget;

                if ( targ != null && targ.Potion == this )
                    Target.Cancel( from );
            }            
            
            // Add delay
            AddDelay( from );
            
            // Effects
            Effects.PlaySound( loc, map, 0x20C );
            
            for ( int i = -2; i <= 2; i ++ )
            {
                for ( int j = -2; j <= 2; j ++ )
                {
                    Point3D p = new Point3D( loc.X + i, loc.Y + j, loc.Z );
                    
                    if ( map.CanFit( p, 12, true, false ) && from.InLOS( p ) )
                        new InternalItem( from, p, map, MinDamage, MaxDamage );
                }
            }            
        }
        
        #region Delay
        private static Hashtable m_Delay = new Hashtable();
        
        public static void AddDelay( Mobile m )
        {
            Timer timer = m_Delay[ m ] as Timer;
            
            if ( timer != null )
                timer.Stop();
            
            m_Delay[ m ] = Timer.DelayCall( TimeSpan.FromSeconds( 30 ), new TimerStateCallback( EndDelay_Callback ), m );    
        }
        
        public static int GetDelay( Mobile m )
        {
            Timer timer = m_Delay[ m ] as Timer;
            
            if ( timer != null && timer.Next > DateTime.Now )
                return (int) (timer.Next - DateTime.Now).TotalSeconds;
            
            return 0;
        }
        
        private static void EndDelay_Callback( object obj )
        {
            if ( obj is Mobile )
                EndDelay( (Mobile) obj );            
        }
        
        public static void EndDelay( Mobile m )
        {
            Timer timer = m_Delay[ m ] as Timer;
            
            if ( timer != null )
            {
                timer.Stop();
                m_Delay.Remove( m );
            }
        }
        #endregion

        private class ThrowTarget : Target
        {
            private BaseConflagrationPotion m_Potion;
            
            public BaseConflagrationPotion Potion
            {
                get{ return m_Potion; }
            }

            public ThrowTarget( BaseConflagrationPotion potion ) : base( 12, true, TargetFlags.None )
            {
                m_Potion = potion;
            }

            protected override void OnTarget( Mobile from, object targeted )
            {
                if ( m_Potion.Deleted || m_Potion.Map == Map.Internal )
                    return;
                    
                IPoint3D p = targeted as IPoint3D;

                if ( p == null || from.Map == null )
                    return;

                SpellHelper.GetSurfaceTop( ref p );

                from.RevealingAction();

                IEntity to;

                if ( p is Mobile )
                    to = (Mobile)p;
                else
                    to = new Entity( Serial.Zero, new Point3D( p ), from.Map );

                Effects.SendMovingEffect( from, to, 0xF0D, 7, 0, false, false, m_Potion.Hue, 0 );
                Timer.DelayCall( TimeSpan.FromMilliseconds( GetDelay( from.Location, new Point3D( p ) ) ), new TimerStateCallback( m_Potion.Explode_Callback ), new object[] { from, new Point3D( p ), from.Map } );                 
            }
            
            public int GetDelay( Point3D start, Point3D end )
            {
                double range = Math.Sqrt( Math.Pow( start.X - end.X, 2 ) + Math.Pow( start.Y - end.Y, 2 ) );
                
                return (int) ( 1000 * range / 4 );
            }
        }
        
        public class InternalItem : Item
        {
            private Mobile m_Caster;
            private DateTime m_End;
            private Timer m_Timer;
            private int m_Min;
            private int m_Max;
            
            public override bool BlocksFit{ get{ return true; } }

            public InternalItem( Mobile caster, Point3D loc, Map map, int min, int max ) : base( 0x398C )
            {
                Movable = false;
                Light = LightType.Circle300;

                MoveToWorld( loc, map );

                m_Caster = caster;
                m_End = DateTime.Now + TimeSpan.FromSeconds( 10 );
                m_Min = min;
                m_Max = max;

                m_Timer = new InternalTimer( this, min, max );
                m_Timer.Start();
            }

            public override void OnAfterDelete()
            {
                base.OnAfterDelete();

                if ( m_Timer != null )
                    m_Timer.Stop();
            }

            public InternalItem( Serial serial ) : base( serial )
            {
            }

            public override void Serialize( GenericWriter writer )
            {
                base.Serialize( writer );

                writer.Write( (int) 0 ); // version

                writer.Write( (Mobile) m_Caster );
                writer.Write( (DateTime) m_End );
                writer.Write( (int) m_Min );
                writer.Write( (int) m_Max );
            }

            public override void Deserialize( GenericReader reader )
            {
                base.Deserialize( reader );

                int version = reader.ReadInt();
                
                m_Caster = reader.ReadMobile();
                m_End = reader.ReadDateTime();
                m_Min = reader.ReadInt();
                m_Max = reader.ReadInt();
                
                m_Timer = new InternalTimer( this, m_Min, m_Max );
                m_Timer.Start();
            }

            public override bool OnMoveOver( Mobile m )
            {
                if ( Visible && m_Caster != null && (!Core.AOS || m != m_Caster) && SpellHelper.ValidIndirectTarget( m_Caster, m ) && m_Caster.CanBeHarmful( m, false ) )
                {
                                        m_Caster.DoHarmful( m );

                    int damage = Utility.RandomMinMax( m_Min, m_Max );
[COLOR=Red]                    int alchemybonus = Convert.ToInt16 (Math.Floor(m_Caster.Skills.Alchemy.Value / 13)); //alchemy bonus, 1 damage per 13 skillpoints. If 12 = 0 bonus. If 12, 0 bonus[/COLOR]

                    if ( !Core.AOS && m.CheckSkill( SkillName.MagicResist, 0.0, 30.0 ) )
                    {
                        damage = Math.Max( 1, damage / 5 );
               [COLOR=Red]         damage += alchemybonus;[/COLOR]
                        m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy.
                    }

                    AOS.Damage( m, m_Caster, damage, 0, 100, 0, 0, 0 );
                    m.PlaySound( 0x208 );
                }

                return true;
            }

            private class InternalTimer : Timer
            {
                private InternalItem m_Item;
                private int m_Min;
                private int m_Max;

                private static Queue m_Queue = new Queue();

                public InternalTimer( InternalItem item, int min, int max ) : base( TimeSpan.Zero, TimeSpan.FromSeconds( 1.0 ) )
                {
                    m_Item = item;
                    m_Min = min;
                    m_Max = max;

                    Priority = TimerPriority.FiftyMS;
                }

                protected override void OnTick()
                {
                    if ( m_Item.Deleted )
                        return;

                    if ( DateTime.Now > m_Item.m_End )
                    {
                        m_Item.Delete();
                        Stop();
                    }
                    else
                    {
                        Map map = m_Item.Map;
                        Mobile caster = m_Item.m_Caster;

                        if ( map != null && caster != null )
                        {
                            foreach ( Mobile m in m_Item.GetMobilesInRange( 0 ) )
                            {
                                if ( (m.Z + 16) > m_Item.Z && (m_Item.Z + 12) > m.Z && (!Core.AOS || m != caster) && SpellHelper.ValidIndirectTarget( caster, m ) && caster.CanBeHarmful( m, false ) )
                                    m_Queue.Enqueue( m );
                            }

                            while ( m_Queue.Count > 0 )
                            {
                                Mobile m = (Mobile)m_Queue.Dequeue();

                                caster.DoHarmful( m );

                                int damage = Utility.RandomMinMax( m_Min, m_Max );
[COLOR=Red]                                int alchemybonus = Convert.ToInt16(Math.Floor(caster.Skills.Alchemy.Value / 13)); //alchemy bonus, 1 damage per 13 skillpoints. If 12 = 0 bonus. If 12, 0 bonus[/COLOR]
                                if ( !Core.AOS && m.CheckSkill( SkillName.MagicResist, 0.0, 30.0 ) )
                                {
                                    damage = Math.Max( 1, damage / 5 );
                                    [COLOR=Red]damage += alchemybonus;[/COLOR]
                                    m.SendLocalizedMessage( 501783 ); // You feel yourself resisting magical energy.
                                }

                                AOS.Damage( m, caster, damage, 0, 100, 0, 0, 0 );
                                m.PlaySound( 0x208 );
                            }
                        }
                    }
                }
            }
        }
    }
}
 

Attachments

  • Potions.zip
    19.1 KB · Views: 3

gilgamash

Knight
Re: Missing Necromancy Potions

Hi Daedalus,

from what I found, there are two ways to access the values of the skills:

Code:
Runebook.cs:  int charges = 5 + quality + (int)(from.Skills[SkillName.Inscribe].Value / 30);
Spellbook.cs:   int magery = from.Skills.Magery.BaseFixedPoint;

caster.Skills.Alchemy.Value might not work.

Give it a shot editing your files alike and lemme know whether it works :)

G.
 
Re: Missing Necromancy Potions

I have resolved!

No gilgamash, the matter wasn't there. It was for 2 reasons:

1) Math.Floor wants a double, not an int. It was enough to write 13.0 instead of 13.
2) I am a dumb! I have placed the alchemybonus damage in the if statement about resisting the spell :/

I attach the correct script but isn't finished:

I reached to create an Enhance Potion bonus. I still don't get why it won't take from BasePotion.cs, or why Explosion potions are affected by Enhance Potions.

Anyway, I have added a bonus for Enhance Bonus... it should be accurate but it's not compliant to Stratics:

For Conflagration:

0 alchemy and 80% enhance potions:
script - 4-8 damage
Stratics - 3-7 damage

100 alchemy and 80% enhance potions:
script - 14-18 damage
Stratics - 18-21 damage

An help would be appreciated, although I continue to search for a good solution :)
 

Attachments

  • BaseConflagrationPotion.zip
    2.9 KB · Views: 0
Re: Missing Necromancy Potions

The reason looks like this: (tnx gilgamash for the notice)

Stratics says you will get 1 damage bonus point every 13 alchemy skillpoints.
If you play with its calculator, though, you will find that:

- until 0-13-26-39 skillpoints, it's true
- Then, you get a damage point NOT at 52, but at 50. That's only 11 points!
- Then you have 50-63. Ok, 13 points
- Now you expect a 63-76 range... instead is 75. Only 12 points.
- A 75-88 range. Ok, 13 points.
- At the end, 88-100... only 12 points

So, that's the dilemma:
Stratics' Formula says: If the user of conflagration potions has any alchemy skill the damage will be increased by 1 for every 13 points of alchemy skill the user has.

But Stratics' Calculator: http://uo.stratics.com/content/skills/alchemy.php

says that's a bit variable about.

Now, what system shall we follow?
 

gilgamash

Knight
Re: Missing Necromancy Potions

Hoi,

I'll figure out a 'formula' (let's say an algorithm) in coincidence with stratics tomorrow.

G.
 
Re: Missing Necromancy Potions

gilgamash;566109 said:
Hoi,

I'll figure out a 'formula' (let's say an algorithm) in coincidence with stratics tomorrow.

G.


Nah, that is not a formula. It's only a way to make 50, 75 and 100 skill values useful.

I think I'll follow that way and I'll comment the old one.
Instead to make a formula, I'll use something like
if (alchemy between 0 and 12) { alchemy bonus = 0 } else if 13 and 26 then 1..... classical method :D
I'm working on it ;)

edit:

Hell yeah! Now it works greatly!!

I used this solution. Childish maybe, but efficient ;)
Code:
                    int alchemybonus = (int) (m_Caster.Skills.Alchemy.Value);
                    if (alchemybonus >= 0 && alchemybonus < 13) { alchemybonus = 0 ;}
                    else if (alchemybonus >= 13 && alchemybonus < 25) { alchemybonus = 1 ;}
                    else if (alchemybonus >= 25 && alchemybonus < 38) { alchemybonus = 2 ;}
                    else if (alchemybonus >= 38 && alchemybonus < 50) { alchemybonus = 3 ;}
                    else if (alchemybonus >= 50 && alchemybonus < 63) { alchemybonus = 4 ;}
                    else if (alchemybonus >= 63 && alchemybonus < 75) { alchemybonus = 5 ;}
                    else if (alchemybonus >= 75 && alchemybonus < 88) { alchemybonus = 6 ;}
                    else if (alchemybonus >= 88 && alchemybonus < 100) { alchemybonus = 7 ;}
                    else if (alchemybonus == 100) { alchemybonus = 8 ;}
About damage values, I was experimenting on an ice elemental that has a bit of fire resistances. I have spawned some with 0 fire resist and damages are corresponent to Stratics.

And that's my definitive patch. I ask someone to test it, so I can flag it as ready. edit: patch is in last post.

By the way, before I updated a patch that already included support for Balanced bows, that are bows considered as 1-handed weapons. I have removed that line: better to add less code as possible, I'll think about balanced bows (that are a ML thing) later.
 
Status
Not open for further replies.
Top