uox3/source/cGuild.cpp
Xoduz 82a3ef5386 08/08/2021 - Xuri (0.99.4w)
Added support for new Skills DFN tag:
	SKILLDELAY=# 	// Delay in seconds before another skill can be used after using this skill. Overrides global delay from UOX.INI
Updated skill cSkills::SkillUse() to use skill-specific skill delays if set for a given skill, or global delay from ini if not. Also added a check to see if skill delay timer has been modified by onSkill JS event before attempting to set a default timer
Updated skill delays to better match ~pub15 era:
	Reduced global SKILLDELAY setting in UOX.INI from 2 to 1 second
	Detecting Hidden skill now has a default skill delay of 10 seconds
	Herding skill now has a default skill delay of 10 seconds
	Hiding skill now has a default skill delay of 10 seconds, with shorter delays (global skill delay) for trying to hide while in combat or for successfully hiding
	Meditation skill now has a default skill delay of 10 seconds, with shorter delays (global skill delay) for failing due to hands being occupied or already being at max mana
	Peacemaking skill now has a default skill delay of 10 seconds for failed skill checks, and 5 seconds delay for successful ones
	Poisoning skill now has a default skill delay of 10 seconds
	Provocation skill now has a default skill delay of 10 seconds
	Remove Trap skill now has a default skill delay of 10 seconds
	Stealing skill now has a default skill delay of 10 seconds
	Stealth skill now has a default skill delay of 10 seconds
	Tracking skill now has a default skill delay of 10 seconds
	Veterinary skill now has a default skill delay of 10 seconds
Fixed an issue with global JS Timer object that would reference the wrong timerIDs
Extended global JS timer object to include timers from socket as well (marked with SOCK_ prefix):
	.SOCK_SKILLDELAY	// Delay before the next time player can use another skill
	.SOCK_OBJDELAY		// Delay before next time player can use another object
	.SOCK_SPIRITSPEAK 	// Timer that tracks remaining duration of player's Spirit Speak
	.SOCK_TRACKING		// Timer that tracks remaining duration for player's Tracking skill
	.SOCK_FISHING		// Timer that tracks remaining duration for player's Fishing skill
	.SOCK_MUTETIME 		// Timer that tracks remaining duration a player remains muted
	.SOCK_TRACKINGDISPLAY 	// Timer that tracks interval between each time tracking display is updated
Updated various JS scripts to use the new Timer.TIMERNAME with .GetTimer()/.SetTimer() JS Methods for Characters and Sockets
Updated Persecution ability for player ghosts to use the skill delay of the Spirit Speak skill, if set
Updated Persecution ability to base mana damage primarily on player's Spirit Speak skill rather than their Intelligence
In order to cut down on the amount of messages sent from server to players trying to spam-use objects/skills, UOX3 now only sends a maximum of one message for object use delay and one message for skill use delay while the delay timers for these are in effect. This resets on the next successful use of an object or skill. This is tracked via bools in cSocket class:
	bool objDelayMsgShown
	bool skillDelayMsgShown
Converted DELAY tag in spells.dfn to use seconds (with decimals) instead of tenths of a second, which was not precise enough. This controls the cast time of spells. What would previously say DELAY=10 (10/10ths of a second) now says DELAY=1.0 (1 second)
Added support for new Spells DFN tag to control delay until damage takes place after casting a spell, replacing UOX.INI setting COMBATEXPLODEDELAY, which is no longer used:
	DAMAGEDELAY=# 		// Delay in seconds (decimal) until a direct damage spell deals its damage
Added support for a new Spells DFN tag to control cast recovery time, during which additional spells cannot be cast:
	RECOVERYDELAY=# 	// Delay in seconds (decimal) until player can cast another spell
Added new setting in UOX.INI to control whether player spellcasting gets interrupted upon equipping/picking up items:
	ITEMSINTERRUPTCASTING=1 	// If enabled, spellcasting gets interrupted by equipping/picking up items. Defaults to enabled.
All direct damage spells by default have a 1.0s delay before damage (and VFX) is applied, except Explosion which has a 2.5s delay
All spells by default have a cast recovery duration of 1.0s; from the moment a spellcast is completed/moment targeting cursor appears, the player will be unable to cast any other spell for the duration of the cast recovery
Reagent checks and skill-check now take place AFTER the spellcast animation, not before!
Spell cast times now follow this formula, though values set per spell and can be modified: 0.25 + ( spellCircle * 0.25 )
Overhauled spell sound FX and VFX for for all spells
Players can no longer cast spells while holding items on the cursor
Fixed Magic Trap, Magic Untrap, Magic Lock and Magic Unlock not being usable on containers in one's own backpack
Fixed an issue that caused Magic Trap to deal between 50 to 100 damage to the player. New damage: 5 to 10, depending on Magery skill
Fixed an issue where Magic Untrap spell would completely remove traps from spawn containers instead of disable them
Fixed an issue where Telekinesis spell would not set off traps on containers properly
Added additional FX for Teleport spell played at player's original location before the teleport took place
Fixed a bug where creatures summoned with the Summon Creature spell were not dispellable
Fixed an issue where the Reveal spell would not reveal players hidden using the Hiding skill
Dispel and Mass Dispel spells are no longer guaranteed to succeed at dispelling summoned creatures. Instead, the chance to dispel is based on the following simple formula, with dispelChance capped at 95% to always leave some chance for a creature to resist a dispel:
	dispelChance = ( 50 - ( targetResistSkill - casterMagerySkill )) / 1.5
		The targetResistSkill is based on the highest value of the summoned creature's spell resistance skill and the spell resistance skill of its summoner
Fixed an issue where the Create Food spell attempted to create an invalid item
Fixed issue where code that checked for valid drop locations for items didn't allow negative z values (Dragon Slayer)
Fixed issue where players could drop items on blocking map tiles like water or mountains (Dragon Slayer)
Fixed issue where some JS functions like CheckStaticFlag, CheckDynamicFlag, DoesStaticBlock, DoesDynamicBlock and DoesMapBlock would not work correctly when passed negative Z values
Fixed issue where context menu were listing skills to train from NPCs based on effective skill rather than base skill
Fixed issue where NPCs would offer skills for training even if those skills were not above the minimum 60 skillpoints
Updated clilocID used for Gump JS Method AddToolTip - as well as for some item/character tooltip data - from 1050045 to 1042971 for improved client compatibility
Human/Elf/Gargoyle NPCs with spellcasting capabilities will now play a casting animation and briefly stop moving when they cast spells
Updated NPC spellcasting code to help NPCs make a bit better choices of what spells to cast during combat. Now they take their own health percentage into account, and cast more offensive spells when at near full health vs more defensive spells as their health drops
Fixed an issue where Hirelings wouldn't always immediately start following their new owners
Fixed a bug where the Earthquake spell could incorrectly add NPC characters marked for deletion to the refresh queue
Updated skills and stats of all implemented human NPCs (including vendors) to better match the state of those NPCs around the time of Pub15
Fixed SPATTACK values for a couple of NPCs that were still using values based on spell bitmask instead of spell circle value
Updated stats of Jukan and Meer NPCs (dfndata/npc/lbrraces.dfn) to match stats from official LBR guide
Added support for an optional third parameter for Character/Socket JS Method .CustomTarget() to allow highlighting targeting cursors as neutral (0, default aura), harmful (1, red aura), helpful (2, blue aura). A value of 3 will cancel the currently active targeting cursor. New syntax:
	myChar/mySock.CustomTarget( targetID, txtToSay, cursorType ) 	// supported cursorTypes: 0 = neutral, 1 = harmful, 2 = helpful, 3 = cancel current target cursor
Various target cursors triggered by code (like hard-coded spells, some pet commands) also make use of these cursorTypes
2021-08-08 01:57:25 +08:00

1876 lines
66 KiB
C++

