mirror of
https://github.com/UOX3DevTeam/UOX3
synced 2026-08-13 12:27:04 -04:00
Fixed an issue with an internal movement check that prevented characters from moving in valid map areas in Felucca/Trammel from X 6144 to X 7168 Fixed an issue where .instanceID property was misspelled in 'xgo GM command script, causing characters to be teleported to an out of bounds area where they would no longer be saved (js/commands/targeting/x.js) Added some additional error-checking to .Teleport()/.SetLocation() JS Method to prevent script-accidents from sending characters out of bounds. Updated Poisoning skill to add poison-charges to weapons being poisoned. Charges are consumed when applying poison in combat (js/skill/poisoning.js) Updated combat code to consume poison-charges if a poisoned weapon is used to poison an opponent Updated shoplists for Blacksmiths and Weaponsmiths - they now buy/sell longswords (dfndata/items/shoplist.dfn) Updated MageShopping shoplist for mage vendors - they now buy/sell mass curse scrolls (dfndata/items/shoplist.dfn) Added new Spawn Region DFN tag that can specify which era or eras of UO (Multiple comma-separated entries supported) a given spawn region is valid for. Spawn region not valid for core shard era will be ignored. Syntax: ERAS=UO,T2A,UOR,LBR,AOS,SE,ML,SA,HS,TOL Added new Spawn Region DFN tag that allows using another spawn region as a "parent". All properties of this parent will be inherited except for these, which are ignored: ERAS, NPCLIST, ITEMLIST, NPC and ITEM. Syntax for new tag: GET=# // Inherit a specified spawn region Added spawn region for animal trainer vendor in Vesper stable Added spawn region for fur trader/tanner vendors in The Best Hides of Britain Added spawn region for spinner vendor in The Lord's Clothier's and The Right Fit shops in Britain Added spawn region for tanner NPC to Nujel'm Tannery (and fixed leatherworker spawn region for same area) Added spawn regions for banker NPCs in East Bank of Britain, First Bank of Moonglow, Jhelom Bank and Jeweler, Bank of Skara Brae Added spawn regions for stables, tailor and blacksmith inside Castle British Added spawn regions for mage shops, mage guilds and farm houses in Moonglow Added spawn regions for misc vendors and townfolk in multiple cities Added spawn regions for Fire Island Updated spawn regions for Dagger Isle/Ice Island Added spawn regions for forests and jungles in southern Britannia and on various islands including Bucc's Den, Moonglow, Serpent's Hold, and misc unpopulated islands Added spawn regions for area east of Skara Brae, around Hedge Maze and south of Britain Added spawn regions for wandering healers outside every dungeon entrance in Britannia and Lost Lands Re-integrated ocean spawn regions for ocean creatures (dolphin, walrus, water elemental, sea serpent) from the original community-based spawn file Added reagent spawns in overworld spawn regions in Britannia/Lost Lands Added special reagent spawns in swamp areas Added additional overworld spawn regions in Britannia/Lost Lands Added spawn regions for Khaldun dungeon that spawn some new and some old NPCs: Old: Zombies, skeletons, skeletal mages, skeletal knights, ancient liches New: Cursed (and named) NPCs, shadowfiends, zealots of khaldun (knights/summoners), tentacles of the harrower Updated size and positions of some existing overworld spawn regions Fixed incorrect spawn region size for small island south of Trinsic Added switch/door puzzle functionality in Khaldun dungeon using new switch/door combo script (js/item/dungeons/switch_door_combo.js) Added "smart objects" in Khaldun dungeon that activate when you come close enough (js/item/dungeons/smart_activate_item.js) Added teleport locations within Khaldun dungeon (js/teleport.scp) Added custom AIs to existing NPC spawning in Khaldun dungeon: Ancient Lich (summons other undead, and can turn into one of them for disguise) Added DFN entries for new NPCs spawning in Khaldun dungeon, some with custom AIs: [tentacles_of_the_harrower] -> Tentacles of the Harrower (life steal) [shadowfiend] -> Shadowfiends (seek out and reveal hidden players) [zealot_knight]/[zealot_summoner] -> Zealots of Khaldun (turn into undead on death, male/female variants) [cursed] -> Cursed (male/female variants) [spectralarmor] -> Spectral Armor Added DFN entries for new (named) NPCs spawning in Khaldun dungeon: [lysander_gathenwale] -> Lysander Gathenwale [grimmoch_drummel] -> Grimmoch Drummel [morg_bergen] -> Morg Bergen [tavara_sewel] -> Tavara Sewel Added new NPC DFN entries: [leatherworker] -> alias for male/female leatherworker vendors [mapmaker] -> alias for male/female mapmaker vendors Added new Race DFN entries: [RACE 29] -> Cursed (enemies of RACE 30) [RACE 30] -> Zealots (enemies of RACE 29) Added new book DFN entries for Khaldun journals of Lysander, Tavara and Grimmoch - available as loot from the respective NPCs (dfndata/misc/books.dfn and dfndata/items/misc/books.dfn) Added 25% chance for hit-animations and hit-SFX to play for targets in combat, instead of playing every time - can get very spammy Monsters with actual weapons equipped (like Ophidian Enforcer with Halberd/Bardiche) will now get appropriate combat SFX for hitting with that weapon Updated Healing skill to base cure/resurrection skill requirements on the calculated skill, rather than base skill (js/skill/healing.js) Fixed an issue where healing with bandages and dying in the process would not properly reset the healing-related tags and skills used Updated healing script to show a resurrection confirmation menu for players targeted with bandages for resurrect (js/skill/healing.js) All skill usage states now reset on death, to prevent cases of players being "busy" while trying to use skills that got stuck due to script bugs. The 'regspawn GM command now supports a new parameter called "max". Updated command syntax: 'regspawn # // perform a single respawn cycle in a specific spawn region 'regspawn all // perform a single respawn cycle across all spawn regions 'regspawn max // respawn ALL spawn regions to MAX capacity in one go Added new UOX.INI setting that determines the maximum range at which NPCs can initiate attacks on players/NPCs (the old MAXRANGE=10 setting now instead defines max range at which players can initiate attacks on players/NPCs): MAXNPCAGGRORANGE=10 Optimized performance by significantly reducing the number of line-of-sight checks performed by characters, especially in combat scenarios, or when evaluating potential targets for NPC AIs. The amount of checks done is also affected by the new ini setting for max aggro range. Fixed an issue where both NPC and player characters would instantly drop one hunger level (from 6 to 5) upon creation since hungerrate was not initialized until after first hunger-event Updated character priv property from UI16 to UI32, and added a new flag that determines if fame/karma title is hidden for character: HIDEFAMEKARMATITLE (0x10000) NPCs will no longer aggro other NPCs if the Z difference between them is greater or equal to 20 (i.e. they're on different floors), unless both are using ranged weapons and both are in range Fixed an issue where players could get discounts from shopkeepers even though neither player nor shopkeeper were members of a NPC guild (js/npc/ai/shopkeeper.js) Fixed an issue where the "premium" a player would get when selling items to a shopkeeper in the same NPC guild as them would be 110% extra on top of the item's value, instead of the intended 10% (js/npc/ai/shopkeeper.js) (Thanks, cobrag0318!) Added missing tall straw hat to tailoring crafting scripts (Thanks, Dragon Slayer!) Improved error reporting during compilation of individual scripts being reloaded - will now show more context and line number onCombatEnd JS Event now also triggers when NPCs ignore their target and/or evade during combat Updated 'decorate command to support saving/loading custom tags on items for world templates. These are stored after a @ symbol in the world template, each custom tag separated by a | symbol, and with each custom tag saved using this syntax: key$type$value Updated resource-harvesting scripts to use script-specific global (const) variables, to avoid interference between different scripts (js/server/resource/*) Added new resource-harvesting scripts and added spawn regions for these in fields on farms all over Britannia/Lost Lands cabbages (js/server/resource/cabbages.js) canteloupes (js/server/resource/canteloupes.js) carrots (js/server/resource/carrots.js) garlic (js/server/resource/garlic.js) gourds (js/server/resource/gourds.js) honeydew melons (js/server/resource/honeydewmelon.js) onions (js/server/resource/onions.js) pumpkins (js/server/resource/pumpkins.js) squashes (js/server/resource/squashes.js) turnips (js/server/resource/turnips.js) watermelons (js/server/resource/watermelon.js) Updated CSpawnRegion::FindItemSpotToSpawn() function in cSpawnRegion.cpp to prevent duplicate spawning of exact same item in exact same location Updated sectionid of all potion and scroll aliases to match main item, so they'll get correctly picked up by NPC shopkeepers (dfndata/items/magic/potions.dfn and scrolls.dfn) Specified sectionid for backpacks, so it also gets applied to packs added using the alias [backpack] (dfndata/items/misc/provisions.dfn) Fixed a code issue that prevented players from selling empty containers to NPC shopkeepers willing to buy such containers Fixed an issue where field-spells (wall of stone, poison field, etc) would ignore dynamic/static items that should block these Fixed an issue where field-spells could be cast into houses from the outside by standing next to a wall and targeting self Fixed a War/Peace-mode desync between client and server by having server always notify client (using war-toggle packet) when the "at war" flag is toggled for player character Fixed an issue with hiding skill that wouldn't allow player to hide after having acquired self as target in combat (through spellcasting, for instance) (Thanks, Dragon Slayer!) Fixed an issue where mana/reagents were consumed and skillcheck performed before all spellcast-validations had succeeded, resulting in the occasional loss of reagents/mana when spellcasting was disallowed (code and js/magic/clumsy.js and level1targ.js) Fixed an issue with lack of criminal-flagging for casting of hostile spells scripted in JS (clumsy, magic arrow, feeblemind) vs blue targets (js/magic/clumsy.js and level1targ.js) Fixed some issues with Line-of-Sight checking code that returned incorrect results, which amongst other things affected spellcasting in areas with uneven terrain Fixed some issues with movement code and climbing of ladders, in particular the rope ladder in the 2-story log cabin. Code now sets a "is climbing" flag when character steps onto a rope ladder, and uses that to help resolve some edge cases, and then unsets it when they step off. Renamed section headers of some map-items in DFNs from "locationname" to "locationnamemap" for clarity (example: "britain" to "britainmap") Fixed broken "map wrapping" when sailing to edges of map in Felucca or Trammel Fixed a server crash related to attempts at reading data from invalid map tiles
2208 lines
88 KiB
C++
2208 lines
88 KiB
C++
#include "uox3.h"
|
|
#include "townregion.h"
|
|
#include "cRaces.h"
|
|
#include "cServerDefinitions.h"
|
|
#include "cSpawnRegion.h"
|
|
#include "skills.h"
|
|
#include "speech.h"
|
|
#include "ssection.h"
|
|
#include "CGump.h"
|
|
#include "mapstuff.h"
|
|
#include "scriptc.h"
|
|
#include "CPacketSend.h"
|
|
#include "jail.h"
|
|
#include "Dictionary.h"
|
|
#include "classes.h"
|
|
#include "CJSEngine.h"
|
|
#include "CJSMapping.h"
|
|
#include "StringUtility.hpp"
|
|
// Implementation of town regions
|
|
|
|
const SI08 MAYOR = 0x01;
|
|
//const SI08 ENEMY = 0x02;
|
|
//const SI08 JOINER = 0x03;
|
|
|
|
const UI32 BIT_GUARDED = 0;
|
|
const UI32 BIT_MARK = 1;
|
|
const UI32 BIT_GATE = 2;
|
|
const UI32 BIT_RECALL = 3;
|
|
const UI32 BIT_DISABLED = 5;
|
|
const UI32 BIT_AGGRESSIVE = 6;
|
|
const UI32 BIT_DUNGEON = 7;
|
|
const UI32 BIT_SAFEZONE = 8;
|
|
const UI32 BIT_TELEPORT = 9;
|
|
const UI32 BIT_HOUSING = 10;
|
|
const UI32 BIT_SUBREGION = 11;
|
|
|
|
const RACEID DEFTOWN_RACE = 0;
|
|
const WEATHID DEFTOWN_WEATHER = 255;
|
|
const SI32 DEFTOWN_MUSICLIST = 0;
|
|
const SERIAL DEFTOWN_MAYOR = INVALIDSERIAL;
|
|
const UI16 DEFTOWN_TAXEDRESOURCE = 0x0EED;
|
|
const UI16 DEFTOWN_TAXEDAMOUNT = 0;
|
|
const SI32 DEFTOWN_GOLDRESERVED = 0;
|
|
const SI16 DEFTOWN_GUARDSPURCHASED = 0;
|
|
const UI32 DEFTOWN_RESOURCECOLLECTED = 0;
|
|
const WorldType DEFTOWN_VISUALAPPEARANCE = WRLD_SPRING;
|
|
const SI16 DEFTOWN_HEALTH = 30000;
|
|
const UI32 DEFTOWN_ELECTIONCLOSE = 0;
|
|
const UI32 DEFTOWN_NEXTPOLL = 0;
|
|
const UI32 DEFTOWN_GUARDSPAID = 0;
|
|
const UI32 DEFTOWN_TAXEDMEMBERS = 0;
|
|
const UI08 DEFTOWN_WORLDNUMBER = 0;
|
|
const UI16 DEFTOWN_INSTANCEID = 0;
|
|
const UI16 DEFTOWN_JSSCRIPT = 0xFFFF;
|
|
const UI08 DEFTOWN_FINDBIGORE = 0;
|
|
const UI16 DEFTOWN_NUMGUARDS = 10;
|
|
const UI16 DEFTOWN_PARENTREGION = 0;
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion( UI16 region )
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Constructor for CTownRegion class
|
|
//o------------------------------------------------------------------------------------------------o
|
|
CTownRegion::CTownRegion( UI16 region ) : regionNum( region ), numGuards( DEFTOWN_NUMGUARDS ), parentRegion( DEFTOWN_PARENTREGION ),
|
|
musicList( DEFTOWN_MUSICLIST ), worldNumber( DEFTOWN_WORLDNUMBER ), instanceId( DEFTOWN_INSTANCEID ),
|
|
mayorSerial( DEFTOWN_MAYOR ), race( DEFTOWN_RACE ), weather( DEFTOWN_WEATHER ), goldReserved( DEFTOWN_GOLDRESERVED ),
|
|
visualAppearance( DEFTOWN_VISUALAPPEARANCE ), timeSinceGuardsPaid( DEFTOWN_GUARDSPAID ), timeSinceTaxedMembers( DEFTOWN_TAXEDMEMBERS ),
|
|
timeToElectionClose( DEFTOWN_ELECTIONCLOSE ), timeToNextPoll( DEFTOWN_NEXTPOLL ), guardsPurchased( DEFTOWN_GUARDSPURCHASED ),
|
|
resourceCollected( DEFTOWN_RESOURCECOLLECTED ), taxedResource( DEFTOWN_TAXEDRESOURCE ), taxedAmount( DEFTOWN_TAXEDAMOUNT ),
|
|
health( DEFTOWN_HEALTH ), chanceFindBigOre( DEFTOWN_FINDBIGORE ), jsScript( DEFTOWN_JSSCRIPT )
|
|
{
|
|
priv.reset();
|
|
townMember.resize( 0 );
|
|
alliedTowns.resize( 0 );
|
|
orePreferences.resize( 0 );
|
|
locations.resize( 0 );
|
|
name = Dictionary->GetEntry( 1117 );
|
|
guardowner = Dictionary->GetEntry( 1118 );
|
|
guardList = "guard";
|
|
goodList.clear();
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - ~CTownRegion()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Deconstructor for CTownRegion class
|
|
//o------------------------------------------------------------------------------------------------o
|
|
CTownRegion::~CTownRegion()
|
|
{
|
|
JSEngine->ReleaseObject( IUE_REGION, this );
|
|
|
|
townMember.resize( 0 );
|
|
alliedTowns.resize( 0 );
|
|
orePreferences.resize( 0 );
|
|
locations.resize( 0 );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::Load()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Loads town regions from region world files
|
|
//| Notes - ss is a script section containing all the data!
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::Load( Script *ss )
|
|
{
|
|
size_t location = 0xFFFFFFFF;
|
|
std::string tag;
|
|
std::string data;
|
|
std::string UTag;
|
|
std::string sect = std::string( "TOWNREGION " ) + oldstrutil::number( regionNum );
|
|
if( !ss->IsInSection( sect )) // doesn't exist
|
|
return false;
|
|
|
|
auto target = ss->FindEntry( sect );
|
|
if( target == nullptr )
|
|
return false;
|
|
|
|
for( const auto &sec : target->collection() )
|
|
{
|
|
tag = sec->tag;
|
|
data = sec->data;
|
|
UTag = oldstrutil::upper( tag );
|
|
switch(( UTag.data()[0] ))
|
|
{
|
|
case 'A':
|
|
if( UTag == "ALLYTOWN" )
|
|
{
|
|
alliedTowns.push_back( static_cast<UI08>( std::stoul( data, nullptr, 0 )));
|
|
}
|
|
break;
|
|
case 'E':
|
|
if( UTag == "ELECTIONTIME" )
|
|
{
|
|
timeToElectionClose = static_cast<SI32>( std::stoi( data, nullptr, 0 ));
|
|
}
|
|
break;
|
|
case 'G':
|
|
if( UTag == "GUARDOWNER" )
|
|
{
|
|
guardowner = data;
|
|
}
|
|
else if( UTag == "GUARD" ) // load our purchased guard
|
|
{
|
|
++numGuards;
|
|
}
|
|
else if( UTag == "GUARDSBOUGHT" ) // num guards bought
|
|
{
|
|
guardsPurchased = static_cast<SI16>( std::stoi( data, nullptr, 0 ));
|
|
}
|
|
break;
|
|
case 'H':
|
|
if( UTag == "HEALTH" )
|
|
{
|
|
health = static_cast<SI16>( std::stoi( data, nullptr, 0 ));
|
|
}
|
|
break;
|
|
case 'M':
|
|
if( UTag == "MEMBER" )
|
|
{
|
|
location = townMember.size();
|
|
townMember.resize( location + 1 );
|
|
townMember[location].targVote = INVALIDSERIAL;
|
|
townMember[location].townMember = std::stoul( data, nullptr, 0 );
|
|
}
|
|
else if( UTag == "MAYOR" )
|
|
{
|
|
mayorSerial = std::stoul( data, nullptr, 0 );
|
|
}
|
|
break;
|
|
case 'N':
|
|
if( UTag == "NAME" )
|
|
{
|
|
name = data.substr( 0, 49 );
|
|
}
|
|
else if( UTag == "NUMGUARDS" )
|
|
{
|
|
numGuards = static_cast<UI16>( std::stoul( data, nullptr, 0 ));
|
|
}
|
|
break;
|
|
case 'P':
|
|
if( UTag == "PARENTREGION" )
|
|
{
|
|
if( parentRegion > 0 )
|
|
{
|
|
parentRegion = static_cast<UI16>( std::stoul( data, nullptr, 0 ));
|
|
IsSubRegion( true );
|
|
}
|
|
}
|
|
else if( UTag == "PRIV" )
|
|
{
|
|
// Overwrites privs loaded from regions.dfn, making it impossible to change privs after initial server startup
|
|
// Currently not used for anything, so we disable until we find a better solution.
|
|
//priv = std::bitset<10>( data.toUShort() );
|
|
}
|
|
else if( UTag == "POLLTIME" )
|
|
{
|
|
timeToNextPoll = static_cast<SI32>( std::stoi( data, nullptr, 0 ) == 1 );
|
|
}
|
|
break;
|
|
case 'R':
|
|
if( UTag == "RACE" )
|
|
{
|
|
race = static_cast<UI16>( std::stoul( data, nullptr, 0 ));
|
|
}
|
|
else if( UTag == "RESOURCEAMOUNT" )
|
|
{
|
|
goldReserved = static_cast<SI32>( std::stoi( data, nullptr, 0 ) == 1 );
|
|
}
|
|
else if( UTag == "RESOURCECOLLECTED" )
|
|
{
|
|
resourceCollected = static_cast<SI32>( std::stoi( data, nullptr, 0 ) == 1 );
|
|
}
|
|
break;
|
|
case 'T':
|
|
if( UTag == "TAXEDID" )
|
|
{
|
|
taxedResource = static_cast<UI16>( std::stoul( data, nullptr, 0 ));
|
|
}
|
|
else if( UTag == "TAXEDAMOUNT" )
|
|
{
|
|
taxedAmount = static_cast<UI16>( std::stoul( data, nullptr, 0 ));
|
|
}
|
|
else if( UTag == "TIMET" )
|
|
{
|
|
timeSinceTaxedMembers = static_cast<SI32>( std::stoi( data, nullptr, 0 ) == 1 );
|
|
}
|
|
else if( UTag == "TIMEG" )
|
|
{
|
|
timeSinceGuardsPaid = static_cast<SI32>( std::stoi( data, nullptr, 0 ) == 1 );
|
|
}
|
|
break;
|
|
case 'V':
|
|
if( UTag == "VOTE" && location != 0xFFFFFFFF )
|
|
{
|
|
townMember[location].targVote = std::stoul( data, nullptr, 0 );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::Save()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Saves town region data to worldfiles
|
|
//| Notes - entry is the region #, fp is the file to save in
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::Save( std::ostream &outStream )
|
|
{
|
|
const char newLine = '\n';
|
|
outStream << "[TOWNREGION " + std::to_string( regionNum ) + "]\n{\n";
|
|
outStream << "RACE=" + std::to_string( race ) + newLine;
|
|
outStream << "GUARDOWNER=" + guardowner + newLine;
|
|
outStream << "MAYOR=0x" << std::hex << mayorSerial << std::dec << newLine;
|
|
outStream << "PRIV=" + std::to_string( priv.to_ulong() ) + newLine;
|
|
outStream << "RESOURCEAMOUNT=" + std::to_string( goldReserved ) + newLine;
|
|
outStream << "TAXEDID=0x" << std::hex << taxedResource << std::dec << newLine;
|
|
outStream << "TAXEDAMOUNT=" + std::to_string( taxedAmount ) + newLine;
|
|
outStream << "GUARDSPURCHASED=" + std::to_string( guardsPurchased ) + newLine;
|
|
outStream << "TIMEG=" + std::to_string( timeSinceGuardsPaid ) + newLine;
|
|
outStream << "TIMET=" + std::to_string( timeSinceTaxedMembers ) + newLine;
|
|
outStream << "RESOURCECOLLECTED=" + std::to_string( resourceCollected ) + newLine;
|
|
outStream << "HEALTH=" + std::to_string( health ) + newLine;
|
|
outStream << "ELECTIONTIME=" + std::to_string( timeToElectionClose ) + newLine;
|
|
outStream << "POLLTIME=" + std::to_string( timeToNextPoll ) + newLine;
|
|
outStream << "WORLD=" + std::to_string( worldNumber ) + newLine;
|
|
outStream << "INSTANCEID=" + std::to_string( instanceId ) + newLine;
|
|
outStream << "PARENTREGION=" + std::to_string( parentRegion ) + newLine;
|
|
outStream << "NUMGUARDS=" + std::to_string( numGuards ) + newLine;
|
|
|
|
std::vector<TownPers_st>::const_iterator mIter;
|
|
for( mIter = townMember.begin(); mIter != townMember.end(); ++mIter )
|
|
{
|
|
outStream << "MEMBER=0x" << std::hex << ( *mIter ).townMember << std::dec << newLine;
|
|
outStream << "VOTE=0x" << std::hex << ( *mIter ).targVote << std::dec << newLine;
|
|
}
|
|
std::vector<UI16>::const_iterator aIter;
|
|
for( aIter = alliedTowns.begin(); aIter != alliedTowns.end(); ++aIter )
|
|
{
|
|
outStream << "ALLYTOWN=" << static_cast<UI16>(( *aIter )) << newLine;
|
|
}
|
|
outStream << "}\n\n";
|
|
return true;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::CalcNewMayor()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Calculates new town mayor based on votes
|
|
//| Notes - There has got to be a better way than this hideous O(n^2) algy
|
|
//o------------------------------------------------------------------------------------------------o
|
|
void CTownRegion::CalcNewMayor( void )
|
|
{
|
|
if( townMember.empty() )
|
|
return;
|
|
|
|
// if there are no members, there are no new mayors
|
|
std::vector<SI32> votes;
|
|
votes.resize( townMember.size() );
|
|
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 )
|
|
{
|
|
if( townMember[counter].townMember == townMember[counter2].targVote )
|
|
{
|
|
++votes[counter];
|
|
}
|
|
}
|
|
}
|
|
size_t maxIndex = 0;
|
|
for( size_t indexCounter = 1; indexCounter < votes.size(); ++indexCounter )
|
|
{
|
|
if( votes[indexCounter] > votes[maxIndex] )
|
|
{
|
|
maxIndex = indexCounter;
|
|
}
|
|
}
|
|
// maxIndex is now our new mayor!
|
|
CChar *oldMayor = GetMayor();
|
|
if( ValidateObject( oldMayor ) && mayorSerial == townMember[maxIndex].townMember )
|
|
{
|
|
CSocket *targSock = oldMayor->GetSocket();
|
|
if( targSock != nullptr )
|
|
{
|
|
targSock->SysMessage( 1119 ); // Welcome back for another term, Mr Mayor. // "Mr"?
|
|
}
|
|
// welcome the mayor back for another term
|
|
}
|
|
if( votes[maxIndex] > 0 )
|
|
{
|
|
mayorSerial = townMember[maxIndex].townMember;
|
|
}
|
|
else
|
|
{
|
|
mayorSerial = 0xFFFFFFF;
|
|
}
|
|
|
|
CChar *newMayor = GetMayor();
|
|
if( ValidateObject( oldMayor ))
|
|
{
|
|
oldMayor->SetTownpriv( 1 );
|
|
}
|
|
if( ValidateObject( newMayor ))
|
|
{
|
|
newMayor->SetTownpriv( 2 ); // set mayor priv last
|
|
}
|
|
if( newMayor != oldMayor )
|
|
{
|
|
const bool oldMayorExists = ValidateObject( oldMayor );
|
|
const bool newMayorExists = ValidateObject( newMayor );
|
|
if( !oldMayorExists && newMayorExists )
|
|
{
|
|
TellMembers( 1120, newMayor->GetName().c_str() ); // Your new mayor is %s.
|
|
}
|
|
else if( oldMayorExists && !newMayorExists )
|
|
{
|
|
TellMembers( 1121 ); // Your old mayor has retired and there is no new one.
|
|
}
|
|
else if( oldMayorExists && newMayorExists )
|
|
{
|
|
TellMembers( 1122, oldMayor->GetName().c_str(), newMayor->GetName().c_str() ); // Your old mayor, %s, has retired and your new mayor is %s.
|
|
}
|
|
else
|
|
{
|
|
TellMembers( 1123 ); // There's still no mayor for this town.
|
|
}
|
|
}
|
|
else if( ValidateObject( newMayor ))
|
|
{
|
|
TellMembers( 1124, oldMayor->GetName().c_str() ); // Your old mayor, %s, has stayed on for another term.
|
|
}
|
|
else
|
|
{
|
|
TellMembers( 1123 ); // There's still no mayor for this town.
|
|
}
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetMayor()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Returns the character who is town mayor
|
|
//o------------------------------------------------------------------------------------------------o
|
|
CChar * CTownRegion::GetMayor( void )
|
|
{
|
|
return CalcCharObjFromSer( mayorSerial );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetMayorSerial()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Returns the serial of the character who is town mayor
|
|
//o------------------------------------------------------------------------------------------------o
|
|
SERIAL CTownRegion::GetMayorSerial( void ) const
|
|
{
|
|
return mayorSerial;
|
|
}
|
|
void CTownRegion::SetMayorSerial( SERIAL newValue )
|
|
{
|
|
mayorSerial = newValue;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::AddAsTownMember()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Adds specified character to the town's member list
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::AddAsTownMember( CChar& toAdd )
|
|
{
|
|
if( Races->CompareByRace( toAdd.GetRace(), race ) <= RACE_ENEMY ) // if we're racial enemies
|
|
return false; // we can't have a racial enemy in the town!
|
|
|
|
for( UI32 counter = 0; counter < townMember.size(); ++counter ) // exhaustive error checking
|
|
{
|
|
if( townMember[counter].townMember == toAdd.GetSerial() )
|
|
return false; // already exists in our town!
|
|
}
|
|
townMember.resize( townMember.size() + 1 );
|
|
townMember[townMember.size() - 1].townMember = toAdd.GetSerial();
|
|
townMember[townMember.size() - 1].targVote = INVALIDSERIAL;
|
|
townMember[townMember.size() - 1].PlayerBank = nullptr;
|
|
toAdd.SetTown( regionNum );
|
|
toAdd.SetTownpriv( 1 ); // set as resident
|
|
return true;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::RemoveTownMember()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Removes specified character from the town's member list
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::RemoveTownMember( CChar& toAdd )
|
|
{
|
|
if( toAdd.GetTown() == 0 || toAdd.GetTown() != regionNum )
|
|
return false; // not in our town
|
|
|
|
for( size_t counter = 0; counter < townMember.size(); ++counter )
|
|
{
|
|
if( toAdd.GetSerial() == townMember[counter].townMember )
|
|
{
|
|
RemoveCharacter( counter );
|
|
toAdd.SetTown( 255 ); // don't know what default town is, now it's 255 :>
|
|
toAdd.SetTownpriv( 0 );
|
|
return true;
|
|
}
|
|
}
|
|
return false; // we're not in our town
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::oreSkillComparator()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Sorts list of ore preferences for the town region in descending order based on
|
|
//| minimum skill required to mine said ore
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool oreSkillComparator( OrePref_st o1, OrePref_st o2 )
|
|
{
|
|
if( o1.oreIndex == nullptr )
|
|
return false;
|
|
|
|
if( o2.oreIndex == nullptr )
|
|
return true;
|
|
|
|
return o1.oreIndex->minSkill > o2.oreIndex->minSkill;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::InitFromScript()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Initializes town region from associated script section
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::InitFromScript( CScriptSection *toScan )
|
|
{
|
|
std::string tag;
|
|
std::string data;
|
|
std::string UTag;
|
|
SI32 actgood = -1;
|
|
bool orePrefLoaded = false;
|
|
|
|
// Some default values
|
|
numGuards = 10;
|
|
chanceFindBigOre = 80;
|
|
CanTeleport( true );
|
|
CanPlaceHouse( false );
|
|
|
|
RegLocs_st ourLoc;
|
|
for( const auto &sec : toScan->collection() )
|
|
{
|
|
tag = sec->tag;
|
|
data = sec->data;
|
|
UTag = oldstrutil::upper( tag );
|
|
|
|
switch(( UTag.data()[0] ))
|
|
{
|
|
case 'A':
|
|
if( UTag == "ABWEATH" )
|
|
{
|
|
weather = static_cast<UI08>( std::stoul( data, nullptr, 0 ));
|
|
}
|
|
else if( UTag == "APPEARANCE" )
|
|
{
|
|
visualAppearance = WRLD_COUNT;
|
|
for( WorldType wt = WRLD_SPRING; wt < WRLD_COUNT; wt = static_cast<WorldType>(wt + static_cast<WorldType>( 1 )))
|
|
{
|
|
if( data == WorldTypeNames[wt] )
|
|
{
|
|
visualAppearance = wt;
|
|
break;
|
|
}
|
|
}
|
|
if( visualAppearance == WRLD_COUNT )
|
|
{
|
|
visualAppearance = WRLD_UNKNOWN;
|
|
}
|
|
}
|
|
break;
|
|
case 'B':
|
|
if( UTag == "BUYABLE" )
|
|
{
|
|
if( actgood > - 1 )
|
|
{
|
|
goodList[actgood].buyVal = static_cast<SI32>( std::stoi( data, nullptr, 0 ));
|
|
}
|
|
else
|
|
{
|
|
Console.Error( "regions dfn -> You must write BUYABLE after GOOD <num>!" );
|
|
}
|
|
}
|
|
break;
|
|
case 'C':
|
|
if( UTag == "CHANCEFORBIGORE" )
|
|
{
|
|
chanceFindBigOre =static_cast<UI08>( std::stoul( data, nullptr, 0 ));
|
|
}
|
|
break;
|
|
case 'D':
|
|
if( UTag == "DUNGEON" )
|
|
{
|
|
IsDungeon( std::stoi( data, nullptr, 0 ) == 1 );
|
|
}
|
|
break;
|
|
case 'E':
|
|
if( UTag == "DISABLED" )
|
|
{
|
|
IsDisabled( std::stoi( data, nullptr, 0 ) == 1 );
|
|
}
|
|
else if( UTag == "ESCORTS" )
|
|
{
|
|
// Load the region number in the global array of valid escortable regions
|
|
if( std::stoi( data, nullptr, 0 ) == 1 )
|
|
{
|
|
cwmWorldState->escortRegions.push_back( regionNum );
|
|
}
|
|
}
|
|
break;
|
|
case 'G':
|
|
if( UTag == "GUARDNUM" )
|
|
{
|
|
break;
|
|
}
|
|
else if( UTag == "GUARDLIST" )
|
|
{
|
|
guardList = data;
|
|
}
|
|
else if( UTag == "GUARDOWNER" )
|
|
{
|
|
guardowner = data;
|
|
}
|
|
else if( UTag == "GUARDED" )
|
|
{
|
|
IsGuarded( std::stoi( data, nullptr, 0 ) == 1 );
|
|
}
|
|
else if( UTag == "GATE" )
|
|
{
|
|
CanGate( std::stoi( data, nullptr, 0 ) == 1 );
|
|
}
|
|
else if( UTag == "GOOD" )
|
|
{
|
|
actgood = static_cast<SI32>( std::stoi( data, nullptr, 0 ));
|
|
}
|
|
break;
|
|
case 'H':
|
|
if( UTag == "HOUSING" )
|
|
{
|
|
CanPlaceHouse( std::stoi( data, nullptr, 0 ) == 1 );
|
|
}
|
|
break;
|
|
case 'I':
|
|
if( UTag == "INSTANCEID" )
|
|
{
|
|
instanceId = static_cast<UI16>( std::stoul( data, nullptr, 0 ));
|
|
}
|
|
break;
|
|
case 'M':
|
|
if( UTag == "MUSICLIST" || UTag == "MIDILIST" )
|
|
{
|
|
musicList = static_cast<UI16>( std::stoul( data, nullptr, 0 ));
|
|
}
|
|
else if( UTag == "MAGICDAMAGE" )
|
|
{
|
|
CanCastAggressive( std::stoi( data, nullptr, 0 ) == 1 );
|
|
}
|
|
else if( UTag == "MARK" )
|
|
{
|
|
CanMark( std::stoi( data, nullptr, 0 ) == 1 );
|
|
}
|
|
break;
|
|
case 'N':
|
|
if( UTag == "NAME" )
|
|
{
|
|
name = data;
|
|
actgood = -1; // Loading new region, reset to -1
|
|
}
|
|
break;
|
|
case 'O':
|
|
if( UTag == "OREPREF" )
|
|
{
|
|
std::string numPart;
|
|
std::string oreName;
|
|
OrePref_st toPush;
|
|
data = oldstrutil::simplify( data );
|
|
oreName = oldstrutil::extractSection( data, ",", 0, 0 );
|
|
toPush.oreIndex = Skills->FindOre( oreName );
|
|
if( toPush.oreIndex != nullptr )
|
|
{
|
|
auto csecs = oldstrutil::sections( data, "," );
|
|
if( csecs.size() > 1 )
|
|
{
|
|
// Use chance specified in orepref
|
|
toPush.percentChance = static_cast<UI16>( std::stoul( oldstrutil::trim( oldstrutil::removeTrailing( csecs[1], "//" )), nullptr, 0 ));
|
|
}
|
|
else if( toPush.oreIndex->oreChance > 0 )
|
|
{
|
|
// No chance specified in orepref, use default chance of ore type
|
|
toPush.percentChance = toPush.oreIndex->oreChance;
|
|
}
|
|
else
|
|
{
|
|
// Fallback for older skills.dfn setups
|
|
toPush.percentChance = 1000 / static_cast<UI16>( Skills->GetNumberOfOres() );
|
|
}
|
|
|
|
orePreferences.push_back( toPush );
|
|
orePrefLoaded = true;
|
|
}
|
|
else
|
|
{
|
|
Console.Error( oldstrutil::format( "Invalid ore preference in region %i as %s", regionNum, oreName.c_str() ));
|
|
}
|
|
}
|
|
break;
|
|
case 'P':
|
|
if( UTag == "PARENTREGION" )
|
|
{
|
|
// Region has a parent region! Store reference to parent region...
|
|
parentRegion = static_cast<UI16>( std::stoul( data, nullptr, 0 ));
|
|
|
|
// ...and mark this region as a subregion
|
|
IsSubRegion( true );
|
|
}
|
|
break;
|
|
case 'R':
|
|
if( UTag == "RECALL" )
|
|
{
|
|
CanRecall( std::stoi( data, nullptr, 0 ) == 1 );
|
|
}
|
|
else if( UTag == "RANDOMVALUE" )
|
|
{
|
|
if( actgood > -1 )
|
|
{
|
|
auto ssecs = oldstrutil::sections( data, " " );
|
|
if( ssecs.size() > 1 )
|
|
{
|
|
goodList[actgood].rand1 = std::stoi( oldstrutil::trim( oldstrutil::removeTrailing( ssecs[0], "//" )), nullptr, 0 );
|
|
goodList[actgood].rand2 = std::stoi( oldstrutil::trim( oldstrutil::removeTrailing( ssecs[1], "//" )), nullptr, 0 );
|
|
}
|
|
else
|
|
{
|
|
goodList[actgood].rand1 = static_cast<SI32>( std::stoi( data, nullptr, 0 ));
|
|
goodList[actgood].rand2 = goodList[actgood].rand1;
|
|
}
|
|
if( goodList[actgood].rand2 < goodList[actgood].rand1 )
|
|
{
|
|
Console.Error( oldstrutil::format( " regions dfn -> You must write RANDOMVALUE NUM2[%i] greater than NUM1[%i].", goodList[actgood].rand2, goodList[actgood].rand1 ));
|
|
goodList[actgood].rand2 = goodList[actgood].rand1 = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Console.Error( " regions dfn -> You must write RANDOMVALUE after GOOD <num>!" );
|
|
}
|
|
}
|
|
else if( UTag == "RACE" )
|
|
{
|
|
race = static_cast<UI16>( std::stoul( data, nullptr, 0 ));
|
|
}
|
|
break;
|
|
case 'S':
|
|
if( UTag == "SAFEZONE" )
|
|
{
|
|
IsSafeZone( std::stoi( data, nullptr, 0 ) == 1 );
|
|
}
|
|
else if( UTag == "SELLABLE" )
|
|
{
|
|
if( actgood > - 1 )
|
|
{
|
|
goodList[actgood].sellVal = static_cast<SI32>( std::stoi( data, nullptr, 0 ));
|
|
}
|
|
else
|
|
{
|
|
Console.Error( " regions dfn -> You must write SELLABLE after GOOD <num>!" );
|
|
}
|
|
}
|
|
else if( UTag == "SPAWN" )
|
|
{
|
|
std::string sect = "PREDEFINED_SPAWN " + data;
|
|
CScriptSection *predefSpawn = FileLookup->FindEntry( sect, spawn_def );
|
|
if( predefSpawn == nullptr )
|
|
{
|
|
Console.Warning( oldstrutil::format( "Undefined region spawn %s, check your regions.dfn and spawn.dfn files", data.c_str() ));
|
|
}
|
|
else
|
|
{
|
|
for( UI16 i = 0xFFFF; i > 0; --i )
|
|
{
|
|
if( cwmWorldState->spawnRegions.find( i ) != cwmWorldState->spawnRegions.end() )
|
|
{
|
|
CSpawnRegion *spawnReg = new CSpawnRegion( i );
|
|
cwmWorldState->spawnRegions[i] = spawnReg;
|
|
if( spawnReg != nullptr )
|
|
{
|
|
spawnReg->SetX1( locations[locations.size() - 1].x1 );
|
|
spawnReg->SetY1( locations[locations.size() - 1].y1 );
|
|
spawnReg->SetX2( locations[locations.size() - 1].x2 );
|
|
spawnReg->SetY2( locations[locations.size() - 1].y2 );
|
|
[[maybe_unused]] auto spawnRegResult = spawnReg->Load( predefSpawn );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if( UTag == "SCRIPT" )
|
|
{
|
|
UI16 scriptId = static_cast<UI16>( std::stoul( data, nullptr, 0 ));
|
|
if( scriptId != 0 )
|
|
{
|
|
cScript *toExecute = JSMapping->GetScript( scriptId );
|
|
if( toExecute == nullptr )
|
|
{
|
|
Console.Warning( oldstrutil::format( "SCRIPT tag found with invalid script ID (%s) when loading region data!", oldstrutil::number(scriptId).c_str() ));
|
|
}
|
|
else
|
|
{
|
|
this->AddScriptTrigger( scriptId );
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 'T':
|
|
if( UTag == "TELEPORT" )
|
|
{
|
|
CanTeleport( std::stoi( data, nullptr, 0 ) == 1 );
|
|
}
|
|
break;
|
|
case 'W':
|
|
if( UTag == "WORLD" )
|
|
{
|
|
worldNumber = static_cast<UI08>( std::stoul( data, nullptr, 0 ));
|
|
}
|
|
break;
|
|
case 'X':
|
|
if( UTag == "X1" )
|
|
{
|
|
ourLoc.x1 = static_cast<UI16>( std::stoul( data, nullptr, 0 ));
|
|
}
|
|
else if( UTag == "X2" )
|
|
{
|
|
ourLoc.x2 = static_cast<UI16>( std::stoul( data, nullptr, 0 ));
|
|
}
|
|
break;
|
|
case 'Y':
|
|
if( UTag == "Y1" )
|
|
{
|
|
ourLoc.y1 = static_cast<UI16>( std::stoul( data, nullptr, 0 ));
|
|
}
|
|
else if( UTag == "Y2" )
|
|
{
|
|
ourLoc.y2 = static_cast<UI16>( std::stoul( data, nullptr, 0 ));
|
|
locations.push_back( ourLoc );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// No ore preference tags found for this region, apply default chance to find ores
|
|
if( !orePrefLoaded )
|
|
{
|
|
OrePref_st toLoad;
|
|
size_t numOres = Skills->GetNumberOfOres();
|
|
for( size_t myCounter = 0; myCounter < numOres; ++myCounter )
|
|
{
|
|
toLoad.oreIndex = Skills->GetOre( myCounter );
|
|
toLoad.percentChance = toLoad.oreIndex->oreChance;
|
|
orePreferences.push_back( toLoad );
|
|
}
|
|
}
|
|
// sort orePreferences in order of descending minSkill
|
|
std::sort( orePreferences.begin(), orePreferences.end(), oreSkillComparator );
|
|
return true;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::IsGuarded()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets whether the townregion is protected by guards
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::IsGuarded( void ) const
|
|
{
|
|
return priv.test( BIT_GUARDED );
|
|
}
|
|
void CTownRegion::IsGuarded( bool value )
|
|
{
|
|
priv.set( BIT_GUARDED, value );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::CanPlaceHouse()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets whether the townregion allows player houses
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::CanPlaceHouse( void ) const
|
|
{
|
|
return priv.test( BIT_HOUSING );
|
|
}
|
|
void CTownRegion::CanPlaceHouse( bool value )
|
|
{
|
|
priv.set( BIT_HOUSING, value );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::CanMark()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets whether players can cast the Mark spell in the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::CanMark( void ) const
|
|
{
|
|
return priv.test( BIT_MARK );
|
|
}
|
|
void CTownRegion::CanMark( bool value )
|
|
{
|
|
priv.set( BIT_MARK, value );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::CanGate()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets whether players can cast the Gate spell in the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::CanGate( void ) const
|
|
{
|
|
return priv.test( BIT_GATE );
|
|
}
|
|
void CTownRegion::CanGate( bool value )
|
|
{
|
|
priv.set( BIT_GATE, value );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::CanRecall()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets whether players can cast the Recall spell in the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::CanRecall( void ) const
|
|
{
|
|
return priv.test( BIT_RECALL );
|
|
}
|
|
void CTownRegion::CanRecall( bool value )
|
|
{
|
|
priv.set( BIT_RECALL, value );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::CanCastAggressive()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets whether players can cast Aggressive spells in the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::CanCastAggressive( void ) const
|
|
{
|
|
return priv.test( BIT_AGGRESSIVE );
|
|
}
|
|
void CTownRegion::CanCastAggressive( bool value )
|
|
{
|
|
priv.set( BIT_AGGRESSIVE, value );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::IsSafeZone()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets whether the townregion is considered a safe zone or not
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::IsSafeZone( void ) const
|
|
{
|
|
return priv.test( BIT_SAFEZONE );
|
|
}
|
|
void CTownRegion::IsSafeZone( bool value )
|
|
{
|
|
priv.set( BIT_SAFEZONE, value );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::CanTeleport()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets whether the townregion allows use of the Teleport spell or not
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::CanTeleport( void ) const
|
|
{
|
|
return priv.test( BIT_TELEPORT );
|
|
}
|
|
void CTownRegion::CanTeleport( bool value )
|
|
{
|
|
priv.set( BIT_TELEPORT, value );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetName()
|
|
//| CTownRegion::SetName()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets the name of the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
std::string CTownRegion::GetName( void ) const
|
|
{
|
|
return name;
|
|
}
|
|
void CTownRegion::SetName( std::string toSet )
|
|
{
|
|
name = toSet.substr( 0, 49 );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetOwner()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets the name of the guard owner for the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
std::string CTownRegion::GetOwner( void ) const
|
|
{
|
|
return guardowner;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetWeather()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets the weather in the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
WEATHID CTownRegion::GetWeather( void ) const
|
|
{
|
|
return weather;
|
|
}
|
|
void CTownRegion::SetWeather( WEATHID newValue )
|
|
{
|
|
weather = newValue;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetGoodSell()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets the trade system good sell-value at specified index for the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
SI32 CTownRegion::GetGoodSell( UI08 index ) const
|
|
{
|
|
SI32 rVal = 0;
|
|
std::map<SI32, GoodData_st>::const_iterator gIter = goodList.find( index );
|
|
if( gIter != goodList.end() )
|
|
{
|
|
rVal = gIter->second.sellVal;
|
|
}
|
|
return rVal;
|
|
}
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetGoodBuy()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets the trade system good buy-value at specified index for the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
SI32 CTownRegion::GetGoodBuy( UI08 index ) const
|
|
{
|
|
SI32 rVal = 0;
|
|
std::map<SI32, GoodData_st>::const_iterator gIter = goodList.find( index );
|
|
if( gIter != goodList.end() )
|
|
{
|
|
rVal = gIter->second.buyVal;
|
|
}
|
|
return rVal;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetGoodRnd1()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets minimum random value for trade system good at specified index for the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
SI32 CTownRegion::GetGoodRnd1( UI08 index ) const
|
|
{
|
|
SI32 rVal = 0;
|
|
std::map<SI32, GoodData_st>::const_iterator gIter = goodList.find( index );
|
|
if( gIter != goodList.end() )
|
|
{
|
|
rVal = gIter->second.rand1;
|
|
}
|
|
return rVal;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetGoodRnd2()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets maximum random value for trade system good at specified index for the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
SI32 CTownRegion::GetGoodRnd2( UI08 index ) const
|
|
{
|
|
SI32 rVal = 0;
|
|
std::map<SI32, GoodData_st>::const_iterator gIter = goodList.find( index );
|
|
if( gIter != goodList.end() )
|
|
{
|
|
rVal = gIter->second.rand2;
|
|
}
|
|
return rVal;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetMusicList()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets musicList for the townregion, as originally specified in region DFNs
|
|
//o------------------------------------------------------------------------------------------------o
|
|
UI16 CTownRegion::GetMusicList( void ) const
|
|
{
|
|
return musicList;
|
|
}
|
|
void CTownRegion::SetMusicList( UI16 newValue )
|
|
{
|
|
musicList = newValue;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetRandomGuard()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Spawns and returns a random NPC guard for the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
CChar * CTownRegion::GetRandomGuard( void )
|
|
{
|
|
CChar *ourGuard = Npcs->CreateRandomNPC( guardList );
|
|
ourGuard->SetNPCAiType( AI_GUARD );
|
|
return ourGuard;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::DisplayTownMenu()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Displays town menu for townstone used by the player
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::DisplayTownMenu( CItem *used, CSocket *sock, SI08 flag )
|
|
{
|
|
if( flag == MAYOR )
|
|
{
|
|
SendMayorGump( sock );
|
|
return true;
|
|
}
|
|
CChar *tChar = sock->CurrcharObj();
|
|
if( !IsMemberOfTown( tChar ))
|
|
{
|
|
if( Races->CompareByRace( tChar->GetRace(), race ) <= RACE_ENEMY ) // if we're racial enemies
|
|
{
|
|
if( tChar->GetTown() != 255 )
|
|
{
|
|
SendEnemyGump( sock );
|
|
}
|
|
else
|
|
{
|
|
sock->SysMessage( 1125 ); // ou can not join this town!
|
|
}
|
|
}
|
|
else if( tChar->GetTown() != 255 ) // another town person
|
|
{
|
|
if( tChar->GetTown() == regionNum || tChar->GetTown() == 0 ) // they think we're in this region!!!
|
|
{
|
|
if( !AddAsTownMember(( *tChar )))
|
|
{
|
|
sock->SysMessage( 1126 ); // An error occurred joining you to your rightful town, please call a GM!
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
DisplayTownMenu( used, sock, flag );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SendBasicInfo( sock );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SendPotentialMember( sock );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SendDefaultGump( sock );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::IsMemberOfTown()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Checks whether a specific player is member of the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::IsMemberOfTown( CChar *player ) const
|
|
{
|
|
if( !ValidateObject( player ))
|
|
return false;
|
|
|
|
for( size_t counter = 0; counter < townMember.size(); ++counter )
|
|
{
|
|
if( townMember[counter].townMember == player->GetSerial() )
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::SendEnemyGump()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Sends Gump menu to client with a list of the townregion's enemies
|
|
//o------------------------------------------------------------------------------------------------o
|
|
void CTownRegion::SendEnemyGump( CSocket *sock )
|
|
{
|
|
CPSendGumpMenu toSend;
|
|
toSend.UserId( INVALIDSERIAL );
|
|
toSend.GumpId( 3 );
|
|
|
|
toSend.addCommand( "page 0" );
|
|
toSend.addCommand( oldstrutil::format( "resizepic 0 0 %u 320 340", cwmWorldState->ServerData()->BackgroundPic() ));
|
|
toSend.addCommand( oldstrutil::format( "button 280 10 %u %i 1 0 1", cwmWorldState->ServerData()->ButtonCancel(), cwmWorldState->ServerData()->ButtonCancel() + 1 )); //OKAY
|
|
toSend.addCommand( oldstrutil::format( "text 70 10 %u 0", cwmWorldState->ServerData()->TitleColour() )); //text <Spaces from Left> <Space from top> <Length, Color?> <# in order>
|
|
toSend.addCommand( "page 1" );
|
|
|
|
toSend.addText( "Enemy" );
|
|
toSend.addCommand( "gumppic 25 50 1141" ); // town name
|
|
toSend.addCommand( oldstrutil::format( "text 35 51 %u 1", cwmWorldState->ServerData()->RightTextColour() )); // town name
|
|
toSend.addCommand( oldstrutil::format( "text 25 71 %u 2", cwmWorldState->ServerData()->RightTextColour() )); // population
|
|
toSend.addCommand( oldstrutil::format( "text 55 111 %u 3", cwmWorldState->ServerData()->RightTextColour() )); // Seize townstone
|
|
toSend.addCommand( oldstrutil::format( "text 55 131 %u 4", cwmWorldState->ServerData()->RightTextColour() )); // Destroy townstone
|
|
|
|
toSend.addCommand( oldstrutil::format( "button 25 111 %u %i 1 0 61", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1 )); // seize townstone
|
|
toSend.addCommand( oldstrutil::format( "button 25 131 %u %i 1 0 62", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1 )); // destroy townstone
|
|
toSend.addText( oldstrutil::format( "%s (%s)", name.c_str(), Races->Name( race ).c_str() ));
|
|
toSend.addText( oldstrutil::format( "Population %i", GetPopulation() ));
|
|
toSend.addText( "Seize Townstone" );
|
|
toSend.addText( "Attack Townstone" );
|
|
|
|
toSend.Finalize();
|
|
sock->Send( &toSend );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::SendBasicInfo()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Sends Gump menu to client with basic townstone gump menu
|
|
//o------------------------------------------------------------------------------------------------o
|
|
void CTownRegion::SendBasicInfo( CSocket *sock )
|
|
{
|
|
CGumpDisplay BasicGump( sock );
|
|
BasicGump.SetTitle( "Basic Townstone gump" );
|
|
BasicGump.Send( 4, false, INVALIDSERIAL );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::SendPotentialMember()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Sends Gump menu to client of a potential townregion member
|
|
//o------------------------------------------------------------------------------------------------o
|
|
void CTownRegion::SendPotentialMember( CSocket *sock )
|
|
{
|
|
UnicodeTypes sLang = sock->Language();
|
|
CPSendGumpMenu toSend;
|
|
toSend.UserId( INVALIDSERIAL );
|
|
toSend.GumpId( 3 );
|
|
|
|
toSend.addCommand( "page 0" );
|
|
toSend.addCommand( oldstrutil::format( "resizepic 0 0 %u 320 340", cwmWorldState->ServerData()->BackgroundPic() ));
|
|
toSend.addCommand( oldstrutil::format( "button 280 10 %u %i 1 0 1", cwmWorldState->ServerData()->ButtonCancel(), cwmWorldState->ServerData()->ButtonCancel() + 1 )); //OKAY
|
|
toSend.addCommand( oldstrutil::format( "text 70 10 %u 0", cwmWorldState->ServerData()->TitleColour() )); //text <Spaces from Left> <Space from top> <Length, Color?> <# in order>
|
|
toSend.addCommand( "page 1" );
|
|
|
|
toSend.addText( "Outsider" ); // our title
|
|
toSend.addCommand( "gumppic 25 50 1141" ); // town name
|
|
toSend.addCommand( oldstrutil::format( "text 35 51 %u 1", cwmWorldState->ServerData()->RightTextColour() )); // town name
|
|
toSend.addCommand( oldstrutil::format( "text 25 71 %u 2", cwmWorldState->ServerData()->RightTextColour() )); // population
|
|
toSend.addCommand( oldstrutil::format( "text 55 91 %u 3", cwmWorldState->ServerData()->RightTextColour() )); // join town
|
|
toSend.addCommand( oldstrutil::format( "text 55 111 %u 4", cwmWorldState->ServerData()->RightTextColour() )); // view taxes (to help make decisions about joining?)
|
|
|
|
toSend.addCommand( oldstrutil::format( "button 25 91 %u %i 1 0 41", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1 )); // leave town
|
|
toSend.addCommand( oldstrutil::format( "button 25 111 %u %i 1 0 3", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1 )); // view taxes
|
|
|
|
toSend.addText( oldstrutil::format( "%s (%s)", name.c_str(), Races->Name( race ).c_str() ));
|
|
|
|
toSend.addText( oldstrutil::format(Dictionary->GetEntry( 1127, sLang ), GetPopulation() ));
|
|
toSend.addText( Dictionary->GetEntry( 1128, sLang ));
|
|
toSend.addText( Dictionary->GetEntry( 1129, sLang ));
|
|
|
|
toSend.Finalize();
|
|
sock->Send( &toSend );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::SendMayorGump()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Sends Gump menu to client with townregion mayor info and functions
|
|
//o------------------------------------------------------------------------------------------------o
|
|
void CTownRegion::SendMayorGump( CSocket *sock )
|
|
{
|
|
UnicodeTypes sLang = sock->Language();
|
|
CPSendGumpMenu toSend;
|
|
toSend.UserId( INVALIDSERIAL );
|
|
toSend.GumpId( 3 );
|
|
|
|
toSend.addCommand( "page 0" );
|
|
toSend.addCommand( oldstrutil::format( "resizepic 0 0 %u 320 340", cwmWorldState->ServerData()->BackgroundPic() ));
|
|
toSend.addCommand( oldstrutil::format( "button 280 10 %u %i 1 0 1", cwmWorldState->ServerData()->ButtonCancel(), cwmWorldState->ServerData()->ButtonCancel() + 1 )); //OKAY
|
|
toSend.addCommand( oldstrutil::format( "text 70 10 %u 0", cwmWorldState->ServerData()->TitleColour() )); //text <Spaces from Left> <Space from top> <Length, Color?> <# in order>
|
|
toSend.addCommand( "page 1" );
|
|
|
|
toSend.addText( "Mayor Controls" ); // our title
|
|
|
|
toSend.addCommand( "gumppic 25 50 1141" ); // town name
|
|
toSend.addCommand( "gumppic 25 260 1141" );
|
|
toSend.addCommand( oldstrutil::format( "text 35 51 %u 1", cwmWorldState->ServerData()->RightTextColour() )); // town name
|
|
toSend.addCommand( oldstrutil::format( "text 25 71 %u 2", cwmWorldState->ServerData()->RightTextColour() )); // population
|
|
toSend.addCommand( oldstrutil::format( "text 55 91 %u 3", cwmWorldState->ServerData()->RightTextColour() )); // set taxes
|
|
toSend.addCommand( oldstrutil::format( "text 55 280 %u 4", cwmWorldState->ServerData()->RightTextColour() )); // return to main menu
|
|
toSend.addCommand( oldstrutil::format( "text 55 111 %u 5", cwmWorldState->ServerData()->RightTextColour() )); // list town members
|
|
toSend.addCommand( oldstrutil::format( "text 55 131 %u 6", cwmWorldState->ServerData()->RightTextColour() )); // force early election
|
|
toSend.addCommand( oldstrutil::format( "text 55 151 %u 7", cwmWorldState->ServerData()->RightTextColour() )); // purchase more guards
|
|
toSend.addCommand( oldstrutil::format( "text 55 171 %u 8", cwmWorldState->ServerData()->RightTextColour() )); // fire a guard
|
|
toSend.addCommand( oldstrutil::format( "text 55 261 %u 9", cwmWorldState->ServerData()->RightTextColour() )); // treasury amount
|
|
toSend.addCommand( oldstrutil::format( "text 55 191 %u 10", cwmWorldState->ServerData()->RightTextColour() )); // make ally
|
|
|
|
toSend.addCommand( oldstrutil::format( "button 25 91 %u %i 1 0 21", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1 )); // set taxes
|
|
toSend.addCommand( oldstrutil::format( "button 25 111 %u %i 1 0 22", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1 )); // list town members
|
|
toSend.addCommand( oldstrutil::format( "button 25 131 %u %i 1 0 23", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1 )); // force early election
|
|
toSend.addCommand( oldstrutil::format( "button 25 151 %u %i 1 0 24", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1 )); // purchase more guards
|
|
toSend.addCommand( oldstrutil::format( "button 25 171 %u %i 1 0 25", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1 )); // fire a guard
|
|
toSend.addCommand( oldstrutil::format( "button 25 280 %u %i 1 0 40", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1 )); // return to main menu
|
|
toSend.addCommand( oldstrutil::format( "button 25 191 %u %i 1 0 26", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1 )); // make ally of other town
|
|
|
|
toSend.addText( oldstrutil::format( "%s (%s)", name.c_str(), Races->Name( race ).c_str() ));
|
|
toSend.addText( oldstrutil::format( Dictionary->GetEntry( 1130, sLang ), GetPopulation() ));
|
|
toSend.addText( Dictionary->GetEntry( 1131, sLang ));
|
|
toSend.addText( Dictionary->GetEntry( 1132, sLang ));
|
|
toSend.addText( Dictionary->GetEntry( 1133, sLang ));
|
|
toSend.addText( Dictionary->GetEntry( 1134, sLang ));
|
|
toSend.addText( Dictionary->GetEntry( 1135, sLang ));
|
|
toSend.addText( Dictionary->GetEntry( 1136, sLang ));
|
|
toSend.addText( oldstrutil::format( Dictionary->GetEntry( 1137, sLang ), goldReserved ));
|
|
toSend.addText( Dictionary->GetEntry( 1138, sLang ));
|
|
|
|
toSend.Finalize();
|
|
sock->Send( &toSend );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::SendDefaultGump()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Sends default townregion gump menu to client
|
|
//o------------------------------------------------------------------------------------------------o
|
|
void CTownRegion::SendDefaultGump( CSocket *sock )
|
|
{
|
|
CPSendGumpMenu toSend;
|
|
toSend.UserId( INVALIDSERIAL );
|
|
toSend.GumpId( 3 );
|
|
|
|
toSend.addCommand( "page 0" );
|
|
toSend.addCommand( oldstrutil::format( "resizepic 0 0 %u 320 340", cwmWorldState->ServerData()->BackgroundPic() ));
|
|
toSend.addCommand( oldstrutil::format( "button 280 10 %u %i 1 0 1", cwmWorldState->ServerData()->ButtonCancel(), cwmWorldState->ServerData()->ButtonCancel() + 1 )); //OKAY
|
|
toSend.addCommand( oldstrutil::format( "text 70 10 %u 0", cwmWorldState->ServerData()->TitleColour() )); //text <Spaces from Left> <Space from top> <Length, Color?> <# in order>
|
|
toSend.addCommand( "page 1" );
|
|
|
|
toSend.addText( "Generic View" ); // our title
|
|
toSend.addCommand( "gumppic 25 50 1141" ); // town name
|
|
toSend.addCommand( oldstrutil::format( "text 35 51 %u 1", cwmWorldState->ServerData()->RightTextColour() )); // town name
|
|
toSend.addCommand( oldstrutil::format( "text 25 71 %u 2", cwmWorldState->ServerData()->RightTextColour() )); // population
|
|
toSend.addCommand( oldstrutil::format( "text 55 91 %u 3", cwmWorldState->ServerData()->RightTextColour() )); // leave town
|
|
toSend.addCommand( oldstrutil::format( "text 55 111 %u 4", cwmWorldState->ServerData()->RightTextColour() )); // view taxes
|
|
toSend.addCommand( oldstrutil::format( "text 55 131 %u 5", cwmWorldState->ServerData()->RightTextColour() )); // toggle town title on/off
|
|
toSend.addCommand( oldstrutil::format( "text 55 151 %u 6", cwmWorldState->ServerData()->RightTextColour() )); // vote for mayor
|
|
toSend.addCommand( oldstrutil::format( "text 55 171 %u 7", cwmWorldState->ServerData()->RightTextColour() )); // donate resource
|
|
toSend.addCommand( oldstrutil::format( "tilepic 205 171 %u", GetResourceId() )); // picture of the resource
|
|
toSend.addCommand( oldstrutil::format( "text 55 191 %u 8", cwmWorldState->ServerData()->RightTextColour() )); // view budget
|
|
toSend.addCommand( oldstrutil::format( "text 55 211 %u 9", cwmWorldState->ServerData()->RightTextColour() )); // view allied towns
|
|
toSend.addCommand( oldstrutil::format( "text 55 231 %u 10", cwmWorldState->ServerData()->RightTextColour() )); // view enemy towns
|
|
|
|
toSend.addCommand( oldstrutil::format( "button 25 91 %u %i 1 0 2", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1 )); // leave town
|
|
toSend.addCommand( oldstrutil::format( "button 25 111 %u %i 1 0 3", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1 )); // view taxes
|
|
toSend.addCommand( oldstrutil::format( "button 25 131 %u %i 1 0 4", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1 )); // toggle title
|
|
toSend.addCommand( oldstrutil::format( "button 25 151 %u %i 1 0 5", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1 )); // vote for mayor
|
|
toSend.addCommand( oldstrutil::format( "button 25 171 %u %i 1 0 6", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1 )); // donate gold
|
|
toSend.addCommand( oldstrutil::format( "button 25 191 %u %i 1 0 7", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1 )); // view budget
|
|
toSend.addCommand( oldstrutil::format( "button 25 211 %u %i 1 0 8", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1 )); // view allied towns
|
|
toSend.addCommand( oldstrutil::format( "button 25 231 %u %i 1 0 9", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1 )); // view enemy towns
|
|
|
|
CChar *mChar = sock->CurrcharObj();
|
|
UnicodeTypes sLang = sock->Language();
|
|
toSend.addText( oldstrutil::format( "%s (%s)", name.c_str(), Races->Name( race ).c_str() ));
|
|
toSend.addText( oldstrutil::format( Dictionary->GetEntry( 1139, sLang ), GetPopulation() ));
|
|
toSend.addText( Dictionary->GetEntry( 1140, sLang ));
|
|
toSend.addText( Dictionary->GetEntry( 1141, sLang ));
|
|
toSend.addText( oldstrutil::format(Dictionary->GetEntry( 1142, sLang ), mChar->GetTownTitle()?"Off":"On" ));
|
|
toSend.addText( Dictionary->GetEntry( 1143, sLang ));
|
|
toSend.addText( Dictionary->GetEntry( 1144, sLang ));
|
|
toSend.addText( Dictionary->GetEntry( 1145, sLang ));
|
|
toSend.addText( Dictionary->GetEntry( 1146, sLang ));
|
|
toSend.addText( Dictionary->GetEntry( 1147, sLang ));
|
|
|
|
if( mChar->GetTownPriv() == 2 || mChar->IsGM() ) // if we've got a mayor (remove isGM check!)
|
|
{
|
|
toSend.addCommand( oldstrutil::format( "button 25 281 %u %i 1 0 20", cwmWorldState->ServerData()->ButtonRight(), cwmWorldState->ServerData()->ButtonRight() + 1 ));
|
|
toSend.addCommand( oldstrutil::format( "text 55 281 %u 11", cwmWorldState->ServerData()->LeftTextColour() ));
|
|
toSend.addText( Dictionary->GetEntry( 1148, sLang ));
|
|
}
|
|
toSend.Finalize();
|
|
sock->Send( &toSend );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetPopulation()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets population of townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
size_t CTownRegion::GetPopulation( void ) const
|
|
{
|
|
return townMember.size();
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::DisplayTownMembers()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets population of townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
void CTownRegion::DisplayTownMembers( CSocket *sock )
|
|
{
|
|
CGumpDisplay townListing( sock, 300, 300 );
|
|
townListing.SetTitle( Dictionary->GetEntry( 1149, sock->Language() ));
|
|
CChar *sChar = sock->CurrcharObj();
|
|
for( size_t counter = 0; counter < townMember.size(); ++counter )
|
|
{
|
|
CChar *townChar = CalcCharObjFromSer( townMember[counter].townMember );
|
|
if( ValidateObject( townChar ))
|
|
{
|
|
if( sChar->IsGM() )
|
|
{
|
|
townListing.AddData( townChar->GetName(), townChar->GetSerial(), 3 );
|
|
}
|
|
else
|
|
{
|
|
townListing.AddData( townChar->GetName(), " " ); // don't want them to know the serial
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RemoveCharacter( counter );
|
|
--counter;
|
|
}
|
|
}
|
|
townListing.Send( 4, false, INVALIDSERIAL );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetTownMemberSerials()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Returns a comma-separated string of town member serials
|
|
//o------------------------------------------------------------------------------------------------o
|
|
std::string CTownRegion::GetTownMemberSerials( void ) const
|
|
{
|
|
std::string townMemberSerials;
|
|
for( size_t counter = 0; counter < townMember.size(); ++counter )
|
|
{
|
|
CChar const * townMemberChar = CalcCharObjFromSer( townMember[counter].townMember );
|
|
if( ValidateObject( townMemberChar ))
|
|
{
|
|
if( townMemberSerials.empty() )
|
|
{
|
|
townMemberSerials += std::to_string( townMember[counter].townMember );
|
|
}
|
|
else
|
|
{
|
|
townMemberSerials += std::string( "," ) + std::to_string(townMember[counter].townMember );
|
|
}
|
|
}
|
|
}
|
|
return townMemberSerials;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetTownMembers()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Returns a comma-separated string of town member serials
|
|
//o------------------------------------------------------------------------------------------------o
|
|
std::vector<CTownRegion::TownPers_st> CTownRegion::GetTownMembers( void ) const
|
|
{
|
|
return townMember;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::VoteForMayor()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Submits player's vote for mayor
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::VoteForMayor( CSocket *sock )
|
|
{
|
|
SERIAL serial = sock->GetDWord( 7 );
|
|
CChar *srcChar = sock->CurrcharObj();
|
|
CChar *target = CalcCharObjFromSer( serial );
|
|
if( ValidateObject( target ))
|
|
{
|
|
if( !IsMemberOfTown( target )) // he's not in our town!
|
|
{
|
|
sock->SysMessage( 1150 ); // The person you have voted for is not of your town.
|
|
return false;
|
|
}
|
|
SERIAL serialPos = FindPositionOf(( *srcChar ));
|
|
if( serialPos == INVALIDSERIAL )
|
|
{
|
|
sock->SysMessage( 1151 ); // An error occurred finding you in the town roster!
|
|
return false;
|
|
}
|
|
if( townMember[serialPos].targVote != INVALIDSERIAL )
|
|
{
|
|
sock->SysMessage( 1152 ); // You have already voted in this election!
|
|
return false;
|
|
}
|
|
townMember[serialPos].targVote = target->GetSerial();
|
|
sock->SysMessage( 1153 ); // Thank you for your vote in this election!
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
sock->SysMessage( 1154 ); // That is not a valid person!
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::FindPositionOf()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Find position of specified player in townregion's member list
|
|
//o------------------------------------------------------------------------------------------------o
|
|
SERIAL CTownRegion::FindPositionOf( CChar& toAdd )
|
|
{
|
|
for( SERIAL counter = 0; counter < townMember.size(); ++counter )
|
|
{
|
|
if( townMember[counter].townMember == toAdd.GetSerial() )
|
|
return counter;
|
|
}
|
|
return INVALIDSERIAL;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetResourceId()
|
|
//| CTownRegion::SetResourceId()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets ID of resource taxed in townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
UI16 CTownRegion::GetResourceId( void ) const
|
|
{
|
|
return taxedResource;
|
|
}
|
|
void CTownRegion::SetResourceId( UI16 resId )
|
|
{
|
|
taxedResource = resId;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::DonateResource()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Register player's resource donation for townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::DonateResource( CSocket *s, SI32 amount )
|
|
{
|
|
goldReserved += amount;
|
|
CChar *tChar = s->CurrcharObj();
|
|
if( amount > 1000 )
|
|
{
|
|
s->SysMessage( 1155, tChar->GetName().c_str() ); // Thank you most kindly %s for your most generous donation!
|
|
}
|
|
else if( amount > 750 )
|
|
{
|
|
s->SysMessage( 1156, tChar->GetName().c_str() ); // Thank you %s for your significant contribution!
|
|
}
|
|
else if( amount > 500 )
|
|
{
|
|
s->SysMessage( 1157, tChar->GetName().c_str() ); // Thank you %s for a generous donation!
|
|
}
|
|
else if( amount > 250 )
|
|
{
|
|
s->SysMessage( 1158, tChar->GetName().c_str() ); // Thank you %s for your donation.
|
|
}
|
|
else
|
|
{
|
|
s->SysMessage( 1159, tChar->GetName().c_str() ); // =Thank you %s for your pitiful donation.
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::PurchaseGuard()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Purchase a new town guard for the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::PurchaseGuard( CSocket *sock, UI08 number )
|
|
{
|
|
if( number * 10000 < goldReserved ) // if we don't have the cash
|
|
{
|
|
sock->SysMessage( 1160 ); // You cannot afford that many guards!
|
|
return false;
|
|
}
|
|
|
|
goldReserved -= ( number * 10000 );
|
|
for( UI08 counter = 0; counter < number; ++counter )
|
|
{
|
|
++numGuards;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::ViewBudget()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - View townregion's budget for guards
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::ViewBudget( CSocket *sock )
|
|
{
|
|
UnicodeTypes sLang = sock->Language();
|
|
CGumpDisplay Budget( sock, 300, 300 );
|
|
Budget.SetTitle( Dictionary->GetEntry( 1161, sLang )); // Budget
|
|
Budget.AddData( Dictionary->GetEntry( 1162, sLang ), guardsPurchased ); // Guards Bought
|
|
Budget.AddData( Dictionary->GetEntry( 1163, sLang ), numGuards ); // Guards Total
|
|
Budget.AddData( Dictionary->GetEntry( 1164, sLang ), numGuards * 20 ); // Guard Upkeep
|
|
Budget.Send( 4, false, INVALIDSERIAL );
|
|
|
|
return true;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::PeriodicCheck()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Perform periodic check of townregion related functions
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::PeriodicCheck( void )
|
|
{
|
|
time_t now;
|
|
time( &now );
|
|
if( difftime( now, timeSinceTaxedMembers ) >= cwmWorldState->ServerData()->TownTaxPeriod() )
|
|
{
|
|
for( size_t memberCounter = 0; memberCounter < townMember.size(); ++memberCounter )
|
|
{
|
|
CChar *townMem = CalcCharObjFromSer( townMember[memberCounter].townMember );
|
|
if( ValidateObject( townMem ))
|
|
{
|
|
UI16 resourceId = GetResourceId();
|
|
UI32 numResources = GetItemAmount( townMem, resourceId );
|
|
|
|
if( taxedAmount > numResources )
|
|
{
|
|
UI32 bankAmount = GetBankCount( townMem, resourceId, 0, 0 );
|
|
if( taxedAmount > ( numResources + bankAmount ))
|
|
{
|
|
JailSys->JailPlayer( townMem, 900 );
|
|
}
|
|
else
|
|
{
|
|
DeleteItemAmount( townMem, numResources, resourceId );
|
|
DeleteBankItem( townMem, bankAmount - numResources, resourceId );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DeleteItemAmount( townMem, taxedAmount, resourceId );
|
|
resourceCollected += taxedAmount;
|
|
}
|
|
}
|
|
}
|
|
timeSinceTaxedMembers = static_cast<SI32>( now );
|
|
}
|
|
if( difftime( now, timeSinceGuardsPaid ) >= cwmWorldState->ServerData()->TownGuardPayment() ) // init to 1000 seconds
|
|
{
|
|
if( goldReserved < static_cast<SI32>(( 20 * numGuards )))
|
|
{
|
|
// insufficient resources
|
|
bool enoughGuards = false;
|
|
while( !enoughGuards )
|
|
{
|
|
--numGuards;
|
|
enoughGuards = ( goldReserved >= static_cast<SI32>(( 20 * numGuards )));
|
|
}
|
|
}
|
|
goldReserved -= 20 * numGuards;
|
|
timeSinceGuardsPaid = static_cast<SI32>( now );
|
|
}
|
|
|
|
if( now > timeToNextPoll && !townMember.empty() )
|
|
{
|
|
TellMembers( 1165 ); // Time to head to the polling booths again folks, vote for your mayor today!
|
|
for( size_t counter = 0; counter < townMember.size(); ++counter )
|
|
{
|
|
townMember[counter].targVote = INVALIDSERIAL;
|
|
}
|
|
timeToElectionClose = static_cast<SI32>( now ) + cwmWorldState->ServerData()->TownNumSecsPollOpen(); // 2 days polls are open
|
|
timeToNextPoll = timeToElectionClose + cwmWorldState->ServerData()->TownNumSecsAsMayor(); // secs as mayor over the top of the end of the poll
|
|
CChar *mayor = GetMayor();
|
|
if( ValidateObject( mayor ))
|
|
{
|
|
mayor->SetTownpriv( 1 ); // mayor becomes a basic member again, so he can't do anything while the poll is occuring :>
|
|
}
|
|
}
|
|
|
|
if( now > timeToElectionClose && !townMember.empty() ) // election finished
|
|
{
|
|
TellMembers( 1166 ); // The voting has finished, thank you for your participation!
|
|
CalcNewMayor();
|
|
timeToElectionClose = timeToNextPoll + 1000; // just so long as it's after the next election
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetAppearance()
|
|
//| CTownRegion::SetAppearance()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets visual appearance (season) of townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
WorldType CTownRegion::GetAppearance( void ) const
|
|
{
|
|
return visualAppearance;
|
|
}
|
|
void CTownRegion::SetAppearance( WorldType worldType )
|
|
{
|
|
visualAppearance = worldType;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::ViewTaxes()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Send Gump menu with information about townregion's taxes
|
|
//o------------------------------------------------------------------------------------------------o
|
|
void CTownRegion::ViewTaxes( CSocket *sock )
|
|
{
|
|
CPSendGumpMenu toSend;
|
|
toSend.UserId( INVALIDSERIAL );
|
|
toSend.GumpId( 3 );
|
|
|
|
toSend.addCommand( "page 0" );
|
|
toSend.addCommand( oldstrutil::format( "resizepic 0 0 %u 320 340", cwmWorldState->ServerData()->BackgroundPic() ));
|
|
toSend.addCommand( oldstrutil::format( "button 280 10 %u %i 1 0 1", cwmWorldState->ServerData()->ButtonCancel(), cwmWorldState->ServerData()->ButtonCancel() + 1 )); //OKAY
|
|
toSend.addCommand( oldstrutil::format( "text 70 10 %u 0", cwmWorldState->ServerData()->TitleColour() )); //text <Spaces from Left> <Space from top> <Length, Color?> <# in order>
|
|
toSend.addCommand( "page 1" );
|
|
|
|
toSend.addText( "Taxes" ); // our title
|
|
toSend.addCommand( "gumppic 25 50 1141" ); // town name
|
|
toSend.addCommand( oldstrutil::format( "text 35 51 %u 1", cwmWorldState->ServerData()->RightTextColour() )); // town name
|
|
toSend.addCommand( oldstrutil::format( "text 35 71 %u 2", cwmWorldState->ServerData()->RightTextColour() )); // population
|
|
toSend.addCommand( oldstrutil::format( "text 35 111 %u 3", cwmWorldState->ServerData()->RightTextColour() )); // # of resources
|
|
toSend.addCommand( oldstrutil::format( "tilepic 5 111 %u", GetResourceId() )); // picture of the resource
|
|
|
|
toSend.addText( oldstrutil::format( "%s (%s)", name.c_str(), Races->Name( race ).c_str() ));
|
|
toSend.addText( oldstrutil::format( "Population %i", GetPopulation() ));
|
|
CTile& tile = Map->SeekTile( GetResourceId() );
|
|
toSend.addText( oldstrutil::format( "%i %ss", taxedAmount, tile.Name().c_str() ));
|
|
toSend.Finalize();
|
|
sock->Send( &toSend );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetHealth()
|
|
//| vCTownRegion::SetHealth()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets the health of townstone in this townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
SI16 CTownRegion::GetHealth( void ) const
|
|
{
|
|
return health;
|
|
}
|
|
void CTownRegion::SetHealth( SI16 newValue )
|
|
{
|
|
health = newValue;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::DoDamage()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Deal damage to townregion's townstone and notify online townregion members
|
|
//o------------------------------------------------------------------------------------------------o
|
|
void CTownRegion::DoDamage( SI16 reduction )
|
|
{
|
|
health -= reduction;
|
|
if( health < 0 )
|
|
{
|
|
health = 0;
|
|
}
|
|
if( health == 0 )
|
|
{
|
|
TellMembers( 1167 ); // Your town has been taken over!
|
|
}
|
|
else if( health <= 1000 )
|
|
{
|
|
TellMembers( 1168 ); // Your town is nearing destruction!
|
|
}
|
|
else if( health <= 5000 )
|
|
{
|
|
TellMembers( 1169 ); // Your town is looking decidedly unhealthy!
|
|
}
|
|
else
|
|
{
|
|
TellMembers( 1170 ); // Your town is under attack!
|
|
}
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::IsAlliedTown()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Checks whether another townregion is in the list of allies for the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::IsAlliedTown( UI16 townToCheck ) const
|
|
{
|
|
for( size_t counter = 0; counter < alliedTowns.size(); ++counter )
|
|
{
|
|
if( alliedTowns[counter] == townToCheck )
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::MakeAlliedTown()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Adds specified townregion to townregion's list of allied townregions
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::MakeAlliedTown( UI16 townToMake )
|
|
{
|
|
if( regionNum == townToMake )
|
|
return false;
|
|
|
|
if( IsAlliedTown( townToMake )) // already allied
|
|
{
|
|
TellMembers( 1171 ); // The mayor attempted to ally you with a town you already belong to.
|
|
return false;
|
|
}
|
|
|
|
if( Races->CompareByRace( cwmWorldState->townRegions[townToMake]->GetRace(), race ) <= RACE_ENEMY ) // if we're racial enemies
|
|
return false;
|
|
|
|
// let's ally ourselves
|
|
alliedTowns.push_back( townToMake );
|
|
TellMembers( 1172, name.c_str(), cwmWorldState->townRegions[townToMake]->GetName().c_str() ); // Your town of %s has now allied itself with %s.
|
|
return true;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::TellMembers()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Sends a client system message to all online members of townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
void CTownRegion::TellMembers( SI32 dictEntry, ...)
|
|
{
|
|
for( size_t memberCounter = 0; memberCounter < townMember.size(); ++memberCounter )
|
|
{
|
|
CChar *targetChar = CalcCharObjFromSer( townMember[memberCounter].townMember );
|
|
if( !ValidateObject( targetChar ))
|
|
continue;
|
|
|
|
CSocket *targetSock = targetChar->GetSocket();
|
|
if( targetSock != nullptr )
|
|
{
|
|
std::string txt = Dictionary->GetEntry( dictEntry, targetSock->Language() );
|
|
std::string msg = "TOWN: ";
|
|
va_list argptr;
|
|
va_start( argptr, dictEntry );
|
|
msg += oldstrutil::format( txt, argptr );
|
|
va_end( argptr ); // va_end in same function as va_start
|
|
|
|
if( cwmWorldState->ServerData()->UseUnicodeMessages() )
|
|
{
|
|
CPUnicodeMessage unicodeMessage;
|
|
unicodeMessage.Message( msg );
|
|
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( msg );
|
|
toAdd.Font( FNT_NORMAL );
|
|
toAdd.Speaker( INVALIDSERIAL );
|
|
toAdd.SpokenTo( townMember[memberCounter].townMember );
|
|
toAdd.Colour( 0x000B );
|
|
toAdd.Type( SYSTEM );
|
|
toAdd.At( cwmWorldState->GetUICurrentTime() );
|
|
toAdd.TargType( SPTRG_INDIVIDUAL );
|
|
}
|
|
va_end( argptr );
|
|
}
|
|
}
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetRace()
|
|
//| CTownRegion::SetRace()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets race ID associated with townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
RACEID CTownRegion::GetRace( void ) const
|
|
{
|
|
return race;
|
|
}
|
|
void CTownRegion::SetRace( RACEID newRace )
|
|
{
|
|
race = newRace;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::SendAlliedTowns()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Sends list of townregion's allied townregions to client
|
|
//o------------------------------------------------------------------------------------------------o
|
|
void CTownRegion::SendAlliedTowns( CSocket *sock )
|
|
{
|
|
CGumpDisplay Ally( sock, 300, 300 );
|
|
|
|
auto temp = oldstrutil::format( Dictionary->GetEntry( 1173, sock->Language() ).c_str(), alliedTowns.size() ); // Allied Towns (%i)
|
|
Ally.SetTitle( temp );
|
|
for( size_t counter = 0; counter < alliedTowns.size(); ++counter )
|
|
{
|
|
Ally.AddData( cwmWorldState->townRegions[alliedTowns[counter]]->GetName(), " " );
|
|
}
|
|
|
|
Ally.Send( 4, false, INVALIDSERIAL );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::ForceEarlyElection()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Forces early election for townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
void CTownRegion::ForceEarlyElection( void )
|
|
{
|
|
time_t now;
|
|
time( &now );
|
|
CChar *mayor = GetMayor();
|
|
timeToNextPoll = static_cast<SI32>( now ); // time to open poll
|
|
TellMembers( 1174 ); // An early election has been forced, please proceed to all polling booths.
|
|
for( size_t counter = 0; counter < townMember.size(); ++counter )
|
|
{
|
|
townMember[counter].targVote = INVALIDSERIAL;
|
|
}
|
|
if( ValidateObject( mayor ))
|
|
{
|
|
mayor->SetTownpriv( 1 );
|
|
}
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::SendEnemyTowns()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Sends list of townregion's enemy townregions to client
|
|
//o------------------------------------------------------------------------------------------------o
|
|
auto CTownRegion::SendEnemyTowns( CSocket *sock ) -> void
|
|
{
|
|
auto Enemy = CGumpDisplay( sock, 300, 300 );
|
|
|
|
UI08 enemyCount = 0;
|
|
std::for_each( cwmWorldState->townRegions.begin(), cwmWorldState->townRegions.end(), [this, &enemyCount, &Enemy]( const std::pair<UI16, CTownRegion*> &entry )
|
|
{
|
|
if(( entry.first != regionNum ) && ( Races->CompareByRace( race, entry.second->GetRace() ) <= RACE_ENEMY ))
|
|
{
|
|
++enemyCount;
|
|
Enemy.AddData( entry.second->GetName(), Races->Name( entry.second->GetRace() ));
|
|
}
|
|
});
|
|
|
|
Enemy.SetTitle( oldstrutil::format( "Enemy Towns (%u)", enemyCount ));
|
|
Enemy.Send( 4, false, INVALIDSERIAL );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::Possess()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Another townregion takes possession of the townregion, and clears out old
|
|
//| memberlist for the possessed townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
void CTownRegion::Possess( CTownRegion *possessorTown )
|
|
{
|
|
possessorTown->SetRace( race );
|
|
possessorTown->TellMembers( 1175 ); // There has been an influx of money due to theft of another town's stone!
|
|
possessorTown->SetReserves( possessorTown->GetReserves() + GetReserves() / 3 * 2 );
|
|
possessorTown->SetTaxesLeft( possessorTown->GetTaxes() + GetTaxes() / 3 * 2 );
|
|
TellMembers( 1176 ); // The town has been destroyed, beware the guards!
|
|
MakeAlliedTown( possessorTown->GetRegionNum() );
|
|
possessorTown->MakeAlliedTown( regionNum );
|
|
|
|
// remove the old members, preparing the way for the new ones
|
|
CChar *targChar;
|
|
for( size_t counter = townMember.size(); counter-- > 0 && counter < townMember.size(); )
|
|
{
|
|
targChar = CalcCharObjFromSer( townMember[counter].townMember );
|
|
RemoveCharacter( counter );
|
|
if( ValidateObject( targChar ))
|
|
{
|
|
targChar->SetTown( 255 );
|
|
targChar->SetTownpriv( 0 );
|
|
}
|
|
}
|
|
townMember.resize( 0 );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetReserves()
|
|
//| CTownRegion::SetReserves()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets collected resource reserves for townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
UI32 CTownRegion::GetReserves( void ) const
|
|
{
|
|
return resourceCollected;
|
|
}
|
|
void CTownRegion::SetReserves( UI32 newValue )
|
|
{
|
|
resourceCollected = newValue;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetTaxes()
|
|
//| CTownRegion::SetTaxesLeft()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets collected gold reserves for townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
UI32 CTownRegion::GetTaxes( void ) const
|
|
{
|
|
return goldReserved;
|
|
}
|
|
void CTownRegion::SetTaxesLeft( UI32 newValue )
|
|
{
|
|
goldReserved = newValue;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetChanceBigOre()
|
|
//| CTownRegion::SetChanceBigOre()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets chance to find big ore in the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
UI08 CTownRegion::GetChanceBigOre( void ) const
|
|
{
|
|
return chanceFindBigOre;
|
|
}
|
|
void CTownRegion::SetChanceBigOre( UI08 newValue )
|
|
{
|
|
chanceFindBigOre = newValue;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::RemoveCharacter()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Remove character from townregion's member list
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::RemoveCharacter( size_t position )
|
|
{
|
|
townMember.erase( townMember.begin() + position );
|
|
return true;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetNumOrePreferences()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets the number of ore preferences present for the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
size_t CTownRegion::GetNumOrePreferences( void ) const
|
|
{
|
|
return orePreferences.size();
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetOrePreference()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets the townregion's preference for a specified ore
|
|
//o------------------------------------------------------------------------------------------------o
|
|
const OrePref_st *CTownRegion::GetOrePreference( size_t targValue ) const
|
|
{
|
|
if( targValue >= orePreferences.size() )
|
|
return nullptr;
|
|
|
|
return &orePreferences[targValue];
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetOreChance()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets the chance to find ore when mining in the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
SI32 CTownRegion::GetOreChance( void ) const
|
|
{
|
|
SI32 sumReturn = 0;
|
|
std::vector<OrePref_st>::const_iterator oIter;
|
|
for( oIter = orePreferences.begin(); oIter != orePreferences.end(); ++oIter )
|
|
{
|
|
sumReturn += ( *oIter ).percentChance;
|
|
}
|
|
return sumReturn;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::IsDungeon()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets whether townregion is a dungeon
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::IsDungeon( void ) const
|
|
{
|
|
return priv.test( BIT_DUNGEON );
|
|
}
|
|
void CTownRegion::IsDungeon( bool value )
|
|
{
|
|
priv.set( BIT_DUNGEON, value );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::IsDisabled()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets whether townregion is disabled
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::IsDisabled( void ) const
|
|
{
|
|
return priv.test( BIT_DISABLED );
|
|
}
|
|
void CTownRegion::IsDisabled( bool value )
|
|
{
|
|
priv.set( BIT_DISABLED, value );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::IsSubRegion()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets whether townregion is subregion of another region
|
|
//o------------------------------------------------------------------------------------------------o
|
|
bool CTownRegion::IsSubRegion( void ) const
|
|
{
|
|
return priv.test( BIT_SUBREGION );
|
|
}
|
|
void CTownRegion::IsSubRegion( bool value )
|
|
{
|
|
priv.set( BIT_SUBREGION, value );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::NumGuards()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets the number of guards in the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
UI16 CTownRegion::NumGuards( void ) const
|
|
{
|
|
return numGuards;
|
|
}
|
|
void CTownRegion::SetNumGuards( UI16 newValue )
|
|
{
|
|
numGuards = newValue;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::WorldNumber()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets the worldnumber of the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
UI08 CTownRegion::WorldNumber( void ) const
|
|
{
|
|
return worldNumber;
|
|
}
|
|
void CTownRegion::WorldNumber( UI08 newValue )
|
|
{
|
|
worldNumber = newValue;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetInstanceId()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets the worldnumber of the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
UI16 CTownRegion::GetInstanceId( void ) const
|
|
{
|
|
return instanceId;
|
|
}
|
|
void CTownRegion::SetInstanceId( UI16 newValue )
|
|
{
|
|
instanceId = newValue;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::TaxedAmount()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets the amount of gold taxed from townregion members
|
|
//o------------------------------------------------------------------------------------------------o
|
|
void CTownRegion::TaxedAmount( UI16 amount )
|
|
{
|
|
taxedAmount = amount;
|
|
}
|
|
UI16 CTownRegion::TaxedAmount( void ) const
|
|
{
|
|
return taxedAmount;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetScriptTriggers()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets list of script triggers on object
|
|
//o------------------------------------------------------------------------------------------------o
|
|
std::vector<UI16> CTownRegion::GetScriptTriggers( void )
|
|
{
|
|
return scriptTriggers;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::AddScriptTrigger()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Adds a script trigger to object's list of script triggers
|
|
//o------------------------------------------------------------------------------------------------o
|
|
void CTownRegion::AddScriptTrigger( UI16 newValue )
|
|
{
|
|
if( std::find( scriptTriggers.begin(), scriptTriggers.end(), newValue ) == scriptTriggers.end() )
|
|
{
|
|
// Add scriptId to scriptTriggers if not already present
|
|
scriptTriggers.push_back( newValue );
|
|
}
|
|
|
|
// Sort vector in ascending order, so order in which scripts are evaluated is predictable
|
|
std::sort( scriptTriggers.begin(), scriptTriggers.end() );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::RemoveScriptTrigger()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Removes a specific script trigger to object's list of script triggers
|
|
//o------------------------------------------------------------------------------------------------o
|
|
void CTownRegion::RemoveScriptTrigger( UI16 newValue )
|
|
{
|
|
// Remove all elements containing specified script trigger from vector
|
|
scriptTriggers.erase( std::remove( scriptTriggers.begin(), scriptTriggers.end(), newValue ), scriptTriggers.end() );
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::ClearScriptTriggers()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Clears out all script triggers from object
|
|
//o------------------------------------------------------------------------------------------------o
|
|
void CTownRegion::ClearScriptTriggers( void )
|
|
{
|
|
scriptTriggers.clear();
|
|
scriptTriggers.shrink_to_fit();
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetRegionNum()
|
|
//| CTownRegion::SetRegionNum()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets/Sets region number (from region DFNs) for the townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
UI16 CTownRegion::GetRegionNum( void ) const
|
|
{
|
|
return regionNum;
|
|
}
|
|
void CTownRegion::SetRegionNum( UI16 newVal )
|
|
{
|
|
regionNum = newVal;
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetNumLocations()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets number of locations in townregion as defined in region DFNs via X1/Y1, X2/Y2 pairs
|
|
//o------------------------------------------------------------------------------------------------o
|
|
size_t CTownRegion::GetNumLocations( void ) const
|
|
{
|
|
return locations.size();
|
|
}
|
|
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Function - CTownRegion::GetLocation()
|
|
//o------------------------------------------------------------------------------------------------o
|
|
//| Purpose - Gets specified location in townregion
|
|
//o------------------------------------------------------------------------------------------------o
|
|
const RegLocs_st *CTownRegion::GetLocation( size_t locNum ) const
|
|
{
|
|
if( locNum >= locations.size() )
|
|
return nullptr;
|
|
|
|
return &locations[locNum];
|
|
}
|