|
||
|
|||||||
| Other Cant find a category above, use this one! Core mods not listed above go here! |
![]() |
|
|
Thread Tools | Display Modes |
|
|
#1 (permalink) |
|
Hi all, this started off on another topic from Starbucks but tought I'd post it here since it's more of a coding support topic:
Essentially what I'm doing is coding a sanity system for a gothic/lovecraftian themed shard. One of the side effect of sanity loss are phobias and hallucinations. So for instance if your character has a fear of spiders and they fail a sanity check they should start seeing all human mobiles as spiders for a fixed period of time. Now I've pretty much done my due diligence here and read through all the topics pertaining to hallucination effects with little to know resolution - it was determined it can be done but the concensus was that in order to do it right it would require a modification to the core. So I got the source code and started digging through it. I have a lot of programming background so I'm not afraid to mess around with the core. However, since there's no documentation for the source (and nor am I asking for any - the core team has enough on their plates) I'm not sure WHERE I'll need to make the necessary changes to implement the sanity hallucination effects. I know HOW to do it, just not WHERE to do it. On the script side I have flags in a custommobile script for different phobias and a sanity amount. In addition I have two properties: SeeMobilesAsBody and SeeMobilesAsHue. So, when a phobia kicks in the two above values are set to non-zero values (setting hue to a -1 to generate a random hue). Then on the core side I would look at these two values before sending out mobile packets. If SeeMobileAsBody is set to a value > 0 then all mobile packets destined to the infected player's client would have the body and hue set accordingly before the packet goes out. The process is pretty straight forward. I just can't figure out where I need to code it. I've narrowed my search to the packets.cs file but I'm having difficulty decyphering which function needs to be changed. If anyone from the core team (or anyone else in the know) can just point me to the right function, I can drive from there. I'm pretty sure it's one of the functions that accepts beholder and beholdee. The original topic on starbucks can be found here: Halloween bag 2005 Thanks in advance for any and all help, -TM |
|
|
|
|
|
|
#2 (permalink) |
|
Forum Novice
|
well, first of all: you can not access your custom mobile script from the core, except you do it with reflection (which i absolutely do not advise you because it is really very, very slow). so in order to make this change you have to modify the mobile.cs and put your two fields there - or messing around with some interfaces.
then, to send the right packets at the right time, you have to understand the uo packet protocol. there are several sites dedicated to it, for example http://necrotoolz.sourceforge.net/ka...uide/index.htm, http://gonzo.kiev.ua/guide/guide.html or http://uopackets.emuresource.com/packets.php?style= (not complete, but a good start). you have to take a look where the body id and hue is sended and replace the correct values with your halluzination stuff. there will be several places to change this, i think. maybe an easy way to find those code pieces is to follow the way the server goes if the body or the hue is changed, but you won't learn that much about the uo protocol that way ![]() |
|
|
|
|
|
#3 (permalink) |
|
Forum Expert
Join Date: Jul 2005
Location: Istanbul/Turkey
Age: 27
Posts: 425
|
you dont need to deal with uo protocols to do such a thing.
here is a starting point for you: a) add a variable to Mobile/PlayerMobile for hallucination. (implement getter/setter) b) in Mobile.cs (core), there is a method called ProcessDelta. This is where the packets are sent to the clients. First it updates the client itself, then sends new packets the other clients around. some code from core: Code:
IPooledEnumerable eable = m.Map.GetClientsInRange( m.m_Location );
Mobile beholder;
foreach ( NetState state in eable )
{
beholder = state.Mobile;
if ( beholder != m && beholder.CanSee( m ) )
{
//it sends some packets to clients
//this is where you need to check whether if
//beholder is hallucinating.
}
}
you need to change some of these packets' constructors. ex) from public MobileIncoming( Mobile beholder, Mobile beheld ) : base( 0x78 ) to public MobileIncoming( Mobile beholder, Mobile beheld, bool hallucination ) : base( 0x78 ) or just add another constructor.. if the boolean variable is true, then you need to pick a random hue for each item. see the whole code for MobileIncoming, you will get the idea. you might wanna choose a random hue range first, then pick a random hue for each item if you want colors not to be so much different. you might not need to modify every packet in there. |
|
|
|
|
|
#4 (permalink) | |
|
Thanks Noobie, thats exactly what I was looking for - the WHERE. Gonna hit this evening.
Quote:
public MobileIncoming( Mobile beholder, Mobile beheld ) : base( 0x78 ) to something like Code:
if ( beholder.SeeBodyAs == 0 )
m_Stream.Write( (short) beheld.Body );
else
m_Stream.Write( (short) beholder.SeeBodyAs );
Thanks Noobie, -TM |
||
|
|
|
|
|
#5 (permalink) |
|
Forum Expert
Join Date: Jul 2005
Location: Istanbul/Turkey
Age: 27
Posts: 425
|
hehe, thats not reflection, its overloading (defining extra constructor/method)
![]() btw, you could use some kind of your own method to pick a random hue. lets say ProcessDelta method is called 5 times in a second. for each call, you dont want to pick a new hue for the same player. so you could use a random "seed" for some period (use a seed for randomization), and change it after a while. otherwise, client would see some kind of chameleon which changes its color so rapidly ![]() |
|
|
|
|
|
#6 (permalink) | |
|
Quote:
But yeah, I knew what you mean by overloading. What I meant by Reflection was the defining of props in the scripts and trying to access them from the core. Haven't done any reflections stuff yet but I know at a high-level what it is kinda. So, I want to put the SeeBodyAs and SeeHueAs in the core instead of the scripts. Anyways, since I stopped in at home fer lunch (to get the vidcam) I decided to do a recompile on clean unaltered core code... Compiles fine but won't run - gets to verifying and throws an exception. I always test original source compile before making any changes to make sure I have a good point of reference for debugging. I'll post the specifics of the exception when I get back home. But anyone know why a fresh core recompile would crap out when ran? -TM |
||
|
|
|
|
|
#8 (permalink) | |
|
Quote:
-TM |
||
|
|
|
|
|
#9 (permalink) |
|
WOOHOO! Got this to work, yehah! Had some interesting hickups on the way. For some reason the first iteration behaved rather bizaar - everyone within range of the affected player saw the effects as well.
After commenting out a particular piece of core code in two spots I got the sucker to work. However, I'm not 100% certain as to why it created the above behavior nor do I completely understand the logic behind its inclusion. The code in question is as follows: Code:
if ( p == null )
p = cache[noto] = new MobileMoving( m, noto );
-TM |
|
|
|
|
|
|
#11 (permalink) |
|
Is it possible that the cache[] array is not localized? Because when I comment out the conditional and just force a value into it and P the error goes away. Here's the full extent of the code I modified in mobile.cs:
move() method: Code:
public virtual bool Move( Direction d )
{
if ( m_Deleted )
return false;
BankBox box = FindBankNoCreate();
if ( box != null && box.Opened )
box.Close();
Point3D newLocation = Location;
Point3D oldLocation = newLocation;
if ( (m_Direction & Direction.Mask) == (d & Direction.Mask) )
{
// We are actually moving (not just a direction change)
if ( m_Spell != null && !m_Spell.OnCasterMoving( d ) )
return false;
if ( m_Paralyzed || m_Frozen )
{
SendLocalizedMessage( 500111 ); // You are frozen and can not move.
return false;
}
int newZ;
if ( CheckMovement( d, out newZ ) )
{
int x = m_Location.m_X, y = m_Location.m_Y;
int oldX = x, oldY = y;
int oldZ = m_Location.m_Z;
switch ( d & Direction.Mask )
{
case Direction.North: --y; break;
case Direction.Right: ++x; --y; break;
case Direction.East: ++x; break;
case Direction.Down: ++x; ++y; break;
case Direction.South: ++y; break;
case Direction.Left: --x; ++y; break;
case Direction.West: --x; break;
case Direction.Up: --x; --y; break;
}
m_Pushing = false;
Map map = m_Map;
if ( map != null )
{
Sector oldSector = map.GetSector( oldX, oldY );
Sector newSector = map.GetSector( x, y );
ArrayList list;
if ( oldSector != newSector )
{
list = oldSector.Mobiles;
for ( int i = 0; i < list.Count; ++i )
{
Mobile m = (Mobile)list[i];
if ( m != this && m.X == oldX && m.Y == oldY && (m.Z + 15) > oldZ && (oldZ + 15) > m.Z && !m.OnMoveOff( this ) )
return false;
}
list = oldSector.Items;
for ( int i = 0; i < list.Count; ++i )
{
Item item = (Item)list[i];
if ( item.AtWorldPoint( oldX, oldY ) && (item.Z == oldZ || ((item.Z + item.ItemData.Height) > oldZ && (oldZ + 15) > item.Z)) && !item.OnMoveOff( this ) )
return false;
}
list = newSector.Mobiles;
for ( int i = 0; i < list.Count; ++i )
{
Mobile m = (Mobile)list[i];
if ( m.X == x && m.Y == y && (m.Z + 15) > newZ && (newZ + 15) > m.Z && !m.OnMoveOver( this ) )
return false;
}
list = newSector.Items;
for ( int i = 0; i < list.Count; ++i )
{
Item item = (Item)list[i];
if ( item.AtWorldPoint( x, y ) && (item.Z == newZ || ((item.Z + item.ItemData.Height) > newZ && (newZ + 15) > item.Z)) && !item.OnMoveOver( this ) )
return false;
}
}
else
{
list = oldSector.Mobiles;
for ( int i = 0; i < list.Count; ++i )
{
Mobile m = (Mobile)list[i];
if ( m != this && m.X == oldX && m.Y == oldY && (m.Z + 15) > oldZ && (oldZ + 15) > m.Z && !m.OnMoveOff( this ) )
return false;
else if ( m.X == x && m.Y == y && (m.Z + 15) > newZ && (newZ + 15) > m.Z && !m.OnMoveOver( this ) )
return false;
}
list = oldSector.Items;
for ( int i = 0; i < list.Count; ++i )
{
Item item = (Item)list[i];
if ( item.AtWorldPoint( oldX, oldY ) && (item.Z == oldZ || ((item.Z + item.ItemData.Height) > oldZ && (oldZ + 15) > item.Z)) && !item.OnMoveOff( this ) )
return false;
else if ( item.AtWorldPoint( x, y ) && (item.Z == newZ || ((item.Z + item.ItemData.Height) > newZ && (newZ + 15) > item.Z)) && !item.OnMoveOver( this ) )
return false;
}
}
Region region = Region.Find( new Point3D( x, y, newZ ), m_Map );
if ( region != null && !region.OnMoveInto( this, d, new Point3D( x, y, newZ ), oldLocation ) )
return false;
}
else
{
return false;
}
if ( !InternalOnMove( d ) )
return false;
if ( m_FwdEnabled && m_NetState != null && m_AccessLevel < m_FwdAccessOverride && (!m_FwdUOTDOverride || (m_NetState.Version != null && m_NetState.Version.Type != ClientType.UOTD)) )
{
if ( m_MoveRecords == null )
m_MoveRecords = new Queue( 6 );
while ( m_MoveRecords.Count > 0 )
{
MovementRecord r = (MovementRecord)m_MoveRecords.Peek();
if ( r.Expired() )
m_MoveRecords.Dequeue();
else
break;
}
if ( m_MoveRecords.Count >= m_FwdMaxSteps )
{
FastWalkEventArgs fw = new FastWalkEventArgs( m_NetState );
EventSink.InvokeFastWalk( fw );
if ( fw.Blocked )
return false;
}
TimeSpan delay;
if ( Mounted )
delay = (d & Direction.Running) != 0 ? m_RunMount : m_WalkMount;
else
delay = (d & Direction.Running) != 0 ? m_RunFoot : m_WalkFoot;
DateTime end;
if ( m_MoveRecords.Count > 0 )
end = m_EndQueue + delay;
else
end = DateTime.Now + delay;
m_MoveRecords.Enqueue( MovementRecord.NewInstance( end ) );
m_EndQueue = end;
}
m_LastMoveTime = DateTime.Now;
newLocation = new Point3D( x, y, newZ );
}
else
{
return false;
}
DisruptiveAction();
}
if ( m_NetState != null )
m_NetState.Send( MovementAck.Instantiate( m_NetState.Sequence, this ) );//new MovementAck( m_NetState.Sequence, this ) );
SetLocation( newLocation, false );
SetDirection( d );
if ( m_Map != null )
{
MobileMoving[] cache = m_MovingPacketCache;
for ( int i = 0; i < cache.Length; ++i )
cache[i] = null;
IPooledEnumerable eable = m_Map.GetObjectsInRange( m_Location, Core.GlobalMaxUpdateRange );
foreach ( object o in eable )
{
if ( o == this )
continue;
if ( o is Mobile )
{
m_MoveList.Add( o );
}
else if ( o is Item )
{
Item item = (Item)o;
if ( item.HandlesOnMovement )
m_MoveList.Add( item );
}
}
eable.Free();
for ( int i = 0; i < m_MoveList.Count; ++i )
{
object o = m_MoveList[i];
if ( o is Mobile )
{
Mobile m = (Mobile)m_MoveList[i];
NetState ns = m.NetState;
if ( ns != null && Utility.InUpdateRange( m_Location, m.m_Location ) && m.CanSee( this ) )
{
int noto = Notoriety.Compute( m, this );
MobileMoving p = cache[noto];
/// NECROPOLIS: removed cache conditional to correct bug with hallucination code - TM, 08-19-05
//if ( p == null ) //** ORIGINAL CORE **//
// p = cache[noto] = new MobileMoving( m, noto ); //** ORIGINAL CORE **//
p = cache[noto] = new MobileMoving( this, noto, m );
ns.Send( p );
}
m.OnMovement( this, oldLocation );
}
else if ( o is Item )
{
((Item)o).OnMovement( this, oldLocation );
}
}
if ( m_MoveList.Count > 0 )
m_MoveList.Clear();
}
return true;
}
Code:
public virtual void ProcessDelta()
{
Mobile m = this;
MobileDelta delta;
MobileDelta attrs;
delta = m.m_DeltaFlags;
if ( delta == MobileDelta.None )
return;
attrs = delta & MobileDelta.Attributes;
m.m_DeltaFlags = MobileDelta.None;
m.m_InDeltaQueue = false;
bool sendHits = false, sendStam = false, sendMana = false, sendAll = false, sendAny = false;
bool sendIncoming = false, sendNonlocalIncoming = false;
bool sendUpdate = false, sendRemove = false;
bool sendPublicStats = false, sendPrivateStats = false;
bool sendMoving = false, sendNonlocalMoving = false;
bool sendOPLUpdate = Core.AOS && (delta & MobileDelta.Properties) != 0;
if ( attrs != MobileDelta.None )
{
sendAny = true;
if ( attrs == MobileDelta.Attributes )
{
sendAll = true;
}
else
{
sendHits = ( (attrs & MobileDelta.Hits) != 0 );
sendStam = ( (attrs & MobileDelta.Stam) != 0 );
sendMana = ( (attrs & MobileDelta.Mana) != 0 );
}
}
if ( (delta & MobileDelta.GhostUpdate) != 0 )
{
sendNonlocalIncoming = true;
}
if ( (delta & MobileDelta.Hue) != 0 )
{
sendNonlocalIncoming = true;
sendUpdate = true;
sendRemove = true;
}
if ( (delta & MobileDelta.Direction) != 0 )
{
sendNonlocalMoving = true;
sendUpdate = true;
}
if ( (delta & MobileDelta.Body) != 0 )
{
sendUpdate = true;
sendIncoming = true;
}
/*if ( (delta & MobileDelta.Hue) != 0 )
{
sendNonlocalIncoming = true;
sendUpdate = true;
}
else if ( (delta & (MobileDelta.Direction | MobileDelta.Body)) != 0 )
{
sendNonlocalMoving = true;
sendUpdate = true;
}
else*/ if ( (delta & (MobileDelta.Flags | MobileDelta.Noto)) != 0 )
{
sendMoving = true;
}
if ( (delta & MobileDelta.Name) != 0 )
{
sendAll = false;
sendHits = false;
sendAny = sendStam || sendMana;
sendPublicStats = true;
}
if ( (delta & (MobileDelta.WeaponDamage | MobileDelta.Resistances | MobileDelta.Stat | MobileDelta.Weight | MobileDelta.Gold | MobileDelta.Armor | MobileDelta.StatCap | MobileDelta.Followers | MobileDelta.TithingPoints)) != 0 )
{
sendPrivateStats = true;
}
MobileMoving[] cache = m_MovingPacketCache;
if ( sendMoving || sendNonlocalMoving )
{
for ( int i = 0; i < cache.Length; ++i )
cache[i] = null;
}
NetState ourState = m.m_NetState;
if ( ourState != null )
{
if ( sendUpdate )
{
ourState.Sequence = 0;
ourState.Send( new MobileUpdate( m ) );
ClearFastwalkStack();
}
if ( sendIncoming )
ourState.Send( new MobileIncoming( m, m ) );
if ( sendMoving )
{
int noto = Notoriety.Compute( m, m );
ourState.Send( cache[noto] = new MobileMoving( m, noto ) );
}
if ( sendPublicStats || sendPrivateStats )
{
ourState.Send( new MobileStatusExtended( m ) );
}
else if ( sendAll )
{
ourState.Send( new MobileAttributes( m ) );
}
else if ( sendAny )
{
if ( sendHits )
ourState.Send( new MobileHits( m ) );
if ( sendStam )
ourState.Send( new MobileStam( m ) );
if ( sendMana )
ourState.Send( new MobileMana( m ) );
}
if ( sendStam || sendMana )
{
IParty ip = m_Party as IParty;
if ( ip != null && sendStam )
ip.OnStamChanged( this );
if ( ip != null && sendMana )
ip.OnManaChanged( this );
}
if ( sendOPLUpdate )
ourState.Send( OPLPacket );
}
sendMoving = sendMoving || sendNonlocalMoving;
sendIncoming = sendIncoming || sendNonlocalIncoming;
sendHits = sendHits || sendAll;
if ( m.m_Map != null && (sendRemove || sendIncoming || sendPublicStats || sendHits || sendMoving || sendOPLUpdate) )
{
Mobile beholder;
IPooledEnumerable eable = m.Map.GetClientsInRange( m.m_Location );
Packet hitsPacket = null;
Packet statPacketTrue = null, statPacketFalse = null;
Packet deadPacket = null;
foreach ( NetState state in eable )
{
beholder = state.Mobile;
if ( beholder != m && beholder.CanSee( m ) )
{
if ( sendRemove )
state.Send( m.RemovePacket );
if ( sendIncoming )
{
state.Send( new MobileIncoming( beholder, m ) );
if ( m.IsDeadBondedPet )
{
if ( deadPacket == null )
deadPacket = new BondedStatus( 0, m.m_Serial, 1 );
state.Send( deadPacket );
}
}
if ( sendMoving )
{
int noto = Notoriety.Compute( beholder, m );
MobileMoving p = cache[noto];
/// NECROPOLIS: removed cache conditional to correct bug with hallucination code - TM, 08-19-05
//if ( p == null ) //** ORIGINAL CORE **//
// cache[noto] = p = new MobileMoving( m, noto ); //** ORIGINAL CORE **//
cache[noto] = p = new MobileMoving( m, noto, beholder );
state.Send( p );
}
if ( sendPublicStats )
{
if ( m.CanBeRenamedBy( beholder ) )
{
if ( statPacketTrue == null )
statPacketTrue = new MobileStatusCompact( true, m );
state.Send( statPacketTrue );
}
else
{
if ( statPacketFalse == null )
statPacketFalse = new MobileStatusCompact( false, m );
state.Send( statPacketFalse );
}
}
else if ( sendHits )
{
if ( hitsPacket == null )
hitsPacket = new MobileHitsN( m );
state.Send( hitsPacket );
}
if ( sendOPLUpdate )
state.Send( OPLPacket );
}
}
eable.Free();
}
}
Code:
/// NECROPOLIS: ==============================================================
/// Begin modifications for Necropolis Sanity system
/// ==========================================================================
private short m_SeeBodyAs = 0;
[CommandProperty( AccessLevel.GameMaster )]
public short SeeBodyAs
{
get{ return m_SeeBodyAs; }
set{ m_SeeBodyAs = value; }
}
/// ==========================================================================
MobileIncoming() class Code:
public sealed class MobileIncoming : Packet
{
private static int[] m_DupedLayers = new int[256];
private static int m_Version;
public Mobile m_Beheld;
public MobileIncoming( Mobile beholder, Mobile beheld ) : base( 0x78 )
{
m_Beheld = beheld;
++m_Version;
ArrayList eq = beheld.Items;
int count = eq.Count;
this.EnsureCapacity( 23 + (count * 9) );
int hue = beheld.Hue;
if ( beheld.SolidHueOverride >= 0 )
hue = beheld.SolidHueOverride;
m_Stream.Write( (int) beheld.Serial );
/// NECROPOLIS: Added conditional for Hallucination support - TM, 08-19-05
if ( beholder.SeeBodyAs == 0 || beholder == beheld )
m_Stream.Write( (short) beheld.Body );
else
m_Stream.Write( (short) beholder.SeeBodyAs );
/// NECROPOLIS ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
m_Stream.Write( (short) beheld.X );
m_Stream.Write( (short) beheld.Y );
m_Stream.Write( (sbyte) beheld.Z );
m_Stream.Write( (byte) beheld.Direction );
m_Stream.Write( (short) hue );
m_Stream.Write( (byte) beheld.GetPacketFlags() );
m_Stream.Write( (byte) Notoriety.Compute( beholder, beheld ) );
for ( int i = 0; i < count; ++i )
{
Item item = (Item)eq[i];
byte layer = (byte) item.Layer;
if ( !item.Deleted && beholder.CanSee( item ) && m_DupedLayers[layer] != m_Version )
{
m_DupedLayers[layer] = m_Version;
hue = item.Hue;
if ( beheld.SolidHueOverride >= 0 )
hue = beheld.SolidHueOverride;
int itemID = item.ItemID & 0x3FFF;
bool writeHue = ( hue != 0 );
if ( writeHue )
itemID |= 0x8000;
m_Stream.Write( (int) item.Serial );
m_Stream.Write( (short) itemID );
m_Stream.Write( (byte) layer );
if ( writeHue )
m_Stream.Write( (short) hue );
}
}
m_Stream.Write( (int) 0 ); // terminate
}
}
Code:
public sealed class MobileMoving : Packet
{
public MobileMoving( Mobile m, int noto/*Mobile beholder, Mobile beheld*/ ) : base( 0x77, 17 )
{
Point3D loc = m.Location;
int hue = m.Hue;
if ( m.SolidHueOverride >= 0 )
hue = m.SolidHueOverride;
m_Stream.Write( (int) m.Serial );
m_Stream.Write( (short) m.Body );
m_Stream.Write( (short) loc.m_X );
m_Stream.Write( (short) loc.m_Y );
m_Stream.Write( (sbyte) loc.m_Z );
m_Stream.Write( (byte) m.Direction );
m_Stream.Write( (short) hue );
m_Stream.Write( (byte) m.GetPacketFlags() );
m_Stream.Write( (byte) noto );//Notoriety.Compute( beholder, beheld ) );
}
/// NECROPOLIS: Added overload for Hallucination support - TM, 08-19-05
public MobileMoving( Mobile m, int noto, Mobile beholder ) : base( 0x77, 17 )
{
Point3D loc = m.Location;
int hue = m.Hue;
if ( m.SolidHueOverride >= 0 )
hue = m.SolidHueOverride;
m_Stream.Write( (int) m.Serial );
if ( beholder.SeeBodyAs == 0 || m == beholder )
m_Stream.Write( (short) m.Body );
else
m_Stream.Write( (short) beholder.SeeBodyAs );
m_Stream.Write( (short) loc.m_X );
m_Stream.Write( (short) loc.m_Y );
m_Stream.Write( (sbyte) loc.m_Z );
m_Stream.Write( (byte) m.Direction );
m_Stream.Write( (short) hue );
m_Stream.Write( (byte) m.GetPacketFlags() );
m_Stream.Write( (byte) noto );
}
}
The SeeBodyAs will be managed script side from the sanity system to keep all the sanity rules out of the core. Also, I had to mod both Move() and ProcessDelta() for this to work - modding ProcessDelta() only resulted in bizaar flickering effects where the mobile would occasionally toggle back to their normal state. -TM FYI: ALPHA VERSION / PROOF OF CONCEPT This core modification is alpha only as proof of concept. Install into the core at your own risk. Once I have finished testing, and am confident the code is pretty solid I will release it for public consumption with support and detailed installation instructions. |
|
|
|
|
|
|
#15 (permalink) | |
|
Quote:
Now all is left is to find out what the reprecussions of commenting out those IFs are and I'll be set to roll forward. Gonna wrap up the remainder of the design for the sanity system and begin implementation. Thanks again for all the help everyone, -TM |
||
|
|
|
|
|
#16 (permalink) |
|
Join Date: Jan 2006
Posts: 1
|
You can mantain the caching system for non-Hallucinated mobile.
when the code send the Mobilemoving packet you can check if the beholding mobile are hallucinated or not. Then you can sent the cached packet (if the mob aren't hallucinated), or a new one for the hallucination. |
|
|
|
![]() |
| Bookmarks |
| Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
| Thread Tools | |
| Display Modes | |
|
|