Open uox3.cpp and find the "void checkNPC( CChar& mChar, bool checkAI, bool doRestock )" function. In this function add:
Code: Select all
if( mChar.IsCriminal() && mChar.GetTimer( tCHAR_CRIMFLAG ) && ( mChar.GetTimer( tCHAR_CRIMFLAG ) <= cwmWorldState->GetUICurrentTime() || cwmWorldState->GetOverflow() ) )
{
mChar.SetTimer( tCHAR_CRIMFLAG, 0 );
setcharflag( &mChar );
}
if( mChar.GetTimer( tCHAR_MURDERRATE ) && ( mChar.GetTimer( tCHAR_MURDERRATE ) <= cwmWorldState->GetUICurrentTime() || cwmWorldState->GetOverflow() ) )
{
mChar.SetTimer( tCHAR_MURDERRATE, 0 );
if( mChar.GetKills() )
mChar.SetKills( static_cast<SI16>( mChar.GetKills() - 1 ) );
if( mChar.GetKills() )
mChar.SetTimer( tCHAR_MURDERRATE, cwmWorldState->ServerData()->BuildSystemTimeValue( tSERVER_MURDERDECAY ) );
else
mChar.SetTimer( tCHAR_MURDERRATE, 0 );
if( mChar.GetKills() == cwmWorldState->ServerData()->RepMaxKills() )
setcharflag( &mChar );
}
Then find the "void setcharflag( CChar *c )" function, and there the following:
Code: Select all
if( !c->IsNpc() )
{
if( c->GetKills() > cwmWorldState->ServerData()->RepMaxKills() )
c->SetFlagRed();
else if( c->GetTimer( tCHAR_CRIMFLAG ) != 0 )
c->SetFlagGray();
else
c->SetFlagBlue();
}
else
{
switch( c->GetNPCAiType() )
{
case aiEVIL: // Evil
case aiHEALER_E: // Evil healer
case aiCHAOTIC: // BS/EV
c->SetFlagRed();
break;
case aiHEALER_G: // Good Healer
case aiPLAYERVENDOR:// Player Vendor
case aiGUARD: // Guard
case aiBANKER: // Banker
case aiFIGHTER: // Fighter
c->SetFlagBlue();
break;
default:
if( c->GetID() == 0x0190 || c->GetID() == 0x0191 )
{
c->SetFlagBlue();
break;
}
else if( cwmWorldState->ServerData()->CombatAnimalsGuarded() && cwmWorldState->creatures[c->GetID()].IsAnimal() )
{
if( c->GetRegion()->IsGuarded() ) // in a guarded region, with guarded animals, animals == blue
c->SetFlagBlue();
else
c->SetFlagGray();
}
else // if it's not a human form, and animal's aren't guarded, then they're gray
c->SetFlagGray();
if( ValidateObject( c->GetOwnerObj() ) && c->IsTamed() )
{
CChar *i = c->GetOwnerObj();
if( ValidateObject( i ) )
c->SetFlag( i->GetFlag() );
else
c->SetFlagBlue();
if( c->IsInnocent() && !cwmWorldState->ServerData()->CombatAnimalsGuarded() )
c->SetFlagBlue();
}
break;
}
}
Code: Select all
if( !c->IsNpc() )
{
if( c->GetKills() > cwmWorldState->ServerData()->RepMaxKills() )
c->SetFlagRed();
else if( c->GetTimer( tCHAR_CRIMFLAG ) != 0 )
c->SetFlagGray();
else if( c->IsNeutral() )
return;
else
c->SetFlagBlue();
}
else
{
if( c->GetKills() > cwmWorldState->ServerData()->RepMaxKills() )
c->SetFlagRed();
else if( c->GetTimer( tCHAR_CRIMFLAG ) != 0 )
c->SetFlagGray();
else {
switch( c->GetNPCAiType() )
{
case aiEVIL: // Evil
case aiHEALER_E: // Evil healer
case aiCHAOTIC: // BS/EV
if( !c->IsNeutral() )
c->SetFlagRed();
break;
case aiHEALER_G: // Good Healer
case aiPLAYERVENDOR:// Player Vendor
case aiGUARD: // Guard
case aiBANKER: // Banker
case aiFIGHTER: // Fighter
if( !c->IsNeutral() )
c->SetFlagBlue();
default:
if( c->GetID() == 0x0190 || c->GetID() == 0x0191 )
{
if( !c->IsNeutral() )
c->SetFlagBlue();
break;
}
else if( cwmWorldState->ServerData()->CombatAnimalsGuarded() && cwmWorldState->creatures[c->GetID()].IsAnimal() )
{
if( c->GetRegion()->IsGuarded() ) // in a guarded region, with guarded animals, animals == blue
c->SetFlagBlue();
else
c->SetFlagNeutral();
}
else // if it's not a human form, and animal's aren't guarded, then they're gray
c->SetFlagNeutral();
if( ValidateObject( c->GetOwnerObj() ) && c->IsTamed() )
{
CChar *i = c->GetOwnerObj();
if( ValidateObject( i ) )
c->SetFlag( i->GetFlag() );
else
c->SetFlagBlue();
if( c->IsInnocent() && !cwmWorldState->ServerData()->CombatAnimalsGuarded() )
c->SetFlagBlue();
}
break;
}
}
}
It's still not complete, for example calling a guard near such an NPC does nothing. I'm also not shure if it may break some stuff as I just came up with it and haven't tested it much. But at least it's a start. Any improvements from the devs are welcome
Edit:
Improved the above code to support npc murderers, and also changed the setcharflag function a bit.
To let guards and fighters work on npc criminals or murders make the following changes:
finf the "void callGuards( CChar *mChar )" function in uox3.cpp and there this code:
Code: Select all
if( !tempChar->IsDead() && ( tempChar->IsCriminal() || tempChar->IsMurderer() ) )
{
SI16 aiType = tempChar->GetNPCAiType();
if( !tempChar->IsNpc() || ( aiType == aiEVIL || aiType == aiCHAOTIC || aiType == aiHEALER_E ) )
{
if( charInRange( tempChar, mChar ) )
{
Combat->SpawnGuard( mChar, tempChar, tempChar->GetX(), tempChar->GetY(), tempChar->GetZ() );
break;
}
}
}
Code: Select all
if( !tempChar->IsDead() && ( tempChar->IsCriminal() || tempChar->IsMurderer() ) )
{
if( charInRange( tempChar, mChar ) )
{
Combat->SpawnGuard( mChar, tempChar, tempChar->GetX(), tempChar->GetY(), tempChar->GetZ() );
break;
}
}
Code: Select all
void HandleGuardAI( CChar& mChar )
{
if( !mChar.IsAtWar() )
{
REGIONLIST nearbyRegions = MapRegion->PopulateList( &mChar );
for( REGIONLIST_CITERATOR rIter = nearbyRegions.begin(); rIter != nearbyRegions.end(); ++rIter )
{
SubRegion *MapArea = (*rIter);
if( MapArea == NULL ) // no valid region
continue;
CDataList< CChar * > *regChars = MapArea->GetCharList();
regChars->Push();
for( CChar *tempChar = regChars->First(); !regChars->Finished(); tempChar = regChars->Next() )
{
if( isValidAttackTarget( mChar, tempChar ) )
{
if( !tempChar->IsDead() && ( tempChar->IsCriminal() || tempChar->IsMurderer() ) )
{
Combat->AttackTarget( &mChar, tempChar );
mChar.talkAll( 313, true );
regChars->Pop();
return;
}
}
}
regChars->Pop();
}
}
}
Code: Select all
void HandleFighterAI( CChar& mChar )
{
if( !mChar.IsAtWar() )
{
REGIONLIST nearbyRegions = MapRegion->PopulateList( &mChar );
for( REGIONLIST_CITERATOR rIter = nearbyRegions.begin(); rIter != nearbyRegions.end(); ++rIter )
{
SubRegion *MapArea = (*rIter);
if( MapArea == NULL ) // no valid region
continue;
CDataList< CChar * > *regChars = MapArea->GetCharList();
regChars->Push();
for( CChar *tempChar = regChars->First(); !regChars->Finished(); tempChar = regChars->Next() )
{
if( isValidAttackTarget( mChar, tempChar ) )
{
if( !tempChar->IsDead() && ( tempChar->IsCriminal() || tempChar->IsMurderer() ) )
{
Combat->AttackTarget( &mChar, tempChar );
regChars->Pop();
return;
}
}
}
regChars->Pop();
}
}
}
Edit: Changes to support the neutral flag:
open cChar.h and find:
Code: Select all
void SetFlagRed( void );
void SetFlagBlue( void );
void SetFlagGray( void );
Code: Select all
void SetFlagNeutral( void );Code: Select all
bool IsMurderer( void ) const;
bool IsCriminal( void ) const;
bool IsInnocent( void ) const;
Code: Select all
bool IsNeutral(void) const;Code: Select all
else
{
if( IsMurderer() ) // Murderer
rFlag = 6;
else if( IsCriminal() ) // Criminal
rFlag = 3;
}
toSend.SetRepFlag( rFlag );
Code: Select all
else
{
if( IsMurderer() ) // Murderer
rFlag = 6;
else if( IsCriminal() ) // Criminal
rFlag = 4;
else if( IsNeutral() ) // Neutral
rFlag = 3;
}
toSend.SetRepFlag( rFlag );
Code: Select all
bool CChar::IsInnocent( void ) const
{
return ( (GetFlag()&0x04) == 0x04 );
}
Code: Select all
//o---------------------------------------------------------------------------o
//| Function - bool IsNeutral( void ) const
//| Date - 18 July 2005
//| Programmer - Grimson
//o---------------------------------------------------------------------------o
//| Purpose - Returns true if the character is neutral
//o---------------------------------------------------------------------------o
bool CChar::IsNeutral( void ) const
{
return ( (GetFlag()&0x20) == 0x20 );
}
Code: Select all
void CChar::SetFlagGray( void )
{
flag |= 0x02;
flag &= 0x1B;
}
Code: Select all
//o---------------------------------------------------------------------------o
//| Function - void SetFlagNeutral( void )
//| Date - 18th July, 2005
//| Programmer - Grimson
//o---------------------------------------------------------------------------o
//| Purpose - Updates the character's flag to reflect neutrality
//o---------------------------------------------------------------------------o
void CChar::SetFlagNeutral( void )
{
flag |= 0x20;
flag &= 0x38;
}
Code: Select all
if( a->IsMurderer() )
return 6; // If a bad, show as red.
else if( a->IsInnocent() )
return 1; // If a good, show as blue.
else
return 3; // grey
Code: Select all
if( a->IsMurderer() )
return 6; // If a bad, show as red.
else if( a->IsInnocent() )
return 1; // If a good, show as blue.
else if( a->IsCriminal() )
return 4; // If a criminal show grey
else
return 3; // neutral grey
Code: Select all
else if( trg->IsCriminal() )
retVal = 0x03B2;//grey
Code: Select all
else if( trg->IsCriminal() || trg->IsNeutral() )
retVal = 0x03B2;//grey
And here now the code for the scripting implementation:
open UOXJSPropertyEnums.h and find:
Code: Select all
CCP_CRIMINAL,
CCP_MURDERER,
CCP_INNOCENT,
CCP_MURDERCOUNT,
Code: Select all
CCP_NEUTRAL,
Code: Select all
{ "criminal", CCP_CRIMINAL, JSPROP_ENUMANDPERM },
{ "murderer", CCP_MURDERER, JSPROP_ENUMPERMRO },
{ "innocent", CCP_INNOCENT, JSPROP_ENUMANDPERM },
{ "murdercount", CCP_MURDERCOUNT, JSPROP_ENUMANDPERM },
Code: Select all
{ "neutral", CCP_NEUTRAL, JSPROP_ENUMANDPERM },
Code: Select all
case CCP_CRIMINAL: *vp = BOOLEAN_TO_JSVAL( gPriv->IsCriminal() ); break;
case CCP_MURDERER: *vp = BOOLEAN_TO_JSVAL( gPriv->IsMurderer() ); break;
case CCP_INNOCENT: *vp = BOOLEAN_TO_JSVAL( gPriv->IsInnocent() ); break;
case CCP_MURDERCOUNT: *vp = INT_TO_JSVAL( gPriv->GetKills() ); break;
Code: Select all
case CCP_NEUTRAL: *vp = BOOLEAN_TO_JSVAL( gPriv->IsNeutral() ); break;
Code: Select all
case CCP_MURDERCOUNT:
gPriv->SetKills( (SI16)encaps.toInt() );
setcharflag( gPriv );
break;
Code: Select all
case CCP_NEUTRAL:
if( encaps.toBool() ) {
gPriv->SetTimer( tCHAR_CRIMFLAG, 0 );
gPriv->SetFlagNeutral();
}
else
{
gPriv->SetTimer( tCHAR_CRIMFLAG, 0 );
gPriv->SetFlagBlue();
setcharflag( gPriv );
}
break;