#include "uox3.h"
#include "cGuild.h"
#include "speech.h"
#include "ssection.h"
#include "scriptc.h"
#include "classes.h"
#include "CPacketSend.h"
#include "Dictionary.h"
#include "CJSEngine.h"
#include "StringUtility.hpp"
#ifndef va_start
#include <cstdarg>
#endif
CGuildCollection *GuildSys;
#define DEFAULTCHARTER "UOX3 Guildstone"
#define DEFAULTWEBPAGE "http://www.uox3.org/"
CGuild::CGuild() : name( "" ), gType( GT_STANDARD ), charter( "" ), webpage( "" ), stone( INVALIDSERIAL ), master( INVALIDSERIAL )
{
abbreviation[0] = 0;
recruits.resize( 0 );
members.resize( 0 );
recruitPtr = recruits.end();
memberPtr = members.end();
warPtr = relationList.end();
allyPtr = relationList.end();
}
CGuild::~CGuild()
{
JSEngine->ReleaseObject( IUE_GUILD, this );
recruits.clear();
members.clear();
relationList.clear();
}
//o-----------------------------------------------------------------------------------------------o
//| Function - GUILDID FirstWar( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Moves to start of the relation list and returns the next
//| relation which is at war
//o-----------------------------------------------------------------------------------------------o
GUILDID CGuild::FirstWar( void )
{
warPtr = relationList.begin();
return NextWar();
}
//o-----------------------------------------------------------------------------------------------o
//| Function - GUILDID NextWar( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Moves through relation list, returning guild ID of next
//| guild at war, or -1 if no war
//o-----------------------------------------------------------------------------------------------o
GUILDID CGuild::NextWar( void )
{
while( warPtr != relationList.end() )
{
if( warPtr->second == GR_WAR )
return warPtr->first;
++warPtr;
}
return -1;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool FinishedWar( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns true if at end of war list, or false if not
//| Must iterate through war list if not at end of relation list
//| Moves back one if it does find something it's at war with
//| to ensure pointer integrity
//o-----------------------------------------------------------------------------------------------o
bool CGuild::FinishedWar( void )
{
if( warPtr == relationList.end() )
return true;
if( NextWar() == -1 )
return true;
else if( warPtr != relationList.begin() ) // we move back if we found it, so NextWar will return a valid warring guild
--warPtr;
return false;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - GUILDID FirstAlly( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Moves to start of the relation list and returns the next
//| relation which is at ally
//o-----------------------------------------------------------------------------------------------o
GUILDID CGuild::FirstAlly( void )
{
allyPtr = relationList.begin();
return NextAlly();
}
//o-----------------------------------------------------------------------------------------------o
//| Function - GUILDID NextAlly( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Moves through relation list, returning guild ID of next
//| guild as ally, or -1 if no ally
//o-----------------------------------------------------------------------------------------------o
GUILDID CGuild::NextAlly( void )
{
while( allyPtr != relationList.end() )
{
if( allyPtr->second == GR_ALLY )
return allyPtr->first;
++allyPtr;
}
return -1;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool FinishedAlly( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns true if at end of ally list, or false if not
//| Must iterate through ally list if not at end of relation list
//| Moves back one if it does find something it's an ally with
//| to ensure pointer integrity
//o-----------------------------------------------------------------------------------------------o
bool CGuild::FinishedAlly( void )
{
if( allyPtr == relationList.end() )
return true;
if( NextAlly() == -1 )
return true;
else if( allyPtr != relationList.begin() ) // we move back if we found it, so NextWar will return a valid warring guild
--allyPtr;
return false;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - const std::string Name( void ) const
//| void Name( std::string txt )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Gets/Sets the name of the guild.
//| Setting also updates name of guildstone, if it exists
//o-----------------------------------------------------------------------------------------------o
const std::string CGuild::Name( void ) const
{
return name;
}
void CGuild::Name( std::string txt )
{
name = txt;
if( Stone() != INVALIDSERIAL ) // we have a guildstone
{
CItem *gStone = calcItemObjFromSer( Stone() );
if( ValidateObject( gStone ) )
gStone->SetName( txt );
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - const char *Abbreviation( void ) const
//| void Abbreviation( const char *txt )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Gets/Sets the abbreviation of the guild
//o-----------------------------------------------------------------------------------------------o
const char *CGuild::Abbreviation( void ) const
{
return abbreviation;
}
void CGuild::Abbreviation( const char *txt )
{
if( strlen( txt ) > 3 )
{
strncpy( abbreviation, txt, 3 );
abbreviation[3] = 0;
}
else
strcpy( abbreviation, txt );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - GuildType Type( void ) const
//| void Type( GuildType nType )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Gets/Sets the guild's type
//| GT_STANDARD = 0,
//| GT_ORDER,
//| GT_CHAOS,
//| GT_UNKNOWN,
//| GT_COUNT
//o-----------------------------------------------------------------------------------------------o
GuildType CGuild::Type( void ) const
{
return gType;
}
void CGuild::Type( GuildType nType )
{
gType = nType;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - const std::string Charter( void ) const
//| void Charter( const std::string &txt )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Gets/Sets the charter of the guild
//o-----------------------------------------------------------------------------------------------o
const std::string CGuild::Charter( void ) const
{
return charter;
}
void CGuild::Charter( const std::string &txt )
{
charter = txt;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - const std::string Webpage( void ) const
//| void Webpage( const std::string &txt )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns the webpage of the guild
//o-----------------------------------------------------------------------------------------------o
const std::string CGuild::Webpage( void ) const
{
return webpage;
}
void CGuild::Webpage( const std::string &txt )
{
webpage = txt;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - SERIAL Stone( void ) const
//| void Stone( SERIAL newStone )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Gets/Sets the serial of the guild stone
//o-----------------------------------------------------------------------------------------------o
SERIAL CGuild::Stone( void ) const
{
return stone;
}
void CGuild::Stone( SERIAL newStone )
{
stone = newStone;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - SERIAL Master( void ) const
//| void Master( SERIAL newMaster )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Gets/Sets the serial of the guild master (if any)
//o-----------------------------------------------------------------------------------------------o
SERIAL CGuild::Master( void ) const
{
return master;
}
void CGuild::Master( SERIAL newMaster )
{
master = newMaster;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - SERIAL FirstRecruit( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns the serial of the first recruit in the recruit list
//| If no recruits, returns INVALIDSERIAL
//o-----------------------------------------------------------------------------------------------o
SERIAL CGuild::FirstRecruit( void )
{
SERIAL retVal = INVALIDSERIAL;
recruitPtr = recruits.begin();
if( !FinishedRecruits() )
retVal = (*recruitPtr);
return retVal;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - SERIAL NextRecruit( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns the serial of the next recruit in the recruit list
//| If there are no more, it returns INVALIDSERIAL
//o-----------------------------------------------------------------------------------------------o
SERIAL CGuild::NextRecruit( void )
{
SERIAL retVal = INVALIDSERIAL;
if( !FinishedRecruits() )
{
++recruitPtr;
if( !FinishedRecruits() )
retVal = (*recruitPtr);
}
return retVal;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool FinishedRecruits( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns true if there are no more recruits left
//o-----------------------------------------------------------------------------------------------o
bool CGuild::FinishedRecruits( void )
{
return ( recruitPtr == recruits.end() );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - SERIAL RecruitNumber( size_t rNum ) const
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns the serial of the recruit in slot rNum
//| If rNum is invalid, it returns INVALIDSERIAL
//o-----------------------------------------------------------------------------------------------o
SERIAL CGuild::RecruitNumber( size_t rNum ) const
{
if( rNum >= recruits.size() )
return INVALIDSERIAL;
else
return recruits[rNum];
}
//o-----------------------------------------------------------------------------------------------o
//| Function - SERIAL MemberNumber( size_t rNum ) const
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns the serial of the member in slot rNum
//| If rNum is invalid, it returns INVALIDSERIAL
//o-----------------------------------------------------------------------------------------------o
SERIAL CGuild::MemberNumber( size_t rNum ) const
{
if( rNum >= members.size() )
return INVALIDSERIAL;
else
return members[rNum];
}
//o-----------------------------------------------------------------------------------------------o
//| Function - SERIAL FirstMember( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns the serial of the first member of the guild
//| If no members, returns INVALIDSERIAL
//o-----------------------------------------------------------------------------------------------o
SERIAL CGuild::FirstMember( void )
{
SERIAL retVal = INVALIDSERIAL;
memberPtr = members.begin();
if( !FinishedMember() )
retVal = (*memberPtr);
return retVal;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - SERIAL NextMember( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns the serial of the next member of the guild, if any
//| If none, it returns INVALIDSERIAL
//o-----------------------------------------------------------------------------------------------o
SERIAL CGuild::NextMember( void )
{
SERIAL retVal = INVALIDSERIAL;
if( !FinishedMember() )
{
++memberPtr; // post ++ forces a copy constructor
if( !FinishedMember() )
retVal = (*memberPtr);
}
return retVal;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool FinishedMember( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Returns true if there are no more members left
//o-----------------------------------------------------------------------------------------------o
bool CGuild::FinishedMember( void )
{
return ( memberPtr == members.end() );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void Stone( CItem &newStone )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Sets the guild's stone serial to the CItem newStone
//o-----------------------------------------------------------------------------------------------o
void CGuild::Stone( CItem &newStone )
{
stone = newStone.GetSerial();
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void Master( CChar &newMaster )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Sets the guild's master serial to CChar newMaster's serial
//o-----------------------------------------------------------------------------------------------o
void CGuild::Master( CChar &newMaster )
{
master = newMaster.GetSerial();
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void NewRecruit( CChar &newRecruit )
//| void NewRecruit( SERIAL newRecruit )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Add new recruit to guild
//o-----------------------------------------------------------------------------------------------o
void CGuild::NewRecruit( CChar &newRecruit )
{
NewRecruit( newRecruit.GetSerial() );
}
void CGuild::NewRecruit( SERIAL newRecruit )
{
if( IsMember( newRecruit ) )
RemoveMember( newRecruit );
recruits.push_back( newRecruit );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void NewMember( CChar &newMember )
//| void NewMember( SERIAL newMember )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Add new member to guild
//o-----------------------------------------------------------------------------------------------o
void CGuild::NewMember( CChar &newMember )
{
NewMember( newMember.GetSerial() );
}
void CGuild::NewMember( SERIAL newMember )
{
if( IsRecruit( newMember ) )
RemoveRecruit( newMember );
members.push_back( newMember );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void RemoveRecruit( CChar &newRecruit )
//| void RemoveRecruit( SERIAL newRecruit )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Remove recruit from guild
//o-----------------------------------------------------------------------------------------------o
void CGuild::RemoveRecruit( CChar &newRecruit )
{
RemoveRecruit( newRecruit.GetSerial() );
}
void CGuild::RemoveRecruit( SERIAL newRecruit )
{
SERLIST_ITERATOR toFind = recruits.begin();
while( toFind != recruits.end() )
{
if( (*toFind) == newRecruit )
{
if( recruitPtr != recruits.begin() && recruitPtr >= toFind )
--recruitPtr;
recruits.erase( toFind );
return;
}
++toFind;
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void RemoveMember( CChar &newMember )
//| void RemoveMember( SERIAL newMember )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Remove member from guild
//o-----------------------------------------------------------------------------------------------o
void CGuild::RemoveMember( CChar &newMember )
{
RemoveMember( newMember.GetSerial() );
}
void CGuild::RemoveMember( SERIAL newMember )
{
SERLIST_ITERATOR toFind = members.begin();
while( toFind != members.end() )
{
if( (*toFind) == newMember )
{
if( memberPtr != members.begin() && memberPtr >= toFind )
--memberPtr;
members.erase( toFind );
return;
}
++toFind;
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void RecruitToMember( CChar &newMember )
//| void RecruitToMember( SERIAL newMember )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Change guild recruit to member
//o-----------------------------------------------------------------------------------------------o
void CGuild::RecruitToMember( CChar &newMember )
{
RemoveRecruit( newMember );
NewMember( newMember );
}
void CGuild::RecruitToMember( SERIAL newMember )
{
RemoveRecruit( newMember );
NewMember( newMember );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool IsRecruit( CChar &toCheck ) const
//| bool IsRecruit( SERIAL toCheck ) const
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Check if character can be found in list of guild recruits
//o-----------------------------------------------------------------------------------------------o
bool CGuild::IsRecruit( CChar &toCheck ) const
{
return IsRecruit( toCheck.GetSerial() );
}
bool CGuild::IsRecruit( SERIAL toCheck ) const
{
SERLIST_CITERATOR toFind = recruits.begin();
while( toFind != recruits.end() )
{
if( (*toFind) == toCheck )
return true;
++toFind;
}
return false;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool IsMember( CChar &toCheck ) const
//| bool IsMember( SERIAL toCheck ) const
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Check if character can be found in list of guild members
//o-----------------------------------------------------------------------------------------------o
bool CGuild::IsMember( CChar &toCheck ) const
{
return IsMember( toCheck.GetSerial() );
}
bool CGuild::IsMember( SERIAL toCheck ) const
{
SERLIST_CITERATOR toFind = members.begin();
while( toFind != members.end() )
{
if( (*toFind) == toCheck )
return true;
++toFind;
}
return false;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - GUILDRELATION RelatedToGuild( GUILDID otherGuild ) const
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Determine other guild's relation (Alliance/War) to this guild
//o-----------------------------------------------------------------------------------------------o
GUILDRELATION CGuild::RelatedToGuild( GUILDID otherGuild ) const
{
GUILDREL::const_iterator toFind = relationList.find( otherGuild );
if( toFind == relationList.end() )
return GR_UNKNOWN;
else
return toFind->second;
}
bool CGuild::IsAtWar( GUILDID otherGuild ) const
{
GUILDREL::const_iterator toFind = relationList.find( otherGuild );
if( toFind == relationList.end() )
return false;
else
return ( toFind->second == GR_WAR );
}
bool CGuild::IsNeutral( GUILDID otherGuild ) const
{
GUILDREL::const_iterator toFind = relationList.find( otherGuild );
if( toFind == relationList.end() )
return false;
else
return ( toFind->second == GR_NEUTRAL );
}
bool CGuild::IsAlly( GUILDID otherGuild ) const
{
GUILDREL::const_iterator toFind = relationList.find( otherGuild );
if( toFind == relationList.end() )
return false;
else
return ( toFind->second == GR_ALLY );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void SetGuildRelation( GUILDID otherGuild, GUILDRELATION toSet )
//| GUILDREL *GuildRelationList( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Gets/Sets guild's relation to another guild
//| Notes - NOTE: This is aimed ONLY at menu stuff
//o-----------------------------------------------------------------------------------------------o
void CGuild::SetGuildRelation( GUILDID otherGuild, GUILDRELATION toSet )
{
relationList[otherGuild] = toSet;
}
GUILDREL *CGuild::GuildRelationList( void )
{
return &relationList;
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void Save( std::ofstream &toSave, GUILDID gNum )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Save guild data to worldfiles
//o-----------------------------------------------------------------------------------------------o
void CGuild::Save( std::ofstream &toSave, GUILDID gNum )
{
toSave << "[GUILD " << gNum << ']' << '\n' << "{" << '\n';
toSave << "NAME=" << name << '\n';
toSave << "ABBREVIATION=" << abbreviation << '\n';
toSave << "TYPE=" << GTypeNames[gType] << '\n';
toSave << "CHARTER=" << charter << '\n';
toSave << "WEBPAGE=" << webpage << '\n';
toSave << "STONE=" << stone << '\n';
toSave << "MASTER=" << master << '\n';
SERLIST_ITERATOR counter;
counter = recruits.begin();
while( counter != recruits.end() )
{
toSave << "RECRUIT=" << (*counter) << '\n';
++counter;
}
counter = members.begin();
while( counter != members.end() )
{
toSave << "MEMBER=" << (*counter) << '\n';
++counter;
}
GUILDREL::const_iterator relly = relationList.begin();
while( relly != relationList.end() )
{
toSave << GRelationNames[relly->second] << " " << relly->first <<'\n';
++relly;
}
toSave << "}" << '\n' << '\n';
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void Load( ScriptSection *toRead )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Load guilds from guilds worldfile
//o-----------------------------------------------------------------------------------------------o
void CGuild::Load( ScriptSection *toRead )
{
std::string tag;
std::string data;
std::string UTag;
for( tag = toRead->First(); !toRead->AtEnd(); tag = toRead->Next() )
{
data = toRead->GrabData();
if( tag.empty() )
continue;
UTag = strutil::upper( tag );
switch( (UTag.data()[0]) )
{
case '{':
case '/': break; // open section, comment, we don't really care ;)
case 'A':
if( UTag == "ABBREVIATION" )
{
Abbreviation( data.c_str() );
}
else if( UTag == "ALLY" )
{
SetGuildRelation( static_cast<SI16>(std::stoi(data, nullptr, 0)), GR_ALLY );
}
break;
case 'C':
if( UTag == "CHARTER" )
{
Charter( data );
}
break;
case 'M':
if( UTag == "MASTER" )
{
Master( static_cast<UI32>(std::stoul(data, nullptr, 0)) );
}
else if( UTag == "MEMBER" )
{
NewMember( static_cast<UI32>(std::stoul(data, nullptr, 0)) );
}
break;
case 'N':
if( UTag == "NAME" )
{
Name( data );
}
else if( UTag == "NEUTRAL" )
{
SetGuildRelation( static_cast<SI16>(std::stoi(data, nullptr, 0)), GR_NEUTRAL );
}
break;
case 'R':
if( UTag == "RECRUIT" )
{
NewRecruit( static_cast<UI32>(std::stoul(data, nullptr, 0)) );
}
break;
case 'S':
if( UTag == "STONE" )
{
Stone( static_cast<UI32>(std::stoul(data, nullptr, 0)) );
}
break;
case 'T':
if( UTag == "TYPE" )
{
for( GuildType gt = GT_STANDARD; gt < GT_COUNT; gt = (GuildType)(gt + (GuildType)1) )
{
if( data == GTypeNames[gt] )
{
Type( gt );
break;
}
}
}
break;
case 'U':
if( UTag == "UNKNOWN" )
{
SetGuildRelation( static_cast<SI16>(std::stoi(data, nullptr, 0)), GR_UNKNOWN );
}
break;
case 'W':
if( UTag == "WEBPAGE" )
{
Webpage( data );
}
else if( UTag == "WAR" )
{
SetGuildRelation( static_cast<SI16>(std::stoi(data, nullptr, 0)), GR_WAR );
}
break;
}
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - size_t NumMembers( void ) const
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Gets number of guild members
//o-----------------------------------------------------------------------------------------------o
size_t CGuild::NumMembers( void ) const
{
return members.size();
}
//o-----------------------------------------------------------------------------------------------o
//| Function - size_t NumRecruits( void ) const
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Gets number of guild recruits
//o-----------------------------------------------------------------------------------------------o
size_t CGuild::NumRecruits( void ) const
{
return recruits.size();
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void CalcMaster( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Calculate next guild master based on vote count
//o-----------------------------------------------------------------------------------------------o
void CGuild::CalcMaster( void )
{
if( members.empty() )
{
Master( INVALIDSERIAL );
return;
}
std::vector< SI32 > votes;
votes.resize( members.size() );
UI32 maxIndex = 0;
for( size_t counter = 0; counter < votes.size(); ++counter )
{
votes[counter] = 0; // init the count before adding
for( size_t counter2 = 0; counter2 < votes.size(); ++counter2 )
{
CChar *myChar = calcCharObjFromSer( members[counter2] );
if( ValidateObject( myChar ) && myChar->GetGuildFealty() == members[counter] )
++votes[counter];
}
if( votes[counter] > votes[maxIndex] )
maxIndex = static_cast<UI32>(counter);
}
Master( members[maxIndex] );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void TellMembers( SI32 dictEntry, ... )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Tell all guild members a message
//o-----------------------------------------------------------------------------------------------o
void CGuild::TellMembers( SI32 dictEntry, ... )
{
SERLIST_CITERATOR cIter;
for( cIter = members.begin(); cIter != members.end(); ++cIter )
{
CChar *targetChar = calcCharObjFromSer( (*cIter) );
CSocket *targetSock = targetChar->GetSocket();
if( targetSock != nullptr )
{
std::string txt = "GUILD: ";
txt += Dictionary->GetEntry( dictEntry, targetSock->Language() );
va_list argptr;
va_start( argptr, dictEntry );
if( cwmWorldState->ServerData()->UseUnicodeMessages() )
{
std::string tempStr = strutil::format( 512, txt, argptr );
CPUnicodeMessage unicodeMessage;
unicodeMessage.Message( tempStr );
unicodeMessage.Font( FNT_NORMAL );
unicodeMessage.Colour( 0x000B );
unicodeMessage.Type( SYSTEM );
unicodeMessage.Language( "ENG" );
unicodeMessage.Name( "System" );
unicodeMessage.ID( INVALIDID );
unicodeMessage.Serial( INVALIDSERIAL );
targetSock->Send( &unicodeMessage );
}
else
{
CSpeechEntry& toAdd = SpeechSys->Add();
toAdd.Speech( strutil::format( 512, txt, argptr ));
toAdd.Font( FNT_NORMAL );
toAdd.Speaker( INVALIDSERIAL );
toAdd.SpokenTo( (*cIter) );
toAdd.Colour( 0x000B );
toAdd.Type( SYSTEM );
toAdd.At( cwmWorldState->GetUICurrentTime() );
toAdd.TargType( SPTRG_INDIVIDUAL );
}
va_end(argptr);
}
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void SetGuildFaction( GuildType newFaction )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Sets the guild's faction - neutral, order or chaos
//o-----------------------------------------------------------------------------------------------o
void CGuild::SetGuildFaction( GuildType newFaction )
{
Type( newFaction );
if( newFaction != GT_STANDARD )
{
SERLIST_CITERATOR cIter;
for( cIter = members.begin(); cIter != members.end(); ++cIter )
{
CChar *memberChar = calcCharObjFromSer( (*cIter) );
if( !memberChar->GetGuildToggle() )
{
memberChar->SetGuildToggle( true );
CSocket *memberSock = memberChar->GetSocket();
if( memberSock != nullptr )
memberSock->sysmessage( 154 ); // Let him know about the change
}
}
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - const std::string TypeName( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Gets guild type as a string
//o-----------------------------------------------------------------------------------------------o
const std::string CGuild::TypeName( void )
{
return GTypeNames[Type()];
}
CGuildCollection::CGuildCollection()
{
}
//o-----------------------------------------------------------------------------------------------o
//| Function - size_t NumGuilds( void ) const
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Gets number of guilds on the server
//o-----------------------------------------------------------------------------------------------o
size_t CGuildCollection::NumGuilds( void ) const
{
return gList.size();
}
//o-----------------------------------------------------------------------------------------------o
//| Function - GUILDID MaximumGuild( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Gets the next available guild ID
//o-----------------------------------------------------------------------------------------------o
GUILDID CGuildCollection::MaximumGuild( void )
{
GUILDID maxVal = -1;
GUILDLIST::const_iterator pFind = gList.begin();
while( pFind != gList.end() )
{
if( pFind->first > maxVal )
maxVal = pFind->first;
++pFind;
}
return static_cast<GUILDID>(maxVal + 1);
}
//o-----------------------------------------------------------------------------------------------o
//| Function - GUILDID NewGuild( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Create a new guild
//o-----------------------------------------------------------------------------------------------o
GUILDID CGuildCollection::NewGuild( void )
{
CGuild *toAdd = new CGuild();
GUILDID gAdd = MaximumGuild();
gList[gAdd] = toAdd;
return gAdd;
}
CGuild *CGuildCollection::Guild( GUILDID num ) const
{
GUILDLIST::const_iterator pFind = gList.find( num );
if( pFind == gList.end() )
return nullptr;
return pFind->second;
}
CGuild *CGuildCollection::operator[]( GUILDID num )
{
return Guild( num );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void Save( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Saves guild to worldfile
//o-----------------------------------------------------------------------------------------------o
void CGuildCollection::Save( void )
{
Console << "Saving guild data.... ";
std::string filename = cwmWorldState->ServerData()->Directory( CSDDP_SHARED ) + "guilds.wsc";
std::ofstream toSave( filename.c_str() );
GUILDLIST::const_iterator pMove = gList.begin();
while( pMove != gList.end() )
{
(pMove->second)->Save( toSave, pMove->first );
++pMove;
}
Console.PrintDone();
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void Load( void )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Load guilds from worldfile
//o-----------------------------------------------------------------------------------------------o
void CGuildCollection::Load( void )
{
std::string filename = cwmWorldState->ServerData()->Directory( CSDDP_SHARED ) + "guilds.wsc";
if( FileExists( filename ) )
{
Script newScript( filename, NUM_DEFS, false );
ScriptSection *testSect = nullptr;
GUILDID guildNum = 0;
for( testSect = newScript.FirstEntry(); testSect != nullptr; testSect = newScript.NextEntry() )
{
std::string text = newScript.EntryName();
text = text.substr( 6 );
guildNum = static_cast<SI16>(std::stoi(text, nullptr, 0));
if( gList[guildNum] != nullptr )
delete gList[guildNum];
gList[guildNum] = new CGuild();
gList[guildNum]->Load( testSect );
}
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - GUILDRELATION Compare( GUILDID srcGuild, GUILDID trgGuild ) const
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Compare the guild relation between two guilds
//o-----------------------------------------------------------------------------------------------o
GUILDRELATION CGuildCollection::Compare( GUILDID srcGuild, GUILDID trgGuild ) const
{
if( srcGuild == -1 || trgGuild == -1 )
return GR_UNKNOWN;
if( srcGuild == trgGuild )
return GR_SAME;
CGuild *mGuild = Guild( srcGuild );
if( mGuild == nullptr )
return GR_UNKNOWN;
return mGuild->RelatedToGuild( trgGuild );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - GUILDRELATION Compare( CChar *src, CChar *trg ) const
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Compare the guild relation between two characters
//o-----------------------------------------------------------------------------------------------o
GUILDRELATION CGuildCollection::Compare( CChar *src, CChar *trg ) const
{
if( src == nullptr || trg == nullptr )
return GR_UNKNOWN;
auto srcGuild = src->GetGuildNumber();
auto trgGuild = trg->GetGuildNumber();
if( srcGuild == -1 || trgGuild == -1 )
return GR_UNKNOWN;
if( srcGuild == trgGuild )
return GR_SAME;
return Compare( srcGuild, trgGuild );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void Menu( CSocket *s, SI16 menu, GUILDID trgGuild, SERIAL plID )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Send guild menu to player
//o-----------------------------------------------------------------------------------------------o
void CGuildCollection::Menu( CSocket *s, SI16 menu, GUILDID trgGuild, SERIAL plID )
{
if( s == nullptr )
return;
if( trgGuild >= static_cast<SI32>(NumGuilds()) )
return;
CPSendGumpMenu toSend;
toSend.GumpID( menu );
toSend.UserID( INVALIDSERIAL );
toSend.addCommand( "page 0" );
toSend.addCommand( strutil::format("resizepic 0 0 %u 600 400", cwmWorldState->ServerData()->BackgroundPic()) );
toSend.addCommand( strutil::format("button 560 10 %u %i 1 0 1", cwmWorldState->ServerData()->ButtonCancel(), cwmWorldState->ServerData()->ButtonCancel() + 1)); //OKAY
toSend.addCommand(strutil::format( "text 120 10 %u 0", cwmWorldState->ServerData()->TitleColour() ));
toSend.addCommand( "page 1" );
SERIAL gMaster = gList[trgGuild]->Master();
CChar *mChar = s->CurrcharObj();
CChar *gMstr = calcCharObjFromSer( gMaster );
UI16 numButtons = 0, numText = 0, numColumns = 1;
char guildfealty[30], guildt[10], toggle[4];
strcpy( guildfealty, "yourself" );
if( mChar->GetGuildFealty() != mChar->GetSerial() && mChar->GetGuildFealty() != INVALIDSERIAL )
{
CChar *fChar = calcCharObjFromSer( mChar->GetGuildFealty() );
if( ValidateObject( fChar ) )
strcpy( guildfealty, fChar->GetName().c_str() );
}
else
mChar->SetGuildFealty( mChar->GetSerial() );
switch( gList[trgGuild]->Type() )
{
case 0:
strcpy( guildt, " Standard" );
break;
case 1:
strcpy( guildt, "n Order" );
break;
case 2:
strcpy( guildt, " Chaos" );
break;
default:
strcpy( guildt, "INVALID" );
break;
}
strcpy( toggle, "Off" );
if( mChar->GetGuildToggle() )
strcpy( toggle, "On" );
std::string gName = gList[trgGuild]->Name();
UI16 tCtr = 0;
SERIAL tChar = 0;
GUILDREL::iterator toCheck;
GUILDREL *ourList;
s->TempInt( trgGuild );
UnicodeTypes sLang = s->Language();
UI32 tCounter = 0;
switch( menu )
{
case -1: break;
case BasePage: break;
case BasePage+1: numButtons = 10; // Main menu
toSend.addText( Dictionary->GetEntry( 102, sLang ) );
toSend.addText( Dictionary->GetEntry( 103, sLang ) );
toSend.addText( Dictionary->GetEntry( 104, sLang ) );
toSend.addText( Dictionary->GetEntry( 105, sLang ) );
toSend.addText( strutil::format(Dictionary->GetEntry( 106, sLang ), guildfealty ));
toSend.addText( strutil::format(Dictionary->GetEntry( 107, sLang ), toggle ));
toSend.addText( Dictionary->GetEntry( 108, sLang ) );
toSend.addText( Dictionary->GetEntry( 109, sLang ) );
toSend.addText( strutil::format(Dictionary->GetEntry( 110, sLang ), gName.c_str()) );
toSend.addText( strutil::format(Dictionary->GetEntry( 111, sLang ), gName.c_str() ));
toSend.addText( Dictionary->GetEntry( 112, sLang ) );
if( mChar->GetSerial() == gMaster || mChar->IsGM() ) // Guildmaster Access?
{
++numButtons;
toSend.addText( strutil::format(Dictionary->GetEntry( 113, sLang ), gMstr->GetGuildTitle().c_str()) );
}
break;
case BasePage+2: numButtons = 16; // Guildmaster menu
toSend.addText( Dictionary->GetEntry( 114, sLang ) );
toSend.addText( Dictionary->GetEntry( 115, sLang ) );
toSend.addText( Dictionary->GetEntry( 116, sLang ) );
toSend.addText(strutil::format( Dictionary->GetEntry( 117, sLang ), guildt ));
for( tCounter = 118; tCounter <= 130; ++tCounter )
toSend.addText( Dictionary->GetEntry( tCounter, sLang ) );
break;
case BasePage+3: numButtons = 4; // Guild type
toSend.addText( Dictionary->GetEntry( 131, sLang ) );
toSend.addText( Dictionary->GetEntry( 133, sLang ) );
toSend.addText( Dictionary->GetEntry( 134, sLang ) );
toSend.addText( Dictionary->GetEntry( 135, sLang ) );
toSend.addText( Dictionary->GetEntry( 130, sLang ) );
break;
case BasePage+4: numButtons = 3; // Set charter
toSend.addText( Dictionary->GetEntry( 136, sLang ) );
toSend.addText( Dictionary->GetEntry( 138, sLang ) );
toSend.addText( Dictionary->GetEntry( 139, sLang ) );
toSend.addText( Dictionary->GetEntry( 130, sLang ) );
break;
case BasePage+5: numButtons = 3; // View charter
toSend.addText( Dictionary->GetEntry( 140, sLang ) );
toSend.addText( gList[trgGuild]->Charter() );
toSend.addText( strutil::format(Dictionary->GetEntry( 142, sLang ), gList[trgGuild]->Webpage().c_str()) );
toSend.addText( Dictionary->GetEntry( 130, sLang ) );
break;
case BasePage+6: // List of recruits
toSend.addText( Dictionary->GetEntry( 143, sLang ) );
tCtr = 0;
for( tChar = gList[trgGuild]->FirstRecruit(); !gList[trgGuild]->FinishedRecruits(); tChar = gList[trgGuild]->NextRecruit() )
{
toSend.addText( calcCharObjFromSer( tChar )->GetName() );
++tCtr;
}
toSend.addText( Dictionary->GetEntry( 130, sLang ) );
numButtons = ++tCtr;
break;
case BasePage+7: // List of members
toSend.addText( Dictionary->GetEntry( 144, sLang ) );
tCtr = 0;
for( tChar = gList[trgGuild]->FirstMember(); !gList[trgGuild]->FinishedMember(); tChar = gList[trgGuild]->NextMember() )
{
toSend.addText( calcCharObjFromSer( tChar )->GetName() );
++tCtr;
}
toSend.addText( Dictionary->GetEntry( 130, sLang ) );
numButtons = ++tCtr;
break;
case BasePage+8: // Member dismiss
toSend.addText( Dictionary->GetEntry( 145, sLang ) );
tCtr = 0;
for( tChar = gList[trgGuild]->FirstMember(); !gList[trgGuild]->FinishedMember(); tChar = gList[trgGuild]->NextMember() )
{
toSend.addText( calcCharObjFromSer( tChar )->GetName() );
++tCtr;
}
toSend.addText( Dictionary->GetEntry( 130, sLang ) );
numButtons = ++tCtr; break;
case BasePage+9: // Dismiss recruit
toSend.addText( Dictionary->GetEntry( 146, sLang ) );
tCtr = 0;
for( tChar = gList[trgGuild]->FirstRecruit(); !gList[trgGuild]->FinishedRecruits(); tChar = gList[trgGuild]->NextRecruit() )
{
toSend.addText( calcCharObjFromSer( tChar )->GetName() );
++tCtr;
}
toSend.addText( Dictionary->GetEntry( 130, sLang ) );
numButtons = ++tCtr; break;
case BasePage+10: // Accept recruit
toSend.addText( Dictionary->GetEntry( 147, sLang ) );
tCtr = 0;
for( tChar = gList[trgGuild]->FirstRecruit(); !gList[trgGuild]->FinishedRecruits(); tChar = gList[trgGuild]->NextRecruit() )
{
toSend.addText( calcCharObjFromSer( tChar )->GetName() );
++tCtr;
}
toSend.addText( Dictionary->GetEntry( 130, sLang ) );
numButtons = ++tCtr; break;
case BasePage+11: // War list
toSend.addText( Dictionary->GetEntry( 148, sLang ) );
tCtr = 0;
ourList = gList[trgGuild]->GuildRelationList();
toCheck = ourList->begin();
while( toCheck != ourList->end() )
{
if( toCheck->second == GR_WAR )
{
toSend.addText( gList[toCheck->first]->Name() );
++tCtr;
}
++toCheck;
}
toSend.addText( Dictionary->GetEntry( 130, sLang ) );
numButtons = ++tCtr; break;
case BasePage+12: // Grant title
numButtons = 1;
toSend.addText( "Unfilled functionality" );
toSend.addText( Dictionary->GetEntry( 130, sLang ) );
break;
case BasePage+13: // Declare war list
toSend.addText( Dictionary->GetEntry( 149, sLang ) );
tCtr = 0;
ourList = gList[trgGuild]->GuildRelationList();
toCheck = ourList->begin();
while( toCheck != ourList->end() )
{
if( toCheck->second != GR_WAR )
{
toSend.addText( gList[toCheck->first]->Name() );
++tCtr;
}
++toCheck;
}
toSend.addText( Dictionary->GetEntry( 130, sLang ) );
numButtons = ++tCtr; break;
case BasePage+14: // Declare peace list
toSend.addText( Dictionary->GetEntry( 150, sLang ) );
tCtr = 0;
ourList = gList[trgGuild]->GuildRelationList();
toCheck = ourList->begin();
while( toCheck != ourList->end() )
{
if( toCheck->second == GR_WAR )
{
toSend.addText( gList[toCheck->first]->Name() );
++tCtr;
}
++toCheck;
}
toSend.addText( Dictionary->GetEntry( 130, sLang ) );
numButtons = ++tCtr; break;
case BasePage+15: // List of guilds warring on us
case BasePage+16: // Display recruit information
numButtons = 1;
toSend.addText( "Unfilled functionality" );
toSend.addText( Dictionary->GetEntry( 130, sLang ) );
break;
case BasePage+17: // Display member information
CChar *kChar;
kChar = calcCharObjFromSer( plID );
if( ValidateObject( kChar ) )
{
auto temp = kChar->GetName();
if( kChar->IsInnocent() )
temp += std::string(" Innocent");
else if( kChar->IsMurderer() )
temp += std::string(" Murderer");
else
temp += std::string(" Criminal");
toSend.addText( temp );
// To display: Name, str, dex, int, # kills, # deaths, status (criminal, murderer, innocent), top x skills
toSend.addText( "Strength" );
toSend.addText( strutil::format("%i", kChar->GetStrength()) );
toSend.addText( "Dexterity" );
toSend.addText( strutil::format("%i", kChar->GetDexterity() ));
toSend.addText( "Intelligence" );
toSend.addText( strutil::format("%i", kChar->GetIntelligence()) );
toSend.addText( "Kills" );
toSend.addText( strutil::format("%i", kChar->GetKills() ));
toSend.addText( "Deaths" );
toSend.addText( strutil::format("%u", kChar->GetDeaths()) );
numText = 10;
numColumns = 2;
numButtons = 1;
}
else
{
numButtons = 1;
toSend.addText( "Unknown player" );
}
toSend.addText( Dictionary->GetEntry( 130, sLang ) );
break;
case BasePage+18: // Ally list
toSend.addText( Dictionary->GetEntry( 151, sLang ) );
tCtr = 0;
ourList = gList[trgGuild]->GuildRelationList();
toCheck = ourList->begin();
while( toCheck != ourList->end() )
{
if( toCheck->second == GR_ALLY )
{
toSend.addText( gList[toCheck->first]->Name() );
++tCtr;
}
++toCheck;
}
toSend.addText( Dictionary->GetEntry( 130, sLang ) );
numButtons = ++tCtr; break;
case BasePage+19: // Declare Ally list
toSend.addText( Dictionary->GetEntry( 152, sLang ) );
tCtr = 0;
ourList = gList[trgGuild]->GuildRelationList();
toCheck = ourList->begin();
while( toCheck != ourList->end() )
{
if( toCheck->second != GR_ALLY )
{
toSend.addText( gList[toCheck->first]->Name() );
++tCtr;
}
++toCheck;
}
toSend.addText( Dictionary->GetEntry( 130, sLang ) );
numButtons = ++tCtr; break;
}
for( UI16 iCtr = 0; iCtr < numButtons; ++iCtr )
{
toSend.addCommand( strutil::format("button 20 %i %i %i 1 0 %i", 30 + 20 * iCtr, cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1, iCtr + 2) );
toSend.addCommand( strutil::format("text 50 %i %i %i", 30 + 20 * iCtr, cwmWorldState->ServerData()->LeftTextColour(), iCtr + 1) );
}
if( numText != 0 )
{
for( UI16 iCtr = 0; iCtr < numText; ++iCtr )
{
if( numColumns == 1 )
toSend.addCommand( strutil::format("text 50 %i %i %i", 30 + 20 * ( iCtr + numButtons ), cwmWorldState->ServerData()->LeftTextColour(), iCtr + numButtons + 1 ));
else
toSend.addCommand(strutil::format( "text %i %i %i %i", 50 + (iCtr % numColumns) * 100, 30 + 20 * ( ( iCtr / 2 ) + numButtons ), cwmWorldState->ServerData()->LeftTextColour(), iCtr + numButtons + 1) );
}
}
toSend.Finalize();
s->Send( &toSend );
}
void CGuildCollection::GumpInput( CPIGumpInput *gi )
{
UI08 type = gi->Type();
UI08 index = gi->Index();
std::string text = gi->Reply();
CSocket *s = gi->GetSocket();
if( type != 100 )
return;
GUILDID trgGuild = static_cast<GUILDID>(s->TempInt());
CChar *gMaster = calcCharObjFromSer( gList[trgGuild]->Master() );
switch( index )
{
case 1: gList[trgGuild]->Name( text ); break; // set guild name
case 2: gList[trgGuild]->Abbreviation( text.c_str() ); break; // set guild abbreviation
case 3: gMaster->SetGuildTitle( text ); break; // set guildmaster title
case 4: gList[trgGuild]->Charter( text ); break; // new charter
case 5: gList[trgGuild]->Webpage( text ); break; // new webpage
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void ToggleAbbreviation( CSocket *s )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Toggles guild abbreviation on/off - except for order/chaos, which must show
//o-----------------------------------------------------------------------------------------------o
void CGuildCollection::ToggleAbbreviation( CSocket *s )
{
CChar *mChar = s->CurrcharObj();
GUILDID guildnumber = mChar->GetGuildNumber();
if( guildnumber == -1 )
return;
if( gList[guildnumber]->Type() != GT_STANDARD ) // Check for Order/Chaos
s->sysmessage( 153 ); // They may not toggle it off!
else
{
mChar->SetGuildToggle( !mChar->GetGuildToggle() );
if( mChar->GetGuildToggle() ) // If set to On then
s->sysmessage( 154 ); // Tell player about the change
else // Otherwise
s->sysmessage( 155 ); // And tell him also
}
}
void CGuildCollection::TransportGuildStone( CSocket *s, GUILDID guildID )
{
CChar *mChar = s->CurrcharObj();
if( guildID == -1 )
return;
if( gList[guildID]->Stone() == INVALIDSERIAL )
return;
// Make sure this is the guild master
if( gList[guildID]->Master() == mChar->GetSerial() )
{
CItem *gTransportStone = Items->CreateItem( s, mChar, 0x1869, 1, 0, OT_ITEM, true );
if( ValidateObject( gTransportStone ) )
{
gTransportStone->SetTempVar( CITV_MORE, guildID );
gTransportStone->SetNewbie( true );
gTransportStone->SetWeight( 1, true );
gTransportStone->SetType( IT_GUILDSTONE );
gTransportStone->SetName( strutil::format( Dictionary->GetEntry( 101 ), gList[guildID]->Name().c_str() ));
CItem *gStone = calcItemObjFromSer( gList[guildID]->Stone() );
gStone->Delete();
// A guildstone transporter object has been placed in your backpack. Use it to move the guildstone to a new location.
s->sysmessage( 1972 );
}
}
}
void TextEntryGump( CSocket *s, SERIAL ser, UI08 type, UI08 index, SI16 maxlength, SI32 dictEntry );
//o-----------------------------------------------------------------------------------------------o
//| Function - void GumpChoice( CSocket *s )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Handles button presses in guild menus
//o-----------------------------------------------------------------------------------------------o
void CGuildCollection::GumpChoice( CSocket *s )
{
UI32 realType = s->GetDWord( 7 );
UI32 button = s->GetDWord( 11 );
GUILDID trgGuild = (GUILDID)s->TempInt();
if( button == 1 ) // hit cancel
return;
CChar *mChar = s->CurrcharObj();
if( !ValidateObject( mChar ) )
return;
SERIAL ser = mChar->GetSerial();
UI16 tCtr = 0;
GUILDREL::iterator toCheck;
GUILDREL *ourList;
size_t offCounter;
CChar *tChar = nullptr;
switch( realType )
{
case INVALIDSERIAL:
case BasePage:
case BasePage+1: // Main menu
switch( button )
{
case 2: s->target( 2, 0, 0, 156 ); break; // recruit into guild
case 3: Menu( s, BasePage + 7, trgGuild ); break;
case 4: Menu( s, BasePage + 5, trgGuild ); break;
case 5: s->target( 2, 1, 0, 157 ); break; // declare fealty
case 6: ToggleAbbreviation( s ); break; // toggle abbreviation
case 7: Resign( s ); break; // Resign from guild
case 8: Menu( s, BasePage + 6, trgGuild ); break; // View candidates
case 9: Menu( s, BasePage + 11, trgGuild ); break; // View warring guilds
case 10: Menu( s, BasePage + 15, trgGuild ); break; // View guilds that declared war on us
case 11: Menu( s, BasePage + 18, trgGuild ); break; // View list of allied guilds
case 12: Menu( s, BasePage + 2, trgGuild ); break; // Access guildmaster functions
}
break;
case BasePage+2: // Guildmaster menu
switch( button )
{
case 2: TextEntryGump( s, ser, 100, 1, 30, 158 ); break; // set guild name
case 3: TextEntryGump( s, ser, 100, 2, 3, 159 ); break; // set guild abbreviation
case 4: Menu( s, BasePage + 3, trgGuild ); break; // set guild type
case 5: Menu( s, BasePage + 4, trgGuild ); break; // set guild charter
case 6: Menu( s, BasePage + 8, trgGuild ); break; // dismiss a member
case 7: Menu( s, BasePage + 13, trgGuild ); break; // declare war from menu
case 8: s->target( 2, 2, 0, 160 ); break; // declare war from target
case 9: Menu( s, BasePage + 14, trgGuild ); break; // declare peace
case 10: Menu( s, BasePage + 19, trgGuild ); break; // declare ally from menu
case 11: s->target( 2, 3, 0, 161 ); break; // declare ally from target
case 12: Menu( s, BasePage + 10, trgGuild ); break; // accept candidate seeking membership
case 13: Menu( s, BasePage + 9, trgGuild ); break; // refuse candidate seeking membership
case 14: TextEntryGump( s, ser, 100, 3, 15, 162 ); break; // set guild master's title
case 15: Menu( s, BasePage + 12, trgGuild ); break; // grant title to another member
#if defined( _MSC_VER )
#pragma note( "Move guildstone functionality goes here" )
#endif
case 16: TransportGuildStone( s, trgGuild ); break; // move guildstone
case 17: Menu( s, BasePage + 1, trgGuild ); break; // return to main menu
}
break;
case BasePage+3: // Guild type
switch( button )
{
case 2: gList[trgGuild]->SetGuildFaction( GT_STANDARD ); break;
case 3: gList[trgGuild]->SetGuildFaction( GT_ORDER ); break;
case 4: gList[trgGuild]->SetGuildFaction( GT_CHAOS ); break;
case 5: Menu( s, BasePage + 2, trgGuild ); break;
}
break;
case BasePage+4: // Set charter
switch( button )
{
case 2: TextEntryGump( s, ser, 100, 4, 50, 163 ); break;
case 3: TextEntryGump( s, ser, 100, 5, 50, 164 ); break;
case 4: Menu( s, BasePage + 2, trgGuild ); break;
}
break;
case BasePage+5: // View charter
switch( button )
{
case 3: s->OpenURL( gList[trgGuild]->Webpage() ); break;
case 2:
case 4: Menu( s, BasePage + 1, trgGuild ); break;
}
break;
case BasePage+6: // List of recruits
if( gList[trgGuild]->NumRecruits() >= (button - 2) )
Menu( s, BasePage + 1, trgGuild );
else
Menu( s, BasePage + 16, trgGuild, gList[trgGuild]->RecruitNumber( button - 2 ) ); // display recruit number
break;
case BasePage+7: // List of members
if( gList[trgGuild]->NumMembers() >= (button - 2) )
Menu( s, BasePage + 1, trgGuild );
else
Menu( s, BasePage + 17, trgGuild, gList[trgGuild]->MemberNumber( button - 2 ) ); // display member number
break;
case BasePage+8: // Member dismiss
if( gList[trgGuild]->NumMembers() <= (button - 2) )
Menu( s, BasePage + 2, trgGuild );
else
{
tChar = calcCharObjFromSer( gList[trgGuild]->MemberNumber( button - 2 ) );
if( ValidateObject( tChar ) )
{
gList[trgGuild]->RemoveMember( (*tChar) );
tChar->SetGuildNumber( -1 );
}
}
break;
case BasePage+9: // Dismiss recruit
if( gList[trgGuild]->NumRecruits() <= (button - 2) )
Menu( s, BasePage + 2, trgGuild );
else
gList[trgGuild]->RemoveRecruit( gList[trgGuild]->RecruitNumber( button - 2 ) );
break;
case BasePage+10: // Accept recruit
if( gList[trgGuild]->NumRecruits() <= (button - 2) )
Menu( s, BasePage + 2, trgGuild );
else
{
tChar = calcCharObjFromSer( gList[trgGuild]->RecruitNumber( button - 2 ) );
if( ValidateObject( tChar ) )
{
gList[trgGuild]->RecruitToMember( (*tChar) );
tChar->SetGuildNumber( trgGuild );
if( gList[trgGuild]->Type() != GT_STANDARD )
tChar->SetGuildToggle( true );
}
}
break;
case BasePage+11: // War list
case BasePage+12: // Grant title
Menu( s, BasePage + 2, trgGuild );
break;
case BasePage+13: // Declare war list
offCounter = tCtr = 0;
ourList = gList[trgGuild]->GuildRelationList();
if( ourList->size() <= (button - 2) )
Menu( s, BasePage + 2, trgGuild );
toCheck = ourList->begin();
while( toCheck != ourList->end() )
{
if( toCheck->second != GR_WAR )
{
if( offCounter == (button - 2) )
{
gList[trgGuild]->SetGuildRelation( tCtr, GR_ALLY );
gList[trgGuild]->TellMembers( 165, gList[tCtr]->Name().c_str() );
gList[tCtr]->TellMembers( 166, gList[trgGuild]->Name().c_str() );
break;
}
else
++offCounter;
}
++tCtr;
++toCheck;
}
break;
case BasePage+14: // Declare peace list
offCounter = tCtr = 0;
ourList = gList[trgGuild]->GuildRelationList();
if( ourList->size() <= (button - 2) )
Menu( s, BasePage + 2, trgGuild );
toCheck = ourList->begin();
while( toCheck != ourList->end() )
{
if( toCheck->second == GR_WAR )
{
if( offCounter == (button - 2) )
{
gList[trgGuild]->SetGuildRelation( tCtr, GR_NEUTRAL );
gList[trgGuild]->TellMembers( 167, gList[tCtr]->Name().c_str() );
gList[tCtr]->TellMembers( 168, gList[trgGuild]->Name().c_str() );
break;
}
else
++offCounter;
}
++tCtr;
++toCheck;
}
break;
case BasePage+15: // List of guilds warring on us
Menu( s, BasePage + 1, trgGuild );
break;
case BasePage+16: // Display recruit information
Menu( s, BasePage + 1, trgGuild );
break;
case BasePage+17: // Display member information
Menu( s, BasePage + 1, trgGuild );
break;
case BasePage+18: // Ally list
Menu( s, BasePage + 1, trgGuild );
break;
case BasePage+19: // Declare Ally list
offCounter = tCtr = 0;
ourList = gList[trgGuild]->GuildRelationList();
toCheck = ourList->begin();
while( toCheck != ourList->end() )
{
if( toCheck->second != GR_ALLY )
{
if( offCounter == (button - 2) )
{
gList[trgGuild]->SetGuildRelation( tCtr, GR_ALLY );
gList[trgGuild]->TellMembers( 169, gList[tCtr]->Name().c_str() );
gList[tCtr]->TellMembers( 170, gList[trgGuild]->Name().c_str() );
break;
}
else
++offCounter;
}
++tCtr;
++toCheck;
}
break;
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void Resign( CSocket *s )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Handles player resigning from guild
//o-----------------------------------------------------------------------------------------------o
void CGuildCollection::Resign( CSocket *s )
{
CChar *mChar = s->CurrcharObj();
SI16 guildnumber = mChar->GetGuildNumber();
if( guildnumber == -1 )
return;
CGuild *nGuild = gList[guildnumber];
if( nGuild == nullptr )
return;
nGuild->RemoveMember( *(s->CurrcharObj()) );
s->sysmessage( 171 );
mChar->SetGuildNumber( -1 );
mChar->SetGuildTitle( "" );
if( nGuild->Master() == mChar->GetSerial() && nGuild->NumMembers() != 0 )
nGuild->CalcMaster();
if( nGuild->NumMembers() == 0 )
{
SERIAL stone = nGuild->Stone();
if( stone != INVALIDSERIAL )
{
CItem *gStone = calcItemObjFromSer( stone );
if( ValidateObject( gStone ) )
gStone->Delete();
}
Erase( guildnumber );
s->sysmessage( 172 );
}
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void Erase( GUILDID toErase )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Erase guild - there are no guild members left
//o-----------------------------------------------------------------------------------------------o
void CGuildCollection::Erase( GUILDID toErase )
{
GUILDLIST::iterator pFind = gList.find( toErase );
if( pFind == gList.end() ) // doesn't exist
return;
CGuild *gErase = pFind->second;
if( gErase == nullptr )
{
gList.erase( pFind );
return;
}
for( size_t iCounter = 0; iCounter < gErase->NumMembers(); ++iCounter )
{
SERIAL iMember = gErase->MemberNumber( iCounter );
CChar *member = calcCharObjFromSer( iMember );
if( ValidateObject( member ) )
member->SetGuildNumber( -1 );
}
for( size_t iC = 0; iC < gErase->NumRecruits(); ++iC )
{
SERIAL iRecruit = gErase->RecruitNumber( iC );
CChar *recruit = calcCharObjFromSer( iRecruit );
if( ValidateObject( recruit ) )
recruit->SetGuildNumber( -1 );
}
delete pFind->second;
gList.erase( pFind );
}
CGuildCollection::~CGuildCollection()
{
GUILDLIST::const_iterator i = gList.begin();
while( i != gList.end() )
{
if( i->second != nullptr )
delete i->second;
++i;
}
gList.clear();
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void PlaceStone( CSocket *s, CItem *deed )
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Handle placement of guildstone from deed, by player
//o-----------------------------------------------------------------------------------------------o
void CGuildCollection::PlaceStone( CSocket *s, CItem *deed )
{
if( s == nullptr || !ValidateObject( deed ) )
return;
CChar *mChar = s->CurrcharObj();
if( !ValidateObject( mChar ) )
return;
if( deed->GetID() == 0x14F0 )
{
if( mChar->GetGuildNumber() != -1 ) // in a guild
{
s->objMessage( 173, deed );
return;
}
GUILDID gNum = NewGuild();
CGuild *nGuild = Guild( gNum );
if( nGuild == nullptr )
{
s->objMessage( 174, deed );
Console.error(strutil::format( "Critical error adding guildstone, memory allocation failed. Attempted by player 0x%X", mChar->GetSerial()) );
return;
}
mChar->SetGuildNumber( gNum );
s->TempInt( gNum );
nGuild->NewMember( (*mChar) );
CItem *stone = Items->CreateItem( nullptr, mChar, 0x0ED5, 1, 0, OT_ITEM );
if( !ValidateObject( stone ) )
{
s->objMessage( 176, deed );
Console.error( strutil::format("Critical error spawning guildstone, no stone made. Attempted by player 0x%X", mChar->GetSerial()) );
return;
}
stone->SetName( Dictionary->GetEntry( 175 ) );
if( mChar->GetID() == 0x0191 || mChar->GetID() == 0x0193 || mChar->GetID() == 0x025E || mChar->GetID() == 0x0260 )
mChar->SetGuildTitle( "Guildmistress" );
else
mChar->SetGuildTitle( "Guildmaster" );
stone->SetLocation( mChar );
nGuild->Webpage( DEFAULTWEBPAGE );
nGuild->Charter( DEFAULTCHARTER );
stone->SetType( IT_GUILDSTONE );
stone->SetTempVar( CITV_MORE, gNum );
stone->SetWipeable( false );
stone->SetDecayable( false );
deed->Delete();
nGuild->Master( (*mChar) );
nGuild->Stone( (*stone) );
TextEntryGump( s, mChar->GetSerial(), 100, 1, 30, 158 );
}
else if( deed->GetID() == 0x1869 )
{
// Transporter stone for guildstone
if( mChar->GetGuildNumber() == -1 ) // not in a guild
{
s->objMessage( "You don't appear to be in a guild", deed ); // You don't appear to be in a guild
return;
}
GUILDID gNum = deed->GetTempVar( CITV_MORE );
CGuild *nGuild = Guild( gNum );
if( nGuild == nullptr )
{
s->objMessage( 174, deed ); // Critical error adding guildstone, please contact a GM!
Console.error(strutil::format( "Critical error adding guildstone, memory allocation failed. Attempted by player 0x%X", mChar->GetSerial()) );
return;
}
CItem *stone = Items->CreateItem( nullptr, mChar, 0x0ED5, 1, 0, OT_ITEM );
if( !ValidateObject( stone ) )
{
s->objMessage( 176, deed ); // Critical error, unable to spawn guildstone, please contact a GM!
Console.error( strutil::format("Critical error spawning guildstone, no stone made. Attempted by player 0x%X", mChar->GetSerial()) );
return;
}
stone->SetName( strutil::format( Dictionary->GetEntry( 101 ), nGuild->Name().c_str() ));
stone->SetLocation( mChar );
stone->SetType( IT_GUILDSTONE );
stone->SetTempVar( CITV_MORE, gNum );
stone->SetWipeable( false );
stone->SetDecayable( false );
deed->Delete();
nGuild->Stone( (*stone) );
}
else
s->sysmessage( 177 );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - bool ResultInCriminal( GUILDID srcGuild, GUILDID trgGuild ) const
//| bool ResultInCriminal( CChar *src, CChar *trg ) const
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Sets/Gets whether action will result in criminal flag based on guild relation
//o-----------------------------------------------------------------------------------------------o
bool CGuildCollection::ResultInCriminal( GUILDID srcGuild, GUILDID trgGuild ) const
{
GUILDRELATION gRel = Compare( srcGuild, trgGuild );
switch( gRel )
{
case GR_WAR:
case GR_SAME:
return false;
case GR_ALLY:
case GR_NEUTRAL:
case GR_UNKNOWN:
case GR_COUNT:
default:
return true;
}
}
bool CGuildCollection::ResultInCriminal( CChar *src, CChar *trg ) const
{
if( !ValidateObject( src ) || !ValidateObject( trg ) )
return false;
return ResultInCriminal( src->GetGuildNumber(), trg->GetGuildNumber() );
}
//o-----------------------------------------------------------------------------------------------o
//| Function - void DisplayTitle( CSocket *s, CChar *src ) const
//o-----------------------------------------------------------------------------------------------o
//| Purpose - Display guild title for player character
//o-----------------------------------------------------------------------------------------------o
void CGuildCollection::DisplayTitle( CSocket *s, CChar *src ) const
{
if( !ValidateObject( src ) || s == nullptr )
return;
GUILDID sGuild = src->GetGuildNumber();
if( sGuild != -1 && src->GetGuildToggle() )
{
std::string title;
CGuild *mGuild = Guild( sGuild );
if( mGuild == nullptr )
return;
auto abbreviation = std::string(mGuild->Abbreviation()) ;
if( abbreviation.empty() ) // 0 length string
abbreviation="none" ;
if( mGuild->Type() != GT_STANDARD )
{
auto guildtype= GTypeNames[mGuild->Type()] ;
if( src->GetGuildTitle().empty() ){
title= strutil::format( "[%s, %s] [%s]", src->GetGuildTitle().c_str(), abbreviation.c_str(), guildtype.c_str() );
}
else{
title = strutil::format( "[%s] [%s]", abbreviation.c_str(), guildtype.c_str() );
}
}
else
{
if( src->GetGuildTitle().empty() ){
title = strutil::format("[%s, %s]", src->GetGuildTitle().c_str(), abbreviation.c_str() );
}
else{
title = strutil::format( "[%s]", abbreviation.c_str() );
}
}
s->objMessage( title, src );
}
}