2002-04-07 21:27:53 +00:00
# include "uox3.h"
2012-11-03 18:11:04 +00:00
# include "regions.h"
Housing Revamp and more
Updated JS SysMessage function to accept up to 10 extra, optional arguments, which can be used with dictionary messages that require additional parameters like %s or %i
Added new type of house privilege in cMultiObj.cpp to keep track of friends of the multi - HOUSEPRIV_FRIEND - which is stored during worldsaves as one or more Friend=<player serial> tags in house.wsc
Added new type of house privilege in cMultiObj.cpp to keep track of guests of the multi - HOUSEPRIV_GUEST - which is stored during worldsaves as one or more Guest=<player serial> tags in house.wsc
When items are created for houses upon house placement, a reference to the multi's serial is now stored in the house sign's MORE property to allow easier tracking of which house a particular sign belongs to
Added tracking of new, persistent properties for houses via cMultiObj.cpp/h:
lockdowns, secure containers, vendors, guests, friends, owners, ban location, public status, number of visits, timestamps
Added a multitude of new methods in cMultiObj.cpp/h to assist in improving the functionality of houses
Added new tags for houses in house.dfn (default values applied if tag not specified):
MAXSECURECONTAINERS=4 - Max amount of secure containers allowed in a multi
MAXLOCKDOWNS=256 - Max amount of lockdowns allowed in a multi
MAXVENDORS=10 - Max amount of vendors allowed in a multi
MAXBANS=50 - Max amount of bans in a multi's ban list
MAXFRIENDS=50 - Max amount of friends in a multi's friend list
MAXGUESTS=50 - Max amount of guests in a multi's guest list
MAXOWNERS=8 - Max amount of owners and co-owners in a multi's owner list
MAXTRASHCONTAINERS=1 - Max amount of trash containers allowed in multi
SCRIPT=<scriptID> - Assign a JS script-ID directly to a multi
FRONTDOOR - indicates that a door is the front door of a house. Cannot be locked in public houses!
INTERIORDOOR - indicates that a door is an interior door of a house. Can be locked in public houses.
BANX - Location X offset for multi's ban location, if not used, will try to use SE corner of multi instead
BANY - Location Y offset for multi's ban location, if not used, will try to use SE corner of multi instead
Added JS Event:
onHouseCommand( tSock, multiObj, cmdID ) - For handling spoken house commands via JS scripts attached to multi.
Updated JS Events:
onEntrance() - can now trigger both for multi being entered and/or object entering
onLeaving() - can now trigger both for multi being left and/or object entering
onSpeech() - can now also trigger for items (in addition to chars) with event & script attached, if UOX.INI setting ITEMSDETECTSPEECH is enabled
Added JS Multi methods:
.IsBoat() - Returns whether the item (or multi) is a boat
.IsOwner( playerToCheck ) - Returns whether a player is the owner of a multi
.IsOnOwnerList( playerToCheck ) - Returns whether a player is on the (co-)owner list of a multi
.IsOnFriendList( playerToCheck ) - Returns whether a player is on the friend list of a multi
.IsOnGuestList( playerToCheck ) - Returns whether a player is on the guest list of a multi
.IsOnBanList( playerToCheck ) - Returns whether a player is on the ban list of a multi
.AddToFriendList( playertoAdd ) - Adds player to the friend list of a multi
.RemoveFromFriendList( playertoRemove ) - Removes player from the friend list of a multi
.AddToGuestList( playertoAdd ) - Adds player to the guest list of a multi
.RemoveFromGuestList( playertoRemove ) - Removes player from the guest list of a multi
.ClearOwnerList() - Clears all entries from a multi's (co-)owner list
.ClearFriendList() - Clears all entries from a multi's friend list
.ClearGuestList() - Clears all entries from a multi's guest list
.ClearBanList() - Clears all entries from a multi's ban list
.SecureContainer( itemToSecure ) - Secures a container in a multi
.UnsecureContainer( itemToUnsecure ) - Unsecures a container in a multi
.IsSecureContainer( itemToCheck ) - Checks if specified item is a secure container in a multi
.LockDownItem( itemToLockDown) - Locks down an item in a multi
.ReleaseItem( itemToRelease ) - Releases a locked down item in a multi
.KillKeys() - Deletes ALL keys associated with a multi
.AddTrashCont( itemToAdd ) - Add trash container to multi's list of trash containers
.RemoveTrashCont( itemToRemove ) - Remove trash container from multi's list of trash containers
Added JS Item (Multi only) properties:
.lockdowns - Get the number of lockdowns in a multi
.maxLockdowns - Get/Set the max number of lockdowns allowed in a multi
.secureContainers - Get the number of secure containers in a multi
.maxSecureContainers - Get/Set the max number of secure containers allowed in a multi
.trashContainers - Get the number of trash containers in a multi
.maxTrashContainers - Get/Set the max number of trash containers allowed in a multi
.friends - Get the number of friends in a multi's friend list
.maxFriends - Get/Set the max number of friends allowed in a multi's friend list
.guests - Get the number of guests in a multi's guest list
.maxGuests - Get/Set the max number of guests allowed in a multi's guest list
.owners - Get the number of owners in a multi's owner list
.maxOwners - Get/Set the max number of owners allowed in a multi's owner list
.bans - Get the number of banned players in a multi's ban list
.maxBans - Get/Set the max number of banned players allowed in a multi's ban list
.vendors - Get the number of player vendors in a multi
.maxVendors - Get the max number of player vendors allowed in a multi
.deed - Get the item sectionID for deed used to place multi
.isPublic - Get/Set the private/public state of a multi
.buildTimestamp - Get the timestamp for when the house was originally placed
.tradeTimestamp - Get the timestamp for when the house was last traded to another player
.banX - Get/Set the ban location X offset for the multi
.banY - Get/Set the ban location Y offset for the multi
Added JS Character properties:
.multi = Get/Set the multi object the character is in
.accountNum = Get the account number the character belongs to
.housesOwned = Get a count of houses owned by the character
.housesCoOwned = Get a count of houses co-owned by the character
Updated JS cBaseObject Methods .FirstItem(), .NextItem() and .FinishedItems() to also support iterating through items in multis
Updated JS multi Methods .FirstChar(), .NextChar() and .FinishedChars() to support an additional parameter to specify what kind of characters to loop through:
"default" or no parameter - all characters inside the multi
"owner" - players on multi's owner list
"friend" - players on multi's friend list
"guest" - players on multi's guest list
"banned" - players on multi's ban list
Added new INI tags to a new section of uox.ini called [houses]
DECAYTIMERINHOUSE=3600 // Decay timer in seconds for non-locked down items inside houses
PROTECTPRIVATEHOUSES=1 // Toggles whether private houses will automatically boot unauthorized visitors (1) or not (0)
TRACKHOUSESPERACCOUNT=1 // Toggles whether to track (and restrict) house ownership per account (1) or per character (0)
MAXHOUSESOWNABLE=1 // Specifies the max amount of houses a player can own per account/char, depending on how house ownership is tracked
MAXHOUSESCOOWNABLE=10 // Specifies the max amount of houses a player can co-own per character
CANOWNANDCOOWNHOUSES=1 // Toggles whether players can own and co-own houses at the same time
COOWNHOUSESONSAMEACCOUNT=1 // Toggles whether characters on same account as house owner will be treated as co-owners
Added new INI tags in [settings] section of uox.ini:
ITEMSDETECTSPEECH=0 // If enabled, server will search for nearby items with onSpeech JS event running whenever a character speaks. Disabled by default.
MAXPLAYERPACKITEMS=125 // Defines max item capacity for player (and NPC) backpacks. Defaults to 125.
Moved most of the existing house functionality to JS and expanded upon it to reach feature parity with houses in regular UO around Publish 15/16, with various extras thrown in for good measure and all functionality being customizable:
js/server/house/house.js (15000) - handles detection of house commands and characters entering/leaving houses
js/server/house/houseSign.js (15001) - contains and handles all house-related gumps/menus and what is shown when players interact with house sign
js/server/house/houseCommands.js (15002) - handles functionality of house commands and other functionality such as transfer of ownership, demolishing house, etc.
js/server/house/houseDeed.js (15003) - handles initial rules that allow/disallow placement of additional houses for players
All house-related menus now fully handled through JS
All house commands and other functionality now fully handled through JS
Removed redundant hard-coded house functionality
Implemented Co-owners, friends, guests for houses, with access rules in place for entry, lockdowns, house commands, etc.
Implemented Private and Public houses
Implemented Secure Containers and Trash Barrels
Definable max lockdowns, secure containers, player vendors, bans, friends, guests, owners, trash containers and more - per house type
JS scripts can now be attached directly to houses
Doors in houses can be marked as front doors or interior doors, and will be treated differently with regards to private and public houses
Added new item to dfndata/items/containers/misc.dfn - [trashbarrel]
Added new JS script (js/items/trashbarrel.js) with trash barrel functionality for houses. Trash barrels that are marked as secure containers are only accessible by owners, co-owners and friends of the house. Various options available at top of script.
Updated js/items/axe.js to support chopping up trash barrels and house add-ons in houses owned by the player
Fixed an issue with house doors being left behind after demolishing houses while their doors were open
Fixed an issue where GMs could be banned from player houses
Added Line of Sight checks to speech, to give players some privacy in their own homes
Updated house placement code to more accurately check for other multis, dynamic and static objects when placing houses; now requires free space around each house that cannot be blocked by other houses or items that can block player movement, and disallows placement of houses on roads
Updated house placement code to move characters blocking house placement to SE corner of the house
Updated house placement code to disallow placing houses in guarded regions, or in dungeons
Added new DFN tag for regions to enable/disable player houses in specific regions: HOUSING=0/1
Added new region (247) that covers path to Valley of Eodon in Felucca
Added new region (248) that covers Valley of Eodon in Ter-Mur, with player housing disabled
Added new region (249) that covers entire T2A lands, with player housing disabled
Updated SPACEX and SPACEY values for all houses in dfndata/house/house.dfn to match updated house placement code
Added new JS property to Regions that can be used to determine or change state of player housing in a region: .canPlaceHouse()
Updated rules for usage of dye tubs to dye locked down items; now only house owners or co-owners may dye locked down items
Updated rules for usage of the following locked down items in a house, which are now only usable by house owners and co-owners
Dyes, Guildstone Deeds, Recall Runes (renaming), Rename Deeds, Townstone Deeds, House Deeds, Boat Models, Player Vendor Deeds, Ore, Hair Dye
Updated rules for usage of the following locked down items in a house, which are now only usable by house owners, co-owners and friends:
Keys, Dye Tubs, Magic Scrolls, Fireworks Wands, Magic Wands, Smithing Tools, Mining Tools, Fishing Poles
Updated item lockdown rules to allow locking down (and releasing) items in a container as long as the container is locked down, and to only allow releasing a locked down container if it's empty of locked down items
Updated item lockdown rules to only allow locking down movement-blocking items further than 2 tiles away from doors
Updated rules for releasing items in houses - now the house owner can release any locked down items, co-owners can release items locked down by themselves or by friends, while friends can release only items locked down by themselves
Added some feedback to player about why their attempted house placement failed
Items added by GMs directly into multis will now decay based on the house-specific decay timer instead of the regular one
Fixed an issue that could cause items to almost instantly decay after being released from lockdown in a house
Placing house add-ons now properly takes into account SPACEX and SPACEY values when checking if they can fit in selected area of houses
Re-added SPACEX and SPACEY values for Pentagram and Loom house add-ons
House add-ons can now be converted back into house add-on deeds by chopping them with an axe
Added new item type - IT_HOUSEADDON (201) - used by house add-ons placed in player houses
Fixed a bug where keys would stop working after being added to a keyring, and would turn into blank keys upon release from the keyring
Added visitor count for public player houses, which keeps track of how many visits a public house has received, with each player counted max 1 time every 24 hours
Fixed an issue with FindPlayersInOldVisrange() where it didn't take into account that players could see buildings further away than the standard update range. This could cause players to see ghost images of buildings if they were at the "right" distance when the building was being demolished
Added NODECAY tag to all signs and doors in dfndata/house/house.dfn
Added FRONTDOOR or INTERIORDOOR (as appropriate) to all doors in dfndata/house/house.dfn
Added BANX and BANY to specify ban location for some houses in dfndata/house/house.dfn instead of relying on finding SE corner automatically
Implemented strongboxes (js/server/house/strongbox.js) for co-owners of a house, which can be placed with the house command "i wish to place a strongbox". Max capacity is 25 items
Updated 'REMOVE command to take an optional parameter - itemID. If supplied, the command will remove all items with this itemID from a targeted container
Fixed a bug when checking if dynamic items were blocking valid spawn locations for NPCs, some function arguments were in the wrong order!
Improved code that finds valid spawn locations for items and NPCs spawned via spawn regions. As server gradually builds up lists of valid spawn locations per region over time, it will start using these lists more often, rather than always look for brand new spawn locations.
Fixed a bug with CMulHandler::CheckStaticFlag() that prevented NPCs from spawning inside buildings with no static floors!
Fixed an issue with repeating commands that prevented GMs from being able to cancel them when using the ClassicUO client
Exposed character property .accountNum to JS engine
Extended CDataList class to include a Clear() method for clearing lists
Updated JS File method .Open() to support an optional, third argument - subFolderName - that defines in which sub-folder of UOX3/shared/ to store/look for a file. If no third argument is supplied, UOX3 will default to using the shared folder itself.
Updated JS File method .Length() to return a value of -1 for files that don't exist
Added new code function, exposed to JS engine with same parameters, which simply checks if a given tile ID has a specific flag
bool CheckTileFlag( UI16 itemID, TILEFLAG flagToCheck )
Added JS function used to find the root container of an item (if any)
FindRootContainer( itemSerial )
FindRootContainer( item )
Added new JS function that allows deleting files from UOX3/shared/ folder or subfolders of shared folder. If no subFolderName is provided, looks for file directly in shared folder itself. Restrictions on file- and folder-names apply.
bool DeleteFile( fileName, subFolderName )
Added new JS functions for checking if a specific client or server feature is enabled. See documentation for full list of client/server features.
GetClientFeature( bitNum ) // Returns true if specified client feature is enabled on server
GetServerFeature( bitNum ) // Returns true if specified server feature is enabled on server
Added new JS function for returning the value of almost any server setting from UOX.INI
GetServerSetting( settingNameInDoubleQuotes )
Updated JS function DoesDynamicBlock() with two new parameters - checkOnlyMultis and checkOnlyNonMultis
Updated JS function DoesMapBlock() with two new parameters - checkMultiPlacement and checkForRoad
Fixed an issue where a LoS check would prevent players from accessing containers in their own backpack
Added new functions in findfuncs.cpp to make it easier to find items near another object or location:
findNearbyItems( object, distance )
findNearbyItems( x, y, worldNumber, instanceID, distance )
Added new Item property - maxItems - used by containers to determine their max item capacity
Added new Item property - totalItemCount - used to get total item count in a container (including sub-containers)
Added check for max item capacity when creating new items that are added to a character's backpack - items will be created below character's feet if backpack is full!
Added new DFN tag for items, used by containers to determine item capacity for a given container:
MAXITEMS=# // 125 is the default for all containers if not set
Added new JS Item properties:
.maxItems // gets/sets item capacity for a given container
.totalItemCount // gets total item count in a container, including sub-containers
Updated item tooltips for containers to show accurate total item count, as well as to display max item capacity
Fixed a bug where picking up items from a non-locked down pile of items on the floor inside a multi could cause the remaining pile to be seen as no longer inside the multi, disallowing locking it back down and causing it to decay based on regular decay timer instead of house-specific one
Updated JS command set to allow setting poison-level on items ('set poison #) and hunger-level on characters ('set hunger #)
Fixed an issue with js/item/food.js that prevented poisoned food from poisoning characters when eaten
Fixed an issue with js/skill/poisoning.js that prevented players from poisoning food!
Updated various JS scripts and hardcoded targeting functions to disallow the targeting of locked down resources using skills and tools
Updated JS Method TextMessage() to support three extra, optional parameters. Note that if one optional parameter is included, all preceding optional parameters are also required!
speechTarget - What kind of target is this message intended for?
0 - Only visible for sender and receiver of message
1 - Visible to all players in range
2 - Visible to all NPCs and players in range
3 - Visible to all PCs everywhere + NPCs in range
4 - Visible to all PCs everywhere (broadcast)
5 - Only visible for the receiver of the message
speechTargetSerial - The serial of the receiver of the message, used if speechTarget is 0 or 5
speechFontType - The type of font to display the text in. Defaults to normal.
0 - Bold
1 - Normal with shadow
2 - Bold with shadow
3 - Normal
4 - Gothic
5 - Italic
6 - Small, dark
7 - Colourful
8 - Runic (only works with CAPS)
9 - Small, light
Added timestamp to worldsaves in console, to make it easier to see when a particular world-save was done
Added info about compiler/environment displayed at the top of the UOX3 console during startup
Updated dictionary files with new messages primarily related to housing
2020-11-04 02:00:37 +08:00
# include "townregion.h"
2012-11-03 18:11:04 +00:00
# include "cServerDefinitions.h"
# include "ssection.h"
# include "scriptc.h"
2023-04-07 11:17:51 -04:00
# include "strutil.hpp"
2021-06-01 02:44:56 +08:00
# include <filesystem>
2012-11-03 18:11:04 +00:00
2022-06-12 14:31:18 -04:00
# include <algorithm>
# include <array>
# include <fstream>
2022-10-24 18:39:33 +08:00
using namespace std : : string_literals ;
2022-06-12 14:31:18 -04:00
2021-06-12 07:30:23 -04:00
CMulHandler * Map = nullptr ;
2012-11-03 18:11:04 +00:00
2022-06-14 17:53:00 -04:00
//const UI16 LANDDATA_SIZE = 0x4000; //(512 * 32)
2002-04-07 21:27:53 +00:00
2022-10-24 18:39:33 +08:00
/*!
* * New rewrite plans , its way confusing having every function in here using ' Height ' to mean
Numerous changes with focus on feature and stability parity across Windows, Linux and MacOS platforms
Added new Makefile that handles compiling UOX3 and Spidermonkey on both Linux and MacOS (punt)
Added VS solution (SpiderMonkey.sln) and VC++ project files for compiling SpiderMonkey on Windows (Xuri)
Updated SpiderMonkey from v1.6.0 to v1.7.0
Added optimization flag -O2 for release build in CMakeLists.txt in project root (Xuri)
Added StringUtility file with general common string manipulation functions (punt)
Updated RandomNum function to use a "seedless" random number generator from C++11 instead of the old C rand() function. (punt)
Overall code cleanup to remove/replace platform-dependent code (punt)
Replaced potentially unsafe usage of C string stuff like sprintf, vsprintf, vsnprintf, strncat, strcpy and strlen throughout the code with calls to a format() function containing only a single, safe use of vsnprintf, ensuring there's a single place of failure if there's anything to fix and and making it easy to potentially replace this with std::format from C++20 when the time comes. (punt)
Replaced usage of char in many places with std::string (punt)
Started process of replacing UString usage with functions provided through StringUtility instead (punt)
Replaced platform specific fileIO handling in Windows/Linux with cross-platform C++17 standard std::filesystem (punt)
Replaced platform specific time handling by using cross-platform chrono library (punt)
Removed UOX namespace to reduce complexity (punt)
Elimitated template code approach to singletons for more modern c++ constructs, removing dependices in the process (punt)
Removed ODBC support; it hasn't been touched since the initial implementation in 2008, and there is a lack of someone to maintain the code. (punt)
Removed some platform specific files like uoxlinux.h, which is no longer required (punt)
Removed legacy crash protection code, and removed support for cluox (punt)
Removed legacy "support" for Borland compiler (punt)
Removed legacy VC++ 6 Workspace/Project files, VS2005 Solution/Project files, as these are no longer supported (Xuri)
Removed legacy BUILD folder with outdated compilation instructions (Xuri)
Removed old Changelog file (merged into Changelog.txt) (Xuri)
Fixed a pointer bug for items in multis on world load (punt)
Fixed a dictionary related issue that caused segmentation faults on Linux/MacOS (punt)
Fixed an issue with callbacks to JS scripts that caused segmentation faults on Linux/MacOS (punt)
Paths in uox.ini should now load properly on all platforms regardless of whether those paths use slashes or backslashes, and whether or not they end in a slash/backslash. (punt)
Moved to c++17 style of threading, and got rid of threadsafeobject.cpp/h (punt)
Replaced parsing of UOX.INI tags with a system that's more easily maintainable (punt)
Added some new commands to js/commands/custom/misc-cmd.js (Xuri)
cont // Targeted item will be made a container, set to nondecay and movable 2
endfight // Targeted character (and character being fought) will stop fighting
getmulti // Get multiObject for targeted item
finditem // Find item at layer X
movespeed // Set movement speed of target player (0x0 Normal, 0x1 Mounted, 0x2 Slow (walk only), 0x3 Hybrid ("jog"?), 0x4 Frozen)
Added new HTML based documentation in docs folder, and removed many old legacy docs that are either incorporated into this document already or no longer relevant for the current UOX3 version (Xuri)
Co-Authored-By: Charles Kerr <punt1959@users.noreply.github.com>
2020-09-07 18:09:55 +08:00
* * elevation or actual height of a tile . Here ' s the new renaming plan :
* * Elevation - the z value of the bottom edge of an item
* * Height - the height of the item , it is independant of the elevation , like a person is 6f t tall
* * Top - the z value of the top edge of an item , is always Elevation + Height of item
*/
2002-04-07 21:27:53 +00:00
2022-10-24 18:39:33 +08:00
//==================================================================================================
2022-06-15 11:24:57 -04:00
// CMulHandler
2022-10-24 18:39:33 +08:00
//==================================================================================================
//==================================================================================================
2012-11-03 18:11:04 +00:00
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::LoadMapsDFN()
//o------------------------------------------------------------------------------------------------o
Instance-support and misc code cleanup
Misc code and documentation cleanup:
Updated and standardized function comment blocks throughout entire codebase
Grouped getters and setters together in pairs and documented them as one
Removed empty and/or non-useful information from comment blocks
Removed unused function from cItem.cpp/h - IncID() - formerly used to change IDs for doors
Added new feature - Instances
Objects (characters, items, multis, spawnregions) can now make use of a 5th parameter to determine their location in the game world. In addition to the traditional X, Y, Z and WORLDNUMBER parameters, a new one has been added - INSTANCEID - that allows objects to exist at the same coordinates in the same world, but in different "dimensions". Code has been updated in multiple places to support this, and a default instanceID of 0 is assumed if nothing else is specified.
Added support for new DFN tag in town regions, spawn regions and locations - INSTANCEID (defaults to 0 if not present)
Added support for another start location parameter after worldNum in UOX.INI representing instanceID (defaults to 0 if not present)
Updated TWEAK menu to include WorldNumber and instanceID
Fixed BaseWeight option in TWEAK menu
Updated CBase_Teleport - now takes an optional 5th parameter instanceID
Updated SE_SpawnNPC now takes an optional 5th parameter - instanceID
Updated SE_FindMulti now takes an optional 5th parameter - instanceID
Updated SE_GetItem now takes an optional 5th parameter - instanceID
Updated SE_FindItem now takes an optional 6th parameter - instanceID
Added new JS property for Items, Characters, Regions: .instanceID
Added JS property for Regions: .members - returns comma-separated list of town member serials
Updated JS scripts making use of the above-mentioned JS Methods/Functions
Updated dictionaries with new tweak menu entry texts
Exposed SpawnRegions to JS engine, and updated JS docs with details:
SpawnRegion JS Functions
IterateOverSpawnRegions()
GetSpawnRegion( spawnRegNum )
GetSpawnRegionCount()
SpawnRegion JS Properties
name
regionNum
itemList
npcList
item
npc
maxItems
maxNpcs
itemCount
npcCount
onlyOutside
prefZ
x1
y1
x2
y2
world
instanceID
minTime
maxTime
call
2020-08-08 13:57:15 +08:00
//| Purpose - Loads maps.dfn to see which map files to actually load into memory later
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : LoadMapsDFN ( const std : : string & uodir ) - > std : : map < int , MapDfnData_st >
{
auto entrycount = FileLookup - > CountOfEntries ( maps_def ) ;
std : : map < int , MapDfnData_st > results ;
auto uopath = std : : filesystem : : path ( uodir ) ;
2022-12-04 02:03:43 -05:00
for ( auto i = 0 ; i < static_cast < int > ( entrycount ) ; i + + )
2022-10-24 18:39:33 +08:00
{
auto toFind = FileLookup - > FindEntry ( " MAP " s + std : : to_string ( i ) , maps_def ) ;
if ( toFind = = nullptr )
break ;
auto entry = MapDfnData_st ( ) ;
for ( const auto & sec : toFind - > collection ( ) )
{
2023-04-07 11:17:51 -04:00
auto uTag = util : : upper ( sec - > tag ) ;
auto data = util : : trim ( util : : strip ( sec - > data ) ) ;
2022-10-24 18:39:33 +08:00
switch ( uTag . data ( ) [ 0 ] )
{
case ' M ' :
if ( uTag = = " MAP " )
{
entry . mapFile = ( uopath / std : : filesystem : : path ( data ) ) ;
}
else if ( uTag = = " MAPUOPWRAP " )
{
entry . mapUop = ( uopath / std : : filesystem : : path ( data ) ) ;
}
else if ( cwmWorldState - > ServerData ( ) - > MapDiffsEnabled ( ) )
{
if ( uTag = = " MAPDIFF " )
{
entry . mapDiff = ( uopath / std : : filesystem : : path ( data ) ) ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
else if ( uTag = = " MAPDIFFLIST " )
{
entry . mapDiffl = ( uopath / std : : filesystem : : path ( data ) ) ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
}
break ;
case ' S ' :
if ( uTag = = " STATICS " )
{
entry . staMul = ( uopath / std : : filesystem : : path ( data ) ) ;
}
else if ( uTag = = " STAIDX " )
{
entry . staIdx = ( uopath / std : : filesystem : : path ( data ) ) ;
}
else if ( cwmWorldState - > ServerData ( ) - > MapDiffsEnabled ( ) )
{
if ( uTag = = " STATICSDIFF " )
{
entry . staDiff = ( uopath / std : : filesystem : : path ( data ) ) ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
else if ( uTag = = " STATICSDIFFLIST " )
{
entry . staDiffl = ( uopath / std : : filesystem : : path ( data ) ) ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
else if ( uTag = = " STATICSDIFFINDEX " )
{
entry . staDiffi = ( uopath / std : : filesystem : : path ( data ) ) ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
}
break ;
case ' X ' :
if ( uTag = = " X " )
{
2023-04-07 11:17:51 -04:00
entry . width = std : : stoi ( std : : string ( data ) ) ;
2022-10-24 18:39:33 +08:00
}
break ;
case ' Y ' :
if ( uTag = = " Y " )
{
2023-04-07 11:17:51 -04:00
entry . height = std : : stoi ( std : : string ( data ) ) ;
2022-10-24 18:39:33 +08:00
}
break ;
2012-11-03 18:11:04 +00:00
}
2022-12-04 02:03:43 -05:00
results . insert_or_assign ( i , entry ) ;
2002-04-07 21:27:53 +00:00
}
}
2022-10-24 18:39:33 +08:00
return results ;
2002-04-07 21:27:53 +00:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::Load()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Load UO data (tiledata, maps, statics, multis)
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : Load ( ) - > void
{
auto uodir = cwmWorldState - > ServerData ( ) - > Directory ( CSDDP_DATA ) ;
auto mapinfo = LoadMapsDFN ( uodir ) ;
Console . PrintSectionBegin ( ) ;
Console < < " Loading uodata (for maps, only mapfile shown)... " < < myendl < < " (If they don't open, fix your paths in uox.ini or filenames in maps.dfn) " < < myendl ;
LoadTileData ( uodir ) ;
LoadDFNOverrides ( ) ;
LoadMapAndStatics ( mapinfo ) ;
if ( uoWorlds . empty ( ) )
{
Console . Error ( " Fatal Error: No maps found " ) ;
Console . Error ( " Check the settings for DATADIRECTORY in uox.ini " ) ;
Shutdown ( FATAL_UOX3_MAP_NOT_FOUND ) ;
2002-04-07 21:27:53 +00:00
}
2022-10-24 18:39:33 +08:00
LoadMultis ( uodir ) ;
FileLookup - > Dispose ( maps_def ) ;
Console . PrintSectionBegin ( ) ;
2012-11-03 18:11:04 +00:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::LoadTileData()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Loads tiledata file into memory
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : LoadTileData ( const std : : string & uodir ) - > void
{
2022-06-15 11:24:57 -04:00
std : : string lName = uodir + " tiledata.mul " s ;
2012-11-03 18:11:04 +00:00
Console < < " \t " < < lName < < " \t " ;
2022-10-24 18:39:33 +08:00
if ( ! tileInfo . LoadTiles ( lName ) )
{
2012-11-03 18:11:04 +00:00
Console . PrintFailed ( ) ;
Shutdown ( FATAL_UOX3_TILEDATA_NOT_FOUND ) ;
2022-06-15 11:24:57 -04:00
}
Console . PrintDone ( ) ;
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::LoadDFNOverrides()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Override flags/properties for tiles based on DFNDATA/MAPS/tiles.dfn
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : LoadDFNOverrides ( ) - > void
{
std : : uint16_t entryNum ;
for ( auto & mapScp : FileLookup - > ScriptListings [ maps_def ] )
{
if ( mapScp = = nullptr )
continue ;
for ( const auto & [ entryName , toScan ] : mapScp - > collection ( ) )
{
if ( toScan = = nullptr )
continue ;
2023-04-07 11:17:51 -04:00
entryNum = util : : ston < std : : uint16_t > ( oldstrutil : : extractSection ( entryName , " " , 1 , 1 ) ) ;
auto titlePart = util : : upper ( oldstrutil : : extractSection ( entryName , " " , 0 , 0 ) ) ;
2022-10-24 18:39:33 +08:00
// have we got an entry starting with TILE ?
if ( titlePart = = " TILE " & & entryNum )
{
if ( ( entryNum = = INVALIDID ) | | ( entryNum < tileInfo . SizeArt ( ) ) )
continue ;
auto tile = & tileInfo . ArtInfo ( entryNum ) ;
if ( tile )
{
for ( const auto & sec : toScan - > collection ( ) )
{
2023-04-07 11:17:51 -04:00
auto UTag = util : : upper ( sec - > tag ) ;
auto data = std : : string ( util : : trim ( util : : strip ( sec - > data , " // " ) ) ) ;
2022-10-24 18:39:33 +08:00
// CTile properties
if ( UTag = = " WEIGHT " )
{
tile - > Weight ( static_cast < UI08 > ( std : : stoul ( data , nullptr , 0 ) ) ) ;
}
else if ( UTag = = " HEIGHT " )
{
tile - > Height ( static_cast < SI08 > ( std : : stoi ( data , nullptr , 0 ) ) ) ;
}
else if ( UTag = = " LAYER " )
{
tile - > Layer ( static_cast < SI08 > ( std : : stoi ( data , nullptr , 0 ) ) ) ;
}
else if ( UTag = = " HUE " )
{
tile - > Hue ( static_cast < UI08 > ( std : : stoul ( data , nullptr , 0 ) ) ) ;
}
else if ( UTag = = " QUANTITY " )
{
tile - > Quantity ( static_cast < UI08 > ( std : : stoul ( data , nullptr , 0 ) ) ) ;
}
else if ( UTag = = " ANIMATION " )
{
tile - > Animation ( static_cast < UI16 > ( std : : stoul ( data , nullptr , 0 ) ) ) ;
}
else if ( UTag = = " NAME " )
{
tile - > Name ( data ) ;
}
// BaseTile Flag 1
else if ( UTag = = " ATFLOORLEVEL " )
{
tile - > SetFlag ( TF_FLOORLEVEL , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " HOLDABLE " )
{
tile - > SetFlag ( TF_HOLDABLE , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " SIGNGUILDBANNER " )
{
tile - > SetFlag ( TF_TRANSPARENT , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " WEBDIRTBLOOD " )
{
tile - > SetFlag ( TF_TRANSLUCENT , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " WALLVERTTILE " )
{
tile - > SetFlag ( TF_WALL , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " DAMAGING " )
{
tile - > SetFlag ( TF_DAMAGING , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " BLOCKING " )
{
tile - > SetFlag ( TF_BLOCKING , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " LIQUIDWET " )
{
tile - > SetFlag ( TF_WET , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
// BaseTile Flag 2
else if ( UTag = = " UNKNOWNFLAG1 " )
{
tile - > SetFlag ( TF_UNKNOWN1 , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " STANDABLE " )
{
tile - > SetFlag ( TF_SURFACE , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " CLIMBABLE " )
{
tile - > SetFlag ( TF_CLIMBABLE , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " STACKABLE " )
{
tile - > SetFlag ( TF_STACKABLE , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " WINDOWARCHDOOR " )
{
tile - > SetFlag ( TF_WINDOW , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " CANNOTSHOOTTHRU " )
{
tile - > SetFlag ( TF_NOSHOOT , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " DISPLAYASA " )
{
tile - > SetFlag ( TF_DISPLAYA , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " DISPLAYASAN " )
{
tile - > SetFlag ( TF_DISPLAYAN , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
// BaseTile Flag 3
else if ( UTag = = " DESCRIPTIONTILE " )
{
tile - > SetFlag ( TF_DESCRIPTION , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " FADEWITHTRANS " )
{
tile - > SetFlag ( TF_FOLIAGE , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " PARTIALHUE " )
{
tile - > SetFlag ( TF_PARTIALHUE , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " UNKNOWNFLAG2 " )
{
tile - > SetFlag ( TF_UNKNOWN2 , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " MAP " )
{
tile - > SetFlag ( TF_MAP , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " CONTAINER " )
{
tile - > SetFlag ( TF_CONTAINER , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " EQUIPABLE " )
{
tile - > SetFlag ( TF_WEARABLE , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " LIGHTSOURCE " )
{
tile - > SetFlag ( TF_LIGHT , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
// BaseTile Flag 4
else if ( UTag = = " ANIMATED " )
{
tile - > SetFlag ( TF_ANIMATED , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " NODIAGONAL " )
{
tile - > SetFlag ( TF_NODIAGONAL , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " UNKNOWNFLAG3 " )
{
tile - > SetFlag ( TF_UNKNOWN3 , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " WHOLEBODYITEM " )
{
tile - > SetFlag ( TF_ARMOR , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " WALLROOFWEAP " )
{
tile - > SetFlag ( TF_ROOF , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " DOOR " )
{
tile - > SetFlag ( TF_DOOR , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " CLIMBABLEBIT1 " )
{
tile - > SetFlag ( TF_STAIRBACK , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
else if ( UTag = = " CLIMBABLEBIT2 " )
{
tile - > SetFlag ( TF_STAIRRIGHT , ( std : : stoi ( data , nullptr , 0 ) ! = 0 ) ) ;
}
}
}
}
else if ( titlePart = = " LAND " & & entryNum )
{ // let's not deal with this just yet
}
}
2012-11-03 18:11:04 +00:00
}
2002-04-07 21:27:53 +00:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::LoadMapAndStatics()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Loads map and statics files into memory
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : LoadMapAndStatics ( const std : : map < int , MapDfnData_st > & info ) - > void
{
for ( const auto & [ mapNum , dfndata ] : info )
{
uoWorlds . insert_or_assign ( mapNum , UltimaMap ( mapNum , dfndata . width , dfndata . height , & tileInfo ) ) ;
auto rValue = false ;
if ( std : : filesystem : : exists ( dfndata . mapUop ) )
{
Console < < " \t " < < dfndata . mapUop . string ( ) < < " (/ " < < dfndata . mapUop . filename ( ) . string ( ) < < " ) \t \t " ;
rValue = uoWorlds [ mapNum ] . LoadUOPTerrainFile ( dfndata . mapUop . string ( ) ) ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
else
{
Console < < " \t " < < dfndata . mapFile . string ( ) < < " (/ " < < dfndata . mapFile . filename ( ) . string ( ) < < " ) \t \t " ;
rValue = uoWorlds [ mapNum ] . LoadMulTerrainFile ( dfndata . mapFile . string ( ) ) ;
if ( rValue )
{
uoWorlds [ mapNum ] . ApplyTerrainDiff ( dfndata . mapDiffl . string ( ) , dfndata . mapDiff . string ( ) ) ;
2022-06-15 11:24:57 -04:00
}
}
2022-10-24 18:39:33 +08:00
if ( rValue )
{
rValue = uoWorlds [ mapNum ] . LoadArt ( dfndata . staMul . string ( ) , dfndata . staIdx . string ( ) ) ;
if ( rValue )
{
uoWorlds [ mapNum ] . ApplyDiff ( dfndata . staDiffl . string ( ) , dfndata . staDiffi . string ( ) , dfndata . staDiff . string ( ) ) ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
else
{
// this is interesting, we found the terrain, but not the art. Regardless, lets delete it
auto iter = uoWorlds . find ( mapNum ) ;
if ( iter ! = uoWorlds . end ( ) )
{
uoWorlds . erase ( iter ) ;
2022-06-15 11:24:57 -04:00
}
}
}
2022-10-24 18:39:33 +08:00
if ( ! rValue )
{
2022-06-22 09:47:05 -04:00
Console . PrintFailed ( ) ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
else
{
2022-06-15 11:24:57 -04:00
Console . PrintDone ( ) ;
}
}
2002-04-07 21:27:53 +00:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::LoadMultis()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Loads multi files into memory
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : LoadMultis ( const std : : string & uodir ) - > void
{
// now main memory multiItems
Console < < " Loading Multis.... " ;
// Odd we do no check?
if ( ! multiData . LoadMultiCollection ( std : : filesystem : : path ( uodir ) , & tileInfo ) )
{
Console . PrintFailed ( ) ;
Shutdown ( FATAL_UOX3_MULTI_DATA_NOT_FOUND ) ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
Console . PrintDone ( ) ;
}
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::ArtAt()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Try to find and return map tile at specific location in a world
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : ArtAt ( std : : int16_t x , std : : int16_t y , std : : uint8_t world ) - > std : : vector < Tile_st > &
{
static std : : vector < Tile_st > empty ;
try
{
return uoWorlds . at ( world ) . ArtAt ( x , y ) ;
}
catch ( . . . )
{
2022-06-15 11:24:57 -04:00
return empty ;
2002-04-07 21:27:53 +00:00
}
2012-11-03 18:11:04 +00:00
}
2022-10-24 18:39:33 +08:00
//=-----------------------------------------------------------------------------------------------=
auto CMulHandler : : ArtAt ( std : : int16_t x , std : : int16_t y , std : : uint8_t world ) const - > const std : : vector < Tile_st > &
{
static std : : vector < Tile_st > empty ;
try
{
return uoWorlds . at ( world ) . ArtAt ( x , y ) ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
catch ( . . . )
{
2022-06-15 11:24:57 -04:00
return empty ;
}
2021-05-30 03:21:05 +08:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::SizeOfMap()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Return x/y size of specified world
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : SizeOfMap ( std : : uint8_t worldNumber ) const - > std : : pair < int , int >
{
return uoWorlds . at ( worldNumber ) . Size ( ) ;
2002-04-07 21:27:53 +00:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::DiffCountForMap()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Return count of map differences for specified world
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : DiffCountForMap ( std : : uint8_t worldNumber ) const - > std : : pair < int , int >
{
return std : : make_pair ( uoWorlds . at ( worldNumber ) . DiffArt ( ) , uoWorlds . at ( worldNumber ) . DiffTerrain ( ) ) ;
2002-04-07 21:27:53 +00:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::MultiHeight()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Return the height of a multi item at the given x, y.
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : MultiHeight ( CItem * i , std : : int16_t x , std : : int16_t y , std : : int8_t oldZ , std : : int8_t maxZ , bool checkHeight ) - > std : : int8_t
{
UI16 multiId = static_cast < UI16 > ( i - > GetId ( ) - 0x4000 ) ;
2021-05-28 03:41:43 +08:00
2021-05-30 03:21:05 +08:00
SI08 mHeight = ILLEGAL_Z ;
SI08 tmpTop = ILLEGAL_Z ;
2022-10-24 18:39:33 +08:00
if ( ! MultiExists ( multiId ) )
return mHeight ;
2012-11-03 18:11:04 +00:00
const SI16 baseX = i - > GetX ( ) ;
const SI16 baseY = i - > GetY ( ) ;
const SI08 baseZ = i - > GetZ ( ) ;
2022-10-24 18:39:33 +08:00
for ( auto & multi : SeekMulti ( multiId ) . items )
{
if ( ( checkHeight | | multi . flag ) & & ( baseX + multi . offsetX ) = = x & & ( baseY + multi . offsetY ) = = y )
{
if ( checkHeight )
{
2021-05-28 03:41:43 +08:00
// Returns height of highest point of multi
2022-10-24 18:39:33 +08:00
tmpTop = static_cast < SI08 > ( baseZ + multi . altitude ) ;
if ( ( tmpTop < = oldZ + maxZ ) & & tmpTop > oldZ & & tmpTop > mHeight )
{
2021-05-28 03:41:43 +08:00
mHeight = tmpTop ;
2022-06-15 11:24:57 -04:00
}
Numerous changes with focus on feature and stability parity across Windows, Linux and MacOS platforms
Added new Makefile that handles compiling UOX3 and Spidermonkey on both Linux and MacOS (punt)
Added VS solution (SpiderMonkey.sln) and VC++ project files for compiling SpiderMonkey on Windows (Xuri)
Updated SpiderMonkey from v1.6.0 to v1.7.0
Added optimization flag -O2 for release build in CMakeLists.txt in project root (Xuri)
Added StringUtility file with general common string manipulation functions (punt)
Updated RandomNum function to use a "seedless" random number generator from C++11 instead of the old C rand() function. (punt)
Overall code cleanup to remove/replace platform-dependent code (punt)
Replaced potentially unsafe usage of C string stuff like sprintf, vsprintf, vsnprintf, strncat, strcpy and strlen throughout the code with calls to a format() function containing only a single, safe use of vsnprintf, ensuring there's a single place of failure if there's anything to fix and and making it easy to potentially replace this with std::format from C++20 when the time comes. (punt)
Replaced usage of char in many places with std::string (punt)
Started process of replacing UString usage with functions provided through StringUtility instead (punt)
Replaced platform specific fileIO handling in Windows/Linux with cross-platform C++17 standard std::filesystem (punt)
Replaced platform specific time handling by using cross-platform chrono library (punt)
Removed UOX namespace to reduce complexity (punt)
Elimitated template code approach to singletons for more modern c++ constructs, removing dependices in the process (punt)
Removed ODBC support; it hasn't been touched since the initial implementation in 2008, and there is a lack of someone to maintain the code. (punt)
Removed some platform specific files like uoxlinux.h, which is no longer required (punt)
Removed legacy crash protection code, and removed support for cluox (punt)
Removed legacy "support" for Borland compiler (punt)
Removed legacy VC++ 6 Workspace/Project files, VS2005 Solution/Project files, as these are no longer supported (Xuri)
Removed legacy BUILD folder with outdated compilation instructions (Xuri)
Removed old Changelog file (merged into Changelog.txt) (Xuri)
Fixed a pointer bug for items in multis on world load (punt)
Fixed a dictionary related issue that caused segmentation faults on Linux/MacOS (punt)
Fixed an issue with callbacks to JS scripts that caused segmentation faults on Linux/MacOS (punt)
Paths in uox.ini should now load properly on all platforms regardless of whether those paths use slashes or backslashes, and whether or not they end in a slash/backslash. (punt)
Moved to c++17 style of threading, and got rid of threadsafeobject.cpp/h (punt)
Replaced parsing of UOX.INI tags with a system that's more easily maintainable (punt)
Added some new commands to js/commands/custom/misc-cmd.js (Xuri)
cont // Targeted item will be made a container, set to nondecay and movable 2
endfight // Targeted character (and character being fought) will stop fighting
getmulti // Get multiObject for targeted item
finditem // Find item at layer X
movespeed // Set movement speed of target player (0x0 Normal, 0x1 Mounted, 0x2 Slow (walk only), 0x3 Hybrid ("jog"?), 0x4 Frozen)
Added new HTML based documentation in docs folder, and removed many old legacy docs that are either incorporated into this document already or no longer relevant for the current UOX3 version (Xuri)
Co-Authored-By: Charles Kerr <punt1959@users.noreply.github.com>
2020-09-07 18:09:55 +08:00
}
2022-10-24 18:39:33 +08:00
else
{
2022-06-12 19:54:28 -04:00
tmpTop = static_cast < SI08 > ( baseZ + multi . altitude ) ;
2022-10-24 18:39:33 +08:00
if ( std : : abs ( tmpTop - oldZ ) < = maxZ )
{
2023-03-17 16:01:22 +08:00
mHeight = tmpTop + multi . info - > ClimbHeight ( true ) ;
if ( mHeight = = oldZ ) // We found a surface at the suggested height
break ;
2022-06-15 11:24:57 -04:00
}
Numerous changes with focus on feature and stability parity across Windows, Linux and MacOS platforms
Added new Makefile that handles compiling UOX3 and Spidermonkey on both Linux and MacOS (punt)
Added VS solution (SpiderMonkey.sln) and VC++ project files for compiling SpiderMonkey on Windows (Xuri)
Updated SpiderMonkey from v1.6.0 to v1.7.0
Added optimization flag -O2 for release build in CMakeLists.txt in project root (Xuri)
Added StringUtility file with general common string manipulation functions (punt)
Updated RandomNum function to use a "seedless" random number generator from C++11 instead of the old C rand() function. (punt)
Overall code cleanup to remove/replace platform-dependent code (punt)
Replaced potentially unsafe usage of C string stuff like sprintf, vsprintf, vsnprintf, strncat, strcpy and strlen throughout the code with calls to a format() function containing only a single, safe use of vsnprintf, ensuring there's a single place of failure if there's anything to fix and and making it easy to potentially replace this with std::format from C++20 when the time comes. (punt)
Replaced usage of char in many places with std::string (punt)
Started process of replacing UString usage with functions provided through StringUtility instead (punt)
Replaced platform specific fileIO handling in Windows/Linux with cross-platform C++17 standard std::filesystem (punt)
Replaced platform specific time handling by using cross-platform chrono library (punt)
Removed UOX namespace to reduce complexity (punt)
Elimitated template code approach to singletons for more modern c++ constructs, removing dependices in the process (punt)
Removed ODBC support; it hasn't been touched since the initial implementation in 2008, and there is a lack of someone to maintain the code. (punt)
Removed some platform specific files like uoxlinux.h, which is no longer required (punt)
Removed legacy crash protection code, and removed support for cluox (punt)
Removed legacy "support" for Borland compiler (punt)
Removed legacy VC++ 6 Workspace/Project files, VS2005 Solution/Project files, as these are no longer supported (Xuri)
Removed legacy BUILD folder with outdated compilation instructions (Xuri)
Removed old Changelog file (merged into Changelog.txt) (Xuri)
Fixed a pointer bug for items in multis on world load (punt)
Fixed a dictionary related issue that caused segmentation faults on Linux/MacOS (punt)
Fixed an issue with callbacks to JS scripts that caused segmentation faults on Linux/MacOS (punt)
Paths in uox.ini should now load properly on all platforms regardless of whether those paths use slashes or backslashes, and whether or not they end in a slash/backslash. (punt)
Moved to c++17 style of threading, and got rid of threadsafeobject.cpp/h (punt)
Replaced parsing of UOX.INI tags with a system that's more easily maintainable (punt)
Added some new commands to js/commands/custom/misc-cmd.js (Xuri)
cont // Targeted item will be made a container, set to nondecay and movable 2
endfight // Targeted character (and character being fought) will stop fighting
getmulti // Get multiObject for targeted item
finditem // Find item at layer X
movespeed // Set movement speed of target player (0x0 Normal, 0x1 Mounted, 0x2 Slow (walk only), 0x3 Hybrid ("jog"?), 0x4 Frozen)
Added new HTML based documentation in docs folder, and removed many old legacy docs that are either incorporated into this document already or no longer relevant for the current UOX3 version (Xuri)
Co-Authored-By: Charles Kerr <punt1959@users.noreply.github.com>
2020-09-07 18:09:55 +08:00
}
2012-11-03 18:11:04 +00:00
}
Exposed various map and statics related functions to JS engine
Updated JS item properties MORE, MOREX, MOREY, MOREZ and SERIAL, and character property SERIAL, to pass values to JS scripts using JS_NewNumberValue() instead of INT_TO_JSVAL if the property value cannot fit inside JSVAL (checked with INT_FITS_IN_JSVAL)
Added support in CResponse.cpp for client trigger word for securing containers in houses - TW_HOUSESECURE
Updated CMulHandler::CheckStaticFlag() to match with statics that cover/extend across the specified Z coordinate, not just ones that have the same base Z level
Updated CMulHandler::DoesMapBlock() to not deem map tiles as blocking if they are more than 16 Z (height of a character) higher than the specified Z coordinate to check
Exposed method for finding corners of a multi to JS engine:
.GetMultiCorner( cornerID ) - Gets coordinates for specified corner of multi (0 = NW, 1 = NE, 2 = SW, 3 = SE)
Exposed various functions related to map, statics and multis to JS engine:
CalcMultiFromSer( serial ) - Find a multi from a provided serial
GetMapElevation( x, y, z, world) - Returns the map elevation at specified coordinates
IsInBuilding( x, y, z, world, instance, checkHeight ) - Returns true if the specified location is inside a static building (underneath static items), or if player is inside a multi. If the checkHeight argument is true, player is only deemed inside a multi if there are multi-items above the player's head. If player is in a courtyard/on a rooftop, they will be deemed to be NOT in the building. checkHeight is not used for the static part of the function.
CheckStaticFlag( x, y, z, world, tileFlagID ) - Checks to see if any statics at given coordinates has specified tile flag
DoesStaticBlock( x, y, z, world, checkWater ) - Checks if statics at/above given location blocks characters
DoesDynamicBlock( x, y, z, world, instance, checkWater, waterWalk ) - Checks if dynamics at/above given location blocks characters
DoesMapBlock( x, y, z, world, checkWater, waterWalk ) - Checks if map tile at/above given location blocks characters
2020-10-05 23:12:34 +08:00
}
2022-06-15 11:24:57 -04:00
Exposed various map and statics related functions to JS engine
Updated JS item properties MORE, MOREX, MOREY, MOREZ and SERIAL, and character property SERIAL, to pass values to JS scripts using JS_NewNumberValue() instead of INT_TO_JSVAL if the property value cannot fit inside JSVAL (checked with INT_FITS_IN_JSVAL)
Added support in CResponse.cpp for client trigger word for securing containers in houses - TW_HOUSESECURE
Updated CMulHandler::CheckStaticFlag() to match with statics that cover/extend across the specified Z coordinate, not just ones that have the same base Z level
Updated CMulHandler::DoesMapBlock() to not deem map tiles as blocking if they are more than 16 Z (height of a character) higher than the specified Z coordinate to check
Exposed method for finding corners of a multi to JS engine:
.GetMultiCorner( cornerID ) - Gets coordinates for specified corner of multi (0 = NW, 1 = NE, 2 = SW, 3 = SE)
Exposed various functions related to map, statics and multis to JS engine:
CalcMultiFromSer( serial ) - Find a multi from a provided serial
GetMapElevation( x, y, z, world) - Returns the map elevation at specified coordinates
IsInBuilding( x, y, z, world, instance, checkHeight ) - Returns true if the specified location is inside a static building (underneath static items), or if player is inside a multi. If the checkHeight argument is true, player is only deemed inside a multi if there are multi-items above the player's head. If player is in a courtyard/on a rooftop, they will be deemed to be NOT in the building. checkHeight is not used for the static part of the function.
CheckStaticFlag( x, y, z, world, tileFlagID ) - Checks to see if any statics at given coordinates has specified tile flag
DoesStaticBlock( x, y, z, world, checkWater ) - Checks if statics at/above given location blocks characters
DoesDynamicBlock( x, y, z, world, instance, checkWater, waterWalk ) - Checks if dynamics at/above given location blocks characters
DoesMapBlock( x, y, z, world, checkWater, waterWalk ) - Checks if map tile at/above given location blocks characters
2020-10-05 23:12:34 +08:00
return mHeight ;
Numerous changes with focus on feature and stability parity across Windows, Linux and MacOS platforms
Added new Makefile that handles compiling UOX3 and Spidermonkey on both Linux and MacOS (punt)
Added VS solution (SpiderMonkey.sln) and VC++ project files for compiling SpiderMonkey on Windows (Xuri)
Updated SpiderMonkey from v1.6.0 to v1.7.0
Added optimization flag -O2 for release build in CMakeLists.txt in project root (Xuri)
Added StringUtility file with general common string manipulation functions (punt)
Updated RandomNum function to use a "seedless" random number generator from C++11 instead of the old C rand() function. (punt)
Overall code cleanup to remove/replace platform-dependent code (punt)
Replaced potentially unsafe usage of C string stuff like sprintf, vsprintf, vsnprintf, strncat, strcpy and strlen throughout the code with calls to a format() function containing only a single, safe use of vsnprintf, ensuring there's a single place of failure if there's anything to fix and and making it easy to potentially replace this with std::format from C++20 when the time comes. (punt)
Replaced usage of char in many places with std::string (punt)
Started process of replacing UString usage with functions provided through StringUtility instead (punt)
Replaced platform specific fileIO handling in Windows/Linux with cross-platform C++17 standard std::filesystem (punt)
Replaced platform specific time handling by using cross-platform chrono library (punt)
Removed UOX namespace to reduce complexity (punt)
Elimitated template code approach to singletons for more modern c++ constructs, removing dependices in the process (punt)
Removed ODBC support; it hasn't been touched since the initial implementation in 2008, and there is a lack of someone to maintain the code. (punt)
Removed some platform specific files like uoxlinux.h, which is no longer required (punt)
Removed legacy crash protection code, and removed support for cluox (punt)
Removed legacy "support" for Borland compiler (punt)
Removed legacy VC++ 6 Workspace/Project files, VS2005 Solution/Project files, as these are no longer supported (Xuri)
Removed legacy BUILD folder with outdated compilation instructions (Xuri)
Removed old Changelog file (merged into Changelog.txt) (Xuri)
Fixed a pointer bug for items in multis on world load (punt)
Fixed a dictionary related issue that caused segmentation faults on Linux/MacOS (punt)
Fixed an issue with callbacks to JS scripts that caused segmentation faults on Linux/MacOS (punt)
Paths in uox.ini should now load properly on all platforms regardless of whether those paths use slashes or backslashes, and whether or not they end in a slash/backslash. (punt)
Moved to c++17 style of threading, and got rid of threadsafeobject.cpp/h (punt)
Replaced parsing of UOX.INI tags with a system that's more easily maintainable (punt)
Added some new commands to js/commands/custom/misc-cmd.js (Xuri)
cont // Targeted item will be made a container, set to nondecay and movable 2
endfight // Targeted character (and character being fought) will stop fighting
getmulti // Get multiObject for targeted item
finditem // Find item at layer X
movespeed // Set movement speed of target player (0x0 Normal, 0x1 Mounted, 0x2 Slow (walk only), 0x3 Hybrid ("jog"?), 0x4 Frozen)
Added new HTML based documentation in docs folder, and removed many old legacy docs that are either incorporated into this document already or no longer relevant for the current UOX3 version (Xuri)
Co-Authored-By: Charles Kerr <punt1959@users.noreply.github.com>
2020-09-07 18:09:55 +08:00
}
2002-04-07 21:27:53 +00:00
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::MultiTile()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Returns ID of tile in multi at specified coordinates
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : MultiTile ( CItem * i , std : : int16_t x , std : : int16_t y , std : : int8_t oldz , bool checkVisible ) - > std : : uint16_t
{
auto rValue = std : : uint16_t ( ) ;
if ( ! i - > CanBeObjType ( OT_MULTI ) )
2012-11-03 18:11:04 +00:00
return 0 ;
2022-10-24 18:39:33 +08:00
UI16 multiId = static_cast < UI16 > ( i - > GetId ( ) - 0x4000 ) ;
2022-11-14 21:12:12 -05:00
[[maybe_unused]] SI32 length = 0 ;
2022-11-04 17:12:13 -04:00
2022-10-24 18:39:33 +08:00
if ( ! MultiExists ( multiId ) )
{
2012-11-03 18:11:04 +00:00
Console < < " CMulHandler::MultiTile->Bad length in multi file. Avoiding stall. " < < myendl ;
2022-06-15 07:04:28 -04:00
auto map1 = Map - > SeekMap ( i - > GetX ( ) , i - > GetY ( ) , i - > WorldNumber ( ) ) ;
2022-10-24 18:39:33 +08:00
if ( map1 . CheckFlag ( TF_WET ) ) // is it water?
{
i - > SetId ( 0x4001 ) ;
}
2012-11-03 18:11:04 +00:00
else
2022-10-24 18:39:33 +08:00
{
i - > SetId ( 0x4064 ) ;
}
2022-11-14 21:12:12 -05:00
length = 0 ;
2002-04-07 21:27:53 +00:00
}
2022-10-24 18:39:33 +08:00
else
{
2021-05-30 03:21:05 +08:00
// Loop through each item that makes up the multi
// If any of those items intersect with area were are checking, return the ID of that tile
2022-10-24 18:39:33 +08:00
for ( auto & multi : SeekMulti ( multiId ) . items )
{
if ( ! checkVisible )
{
if ( ( i - > GetX ( ) + multi . offsetX = = x ) & & ( i - > GetY ( ) + multi . offsetY = = y ) )
{
rValue = multi . tileId ;
2022-06-15 11:24:57 -04:00
break ;
2021-05-30 03:21:05 +08:00
}
2012-11-03 18:11:04 +00:00
}
2022-10-24 18:39:33 +08:00
else if ( multi . flag > 0 & & ( std : : abs ( i - > GetZ ( ) + multi . altitude - oldz ) < = 1 ) )
{
if ( ( i - > GetX ( ) + multi . offsetX = = x ) & & ( i - > GetY ( ) + multi . offsetY = = y ) )
{
rValue = multi . tileId ;
2022-06-15 11:24:57 -04:00
break ;
2021-05-30 03:21:05 +08:00
}
2021-05-28 03:41:43 +08:00
}
2002-04-07 21:27:53 +00:00
}
}
2021-05-28 03:41:43 +08:00
2022-10-24 18:39:33 +08:00
return rValue ;
2002-04-07 21:27:53 +00:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::DynTile()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Returns which dynamic tile is present at (x,y) or -1 if no tile exists
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : DynTile ( std : : int16_t x , std : : int16_t y , std : : int8_t z , std : : uint8_t worldNumber , std : : uint16_t instanceId , bool checkOnlyMultis , bool checkOnlyNonMultis ) - > CItem *
{
auto rValue = static_cast < CItem * > ( nullptr ) ;
for ( auto & cellResponse : MapRegion - > PopulateList ( x , y , worldNumber ) )
{
if ( cellResponse = = nullptr )
continue ;
auto regItems = cellResponse - > GetItemList ( ) ;
for ( const auto & item : regItems - > collection ( ) )
{
if ( ! ValidateObject ( item ) | | ( item - > GetInstanceId ( ) ! = instanceId ) )
continue ;
if ( ! checkOnlyNonMultis )
{
if ( item - > GetId ( 1 ) > = 0x40 & & ( item - > GetObjType ( ) = = OT_MULTI | | item - > CanBeObjType ( OT_MULTI ) ) )
{
auto multiTileId = MultiTile ( item , x , y , z , false ) ;
if ( multiTileId > 0 )
{
rValue = item ;
break ;
}
}
else if ( item - > GetMulti ( ) ! = INVALIDSERIAL | | ValidateObject ( CalcMultiFromSer ( item - > GetOwner ( ) ) ) )
{
if ( ( item - > GetX ( ) = = x ) & & ( item - > GetY ( ) = = y ) )
{
rValue = item ;
break ;
}
}
}
else if ( ! checkOnlyMultis & & ( item - > GetX ( ) = = x ) & & ( item - > GetY ( ) = = y ) )
{
rValue = item ;
break ;
}
}
if ( rValue )
{
break ;
}
}
return rValue ;
}
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::DoesStaticBlock()
//o------------------------------------------------------------------------------------------------o
2022-06-15 11:24:57 -04:00
//| Purpose - Checks if statics at/above given coordinates blocks movement, etc
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : DoesStaticBlock ( std : : int16_t x , std : : int16_t y , std : : int8_t z , std : : uint8_t worldNumber , bool checkWater ) - > bool
{
auto & artTiles = Map - > ArtAt ( x , y , worldNumber ) ;
auto rValue = false ;
for ( auto & tile : artTiles )
{
auto elev = static_cast < SI08 > ( tile . altitude + tile . artInfo - > ClimbHeight ( ) ) ;
if ( checkWater )
{
if ( elev > = z & & tile . altitude < = z & & ( tile . CheckFlag ( TF_BLOCKING ) | | tile . CheckFlag ( TF_WET ) ) )
{
rValue = true ;
2022-06-15 11:24:57 -04:00
break ;
}
}
2022-10-24 18:39:33 +08:00
else
{
if ( elev > = z & & tile . altitude < = z & & ( tile . CheckFlag ( TF_BLOCKING ) & & ! tile . CheckFlag ( TF_WET ) ) )
{
rValue = true ;
2022-06-15 11:24:57 -04:00
break ;
}
}
}
2022-10-24 18:39:33 +08:00
return rValue ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::DoesDynamicBlock()
//o------------------------------------------------------------------------------------------------o
2022-06-15 11:24:57 -04:00
//| Purpose - Checks if there are any dynamic tiles at given coordinates that block movement
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : DoesDynamicBlock ( std : : int16_t x , std : : int16_t y , std : : int8_t z , std : : uint8_t worldNumber , std : : uint16_t instanceId , bool checkWater , bool waterWalk , bool checkOnlyMultis , bool checkOnlyNonMultis ) - > bool
{
auto rValue = false ;
2022-06-15 11:24:57 -04:00
// get the tile id of any dynamic tiles at this spot
2022-10-24 18:39:33 +08:00
auto dtItem = DynTile ( x , y , z , worldNumber , instanceId , checkOnlyMultis , checkOnlyNonMultis ) ;
if ( ValidateObject ( dtItem ) )
{
2022-06-15 11:24:57 -04:00
// Don't allow placing houses on top of immovable, visible dynamic items
2022-10-24 18:39:33 +08:00
if ( dtItem - > GetMovable ( ) = = 2 & & dtItem - > GetVisible ( ) = = 0 )
return true ;
// Ignore items that are permanently invisible or visible to GMs only
if ( dtItem - > GetVisible ( ) = = 1 | | dtItem - > GetVisible ( ) = = 3 )
return false ;
rValue = false ;
const UI16 dt = dtItem - > GetId ( ) ;
if ( IsValidTile ( dt ) & & dt ! = 0 )
{
auto tile = SeekTile ( dt ) ;
if ( waterWalk )
{
if ( ! tile . CheckFlag ( TF_WET ) )
{
rValue = true ;
2022-06-15 11:24:57 -04:00
}
}
2022-10-24 18:39:33 +08:00
else
{
if ( tile . CheckFlag ( TF_ROOF ) | | tile . CheckFlag ( TF_BLOCKING ) | | ( checkWater & & tile . CheckFlag ( TF_WET ) ) /*|| !tile.CheckFlag( TF_SURFACE ) */ )
{
rValue = true ;
Various changes
Fixed an issue with JS Function DeleteFile(), which would stop calling script from working if no file was found for deletion. Could break demolishing of houses, amongst other things
Fixed an issue with DoSEErrorMessage() function that prevented JS function error messages from being displayed in UOX3 console if message size was below 512
Fixed a bug that allowed players to place items on the same slot of walls when using a client that doesn't automatically restrict this
When dropping items, UOX3 will now look for a valid surface to drop them on, and move the item to said valid surface if applicable
Fixed an issue with loading of MultiCollections.uop where max boundaries of each multi was not set on load, preventing features that relied on finding corners of building from working (like automatic ban location detection for houses)
Added new function in mapstuff.cpp to check flags on dynamic items, and exposed it as a JS Function with same name and parameters:
CheckDynamicFlag( SI16 x, SI16 y, SI08 oldz, UI08 worldNumber, UI16 instanceID, TileFlags toCheck );
Fixed an issue where items were not always properly added to/removed from map regions when picked up or dropped
Added new helper function in dist.cpp to find 3D distance between two points:
getDist3D( point a, point b )
Added JS Function - DistanceBetween() - to find distance between two sets of coordinates, or two objects:
DistanceBetween( x1, y1, x2, y2 )
DistanceBetween( x1, y1, z1, x2, y2, z2 )
DistanceBetween( sourceObject, targObject )
DistanceBetween( sourceObject, targObject, checkZ )
Added Item JS Method - GetTileName() - to get name of an item directly from tiledata
Added new UOX.INI setting that defines the lower limit for when a purchase will withdraw money from bank instead of backpack:
BANKBUYTHRESHOLD=2000
Split the UOX.INI setting CONSOLELOG into three parts, to enable/disable different forms of logging:
CONSOLELOG=1/0 // Toggles logging of console messages, warnings and errors
NETWORKLOG=1/0 // Toggles logging of network traffic
SPEECHLOG=1/0 // Toggles logging of player/staff speech
2021-06-27 23:23:31 +08:00
}
Housing Revamp and more
Updated JS SysMessage function to accept up to 10 extra, optional arguments, which can be used with dictionary messages that require additional parameters like %s or %i
Added new type of house privilege in cMultiObj.cpp to keep track of friends of the multi - HOUSEPRIV_FRIEND - which is stored during worldsaves as one or more Friend=<player serial> tags in house.wsc
Added new type of house privilege in cMultiObj.cpp to keep track of guests of the multi - HOUSEPRIV_GUEST - which is stored during worldsaves as one or more Guest=<player serial> tags in house.wsc
When items are created for houses upon house placement, a reference to the multi's serial is now stored in the house sign's MORE property to allow easier tracking of which house a particular sign belongs to
Added tracking of new, persistent properties for houses via cMultiObj.cpp/h:
lockdowns, secure containers, vendors, guests, friends, owners, ban location, public status, number of visits, timestamps
Added a multitude of new methods in cMultiObj.cpp/h to assist in improving the functionality of houses
Added new tags for houses in house.dfn (default values applied if tag not specified):
MAXSECURECONTAINERS=4 - Max amount of secure containers allowed in a multi
MAXLOCKDOWNS=256 - Max amount of lockdowns allowed in a multi
MAXVENDORS=10 - Max amount of vendors allowed in a multi
MAXBANS=50 - Max amount of bans in a multi's ban list
MAXFRIENDS=50 - Max amount of friends in a multi's friend list
MAXGUESTS=50 - Max amount of guests in a multi's guest list
MAXOWNERS=8 - Max amount of owners and co-owners in a multi's owner list
MAXTRASHCONTAINERS=1 - Max amount of trash containers allowed in multi
SCRIPT=<scriptID> - Assign a JS script-ID directly to a multi
FRONTDOOR - indicates that a door is the front door of a house. Cannot be locked in public houses!
INTERIORDOOR - indicates that a door is an interior door of a house. Can be locked in public houses.
BANX - Location X offset for multi's ban location, if not used, will try to use SE corner of multi instead
BANY - Location Y offset for multi's ban location, if not used, will try to use SE corner of multi instead
Added JS Event:
onHouseCommand( tSock, multiObj, cmdID ) - For handling spoken house commands via JS scripts attached to multi.
Updated JS Events:
onEntrance() - can now trigger both for multi being entered and/or object entering
onLeaving() - can now trigger both for multi being left and/or object entering
onSpeech() - can now also trigger for items (in addition to chars) with event & script attached, if UOX.INI setting ITEMSDETECTSPEECH is enabled
Added JS Multi methods:
.IsBoat() - Returns whether the item (or multi) is a boat
.IsOwner( playerToCheck ) - Returns whether a player is the owner of a multi
.IsOnOwnerList( playerToCheck ) - Returns whether a player is on the (co-)owner list of a multi
.IsOnFriendList( playerToCheck ) - Returns whether a player is on the friend list of a multi
.IsOnGuestList( playerToCheck ) - Returns whether a player is on the guest list of a multi
.IsOnBanList( playerToCheck ) - Returns whether a player is on the ban list of a multi
.AddToFriendList( playertoAdd ) - Adds player to the friend list of a multi
.RemoveFromFriendList( playertoRemove ) - Removes player from the friend list of a multi
.AddToGuestList( playertoAdd ) - Adds player to the guest list of a multi
.RemoveFromGuestList( playertoRemove ) - Removes player from the guest list of a multi
.ClearOwnerList() - Clears all entries from a multi's (co-)owner list
.ClearFriendList() - Clears all entries from a multi's friend list
.ClearGuestList() - Clears all entries from a multi's guest list
.ClearBanList() - Clears all entries from a multi's ban list
.SecureContainer( itemToSecure ) - Secures a container in a multi
.UnsecureContainer( itemToUnsecure ) - Unsecures a container in a multi
.IsSecureContainer( itemToCheck ) - Checks if specified item is a secure container in a multi
.LockDownItem( itemToLockDown) - Locks down an item in a multi
.ReleaseItem( itemToRelease ) - Releases a locked down item in a multi
.KillKeys() - Deletes ALL keys associated with a multi
.AddTrashCont( itemToAdd ) - Add trash container to multi's list of trash containers
.RemoveTrashCont( itemToRemove ) - Remove trash container from multi's list of trash containers
Added JS Item (Multi only) properties:
.lockdowns - Get the number of lockdowns in a multi
.maxLockdowns - Get/Set the max number of lockdowns allowed in a multi
.secureContainers - Get the number of secure containers in a multi
.maxSecureContainers - Get/Set the max number of secure containers allowed in a multi
.trashContainers - Get the number of trash containers in a multi
.maxTrashContainers - Get/Set the max number of trash containers allowed in a multi
.friends - Get the number of friends in a multi's friend list
.maxFriends - Get/Set the max number of friends allowed in a multi's friend list
.guests - Get the number of guests in a multi's guest list
.maxGuests - Get/Set the max number of guests allowed in a multi's guest list
.owners - Get the number of owners in a multi's owner list
.maxOwners - Get/Set the max number of owners allowed in a multi's owner list
.bans - Get the number of banned players in a multi's ban list
.maxBans - Get/Set the max number of banned players allowed in a multi's ban list
.vendors - Get the number of player vendors in a multi
.maxVendors - Get the max number of player vendors allowed in a multi
.deed - Get the item sectionID for deed used to place multi
.isPublic - Get/Set the private/public state of a multi
.buildTimestamp - Get the timestamp for when the house was originally placed
.tradeTimestamp - Get the timestamp for when the house was last traded to another player
.banX - Get/Set the ban location X offset for the multi
.banY - Get/Set the ban location Y offset for the multi
Added JS Character properties:
.multi = Get/Set the multi object the character is in
.accountNum = Get the account number the character belongs to
.housesOwned = Get a count of houses owned by the character
.housesCoOwned = Get a count of houses co-owned by the character
Updated JS cBaseObject Methods .FirstItem(), .NextItem() and .FinishedItems() to also support iterating through items in multis
Updated JS multi Methods .FirstChar(), .NextChar() and .FinishedChars() to support an additional parameter to specify what kind of characters to loop through:
"default" or no parameter - all characters inside the multi
"owner" - players on multi's owner list
"friend" - players on multi's friend list
"guest" - players on multi's guest list
"banned" - players on multi's ban list
Added new INI tags to a new section of uox.ini called [houses]
DECAYTIMERINHOUSE=3600 // Decay timer in seconds for non-locked down items inside houses
PROTECTPRIVATEHOUSES=1 // Toggles whether private houses will automatically boot unauthorized visitors (1) or not (0)
TRACKHOUSESPERACCOUNT=1 // Toggles whether to track (and restrict) house ownership per account (1) or per character (0)
MAXHOUSESOWNABLE=1 // Specifies the max amount of houses a player can own per account/char, depending on how house ownership is tracked
MAXHOUSESCOOWNABLE=10 // Specifies the max amount of houses a player can co-own per character
CANOWNANDCOOWNHOUSES=1 // Toggles whether players can own and co-own houses at the same time
COOWNHOUSESONSAMEACCOUNT=1 // Toggles whether characters on same account as house owner will be treated as co-owners
Added new INI tags in [settings] section of uox.ini:
ITEMSDETECTSPEECH=0 // If enabled, server will search for nearby items with onSpeech JS event running whenever a character speaks. Disabled by default.
MAXPLAYERPACKITEMS=125 // Defines max item capacity for player (and NPC) backpacks. Defaults to 125.
Moved most of the existing house functionality to JS and expanded upon it to reach feature parity with houses in regular UO around Publish 15/16, with various extras thrown in for good measure and all functionality being customizable:
js/server/house/house.js (15000) - handles detection of house commands and characters entering/leaving houses
js/server/house/houseSign.js (15001) - contains and handles all house-related gumps/menus and what is shown when players interact with house sign
js/server/house/houseCommands.js (15002) - handles functionality of house commands and other functionality such as transfer of ownership, demolishing house, etc.
js/server/house/houseDeed.js (15003) - handles initial rules that allow/disallow placement of additional houses for players
All house-related menus now fully handled through JS
All house commands and other functionality now fully handled through JS
Removed redundant hard-coded house functionality
Implemented Co-owners, friends, guests for houses, with access rules in place for entry, lockdowns, house commands, etc.
Implemented Private and Public houses
Implemented Secure Containers and Trash Barrels
Definable max lockdowns, secure containers, player vendors, bans, friends, guests, owners, trash containers and more - per house type
JS scripts can now be attached directly to houses
Doors in houses can be marked as front doors or interior doors, and will be treated differently with regards to private and public houses
Added new item to dfndata/items/containers/misc.dfn - [trashbarrel]
Added new JS script (js/items/trashbarrel.js) with trash barrel functionality for houses. Trash barrels that are marked as secure containers are only accessible by owners, co-owners and friends of the house. Various options available at top of script.
Updated js/items/axe.js to support chopping up trash barrels and house add-ons in houses owned by the player
Fixed an issue with house doors being left behind after demolishing houses while their doors were open
Fixed an issue where GMs could be banned from player houses
Added Line of Sight checks to speech, to give players some privacy in their own homes
Updated house placement code to more accurately check for other multis, dynamic and static objects when placing houses; now requires free space around each house that cannot be blocked by other houses or items that can block player movement, and disallows placement of houses on roads
Updated house placement code to move characters blocking house placement to SE corner of the house
Updated house placement code to disallow placing houses in guarded regions, or in dungeons
Added new DFN tag for regions to enable/disable player houses in specific regions: HOUSING=0/1
Added new region (247) that covers path to Valley of Eodon in Felucca
Added new region (248) that covers Valley of Eodon in Ter-Mur, with player housing disabled
Added new region (249) that covers entire T2A lands, with player housing disabled
Updated SPACEX and SPACEY values for all houses in dfndata/house/house.dfn to match updated house placement code
Added new JS property to Regions that can be used to determine or change state of player housing in a region: .canPlaceHouse()
Updated rules for usage of dye tubs to dye locked down items; now only house owners or co-owners may dye locked down items
Updated rules for usage of the following locked down items in a house, which are now only usable by house owners and co-owners
Dyes, Guildstone Deeds, Recall Runes (renaming), Rename Deeds, Townstone Deeds, House Deeds, Boat Models, Player Vendor Deeds, Ore, Hair Dye
Updated rules for usage of the following locked down items in a house, which are now only usable by house owners, co-owners and friends:
Keys, Dye Tubs, Magic Scrolls, Fireworks Wands, Magic Wands, Smithing Tools, Mining Tools, Fishing Poles
Updated item lockdown rules to allow locking down (and releasing) items in a container as long as the container is locked down, and to only allow releasing a locked down container if it's empty of locked down items
Updated item lockdown rules to only allow locking down movement-blocking items further than 2 tiles away from doors
Updated rules for releasing items in houses - now the house owner can release any locked down items, co-owners can release items locked down by themselves or by friends, while friends can release only items locked down by themselves
Added some feedback to player about why their attempted house placement failed
Items added by GMs directly into multis will now decay based on the house-specific decay timer instead of the regular one
Fixed an issue that could cause items to almost instantly decay after being released from lockdown in a house
Placing house add-ons now properly takes into account SPACEX and SPACEY values when checking if they can fit in selected area of houses
Re-added SPACEX and SPACEY values for Pentagram and Loom house add-ons
House add-ons can now be converted back into house add-on deeds by chopping them with an axe
Added new item type - IT_HOUSEADDON (201) - used by house add-ons placed in player houses
Fixed a bug where keys would stop working after being added to a keyring, and would turn into blank keys upon release from the keyring
Added visitor count for public player houses, which keeps track of how many visits a public house has received, with each player counted max 1 time every 24 hours
Fixed an issue with FindPlayersInOldVisrange() where it didn't take into account that players could see buildings further away than the standard update range. This could cause players to see ghost images of buildings if they were at the "right" distance when the building was being demolished
Added NODECAY tag to all signs and doors in dfndata/house/house.dfn
Added FRONTDOOR or INTERIORDOOR (as appropriate) to all doors in dfndata/house/house.dfn
Added BANX and BANY to specify ban location for some houses in dfndata/house/house.dfn instead of relying on finding SE corner automatically
Implemented strongboxes (js/server/house/strongbox.js) for co-owners of a house, which can be placed with the house command "i wish to place a strongbox". Max capacity is 25 items
Updated 'REMOVE command to take an optional parameter - itemID. If supplied, the command will remove all items with this itemID from a targeted container
Fixed a bug when checking if dynamic items were blocking valid spawn locations for NPCs, some function arguments were in the wrong order!
Improved code that finds valid spawn locations for items and NPCs spawned via spawn regions. As server gradually builds up lists of valid spawn locations per region over time, it will start using these lists more often, rather than always look for brand new spawn locations.
Fixed a bug with CMulHandler::CheckStaticFlag() that prevented NPCs from spawning inside buildings with no static floors!
Fixed an issue with repeating commands that prevented GMs from being able to cancel them when using the ClassicUO client
Exposed character property .accountNum to JS engine
Extended CDataList class to include a Clear() method for clearing lists
Updated JS File method .Open() to support an optional, third argument - subFolderName - that defines in which sub-folder of UOX3/shared/ to store/look for a file. If no third argument is supplied, UOX3 will default to using the shared folder itself.
Updated JS File method .Length() to return a value of -1 for files that don't exist
Added new code function, exposed to JS engine with same parameters, which simply checks if a given tile ID has a specific flag
bool CheckTileFlag( UI16 itemID, TILEFLAG flagToCheck )
Added JS function used to find the root container of an item (if any)
FindRootContainer( itemSerial )
FindRootContainer( item )
Added new JS function that allows deleting files from UOX3/shared/ folder or subfolders of shared folder. If no subFolderName is provided, looks for file directly in shared folder itself. Restrictions on file- and folder-names apply.
bool DeleteFile( fileName, subFolderName )
Added new JS functions for checking if a specific client or server feature is enabled. See documentation for full list of client/server features.
GetClientFeature( bitNum ) // Returns true if specified client feature is enabled on server
GetServerFeature( bitNum ) // Returns true if specified server feature is enabled on server
Added new JS function for returning the value of almost any server setting from UOX.INI
GetServerSetting( settingNameInDoubleQuotes )
Updated JS function DoesDynamicBlock() with two new parameters - checkOnlyMultis and checkOnlyNonMultis
Updated JS function DoesMapBlock() with two new parameters - checkMultiPlacement and checkForRoad
Fixed an issue where a LoS check would prevent players from accessing containers in their own backpack
Added new functions in findfuncs.cpp to make it easier to find items near another object or location:
findNearbyItems( object, distance )
findNearbyItems( x, y, worldNumber, instanceID, distance )
Added new Item property - maxItems - used by containers to determine their max item capacity
Added new Item property - totalItemCount - used to get total item count in a container (including sub-containers)
Added check for max item capacity when creating new items that are added to a character's backpack - items will be created below character's feet if backpack is full!
Added new DFN tag for items, used by containers to determine item capacity for a given container:
MAXITEMS=# // 125 is the default for all containers if not set
Added new JS Item properties:
.maxItems // gets/sets item capacity for a given container
.totalItemCount // gets total item count in a container, including sub-containers
Updated item tooltips for containers to show accurate total item count, as well as to display max item capacity
Fixed a bug where picking up items from a non-locked down pile of items on the floor inside a multi could cause the remaining pile to be seen as no longer inside the multi, disallowing locking it back down and causing it to decay based on regular decay timer instead of house-specific one
Updated JS command set to allow setting poison-level on items ('set poison #) and hunger-level on characters ('set hunger #)
Fixed an issue with js/item/food.js that prevented poisoned food from poisoning characters when eaten
Fixed an issue with js/skill/poisoning.js that prevented players from poisoning food!
Updated various JS scripts and hardcoded targeting functions to disallow the targeting of locked down resources using skills and tools
Updated JS Method TextMessage() to support three extra, optional parameters. Note that if one optional parameter is included, all preceding optional parameters are also required!
speechTarget - What kind of target is this message intended for?
0 - Only visible for sender and receiver of message
1 - Visible to all players in range
2 - Visible to all NPCs and players in range
3 - Visible to all PCs everywhere + NPCs in range
4 - Visible to all PCs everywhere (broadcast)
5 - Only visible for the receiver of the message
speechTargetSerial - The serial of the receiver of the message, used if speechTarget is 0 or 5
speechFontType - The type of font to display the text in. Defaults to normal.
0 - Bold
1 - Normal with shadow
2 - Bold with shadow
3 - Normal
4 - Gothic
5 - Italic
6 - Small, dark
7 - Colourful
8 - Runic (only works with CAPS)
9 - Small, light
Added timestamp to worldsaves in console, to make it easier to see when a particular world-save was done
Added info about compiler/environment displayed at the top of the UOX3 console during startup
Updated dictionary files with new messages primarily related to housing
2020-11-04 02:00:37 +08:00
}
2002-04-07 21:27:53 +00:00
}
}
2022-10-24 18:39:33 +08:00
return rValue ;
2002-04-07 21:27:53 +00:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::DoesMapBlock()
//o------------------------------------------------------------------------------------------------o
2022-06-15 11:24:57 -04:00
//| Purpose - Checks if the map tile at the given coordinates block movement
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : DoesMapBlock ( std : : int16_t x , std : : int16_t y , std : : int8_t z , std : : uint8_t worldNumber , bool checkWater , bool waterWalk , bool checkMultiPlacement , bool checkForRoad ) - > bool
{
if ( checkWater | | waterWalk )
{
2022-06-15 11:24:57 -04:00
const auto & map = SeekMap ( x , y , worldNumber ) ;
2022-10-24 18:39:33 +08:00
if ( ( checkMultiPlacement & & map . altitude = = z ) | | ( ! checkMultiPlacement & & map . altitude > = z & & map . altitude - z < 16 ) )
{
if ( z = = ILLEGAL_Z )
return true ;
if ( waterWalk )
{
if ( ! map . CheckFlag ( TF_WET ) )
{
return true ;
2022-06-15 11:24:57 -04:00
}
}
2022-10-24 18:39:33 +08:00
else
{
if ( map . CheckFlag ( TF_WET ) | | map . CheckFlag ( TF_BLOCKING ) )
{
return true ;
2022-06-15 11:24:57 -04:00
}
}
// Check that player is not attempting to place a multi on a road
2022-10-24 18:39:33 +08:00
if ( checkWater & & checkMultiPlacement & & checkForRoad )
{
if ( map . terrainInfo - > IsRoadId ( ) )
{
return true ;
2022-06-15 11:24:57 -04:00
}
}
}
}
2022-10-24 18:39:33 +08:00
return false ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::CheckStaticFlag()
//o------------------------------------------------------------------------------------------------o
2022-06-15 11:24:57 -04:00
//| Purpose - Checks to see whether any statics at given coordinates has a specific flag
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : CheckStaticFlag ( std : : int16_t x , std : : int16_t y , std : : int8_t z , std : : uint8_t worldNumber , TileFlags toCheck , bool checkSpawnSurface ) - > bool
{
auto rValue = checkSpawnSurface ;
for ( const auto & tile : Map - > ArtAt ( x , y , worldNumber ) )
{
2022-06-15 11:24:57 -04:00
const SI08 elev = static_cast < SI08 > ( tile . altitude ) ;
2022-10-24 18:39:33 +08:00
const SI08 tileHeight = static_cast < SI08 > ( tile . artInfo - > ClimbHeight ( ) ) ;
if ( checkSpawnSurface )
{
2022-06-15 11:24:57 -04:00
// Special case used when checking for spawn surfaces
2022-10-24 18:39:33 +08:00
if ( ( z > = elev & & z < = ( elev + tileHeight ) ) & & ! tile . CheckFlag ( toCheck ) )
{
rValue = false ;
2022-06-15 11:24:57 -04:00
break ;
}
}
2022-10-24 18:39:33 +08:00
else
{
2022-06-15 11:24:57 -04:00
// Generic check exposed to JS
2022-10-24 18:39:33 +08:00
if ( ( z > = elev & & z < = ( elev + tileHeight ) ) & & tile . CheckFlag ( toCheck ) )
{
rValue = true ; // Found static with specified flag
2022-06-15 11:24:57 -04:00
break ;
}
}
}
2022-10-24 18:39:33 +08:00
return rValue ;
2002-04-07 21:27:53 +00:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::CheckDynamicFlag()
//o------------------------------------------------------------------------------------------------o
2022-06-15 11:24:57 -04:00
//| Purpose - Checks to see whether any dynamics at given coordinates has a specific flag
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : CheckDynamicFlag ( std : : int16_t x , std : : int16_t y , std : : int8_t z , std : : uint8_t worldNumber , std : : uint16_t instanceId , TileFlags toCheck ) - > bool
{
2023-03-17 16:01:22 +08:00
// Special case for handling multis that cross over between multiple map regions because of size
CMultiObj * tempMulti = FindMulti ( x , y , z , worldNumber , instanceId ) ;
if ( ValidateObject ( tempMulti ) )
2022-10-24 18:39:33 +08:00
{
2023-03-17 16:01:22 +08:00
// Look for a multi item at specific location
auto multiId = static_cast < UI16 > ( tempMulti - > GetId ( ) - 0x4000 ) ;
for ( auto & multiItem : SeekMulti ( multiId ) . items )
2022-10-24 18:39:33 +08:00
{
2023-03-17 16:01:22 +08:00
if ( multiItem . flag > 0 & & ( abs ( tempMulti - > GetZ ( ) + multiItem . altitude - z ) < = 1 ) )
{
if ( ( tempMulti - > GetX ( ) + multiItem . offsetX = = x ) & & ( tempMulti - > GetY ( ) + multiItem . offsetY = = y ) )
{
if ( SeekTile ( multiItem . tileId ) . CheckFlag ( toCheck ) )
{
return true ;
}
}
}
}
}
else
{
// Search map region of given location for all potentially blocking dynamic items
for ( auto & cellResponse : MapRegion - > PopulateList ( x , y , worldNumber ) )
{
if ( cellResponse = = nullptr )
2022-10-24 18:39:33 +08:00
continue ;
2023-03-17 16:01:22 +08:00
auto regItems = cellResponse - > GetItemList ( ) ;
for ( const auto & item : regItems - > collection ( ) )
2022-10-24 18:39:33 +08:00
{
2023-03-17 16:01:22 +08:00
if ( ! ValidateObject ( item ) | | item - > GetInstanceId ( ) ! = instanceId )
continue ;
if ( ( item - > GetId ( 1 ) > = 0x40 ) & & ( ( item - > GetObjType ( ) = = OT_MULTI ) | | ( item - > CanBeObjType ( OT_MULTI ) ) ) )
2022-10-24 18:39:33 +08:00
{
2023-03-17 16:01:22 +08:00
// Found a multi
// Look for a multi item at specific location
auto multiId = static_cast < UI16 > ( item - > GetId ( ) - 0x4000 ) ;
for ( auto & multiItem : SeekMulti ( multiId ) . items )
2022-10-24 18:39:33 +08:00
{
2023-03-17 16:01:22 +08:00
if ( multiItem . flag > 0 & & ( abs ( item - > GetZ ( ) + multiItem . altitude - z ) < = 1 ) )
2022-10-24 18:39:33 +08:00
{
2023-03-17 16:01:22 +08:00
if ( ( item - > GetX ( ) + multiItem . offsetX = = x ) & & ( item - > GetY ( ) + multiItem . offsetY = = y ) )
2022-10-24 18:39:33 +08:00
{
2023-03-17 16:01:22 +08:00
if ( SeekTile ( multiItem . tileId ) . CheckFlag ( toCheck ) )
{
return true ;
}
2022-06-15 11:24:57 -04:00
}
}
}
2022-10-24 18:39:33 +08:00
}
2023-03-17 16:01:22 +08:00
else
2022-10-24 18:39:33 +08:00
{
2023-03-17 16:01:22 +08:00
// item is not a multi
if ( ( item - > GetX ( ) = = x ) & & ( item - > GetY ( ) = = y ) & & ( item - > GetZ ( ) = = z ) )
2022-10-24 18:39:33 +08:00
{
2023-03-17 16:01:22 +08:00
auto itemZ = item - > GetZ ( ) ;
const SI08 tileHeight = static_cast < SI08 > ( TileHeight ( item - > GetId ( ) ) ) ;
if ( ( itemZ = = z & & itemZ + tileHeight > z ) | | ( itemZ < z & & itemZ + tileHeight > = z ) )
2022-10-24 18:39:33 +08:00
{
2023-03-17 16:01:22 +08:00
if ( SeekTile ( item - > GetId ( ) ) . CheckFlag ( toCheck ) )
{
return true ;
}
2022-06-15 11:24:57 -04:00
}
}
}
}
}
2022-06-14 17:53:00 -04:00
}
2022-06-15 11:24:57 -04:00
return false ;
2002-04-07 21:27:53 +00:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::CheckTileFlag()
//o------------------------------------------------------------------------------------------------o
2022-06-15 11:24:57 -04:00
//| Purpose - Checks to see whether given tile ID has a specified flag
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : CheckTileFlag ( std : : uint16_t itemId , TileFlags flagToCheck ) - > bool
{
if ( ! SeekTile ( itemId ) . CheckFlag ( flagToCheck ) )
{
2021-05-28 03:41:43 +08:00
return false ;
2002-04-07 21:27:53 +00:00
}
2022-06-15 11:24:57 -04:00
return true ;
2002-04-07 21:27:53 +00:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::StaticTop()
//o------------------------------------------------------------------------------------------------o
2022-06-15 11:24:57 -04:00
//| Purpose - Top of statics at/above given coordinates
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : StaticTop ( std : : int16_t x , std : : int16_t y , std : : int8_t z , std : : uint8_t worldNumber , std : : int8_t maxZ ) - > std : : int8_t
{
2022-06-15 11:24:57 -04:00
auto top = ILLEGAL_Z ;
2022-10-24 18:39:33 +08:00
const auto & artTiles = Map - > ArtAt ( x , y , worldNumber ) ;
for ( const auto & tile : artTiles )
{
auto tempTop = static_cast < std : : int8_t > ( tile . altitude + tile . artInfo - > ClimbHeight ( ) ) ;
if ( ( tempTop < = z + maxZ ) & & ( tempTop > top ) )
{
2022-06-15 11:24:57 -04:00
top = tempTop ;
2022-10-24 18:39:33 +08:00
}
2012-11-03 18:11:04 +00:00
}
2022-06-15 11:24:57 -04:00
return top ;
2002-04-07 21:27:53 +00:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::DynamicElevation()
//o------------------------------------------------------------------------------------------------o
2022-06-15 11:24:57 -04:00
//| Purpose - This was fixed to actually return the *elevation* of dynamic items at/above given coordinates
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
2022-11-01 02:25:52 +08:00
auto CMulHandler : : DynamicElevation ( std : : int16_t x , std : : int16_t y , std : : int8_t z , std : : uint8_t worldNumber , std : : uint16_t instanceId , std : : int8_t maxZ ) - > std : : int8_t
2022-10-24 18:39:33 +08:00
{
auto dynZ = ILLEGAL_Z ;
2023-03-08 13:08:12 +08:00
// Special case for handling multis that cross over between multiple map regions because of size
CMultiObj * tempMulti = FindMulti ( x , y , z , worldNumber , instanceId ) ;
2023-03-17 16:01:22 +08:00
if ( ValidateObject ( tempMulti ) )
2022-10-24 18:39:33 +08:00
{
2023-03-08 13:08:12 +08:00
dynZ = MultiHeight ( tempMulti , x , y , z , maxZ ) ;
2023-03-17 16:01:22 +08:00
// Also check dynamic items inside the multi
for ( const auto & tempMultiItem : tempMulti - > GetItemsInMultiList ( ) - > collection ( ) )
{
if ( tempMultiItem - > GetX ( ) = = x & & tempMultiItem - > GetY ( ) = = y )
{
SI08 zTemp = static_cast < SI08 > ( tempMultiItem - > GetZ ( ) + TileHeight ( tempMultiItem - > GetId ( ) ) ) ;
if ( ( zTemp < = z + maxZ ) & & ( zTemp > dynZ | | ( dynZ > = z + maxZ ) ) )
{
dynZ = zTemp ;
}
}
}
2023-03-08 13:08:12 +08:00
}
else
{
auto MapArea = MapRegion - > GetMapRegion ( MapRegion - > GetGridX ( x ) , MapRegion - > GetGridY ( y ) , worldNumber ) ;
if ( MapArea )
2022-10-24 18:39:33 +08:00
{
2023-03-08 13:08:12 +08:00
auto regItems = MapArea - > GetItemList ( ) ;
for ( const auto tempItem : regItems - > collection ( ) )
2022-10-24 18:39:33 +08:00
{
2023-03-08 13:08:12 +08:00
if ( ValidateObject ( tempItem ) | | tempItem - > GetInstanceId ( ) ! = instanceId )
2022-10-24 18:39:33 +08:00
{
2023-03-08 13:08:12 +08:00
if ( tempItem - > GetId ( 1 ) > = 0x40 & & tempItem - > CanBeObjType ( OT_MULTI ) )
2022-10-24 18:39:33 +08:00
{
2023-03-08 13:08:12 +08:00
dynZ = MultiHeight ( tempItem , x , y , z , maxZ ) ;
}
else if ( tempItem - > GetX ( ) = = x & & tempItem - > GetY ( ) = = y )
{
SI08 zTemp = static_cast < SI08 > ( tempItem - > GetZ ( ) + TileHeight ( tempItem - > GetId ( ) ) ) ;
if ( ( zTemp < = z + maxZ ) & & zTemp > dynZ )
{
dynZ = zTemp ;
}
2022-06-15 07:04:28 -04:00
}
Housing Revamp and more
Updated JS SysMessage function to accept up to 10 extra, optional arguments, which can be used with dictionary messages that require additional parameters like %s or %i
Added new type of house privilege in cMultiObj.cpp to keep track of friends of the multi - HOUSEPRIV_FRIEND - which is stored during worldsaves as one or more Friend=<player serial> tags in house.wsc
Added new type of house privilege in cMultiObj.cpp to keep track of guests of the multi - HOUSEPRIV_GUEST - which is stored during worldsaves as one or more Guest=<player serial> tags in house.wsc
When items are created for houses upon house placement, a reference to the multi's serial is now stored in the house sign's MORE property to allow easier tracking of which house a particular sign belongs to
Added tracking of new, persistent properties for houses via cMultiObj.cpp/h:
lockdowns, secure containers, vendors, guests, friends, owners, ban location, public status, number of visits, timestamps
Added a multitude of new methods in cMultiObj.cpp/h to assist in improving the functionality of houses
Added new tags for houses in house.dfn (default values applied if tag not specified):
MAXSECURECONTAINERS=4 - Max amount of secure containers allowed in a multi
MAXLOCKDOWNS=256 - Max amount of lockdowns allowed in a multi
MAXVENDORS=10 - Max amount of vendors allowed in a multi
MAXBANS=50 - Max amount of bans in a multi's ban list
MAXFRIENDS=50 - Max amount of friends in a multi's friend list
MAXGUESTS=50 - Max amount of guests in a multi's guest list
MAXOWNERS=8 - Max amount of owners and co-owners in a multi's owner list
MAXTRASHCONTAINERS=1 - Max amount of trash containers allowed in multi
SCRIPT=<scriptID> - Assign a JS script-ID directly to a multi
FRONTDOOR - indicates that a door is the front door of a house. Cannot be locked in public houses!
INTERIORDOOR - indicates that a door is an interior door of a house. Can be locked in public houses.
BANX - Location X offset for multi's ban location, if not used, will try to use SE corner of multi instead
BANY - Location Y offset for multi's ban location, if not used, will try to use SE corner of multi instead
Added JS Event:
onHouseCommand( tSock, multiObj, cmdID ) - For handling spoken house commands via JS scripts attached to multi.
Updated JS Events:
onEntrance() - can now trigger both for multi being entered and/or object entering
onLeaving() - can now trigger both for multi being left and/or object entering
onSpeech() - can now also trigger for items (in addition to chars) with event & script attached, if UOX.INI setting ITEMSDETECTSPEECH is enabled
Added JS Multi methods:
.IsBoat() - Returns whether the item (or multi) is a boat
.IsOwner( playerToCheck ) - Returns whether a player is the owner of a multi
.IsOnOwnerList( playerToCheck ) - Returns whether a player is on the (co-)owner list of a multi
.IsOnFriendList( playerToCheck ) - Returns whether a player is on the friend list of a multi
.IsOnGuestList( playerToCheck ) - Returns whether a player is on the guest list of a multi
.IsOnBanList( playerToCheck ) - Returns whether a player is on the ban list of a multi
.AddToFriendList( playertoAdd ) - Adds player to the friend list of a multi
.RemoveFromFriendList( playertoRemove ) - Removes player from the friend list of a multi
.AddToGuestList( playertoAdd ) - Adds player to the guest list of a multi
.RemoveFromGuestList( playertoRemove ) - Removes player from the guest list of a multi
.ClearOwnerList() - Clears all entries from a multi's (co-)owner list
.ClearFriendList() - Clears all entries from a multi's friend list
.ClearGuestList() - Clears all entries from a multi's guest list
.ClearBanList() - Clears all entries from a multi's ban list
.SecureContainer( itemToSecure ) - Secures a container in a multi
.UnsecureContainer( itemToUnsecure ) - Unsecures a container in a multi
.IsSecureContainer( itemToCheck ) - Checks if specified item is a secure container in a multi
.LockDownItem( itemToLockDown) - Locks down an item in a multi
.ReleaseItem( itemToRelease ) - Releases a locked down item in a multi
.KillKeys() - Deletes ALL keys associated with a multi
.AddTrashCont( itemToAdd ) - Add trash container to multi's list of trash containers
.RemoveTrashCont( itemToRemove ) - Remove trash container from multi's list of trash containers
Added JS Item (Multi only) properties:
.lockdowns - Get the number of lockdowns in a multi
.maxLockdowns - Get/Set the max number of lockdowns allowed in a multi
.secureContainers - Get the number of secure containers in a multi
.maxSecureContainers - Get/Set the max number of secure containers allowed in a multi
.trashContainers - Get the number of trash containers in a multi
.maxTrashContainers - Get/Set the max number of trash containers allowed in a multi
.friends - Get the number of friends in a multi's friend list
.maxFriends - Get/Set the max number of friends allowed in a multi's friend list
.guests - Get the number of guests in a multi's guest list
.maxGuests - Get/Set the max number of guests allowed in a multi's guest list
.owners - Get the number of owners in a multi's owner list
.maxOwners - Get/Set the max number of owners allowed in a multi's owner list
.bans - Get the number of banned players in a multi's ban list
.maxBans - Get/Set the max number of banned players allowed in a multi's ban list
.vendors - Get the number of player vendors in a multi
.maxVendors - Get the max number of player vendors allowed in a multi
.deed - Get the item sectionID for deed used to place multi
.isPublic - Get/Set the private/public state of a multi
.buildTimestamp - Get the timestamp for when the house was originally placed
.tradeTimestamp - Get the timestamp for when the house was last traded to another player
.banX - Get/Set the ban location X offset for the multi
.banY - Get/Set the ban location Y offset for the multi
Added JS Character properties:
.multi = Get/Set the multi object the character is in
.accountNum = Get the account number the character belongs to
.housesOwned = Get a count of houses owned by the character
.housesCoOwned = Get a count of houses co-owned by the character
Updated JS cBaseObject Methods .FirstItem(), .NextItem() and .FinishedItems() to also support iterating through items in multis
Updated JS multi Methods .FirstChar(), .NextChar() and .FinishedChars() to support an additional parameter to specify what kind of characters to loop through:
"default" or no parameter - all characters inside the multi
"owner" - players on multi's owner list
"friend" - players on multi's friend list
"guest" - players on multi's guest list
"banned" - players on multi's ban list
Added new INI tags to a new section of uox.ini called [houses]
DECAYTIMERINHOUSE=3600 // Decay timer in seconds for non-locked down items inside houses
PROTECTPRIVATEHOUSES=1 // Toggles whether private houses will automatically boot unauthorized visitors (1) or not (0)
TRACKHOUSESPERACCOUNT=1 // Toggles whether to track (and restrict) house ownership per account (1) or per character (0)
MAXHOUSESOWNABLE=1 // Specifies the max amount of houses a player can own per account/char, depending on how house ownership is tracked
MAXHOUSESCOOWNABLE=10 // Specifies the max amount of houses a player can co-own per character
CANOWNANDCOOWNHOUSES=1 // Toggles whether players can own and co-own houses at the same time
COOWNHOUSESONSAMEACCOUNT=1 // Toggles whether characters on same account as house owner will be treated as co-owners
Added new INI tags in [settings] section of uox.ini:
ITEMSDETECTSPEECH=0 // If enabled, server will search for nearby items with onSpeech JS event running whenever a character speaks. Disabled by default.
MAXPLAYERPACKITEMS=125 // Defines max item capacity for player (and NPC) backpacks. Defaults to 125.
Moved most of the existing house functionality to JS and expanded upon it to reach feature parity with houses in regular UO around Publish 15/16, with various extras thrown in for good measure and all functionality being customizable:
js/server/house/house.js (15000) - handles detection of house commands and characters entering/leaving houses
js/server/house/houseSign.js (15001) - contains and handles all house-related gumps/menus and what is shown when players interact with house sign
js/server/house/houseCommands.js (15002) - handles functionality of house commands and other functionality such as transfer of ownership, demolishing house, etc.
js/server/house/houseDeed.js (15003) - handles initial rules that allow/disallow placement of additional houses for players
All house-related menus now fully handled through JS
All house commands and other functionality now fully handled through JS
Removed redundant hard-coded house functionality
Implemented Co-owners, friends, guests for houses, with access rules in place for entry, lockdowns, house commands, etc.
Implemented Private and Public houses
Implemented Secure Containers and Trash Barrels
Definable max lockdowns, secure containers, player vendors, bans, friends, guests, owners, trash containers and more - per house type
JS scripts can now be attached directly to houses
Doors in houses can be marked as front doors or interior doors, and will be treated differently with regards to private and public houses
Added new item to dfndata/items/containers/misc.dfn - [trashbarrel]
Added new JS script (js/items/trashbarrel.js) with trash barrel functionality for houses. Trash barrels that are marked as secure containers are only accessible by owners, co-owners and friends of the house. Various options available at top of script.
Updated js/items/axe.js to support chopping up trash barrels and house add-ons in houses owned by the player
Fixed an issue with house doors being left behind after demolishing houses while their doors were open
Fixed an issue where GMs could be banned from player houses
Added Line of Sight checks to speech, to give players some privacy in their own homes
Updated house placement code to more accurately check for other multis, dynamic and static objects when placing houses; now requires free space around each house that cannot be blocked by other houses or items that can block player movement, and disallows placement of houses on roads
Updated house placement code to move characters blocking house placement to SE corner of the house
Updated house placement code to disallow placing houses in guarded regions, or in dungeons
Added new DFN tag for regions to enable/disable player houses in specific regions: HOUSING=0/1
Added new region (247) that covers path to Valley of Eodon in Felucca
Added new region (248) that covers Valley of Eodon in Ter-Mur, with player housing disabled
Added new region (249) that covers entire T2A lands, with player housing disabled
Updated SPACEX and SPACEY values for all houses in dfndata/house/house.dfn to match updated house placement code
Added new JS property to Regions that can be used to determine or change state of player housing in a region: .canPlaceHouse()
Updated rules for usage of dye tubs to dye locked down items; now only house owners or co-owners may dye locked down items
Updated rules for usage of the following locked down items in a house, which are now only usable by house owners and co-owners
Dyes, Guildstone Deeds, Recall Runes (renaming), Rename Deeds, Townstone Deeds, House Deeds, Boat Models, Player Vendor Deeds, Ore, Hair Dye
Updated rules for usage of the following locked down items in a house, which are now only usable by house owners, co-owners and friends:
Keys, Dye Tubs, Magic Scrolls, Fireworks Wands, Magic Wands, Smithing Tools, Mining Tools, Fishing Poles
Updated item lockdown rules to allow locking down (and releasing) items in a container as long as the container is locked down, and to only allow releasing a locked down container if it's empty of locked down items
Updated item lockdown rules to only allow locking down movement-blocking items further than 2 tiles away from doors
Updated rules for releasing items in houses - now the house owner can release any locked down items, co-owners can release items locked down by themselves or by friends, while friends can release only items locked down by themselves
Added some feedback to player about why their attempted house placement failed
Items added by GMs directly into multis will now decay based on the house-specific decay timer instead of the regular one
Fixed an issue that could cause items to almost instantly decay after being released from lockdown in a house
Placing house add-ons now properly takes into account SPACEX and SPACEY values when checking if they can fit in selected area of houses
Re-added SPACEX and SPACEY values for Pentagram and Loom house add-ons
House add-ons can now be converted back into house add-on deeds by chopping them with an axe
Added new item type - IT_HOUSEADDON (201) - used by house add-ons placed in player houses
Fixed a bug where keys would stop working after being added to a keyring, and would turn into blank keys upon release from the keyring
Added visitor count for public player houses, which keeps track of how many visits a public house has received, with each player counted max 1 time every 24 hours
Fixed an issue with FindPlayersInOldVisrange() where it didn't take into account that players could see buildings further away than the standard update range. This could cause players to see ghost images of buildings if they were at the "right" distance when the building was being demolished
Added NODECAY tag to all signs and doors in dfndata/house/house.dfn
Added FRONTDOOR or INTERIORDOOR (as appropriate) to all doors in dfndata/house/house.dfn
Added BANX and BANY to specify ban location for some houses in dfndata/house/house.dfn instead of relying on finding SE corner automatically
Implemented strongboxes (js/server/house/strongbox.js) for co-owners of a house, which can be placed with the house command "i wish to place a strongbox". Max capacity is 25 items
Updated 'REMOVE command to take an optional parameter - itemID. If supplied, the command will remove all items with this itemID from a targeted container
Fixed a bug when checking if dynamic items were blocking valid spawn locations for NPCs, some function arguments were in the wrong order!
Improved code that finds valid spawn locations for items and NPCs spawned via spawn regions. As server gradually builds up lists of valid spawn locations per region over time, it will start using these lists more often, rather than always look for brand new spawn locations.
Fixed a bug with CMulHandler::CheckStaticFlag() that prevented NPCs from spawning inside buildings with no static floors!
Fixed an issue with repeating commands that prevented GMs from being able to cancel them when using the ClassicUO client
Exposed character property .accountNum to JS engine
Extended CDataList class to include a Clear() method for clearing lists
Updated JS File method .Open() to support an optional, third argument - subFolderName - that defines in which sub-folder of UOX3/shared/ to store/look for a file. If no third argument is supplied, UOX3 will default to using the shared folder itself.
Updated JS File method .Length() to return a value of -1 for files that don't exist
Added new code function, exposed to JS engine with same parameters, which simply checks if a given tile ID has a specific flag
bool CheckTileFlag( UI16 itemID, TILEFLAG flagToCheck )
Added JS function used to find the root container of an item (if any)
FindRootContainer( itemSerial )
FindRootContainer( item )
Added new JS function that allows deleting files from UOX3/shared/ folder or subfolders of shared folder. If no subFolderName is provided, looks for file directly in shared folder itself. Restrictions on file- and folder-names apply.
bool DeleteFile( fileName, subFolderName )
Added new JS functions for checking if a specific client or server feature is enabled. See documentation for full list of client/server features.
GetClientFeature( bitNum ) // Returns true if specified client feature is enabled on server
GetServerFeature( bitNum ) // Returns true if specified server feature is enabled on server
Added new JS function for returning the value of almost any server setting from UOX.INI
GetServerSetting( settingNameInDoubleQuotes )
Updated JS function DoesDynamicBlock() with two new parameters - checkOnlyMultis and checkOnlyNonMultis
Updated JS function DoesMapBlock() with two new parameters - checkMultiPlacement and checkForRoad
Fixed an issue where a LoS check would prevent players from accessing containers in their own backpack
Added new functions in findfuncs.cpp to make it easier to find items near another object or location:
findNearbyItems( object, distance )
findNearbyItems( x, y, worldNumber, instanceID, distance )
Added new Item property - maxItems - used by containers to determine their max item capacity
Added new Item property - totalItemCount - used to get total item count in a container (including sub-containers)
Added check for max item capacity when creating new items that are added to a character's backpack - items will be created below character's feet if backpack is full!
Added new DFN tag for items, used by containers to determine item capacity for a given container:
MAXITEMS=# // 125 is the default for all containers if not set
Added new JS Item properties:
.maxItems // gets/sets item capacity for a given container
.totalItemCount // gets total item count in a container, including sub-containers
Updated item tooltips for containers to show accurate total item count, as well as to display max item capacity
Fixed a bug where picking up items from a non-locked down pile of items on the floor inside a multi could cause the remaining pile to be seen as no longer inside the multi, disallowing locking it back down and causing it to decay based on regular decay timer instead of house-specific one
Updated JS command set to allow setting poison-level on items ('set poison #) and hunger-level on characters ('set hunger #)
Fixed an issue with js/item/food.js that prevented poisoned food from poisoning characters when eaten
Fixed an issue with js/skill/poisoning.js that prevented players from poisoning food!
Updated various JS scripts and hardcoded targeting functions to disallow the targeting of locked down resources using skills and tools
Updated JS Method TextMessage() to support three extra, optional parameters. Note that if one optional parameter is included, all preceding optional parameters are also required!
speechTarget - What kind of target is this message intended for?
0 - Only visible for sender and receiver of message
1 - Visible to all players in range
2 - Visible to all NPCs and players in range
3 - Visible to all PCs everywhere + NPCs in range
4 - Visible to all PCs everywhere (broadcast)
5 - Only visible for the receiver of the message
speechTargetSerial - The serial of the receiver of the message, used if speechTarget is 0 or 5
speechFontType - The type of font to display the text in. Defaults to normal.
0 - Bold
1 - Normal with shadow
2 - Bold with shadow
3 - Normal
4 - Gothic
5 - Italic
6 - Small, dark
7 - Colourful
8 - Runic (only works with CAPS)
9 - Small, light
Added timestamp to worldsaves in console, to make it easier to see when a particular world-save was done
Added info about compiler/environment displayed at the top of the UOX3 console during startup
Updated dictionary files with new messages primarily related to housing
2020-11-04 02:00:37 +08:00
}
Numerous changes with focus on feature and stability parity across Windows, Linux and MacOS platforms
Added new Makefile that handles compiling UOX3 and Spidermonkey on both Linux and MacOS (punt)
Added VS solution (SpiderMonkey.sln) and VC++ project files for compiling SpiderMonkey on Windows (Xuri)
Updated SpiderMonkey from v1.6.0 to v1.7.0
Added optimization flag -O2 for release build in CMakeLists.txt in project root (Xuri)
Added StringUtility file with general common string manipulation functions (punt)
Updated RandomNum function to use a "seedless" random number generator from C++11 instead of the old C rand() function. (punt)
Overall code cleanup to remove/replace platform-dependent code (punt)
Replaced potentially unsafe usage of C string stuff like sprintf, vsprintf, vsnprintf, strncat, strcpy and strlen throughout the code with calls to a format() function containing only a single, safe use of vsnprintf, ensuring there's a single place of failure if there's anything to fix and and making it easy to potentially replace this with std::format from C++20 when the time comes. (punt)
Replaced usage of char in many places with std::string (punt)
Started process of replacing UString usage with functions provided through StringUtility instead (punt)
Replaced platform specific fileIO handling in Windows/Linux with cross-platform C++17 standard std::filesystem (punt)
Replaced platform specific time handling by using cross-platform chrono library (punt)
Removed UOX namespace to reduce complexity (punt)
Elimitated template code approach to singletons for more modern c++ constructs, removing dependices in the process (punt)
Removed ODBC support; it hasn't been touched since the initial implementation in 2008, and there is a lack of someone to maintain the code. (punt)
Removed some platform specific files like uoxlinux.h, which is no longer required (punt)
Removed legacy crash protection code, and removed support for cluox (punt)
Removed legacy "support" for Borland compiler (punt)
Removed legacy VC++ 6 Workspace/Project files, VS2005 Solution/Project files, as these are no longer supported (Xuri)
Removed legacy BUILD folder with outdated compilation instructions (Xuri)
Removed old Changelog file (merged into Changelog.txt) (Xuri)
Fixed a pointer bug for items in multis on world load (punt)
Fixed a dictionary related issue that caused segmentation faults on Linux/MacOS (punt)
Fixed an issue with callbacks to JS scripts that caused segmentation faults on Linux/MacOS (punt)
Paths in uox.ini should now load properly on all platforms regardless of whether those paths use slashes or backslashes, and whether or not they end in a slash/backslash. (punt)
Moved to c++17 style of threading, and got rid of threadsafeobject.cpp/h (punt)
Replaced parsing of UOX.INI tags with a system that's more easily maintainable (punt)
Added some new commands to js/commands/custom/misc-cmd.js (Xuri)
cont // Targeted item will be made a container, set to nondecay and movable 2
endfight // Targeted character (and character being fought) will stop fighting
getmulti // Get multiObject for targeted item
finditem // Find item at layer X
movespeed // Set movement speed of target player (0x0 Normal, 0x1 Mounted, 0x2 Slow (walk only), 0x3 Hybrid ("jog"?), 0x4 Frozen)
Added new HTML based documentation in docs folder, and removed many old legacy docs that are either incorporated into this document already or no longer relevant for the current UOX3 version (Xuri)
Co-Authored-By: Charles Kerr <punt1959@users.noreply.github.com>
2020-09-07 18:09:55 +08:00
}
2002-04-07 21:27:53 +00:00
}
}
2022-10-24 18:39:33 +08:00
return dynZ ;
2002-04-07 21:27:53 +00:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::MapElevation()
//o------------------------------------------------------------------------------------------------o
2022-06-15 11:24:57 -04:00
//| Purpose - Returns the map elevation at given coordinates, we'll assume since its land
//| the height is inherently 0
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : MapElevation ( std : : int16_t x , std : : int16_t y , std : : uint8_t worldNumber ) - > std : : int8_t
{
2022-06-15 11:24:57 -04:00
const auto & map = SeekMap ( x , y , worldNumber ) ;
// make sure nothing can move into black areas
2022-10-24 18:39:33 +08:00
if ( map . isVoid ( ) )
{
2022-06-15 11:24:57 -04:00
return ILLEGAL_Z ;
Housing Revamp and more
Updated JS SysMessage function to accept up to 10 extra, optional arguments, which can be used with dictionary messages that require additional parameters like %s or %i
Added new type of house privilege in cMultiObj.cpp to keep track of friends of the multi - HOUSEPRIV_FRIEND - which is stored during worldsaves as one or more Friend=<player serial> tags in house.wsc
Added new type of house privilege in cMultiObj.cpp to keep track of guests of the multi - HOUSEPRIV_GUEST - which is stored during worldsaves as one or more Guest=<player serial> tags in house.wsc
When items are created for houses upon house placement, a reference to the multi's serial is now stored in the house sign's MORE property to allow easier tracking of which house a particular sign belongs to
Added tracking of new, persistent properties for houses via cMultiObj.cpp/h:
lockdowns, secure containers, vendors, guests, friends, owners, ban location, public status, number of visits, timestamps
Added a multitude of new methods in cMultiObj.cpp/h to assist in improving the functionality of houses
Added new tags for houses in house.dfn (default values applied if tag not specified):
MAXSECURECONTAINERS=4 - Max amount of secure containers allowed in a multi
MAXLOCKDOWNS=256 - Max amount of lockdowns allowed in a multi
MAXVENDORS=10 - Max amount of vendors allowed in a multi
MAXBANS=50 - Max amount of bans in a multi's ban list
MAXFRIENDS=50 - Max amount of friends in a multi's friend list
MAXGUESTS=50 - Max amount of guests in a multi's guest list
MAXOWNERS=8 - Max amount of owners and co-owners in a multi's owner list
MAXTRASHCONTAINERS=1 - Max amount of trash containers allowed in multi
SCRIPT=<scriptID> - Assign a JS script-ID directly to a multi
FRONTDOOR - indicates that a door is the front door of a house. Cannot be locked in public houses!
INTERIORDOOR - indicates that a door is an interior door of a house. Can be locked in public houses.
BANX - Location X offset for multi's ban location, if not used, will try to use SE corner of multi instead
BANY - Location Y offset for multi's ban location, if not used, will try to use SE corner of multi instead
Added JS Event:
onHouseCommand( tSock, multiObj, cmdID ) - For handling spoken house commands via JS scripts attached to multi.
Updated JS Events:
onEntrance() - can now trigger both for multi being entered and/or object entering
onLeaving() - can now trigger both for multi being left and/or object entering
onSpeech() - can now also trigger for items (in addition to chars) with event & script attached, if UOX.INI setting ITEMSDETECTSPEECH is enabled
Added JS Multi methods:
.IsBoat() - Returns whether the item (or multi) is a boat
.IsOwner( playerToCheck ) - Returns whether a player is the owner of a multi
.IsOnOwnerList( playerToCheck ) - Returns whether a player is on the (co-)owner list of a multi
.IsOnFriendList( playerToCheck ) - Returns whether a player is on the friend list of a multi
.IsOnGuestList( playerToCheck ) - Returns whether a player is on the guest list of a multi
.IsOnBanList( playerToCheck ) - Returns whether a player is on the ban list of a multi
.AddToFriendList( playertoAdd ) - Adds player to the friend list of a multi
.RemoveFromFriendList( playertoRemove ) - Removes player from the friend list of a multi
.AddToGuestList( playertoAdd ) - Adds player to the guest list of a multi
.RemoveFromGuestList( playertoRemove ) - Removes player from the guest list of a multi
.ClearOwnerList() - Clears all entries from a multi's (co-)owner list
.ClearFriendList() - Clears all entries from a multi's friend list
.ClearGuestList() - Clears all entries from a multi's guest list
.ClearBanList() - Clears all entries from a multi's ban list
.SecureContainer( itemToSecure ) - Secures a container in a multi
.UnsecureContainer( itemToUnsecure ) - Unsecures a container in a multi
.IsSecureContainer( itemToCheck ) - Checks if specified item is a secure container in a multi
.LockDownItem( itemToLockDown) - Locks down an item in a multi
.ReleaseItem( itemToRelease ) - Releases a locked down item in a multi
.KillKeys() - Deletes ALL keys associated with a multi
.AddTrashCont( itemToAdd ) - Add trash container to multi's list of trash containers
.RemoveTrashCont( itemToRemove ) - Remove trash container from multi's list of trash containers
Added JS Item (Multi only) properties:
.lockdowns - Get the number of lockdowns in a multi
.maxLockdowns - Get/Set the max number of lockdowns allowed in a multi
.secureContainers - Get the number of secure containers in a multi
.maxSecureContainers - Get/Set the max number of secure containers allowed in a multi
.trashContainers - Get the number of trash containers in a multi
.maxTrashContainers - Get/Set the max number of trash containers allowed in a multi
.friends - Get the number of friends in a multi's friend list
.maxFriends - Get/Set the max number of friends allowed in a multi's friend list
.guests - Get the number of guests in a multi's guest list
.maxGuests - Get/Set the max number of guests allowed in a multi's guest list
.owners - Get the number of owners in a multi's owner list
.maxOwners - Get/Set the max number of owners allowed in a multi's owner list
.bans - Get the number of banned players in a multi's ban list
.maxBans - Get/Set the max number of banned players allowed in a multi's ban list
.vendors - Get the number of player vendors in a multi
.maxVendors - Get the max number of player vendors allowed in a multi
.deed - Get the item sectionID for deed used to place multi
.isPublic - Get/Set the private/public state of a multi
.buildTimestamp - Get the timestamp for when the house was originally placed
.tradeTimestamp - Get the timestamp for when the house was last traded to another player
.banX - Get/Set the ban location X offset for the multi
.banY - Get/Set the ban location Y offset for the multi
Added JS Character properties:
.multi = Get/Set the multi object the character is in
.accountNum = Get the account number the character belongs to
.housesOwned = Get a count of houses owned by the character
.housesCoOwned = Get a count of houses co-owned by the character
Updated JS cBaseObject Methods .FirstItem(), .NextItem() and .FinishedItems() to also support iterating through items in multis
Updated JS multi Methods .FirstChar(), .NextChar() and .FinishedChars() to support an additional parameter to specify what kind of characters to loop through:
"default" or no parameter - all characters inside the multi
"owner" - players on multi's owner list
"friend" - players on multi's friend list
"guest" - players on multi's guest list
"banned" - players on multi's ban list
Added new INI tags to a new section of uox.ini called [houses]
DECAYTIMERINHOUSE=3600 // Decay timer in seconds for non-locked down items inside houses
PROTECTPRIVATEHOUSES=1 // Toggles whether private houses will automatically boot unauthorized visitors (1) or not (0)
TRACKHOUSESPERACCOUNT=1 // Toggles whether to track (and restrict) house ownership per account (1) or per character (0)
MAXHOUSESOWNABLE=1 // Specifies the max amount of houses a player can own per account/char, depending on how house ownership is tracked
MAXHOUSESCOOWNABLE=10 // Specifies the max amount of houses a player can co-own per character
CANOWNANDCOOWNHOUSES=1 // Toggles whether players can own and co-own houses at the same time
COOWNHOUSESONSAMEACCOUNT=1 // Toggles whether characters on same account as house owner will be treated as co-owners
Added new INI tags in [settings] section of uox.ini:
ITEMSDETECTSPEECH=0 // If enabled, server will search for nearby items with onSpeech JS event running whenever a character speaks. Disabled by default.
MAXPLAYERPACKITEMS=125 // Defines max item capacity for player (and NPC) backpacks. Defaults to 125.
Moved most of the existing house functionality to JS and expanded upon it to reach feature parity with houses in regular UO around Publish 15/16, with various extras thrown in for good measure and all functionality being customizable:
js/server/house/house.js (15000) - handles detection of house commands and characters entering/leaving houses
js/server/house/houseSign.js (15001) - contains and handles all house-related gumps/menus and what is shown when players interact with house sign
js/server/house/houseCommands.js (15002) - handles functionality of house commands and other functionality such as transfer of ownership, demolishing house, etc.
js/server/house/houseDeed.js (15003) - handles initial rules that allow/disallow placement of additional houses for players
All house-related menus now fully handled through JS
All house commands and other functionality now fully handled through JS
Removed redundant hard-coded house functionality
Implemented Co-owners, friends, guests for houses, with access rules in place for entry, lockdowns, house commands, etc.
Implemented Private and Public houses
Implemented Secure Containers and Trash Barrels
Definable max lockdowns, secure containers, player vendors, bans, friends, guests, owners, trash containers and more - per house type
JS scripts can now be attached directly to houses
Doors in houses can be marked as front doors or interior doors, and will be treated differently with regards to private and public houses
Added new item to dfndata/items/containers/misc.dfn - [trashbarrel]
Added new JS script (js/items/trashbarrel.js) with trash barrel functionality for houses. Trash barrels that are marked as secure containers are only accessible by owners, co-owners and friends of the house. Various options available at top of script.
Updated js/items/axe.js to support chopping up trash barrels and house add-ons in houses owned by the player
Fixed an issue with house doors being left behind after demolishing houses while their doors were open
Fixed an issue where GMs could be banned from player houses
Added Line of Sight checks to speech, to give players some privacy in their own homes
Updated house placement code to more accurately check for other multis, dynamic and static objects when placing houses; now requires free space around each house that cannot be blocked by other houses or items that can block player movement, and disallows placement of houses on roads
Updated house placement code to move characters blocking house placement to SE corner of the house
Updated house placement code to disallow placing houses in guarded regions, or in dungeons
Added new DFN tag for regions to enable/disable player houses in specific regions: HOUSING=0/1
Added new region (247) that covers path to Valley of Eodon in Felucca
Added new region (248) that covers Valley of Eodon in Ter-Mur, with player housing disabled
Added new region (249) that covers entire T2A lands, with player housing disabled
Updated SPACEX and SPACEY values for all houses in dfndata/house/house.dfn to match updated house placement code
Added new JS property to Regions that can be used to determine or change state of player housing in a region: .canPlaceHouse()
Updated rules for usage of dye tubs to dye locked down items; now only house owners or co-owners may dye locked down items
Updated rules for usage of the following locked down items in a house, which are now only usable by house owners and co-owners
Dyes, Guildstone Deeds, Recall Runes (renaming), Rename Deeds, Townstone Deeds, House Deeds, Boat Models, Player Vendor Deeds, Ore, Hair Dye
Updated rules for usage of the following locked down items in a house, which are now only usable by house owners, co-owners and friends:
Keys, Dye Tubs, Magic Scrolls, Fireworks Wands, Magic Wands, Smithing Tools, Mining Tools, Fishing Poles
Updated item lockdown rules to allow locking down (and releasing) items in a container as long as the container is locked down, and to only allow releasing a locked down container if it's empty of locked down items
Updated item lockdown rules to only allow locking down movement-blocking items further than 2 tiles away from doors
Updated rules for releasing items in houses - now the house owner can release any locked down items, co-owners can release items locked down by themselves or by friends, while friends can release only items locked down by themselves
Added some feedback to player about why their attempted house placement failed
Items added by GMs directly into multis will now decay based on the house-specific decay timer instead of the regular one
Fixed an issue that could cause items to almost instantly decay after being released from lockdown in a house
Placing house add-ons now properly takes into account SPACEX and SPACEY values when checking if they can fit in selected area of houses
Re-added SPACEX and SPACEY values for Pentagram and Loom house add-ons
House add-ons can now be converted back into house add-on deeds by chopping them with an axe
Added new item type - IT_HOUSEADDON (201) - used by house add-ons placed in player houses
Fixed a bug where keys would stop working after being added to a keyring, and would turn into blank keys upon release from the keyring
Added visitor count for public player houses, which keeps track of how many visits a public house has received, with each player counted max 1 time every 24 hours
Fixed an issue with FindPlayersInOldVisrange() where it didn't take into account that players could see buildings further away than the standard update range. This could cause players to see ghost images of buildings if they were at the "right" distance when the building was being demolished
Added NODECAY tag to all signs and doors in dfndata/house/house.dfn
Added FRONTDOOR or INTERIORDOOR (as appropriate) to all doors in dfndata/house/house.dfn
Added BANX and BANY to specify ban location for some houses in dfndata/house/house.dfn instead of relying on finding SE corner automatically
Implemented strongboxes (js/server/house/strongbox.js) for co-owners of a house, which can be placed with the house command "i wish to place a strongbox". Max capacity is 25 items
Updated 'REMOVE command to take an optional parameter - itemID. If supplied, the command will remove all items with this itemID from a targeted container
Fixed a bug when checking if dynamic items were blocking valid spawn locations for NPCs, some function arguments were in the wrong order!
Improved code that finds valid spawn locations for items and NPCs spawned via spawn regions. As server gradually builds up lists of valid spawn locations per region over time, it will start using these lists more often, rather than always look for brand new spawn locations.
Fixed a bug with CMulHandler::CheckStaticFlag() that prevented NPCs from spawning inside buildings with no static floors!
Fixed an issue with repeating commands that prevented GMs from being able to cancel them when using the ClassicUO client
Exposed character property .accountNum to JS engine
Extended CDataList class to include a Clear() method for clearing lists
Updated JS File method .Open() to support an optional, third argument - subFolderName - that defines in which sub-folder of UOX3/shared/ to store/look for a file. If no third argument is supplied, UOX3 will default to using the shared folder itself.
Updated JS File method .Length() to return a value of -1 for files that don't exist
Added new code function, exposed to JS engine with same parameters, which simply checks if a given tile ID has a specific flag
bool CheckTileFlag( UI16 itemID, TILEFLAG flagToCheck )
Added JS function used to find the root container of an item (if any)
FindRootContainer( itemSerial )
FindRootContainer( item )
Added new JS function that allows deleting files from UOX3/shared/ folder or subfolders of shared folder. If no subFolderName is provided, looks for file directly in shared folder itself. Restrictions on file- and folder-names apply.
bool DeleteFile( fileName, subFolderName )
Added new JS functions for checking if a specific client or server feature is enabled. See documentation for full list of client/server features.
GetClientFeature( bitNum ) // Returns true if specified client feature is enabled on server
GetServerFeature( bitNum ) // Returns true if specified server feature is enabled on server
Added new JS function for returning the value of almost any server setting from UOX.INI
GetServerSetting( settingNameInDoubleQuotes )
Updated JS function DoesDynamicBlock() with two new parameters - checkOnlyMultis and checkOnlyNonMultis
Updated JS function DoesMapBlock() with two new parameters - checkMultiPlacement and checkForRoad
Fixed an issue where a LoS check would prevent players from accessing containers in their own backpack
Added new functions in findfuncs.cpp to make it easier to find items near another object or location:
findNearbyItems( object, distance )
findNearbyItems( x, y, worldNumber, instanceID, distance )
Added new Item property - maxItems - used by containers to determine their max item capacity
Added new Item property - totalItemCount - used to get total item count in a container (including sub-containers)
Added check for max item capacity when creating new items that are added to a character's backpack - items will be created below character's feet if backpack is full!
Added new DFN tag for items, used by containers to determine item capacity for a given container:
MAXITEMS=# // 125 is the default for all containers if not set
Added new JS Item properties:
.maxItems // gets/sets item capacity for a given container
.totalItemCount // gets total item count in a container, including sub-containers
Updated item tooltips for containers to show accurate total item count, as well as to display max item capacity
Fixed a bug where picking up items from a non-locked down pile of items on the floor inside a multi could cause the remaining pile to be seen as no longer inside the multi, disallowing locking it back down and causing it to decay based on regular decay timer instead of house-specific one
Updated JS command set to allow setting poison-level on items ('set poison #) and hunger-level on characters ('set hunger #)
Fixed an issue with js/item/food.js that prevented poisoned food from poisoning characters when eaten
Fixed an issue with js/skill/poisoning.js that prevented players from poisoning food!
Updated various JS scripts and hardcoded targeting functions to disallow the targeting of locked down resources using skills and tools
Updated JS Method TextMessage() to support three extra, optional parameters. Note that if one optional parameter is included, all preceding optional parameters are also required!
speechTarget - What kind of target is this message intended for?
0 - Only visible for sender and receiver of message
1 - Visible to all players in range
2 - Visible to all NPCs and players in range
3 - Visible to all PCs everywhere + NPCs in range
4 - Visible to all PCs everywhere (broadcast)
5 - Only visible for the receiver of the message
speechTargetSerial - The serial of the receiver of the message, used if speechTarget is 0 or 5
speechFontType - The type of font to display the text in. Defaults to normal.
0 - Bold
1 - Normal with shadow
2 - Bold with shadow
3 - Normal
4 - Gothic
5 - Italic
6 - Small, dark
7 - Colourful
8 - Runic (only works with CAPS)
9 - Small, light
Added timestamp to worldsaves in console, to make it easier to see when a particular world-save was done
Added info about compiler/environment displayed at the top of the UOX3 console during startup
Updated dictionary files with new messages primarily related to housing
2020-11-04 02:00:37 +08:00
}
2022-06-15 11:24:57 -04:00
return map . altitude ;
2002-04-07 21:27:53 +00:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::TileHeight()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Height of a given tile (If climbable it return 1/2 its height).
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : TileHeight ( std : : uint16_t tilenum ) - > std : : int8_t
{
return SeekTile ( tilenum ) . ClimbHeight ( ) ;
2022-06-14 17:53:00 -04:00
}
2002-04-07 21:27:53 +00:00
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::Height()
//o------------------------------------------------------------------------------------------------o
2022-06-15 11:24:57 -04:00
//| Purpose - Returns new height of player who walked to X/Y but from OLDZ
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : Height ( std : : int16_t x , std : : int16_t y , std : : int8_t z , std : : uint8_t worldNumber , std : : uint16_t instanceId ) - > std : : int8_t
{
2022-06-15 11:24:57 -04:00
// let's check in this order.. dynamic, static, then the map
2022-11-01 02:25:52 +08:00
auto dynZ = DynamicElevation ( x , y , z , worldNumber , instanceId , MAX_Z_STEP ) ;
2022-10-24 18:39:33 +08:00
if ( ILLEGAL_Z ! = dynZ )
return dynZ ;
auto staticZ = StaticTop ( x , y , z , worldNumber , MAX_Z_STEP ) ;
if ( ILLEGAL_Z ! = staticZ )
return staticZ ;
2022-06-15 11:24:57 -04:00
return MapElevation ( x , y , worldNumber ) ;
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::InBuilding()
//o------------------------------------------------------------------------------------------------o
2022-06-15 11:24:57 -04:00
//| Purpose - Returns whether give coordinates are inside a building by checking if there is
//| a multi or static above them
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : InBuilding ( std : : int16_t x , std : : int16_t y , std : : int8_t z , std : : uint8_t worldNumber , std : : uint16_t instanceId ) - > bool
{
2022-11-01 02:25:52 +08:00
auto dynZ = Map - > DynamicElevation ( x , y , z , worldNumber , instanceId , static_cast < std : : int8_t > ( 127 ) ) ;
2022-10-24 18:39:33 +08:00
if ( dynZ > ( z + 10 ) )
{
2022-06-15 11:24:57 -04:00
return true ;
}
2022-10-24 18:39:33 +08:00
else
{
const SI08 staticZ = Map - > StaticTop ( x , y , z , worldNumber , static_cast < std : : int8_t > ( 127 ) ) ;
if ( staticZ > ( z + 10 ) )
{
2022-06-15 11:24:57 -04:00
return true ;
}
}
return false ;
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::MultiArea()
//o--------------------------------------------------------------------------
2022-06-15 11:24:57 -04:00
//| Purpose - Finds the corners of a multi object
//o--------------------------------------------------------------------------
2022-10-24 18:39:33 +08:00
auto CMulHandler : : MultiArea ( CMultiObj * i , std : : int16_t & x1 , std : : int16_t & y1 , std : : int16_t & x2 , std : : int16_t & y2 ) - > void
{
if ( ValidateObject ( i ) )
{
2022-06-15 11:24:57 -04:00
const SI16 xAdd = i - > GetX ( ) ;
const SI16 yAdd = i - > GetY ( ) ;
2022-10-24 18:39:33 +08:00
const UI16 multiNum = static_cast < UI16 > ( i - > GetId ( ) - 0x4000 ) ;
if ( MultiExists ( multiNum ) )
{
auto structure = SeekMulti ( multiNum ) ;
x1 = static_cast < SI16 > ( structure . minX + xAdd ) ;
x2 = static_cast < SI16 > ( structure . maxX + xAdd ) ;
y1 = static_cast < SI16 > ( structure . minY + yAdd ) ;
y2 = static_cast < SI16 > ( structure . maxY + yAdd ) ;
2022-06-15 11:24:57 -04:00
}
}
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::MultiExists()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Verify that specified multi exists
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : MultiExists ( std : : uint16_t multinum ) const - > bool
{
return multiData . Exists ( multinum ) ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::SeekMulti()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Returns data for items contained in given multi
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : SeekMulti ( std : : uint16_t multinum ) const - > const CollectionItem_st &
{
return multiData . Multi ( multinum ) ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::IsValidTile()
//o------------------------------------------------------------------------------------------------o
2022-06-15 11:24:57 -04:00
//| Purpose - Checks if a given tile number falls within the range of tiles loaded in memory
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : IsValidTile ( std : : uint16_t tileNum ) const - > bool
{
2022-06-15 11:24:57 -04:00
bool retVal = true ;
2022-10-24 18:39:33 +08:00
if ( ( tileNum = = INVALIDID ) | | ( tileNum > = tileInfo . SizeArt ( ) ) )
{
2022-06-15 11:24:57 -04:00
retVal = false ;
}
return retVal ;
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::SeekTile()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Fetches data about a specific tile from memory
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : SeekTile ( std : : uint16_t tileNum ) - > CTile &
{
if ( ! IsValidTile ( tileNum ) )
{
2023-04-07 11:17:51 -04:00
Console . Warning ( util : : format ( " Invalid tile access, the offending tile number is %u " , tileNum ) ) ;
2022-06-15 11:24:57 -04:00
static CTile emptyTile ;
return emptyTile ;
}
2022-10-24 18:39:33 +08:00
else
{
return tileInfo . ArtInfo ( tileNum ) ;
2022-06-15 11:24:57 -04:00
}
}
2022-10-24 18:39:33 +08:00
//=================================================================================================
auto CMulHandler : : SeekTile ( std : : uint16_t tileNum ) const - > const CTile &
{
if ( ! IsValidTile ( tileNum ) )
{
2023-04-07 11:17:51 -04:00
Console . Warning ( util : : format ( " Invalid tile access, the offending tile number is %u " , tileNum ) ) ;
2022-06-15 11:24:57 -04:00
static CTile emptyTile ;
return emptyTile ;
}
2022-10-24 18:39:33 +08:00
else
{
return tileInfo . ArtInfo ( tileNum ) ;
2022-06-15 11:24:57 -04:00
}
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::SeekLand()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Fetches data about a specific land tile from memory.
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : SeekLand ( std : : uint16_t landNum ) - > CLand &
{
if ( landNum = = INVALIDID | | landNum > = tileInfo . SizeTerrain ( ) )
{
2023-04-07 11:17:51 -04:00
Console . Warning ( util : : format ( " Invalid land access, the offending land number is %u " , landNum ) ) ;
2022-06-15 11:24:57 -04:00
static CLand emptyTile ;
return emptyTile ;
}
2022-10-24 18:39:33 +08:00
else
{
return tileInfo . TerrainInfo ( landNum ) ;
2022-06-15 11:24:57 -04:00
}
}
2022-10-24 18:39:33 +08:00
//=================================================================================================
auto CMulHandler : : SeekLand ( std : : uint16_t landNum ) const - > const CLand &
{
if ( landNum = = INVALIDID | | landNum > = tileInfo . SizeTerrain ( ) )
{
2023-04-07 11:17:51 -04:00
Console . Warning ( util : : format ( " Invalid land access, the offending land number is %u " , landNum ) ) ;
2022-06-15 11:24:57 -04:00
static CLand emptyTile ;
return emptyTile ;
}
2022-10-24 18:39:33 +08:00
else
{
return tileInfo . TerrainInfo ( landNum ) ;
2022-06-15 11:24:57 -04:00
}
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::SeekMap()
//o------------------------------------------------------------------------------------------------o
2022-06-15 11:24:57 -04:00
//| Purpose - Fetches map data for a specific map/world
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : SeekMap ( std : : int16_t x , std : : int16_t y , std : : uint8_t worldNumber ) - > Tile_st &
{
static Tile_st badTile ;
try
{
return uoWorlds . at ( worldNumber ) . TerrainAt ( x , y ) ;
}
catch ( . . . )
{
std : : cerr < < " Bad tile access attempted: " < < x < < " , " < < y < < static_cast < int > ( worldNumber ) < < std : : endl ;
return badTile ;
}
}
//=================================================================================================
auto CMulHandler : : SeekMap ( std : : int16_t x , std : : int16_t y , std : : uint8_t worldNumber ) const - > const Tile_st &
{
static Tile_st badTile ;
try
{
return uoWorlds . at ( worldNumber ) . TerrainAt ( x , y ) ;
}
catch ( . . . )
{
std : : cerr < < " Bad tile access attempted: " < < x < < " , " < < y < < static_cast < int > ( worldNumber ) < < std : : endl ;
return badTile ;
2022-06-15 11:24:57 -04:00
}
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::ValidSpawnLocation()
//o------------------------------------------------------------------------------------------------o
2022-06-15 11:24:57 -04:00
//| Purpose - Checks if location at given coordinates is considered valid for spawning objects
//| Also used to verify teleport location for NPCs teleporting back to bounding box
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : ValidSpawnLocation ( std : : int16_t x , std : : int16_t y , std : : int8_t z , std : : uint8_t worldNumber , std : : uint16_t instanceId , bool checkWater ) - > bool
{
if ( ! InsideValidWorld ( x , y , worldNumber ) )
return false ;
// get the tile id of any dynamic tiles at this spot
if ( DoesDynamicBlock ( x , y , z , worldNumber , instanceId , checkWater , ! checkWater , false , false ) )
return false ;
// if there's a static block here in our way, return false
if ( DoesStaticBlock ( x , y , z , worldNumber , checkWater ) )
return false ;
// if the static isn't a surface return false
if ( ! CheckStaticFlag ( x , y , z , worldNumber , ( checkWater ? TF_SURFACE : TF_WET ) , true ) )
return false ;
if ( DoesMapBlock ( x , y , z , worldNumber , checkWater , ! checkWater , false , false ) )
return false ;
return true ;
2002-04-07 21:27:53 +00:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::ValidMultiLocation()
//o------------------------------------------------------------------------------------------------o
2022-06-15 11:24:57 -04:00
//| Purpose - Checks whether given location is valid for house/boat placement
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : ValidMultiLocation ( std : : int16_t x , std : : int16_t y , std : : int8_t z , std : : uint8_t worldNumber , std : : uint16_t instanceId ,
bool checkWater , bool checkOnlyOtherMultis , bool checkOnlyNonMultis , bool checkForRoads ) - > std : : uint8_t
{
if ( ! InsideValidWorld ( x , y , worldNumber ) )
2022-06-15 11:24:57 -04:00
return 0 ;
2022-10-24 18:39:33 +08:00
const SI08 elev = Height ( x , y , z , worldNumber , instanceId ) ;
2022-06-15 11:24:57 -04:00
if ( ILLEGAL_Z = = elev )
return 0 ;
2022-10-24 18:39:33 +08:00
2022-06-15 11:24:57 -04:00
// We don't want the house to be halfway embedded in a hill... or hanging off one for that matter.
2022-10-24 18:39:33 +08:00
if ( z ! = ILLEGAL_Z )
{
if ( elev - z > MAX_Z_STEP )
{
2022-06-15 11:24:57 -04:00
return 0 ;
}
2022-10-24 18:39:33 +08:00
else if ( z - elev > MAX_Z_FALL )
{
2022-06-15 11:24:57 -04:00
return 0 ;
}
}
2022-10-24 18:39:33 +08:00
2022-06-15 11:24:57 -04:00
// get the tile id of any dynamic tiles at this spot
2022-10-24 18:39:33 +08:00
if ( ! checkOnlyNonMultis & & DoesDynamicBlock ( x , y , elev , worldNumber , instanceId , checkWater , false , checkOnlyOtherMultis , checkOnlyNonMultis ) )
{
2022-06-15 11:24:57 -04:00
return 2 ;
}
2022-10-24 18:39:33 +08:00
2022-06-15 11:24:57 -04:00
// if there's a static block here in our way, return false
2022-10-24 18:39:33 +08:00
if ( ! checkOnlyOtherMultis & & DoesStaticBlock ( x , y , elev , worldNumber , checkWater ) )
{
2022-06-15 11:24:57 -04:00
return 2 ;
}
2022-10-24 18:39:33 +08:00
if ( DoesMapBlock ( x , y , elev , worldNumber , checkWater , false , true , checkForRoads ) )
{
2022-06-15 11:24:57 -04:00
return 0 ;
}
2022-10-24 18:39:33 +08:00
2022-06-15 11:24:57 -04:00
// Check if house placement is allowed in region
2022-10-24 18:39:33 +08:00
CTownRegion * calcReg = CalcRegionFromXY ( x , y , worldNumber , instanceId ) ;
2022-06-15 11:24:57 -04:00
if ( ( ! calcReg - > CanPlaceHouse ( ) & & checkWater ) | | calcReg - > IsDungeon ( ) | | ( calcReg - > IsGuarded ( ) & & checkWater ) )
return 3 ;
2022-10-24 18:39:33 +08:00
2022-06-15 11:24:57 -04:00
// Else, all good!
return 1 ;
2022-06-15 07:32:55 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::MapExists()
//o------------------------------------------------------------------------------------------------o
2022-06-15 11:24:57 -04:00
//| Purpose - Returns true if the server has that map in memory
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : MapExists ( std : : uint8_t worldNumber ) const - > bool
{
auto iter = uoWorlds . find ( worldNumber ) ;
return iter ! = uoWorlds . end ( ) ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::InsideValidWorld()
//o------------------------------------------------------------------------------------------------o
2022-06-15 11:24:57 -04:00
//| Purpose - Checks if a given location is within the bounds of the specified world
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : InsideValidWorld ( std : : int16_t x , std : : int16_t y , std : : uint8_t worldNumber ) const - > bool
{
auto rValue = false ;
try
{
auto [ width , height ] = uoWorlds . at ( worldNumber ) . Size ( ) ;
if ( ( x > = 0 & & x < width ) & & ( y > = 0 & & y < height ) )
{
rValue = true ;
2022-06-15 11:24:57 -04:00
}
}
2022-10-24 18:39:33 +08:00
catch ( . . . )
{
2022-06-15 11:24:57 -04:00
// Do nothing, all rady set to false
}
2022-10-24 18:39:33 +08:00
return rValue ;
2022-06-15 07:32:55 -04:00
}
2022-06-12 14:31:18 -04:00
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - CMulHandler::MapCount()
//o------------------------------------------------------------------------------------------------o
2022-06-15 11:24:57 -04:00
//| Purpose - Returns count of how many maps have been loaded
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
auto CMulHandler : : MapCount ( ) const - > std : : uint8_t
{
2022-06-15 11:24:57 -04:00
// This ASSUMES the map numbers are consequtive. You dont have say map 0,1,3 <<<< missing 2
2022-10-24 18:39:33 +08:00
return static_cast < std : : uint8_t > ( uoWorlds . size ( ) ) ;
2022-06-15 11:24:57 -04:00
}
2022-06-12 14:31:18 -04:00
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| TileInfo
//o------------------------------------------------------------------------------------------------o
//o------------------------------------------------------------------------------------------------o
TileInfo : : TileInfo ( const std : : string & filename ) : isHsFormat ( false )
{
if ( ! filename . empty ( ) )
{
this - > LoadTiles ( filename ) ;
2021-05-28 03:41:43 +08:00
}
2022-06-12 14:31:18 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - TileInfo::LoadTiles()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Loads tiles from tiledata file into memory
//o------------------------------------------------------------------------------------------------o
auto TileInfo : : LoadTiles ( const std : : string & filename ) - > bool
{
auto rValue = false ;
artData . clear ( ) ;
terrainData . clear ( ) ;
isHsFormat = false ;
auto path = std : : filesystem : : path ( filename ) ;
if ( std : : filesystem : : exists ( path ) )
{
if ( std : : filesystem : : file_size ( path ) > = hsSize )
{
isHsFormat = true ;
2022-06-12 14:31:18 -04:00
}
2022-10-24 18:39:33 +08:00
auto input = std : : ifstream ( filename , std : : ios : : binary ) ;
if ( input . is_open ( ) )
{
rValue = true ;
ProcessTerrain ( input ) ;
ProcessArt ( input ) ;
2022-06-12 14:31:18 -04:00
}
}
2022-10-24 18:39:33 +08:00
return rValue ;
2022-06-12 14:31:18 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - TileInfo::TerrainInfo()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Returns terrain data for given tileId
//o------------------------------------------------------------------------------------------------o
auto TileInfo : : TerrainInfo ( std : : uint16_t tileId ) const - > const CLand &
{
return terrainData [ tileId ] ;
}
auto TileInfo : : TerrainInfo ( std : : uint16_t tileId ) - > CLand &
{
return terrainData [ tileId ] ;
2022-06-12 14:31:18 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - TileInfo::ArtInfo()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Returns art/statics data for given tileId
//o------------------------------------------------------------------------------------------------o
auto TileInfo : : ArtInfo ( std : : uint16_t tileId ) const - > const CTile &
{
return artData [ tileId ] ;
}
auto TileInfo : : ArtInfo ( std : : uint16_t tileId ) - > CTile &
{
return artData [ tileId ] ;
2022-06-12 14:31:18 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - TileInfo::SizeTerrain()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Returns size of terrain data loaded by UOX3
//o------------------------------------------------------------------------------------------------o
auto TileInfo : : SizeTerrain ( ) const - > size_t
{
return terrainData . size ( ) ;
2022-06-12 14:31:18 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - TileInfo::SizeArt()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Returns size of art/statics data loaded by UOX3
//o------------------------------------------------------------------------------------------------o
auto TileInfo : : SizeArt ( ) const - > size_t
{
return artData . size ( ) ;
2002-04-07 21:27:53 +00:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - TileInfo::CollectionTerrain()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Returns collection of terrain tiles loaded by UOX3
//o------------------------------------------------------------------------------------------------o
auto TileInfo : : CollectionTerrain ( ) const - > const std : : vector < CLand > &
{
return terrainData ;
}
auto TileInfo : : CollectionTerrain ( ) - > std : : vector < CLand > &
{
return terrainData ;
2022-06-12 14:31:18 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - TileInfo::CollectionArt()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Returns collection of art/statics tiles loaded by UOX3
//o------------------------------------------------------------------------------------------------o
auto TileInfo : : CollectionArt ( ) const - > const std : : vector < CTile > &
{
return artData ;
}
auto TileInfo : : CollectionArt ( ) - > std : : vector < CTile > &
{
return artData ;
2022-06-12 14:31:18 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - TileInfo::ProcessTerrain()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Process terrain data read from tiledata file
//o------------------------------------------------------------------------------------------------o
auto TileInfo : : ProcessTerrain ( std : : ifstream & input ) - > void
{
terrainData . reserve ( 0x4000 ) ;
std : : uint32_t value32 = 0 ;
std : : uint64_t value64 = 0 ;
std : : array < char , 20 > string_buffer ;
string_buffer . fill ( 0 ) ;
for ( auto i = 0 ; i < 0x4000 ; i + + )
{
2022-06-12 14:31:18 -04:00
// We have to get rid of the header on blocks of information
2022-10-24 18:39:33 +08:00
// HS has the first entry messed up
if ( isHsFormat )
{
if ( ( ( ( i & 0x1F ) = = 0 ) & & ( i > 0 ) ) | | ( i = = 1 ) )
{
input . read ( reinterpret_cast < char * > ( & value32 ) , 4 ) ; // read off the group header
2022-06-12 14:31:18 -04:00
}
}
2022-10-24 18:39:33 +08:00
else
{
if ( ( i & 0x1f ) = = 0 )
{
input . read ( reinterpret_cast < char * > ( & value32 ) , 4 ) ; // read off the group header
2022-06-12 14:31:18 -04:00
}
}
// now create the info_t we will use
auto info = CLand ( ) ;
// read off the flags, 32 bit on pre-HS, 64 bit after
2022-10-24 18:39:33 +08:00
if ( isHsFormat )
{
input . read ( reinterpret_cast < char * > ( & value64 ) , 8 ) ;
info . flags = std : : bitset < 64 > ( value64 ) ;
2022-06-12 14:31:18 -04:00
}
2022-10-24 18:39:33 +08:00
else
{
input . read ( reinterpret_cast < char * > ( & value32 ) , 4 ) ;
info . flags = std : : bitset < 64 > ( value32 ) ;
2022-06-12 14:31:18 -04:00
}
// only other thing for terrain is the texture
// and name
2022-10-24 18:39:33 +08:00
input . read ( reinterpret_cast < char * > ( & info . textureId ) , 2 ) ;
input . read ( string_buffer . data ( ) , 20 ) ;
if ( input . gcount ( ) = = 20 )
{
2022-06-12 14:31:18 -04:00
// We need to find the "0", if any
2022-10-24 18:39:33 +08:00
auto iter = std : : find ( string_buffer . begin ( ) , string_buffer . end ( ) , 0 ) ;
info . name = std : : string ( string_buffer . begin ( ) , iter ) ;
terrainData . push_back ( std : : move ( info ) ) ;
2022-06-12 14:31:18 -04:00
}
2022-10-24 18:39:33 +08:00
else
{
2022-06-12 14:31:18 -04:00
break ;
}
2021-05-28 03:41:43 +08:00
}
2022-06-12 14:31:18 -04:00
2002-04-07 21:27:53 +00:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - TileInfo::ProcessArt()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Process art/statics data read from tiledata file
//o------------------------------------------------------------------------------------------------o
auto TileInfo : : ProcessArt ( std : : ifstream & input ) - > void
{
artData . reserve ( 0xFFFF ) ;
std : : uint32_t value32 = 0 ;
std : : uint64_t value64 = 0 ;
std : : array < char , 20 > string_buffer ;
string_buffer . fill ( 0 ) ;
if ( ! ( input . eof ( ) | | input . bad ( ) ) )
{
auto loopCount = 0 ;
do
{
if ( ( loopCount & 0x1f ) = = 0 )
{
input . read ( reinterpret_cast < char * > ( & value32 ) , 4 ) ; // read off the group header
2022-06-12 14:31:18 -04:00
}
auto info = CTile ( ) ;
2022-10-24 18:39:33 +08:00
if ( isHsFormat )
{
input . read ( reinterpret_cast < char * > ( & value64 ) , 8 ) ;
info . flags = std : : bitset < 64 > ( value64 ) ;
2022-06-12 14:31:18 -04:00
}
2022-10-24 18:39:33 +08:00
else
{
input . read ( reinterpret_cast < char * > ( & value32 ) , 4 ) ;
info . flags = std : : bitset < 64 > ( value32 ) ;
2002-04-07 21:27:53 +00:00
2022-06-12 14:31:18 -04:00
}
2022-10-24 18:39:33 +08:00
input . read ( reinterpret_cast < char * > ( & info . weight ) , 1 ) ;
input . read ( reinterpret_cast < char * > ( & info . layer ) , 1 ) ;
2022-06-12 14:31:18 -04:00
//misc data
2022-10-24 18:39:33 +08:00
input . read ( reinterpret_cast < char * > ( & info . unknown1 ) , 2 ) ;
2022-06-12 14:31:18 -04:00
//Second unkown
2022-10-24 18:39:33 +08:00
input . read ( reinterpret_cast < char * > ( & info . unknown2 ) , 1 ) ;
2022-06-12 14:31:18 -04:00
// Quantity
2022-10-24 18:39:33 +08:00
input . read ( reinterpret_cast < char * > ( & info . quantity ) , 1 ) ;
2022-06-12 14:31:18 -04:00
// Animation
2022-10-24 18:39:33 +08:00
input . read ( reinterpret_cast < char * > ( & info . animation ) , 2 ) ;
2022-06-12 14:31:18 -04:00
//Third a byte
2022-10-24 18:39:33 +08:00
input . read ( reinterpret_cast < char * > ( & info . unknown3 ) , 1 ) ;
2022-06-12 14:31:18 -04:00
// Hue/Value
2022-10-24 18:39:33 +08:00
input . read ( reinterpret_cast < char * > ( & info . hue ) , 1 ) ;
2022-06-12 14:31:18 -04:00
//stacking offset/value = 16 bits, but UOX3 doesn't know that, so two eight bit unkowns
2022-10-24 18:39:33 +08:00
input . read ( reinterpret_cast < char * > ( & info . unknown4 ) , 1 ) ;
input . read ( reinterpret_cast < char * > ( & info . unknown5 ) , 1 ) ;
2022-06-12 14:31:18 -04:00
// Height
2022-10-24 18:39:33 +08:00
input . read ( reinterpret_cast < char * > ( & info . height ) , 1 ) ;
2022-06-12 14:31:18 -04:00
// and name
2022-10-24 18:39:33 +08:00
input . read ( string_buffer . data ( ) , 20 ) ;
if ( ( input . gcount ( ) = = 20 ) & & input . good ( ) )
{
2022-06-12 14:31:18 -04:00
// We need to find the "0", if any
2022-10-24 18:39:33 +08:00
auto iter = std : : find ( string_buffer . begin ( ) , string_buffer . end ( ) , 0 ) ;
info . name = std : : string ( string_buffer . begin ( ) , iter ) ;
artData . push_back ( std : : move ( info ) ) ;
2022-06-12 14:31:18 -04:00
}
2022-10-24 18:39:33 +08:00
loopCount + + ;
2022-06-12 14:31:18 -04:00
2022-10-24 18:39:33 +08:00
} while ( ( ! input . eof ( ) ) & & input . good ( ) ) ;
2022-06-12 14:31:18 -04:00
}
2021-05-28 03:41:43 +08:00
2022-06-12 14:31:18 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - TileInfo::TotalMemory()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Calculate total memory used for loading art/terrain tiledata
//o------------------------------------------------------------------------------------------------o
auto TileInfo : : TotalMemory ( ) const - > size_t
{
auto flag = isHsFormat ? 8 : 4 ;
auto terrain = flag + 20 + 2 ;
auto art = flag + 20 + 23 ;
return static_cast < size_t > ( ( terrain * terrainData . size ( ) ) + ( art * artData . size ( ) ) ) ;
2022-06-12 14:31:18 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| TerrainBlock::TerrainBlock()
//o------------------------------------------------------------------------------------------------o
//o------------------------------------------------------------------------------------------------o
TerrainBlock : : TerrainBlock ( std : : uint8_t * data , const TileInfo * info )
{
if ( data ! = nullptr )
{
LoadBlock ( data , info ) ;
2022-06-15 11:24:57 -04:00
}
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - TerrainBlock::LoadBlock()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Load details for terrain tiles in a 8x8 block of the map
//o------------------------------------------------------------------------------------------------o
auto TerrainBlock : : LoadBlock ( std : : uint8_t * data , const TileInfo * info ) - > void
{
if ( data ! = nullptr )
{
data + = 4 ;
for ( auto y = 0 ; y < 8 ; + + y )
{
for ( auto x = 0 ; x < 8 ; + + x )
{
auto tileId = std : : uint16_t ( 0 ) ;
2022-06-15 11:24:57 -04:00
// we copy here, because of potential alignment issues
2022-10-24 18:39:33 +08:00
std : : copy ( data , data + 2 , reinterpret_cast < std : : uint8_t * > ( & ( tileId ) ) ) ;
_tiles [ x ] [ y ] . tileId = tileId ;
if ( info )
{
_tiles [ x ] [ y ] . terrainInfo = & info - > TerrainInfo ( tileId ) ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
_tiles [ x ] [ y ] . altitude = * ( reinterpret_cast < std : : int8_t * > ( data + 2 ) ) ;
data + = 3 ; // advance data three bytes;
2022-06-15 11:24:57 -04:00
}
}
}
}
//=========================================================
2022-10-24 18:39:33 +08:00
auto TerrainBlock : : TerrainTileAt ( int x , int y ) - > Tile_st &
{
return _tiles . at ( x ) . at ( y ) ;
2022-06-15 11:24:57 -04:00
}
//=========================================================
2022-10-24 18:39:33 +08:00
auto TerrainBlock : : TerrainTileAt ( int x , int y ) const - > const Tile_st &
{
return _tiles . at ( x ) . at ( y ) ;
2022-06-15 11:24:57 -04:00
}
//================================================================================
2022-10-24 18:39:33 +08:00
// ArtBlock
2022-06-15 11:24:57 -04:00
//================================================================================
//=========================================================
2022-10-24 18:39:33 +08:00
ArtBlock : : ArtBlock ( int length , std : : uint8_t * data , const TileInfo * info )
{
if ( data ! = nullptr )
{
LoadArtBlock ( length , data , info ) ;
2022-06-15 11:24:57 -04:00
}
}
//=========================================================
2022-10-24 18:39:33 +08:00
auto ArtBlock : : ArtTileAt ( int x , int y ) - > std : : vector < Tile_st > &
{
return _tiles . at ( x ) . at ( y ) ;
2022-06-15 11:24:57 -04:00
}
//=========================================================
2022-10-24 18:39:33 +08:00
auto ArtBlock : : ArtTileAt ( int x , int y ) const - > const std : : vector < Tile_st > &
{
return _tiles . at ( x ) . at ( y ) ;
2022-06-15 11:24:57 -04:00
}
//=========================================================
2022-10-24 18:39:33 +08:00
auto ArtBlock : : Clear ( ) - > void
{
for ( auto & row : _tiles )
{
for ( auto & tile : row )
{
2022-06-15 11:24:57 -04:00
tile . clear ( ) ;
}
}
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - ArtBlock::LoadArtBlock()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Load details for all art/statics tiles in a given location from statics files
//o------------------------------------------------------------------------------------------------o
auto ArtBlock : : LoadArtBlock ( int length , std : : istream & input , const TileInfo * info ) - > void
{
this - > Clear ( ) ;
auto count = length / 7 ;
auto x = std : : uint8_t ( 0 ) ;
auto y = std : : uint8_t ( 0 ) ;
auto alt = std : : int8_t ( 0 ) ;
for ( auto i = 0 ; i < count ; + + i )
{
auto artTile = Tile_st ( ) ;
artTile . type = TileType_t : : art ;
input . read ( reinterpret_cast < char * > ( & artTile . tileId ) , 2 ) ;
input . read ( reinterpret_cast < char * > ( & x ) , 1 ) ;
input . read ( reinterpret_cast < char * > ( & y ) , 1 ) ;
input . read ( reinterpret_cast < char * > ( & alt ) , 1 ) ;
artTile . altitude = alt ;
input . read ( reinterpret_cast < char * > ( & artTile . staticHue ) , 2 ) ;
if ( info )
{
artTile . artInfo = & info - > ArtInfo ( artTile . tileId ) ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
ArtTileAt ( x , y ) . push_back ( std : : move ( artTile ) ) ;
2022-06-15 11:24:57 -04:00
}
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - ArtBlock::LoadArtBlock()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Retrieve details for all art/statics tiles in a given location from memory
//o------------------------------------------------------------------------------------------------o
auto ArtBlock : : LoadArtBlock ( int length , std : : uint8_t * data , const TileInfo * info ) - > void
{
this - > Clear ( ) ;
2022-06-15 11:24:57 -04:00
2022-10-24 18:39:33 +08:00
auto count = length / 7 ;
auto x = std : : uint8_t ( 0 ) ;
auto y = std : : uint8_t ( 0 ) ;
for ( auto i = 0 ; i < count ; + + i )
{
auto artTile = Tile_st ( ) ;
artTile . type = TileType_t : : art ;
std : : copy ( data , data + 2 , reinterpret_cast < char * > ( & artTile . tileId ) ) ;
x = * ( data + 2 ) ;
y = * ( data + 3 ) ;
artTile . altitude = static_cast < int > ( * ( reinterpret_cast < std : : int8_t * > ( data + 4 ) ) ) ;
std : : copy ( data + 5 , data + 7 , reinterpret_cast < char * > ( & artTile . staticHue ) ) ;
if ( info )
{
artTile . artInfo = & info - > ArtInfo ( artTile . tileId ) ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
ArtTileAt ( x , y ) . push_back ( std : : move ( artTile ) ) ;
data + = 7 ;
2022-06-15 11:24:57 -04:00
}
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| UltimaMap
//o------------------------------------------------------------------------------------------------o
//o------------------------------------------------------------------------------------------------o
2022-11-04 17:12:13 -04:00
UltimaMap : : UltimaMap ( ) : tileInfo ( nullptr ) , _width ( 0 ) , _height ( 0 ) , _diffCount ( 0 ) , _diffTerrain ( 0 )
2022-10-24 18:39:33 +08:00
{
2022-06-15 11:24:57 -04:00
}
//=========================================================
2022-10-24 18:39:33 +08:00
UltimaMap : : UltimaMap ( int mapNum , int width , int height , const TileInfo * info ) : UltimaMap ( )
{
_width = width ;
_height = height ;
tileInfo = info ;
_mapNum = mapNum ;
auto size = _mapSizes . at ( mapNum ) ;
if ( _width = = 0 )
{
_width = size . first ;
}
if ( _height = = 0 )
{
_height = size . second ;
}
_terrain . resize ( ( _width / 8 ) * ( _height / 8 ) ) ;
_art . resize ( _terrain . size ( ) ) ;
isUop = true ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - UltimaMap::Width()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Get width of map
//o------------------------------------------------------------------------------------------------o
auto UltimaMap : : Width ( ) const - > int
{
return _width ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - UltimaMap::Height()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Get height of map
//o------------------------------------------------------------------------------------------------o
auto UltimaMap : : Height ( ) const - > int
{
return _height ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - UltimaMap::SetSize()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Set width and height of map
//o------------------------------------------------------------------------------------------------o
auto UltimaMap : : SetSize ( int width , int height ) - > void
{
_width = width ;
_height = height ;
_terrain . resize ( ( _width / 8 ) * ( _height / 8 ) ) ;
_art . resize ( _terrain . size ( ) ) ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - UltimaMap::Size()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Get size of map as width/height pair
//o------------------------------------------------------------------------------------------------o
auto UltimaMap : : Size ( ) const - > std : : pair < int , int >
{
return std : : make_pair ( static_cast < int > ( _width ) , static_cast < int > ( _height ) ) ;
2022-06-15 11:24:57 -04:00
}
//=========================================================
2022-10-24 18:39:33 +08:00
auto UltimaMap : : DiffArt ( ) const - > int
{
return _diffCount ;
2022-06-15 11:24:57 -04:00
}
//=========================================================
2022-10-24 18:39:33 +08:00
auto UltimaMap : : DiffTerrain ( ) const - > int
{
return _diffTerrain ;
}
//o------------------------------------------------------------------------------------------------o
//| Function - UltimaMap::LoadUOPTerrainFile()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Load map data from uop-version of map files
//o------------------------------------------------------------------------------------------------o
auto UltimaMap : : LoadUOPTerrainFile ( const std : : string & fileName ) - > bool
{
auto hash = this - > Format ( " build/map%ilegacymul/%s " , _mapNum , " %.8u.dat " ) ;
//auto fileName = this->format( "map%iLegacyMUL.uop", _mapNum );
isUop = LoadUop ( fileName , 0x300 , hash ) ;
return isUop ;
}
//o------------------------------------------------------------------------------------------------o
//| Function - UltimaMap::LoadMulTerrainFile()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Load map data from mul-version of map files
//o------------------------------------------------------------------------------------------------o
auto UltimaMap : : LoadMulTerrainFile ( const std : : string & fileName ) - > bool {
auto rValue = false ;
auto mul = std : : ifstream ( fileName , std : : ios : : binary ) ;
if ( mul . is_open ( ) )
{
rValue = true ;
isUop = false ;
auto data = std : : vector < std : : uint8_t > ( 196 , 0 ) ;
auto blockNum = 0 ;
while ( mul . good ( ) & & ! mul . eof ( ) )
{
mul . read ( reinterpret_cast < char * > ( data . data ( ) ) , 196 ) ;
if ( mul . gcount ( ) = = 196 )
{
LoadTerrainBlock ( blockNum , data . data ( ) ) ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
blockNum + + ;
2022-06-15 11:24:57 -04:00
}
}
2022-10-24 18:39:33 +08:00
return rValue ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - UltimaMap::LoadArt()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Load data from statics/staidx files
//o------------------------------------------------------------------------------------------------o
auto UltimaMap : : LoadArt ( const std : : string & mulFile , const std : : string & idxFile ) - > bool
{
auto idx = std : : ifstream ( idxFile , std : : ios : : binary ) ;
auto rValue = idx . is_open ( ) ;
if ( rValue )
{
auto mul = std : : ifstream ( mulFile , std : : ios : : binary ) ;
rValue = mul . is_open ( ) ;
if ( rValue )
{
auto offset = std : : uint32_t ( 0 ) ;
auto length = std : : int32_t ( 0 ) ;
auto extra = std : : uint32_t ( 0 ) ;
2022-11-04 17:12:13 -04:00
size_t block = 0 ;
2022-10-24 18:39:33 +08:00
while ( idx . good ( ) & & ! idx . eof ( ) )
{
idx . read ( reinterpret_cast < char * > ( & offset ) , 4 ) ;
idx . read ( reinterpret_cast < char * > ( & length ) , 4 ) ;
idx . read ( reinterpret_cast < char * > ( & extra ) , 4 ) ;
if ( ( length > 0 ) & & ( idx . gcount ( ) = = 4 ) )
{
mul . seekg ( offset , std : : ios : : beg ) ;
if ( block < _art . size ( ) )
{
_art [ block ] . LoadArtBlock ( length , mul , tileInfo ) ;
2022-06-15 11:24:57 -04:00
}
}
2022-10-24 18:39:33 +08:00
+ + block ;
2022-06-15 11:24:57 -04:00
}
}
}
2022-10-24 18:39:33 +08:00
return rValue ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - UltimaMap::ApplyDiff()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Apply patches from diff files to statics for map loaded by UOX3
//o------------------------------------------------------------------------------------------------o
auto UltimaMap : : ApplyDiff ( const std : : string & difflPath , const std : : string & diffiPath , const std : : string & diffPath ) - > int
{
_diffCount = 0 ;
auto diffBlock = std : : ifstream ( difflPath , std : : ios : : binary ) ;
if ( diffBlock . is_open ( ) )
{
auto diffIdx = std : : ifstream ( diffiPath , std : : ios : : binary ) ;
if ( diffIdx . is_open ( ) )
{
auto diff = std : : ifstream ( diffPath , std : : ios : : binary ) ;
if ( diff . is_open ( ) )
{
auto blockNum = std : : uint32_t ( 0 ) ;
auto offset = std : : uint32_t ( 0 ) ;
auto length = std : : int32_t ( 0 ) ;
auto extra = std : : uint32_t ( 0 ) ;
while ( diffBlock . good ( ) & & ! diffBlock . eof ( ) )
{
diffBlock . read ( reinterpret_cast < char * > ( & blockNum ) , 4 ) ;
diffIdx . read ( reinterpret_cast < char * > ( & offset ) , 4 ) ;
diffIdx . read ( reinterpret_cast < char * > ( & length ) , 4 ) ;
diffIdx . read ( reinterpret_cast < char * > ( & extra ) , 4 ) ;
if ( ( diffBlock . gcount ( ) = = 4 ) & & ( diffIdx . gcount ( ) = = 4 ) )
{
if ( blockNum < _art . size ( ) )
{
if ( length > 0 )
{
diff . seekg ( offset , std : : ios : : beg ) ;
_art [ blockNum ] . LoadArtBlock ( length , diff , tileInfo ) ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
else
{
_art [ blockNum ] . Clear ( ) ;
2022-06-15 11:24:57 -04:00
}
}
2022-10-24 18:39:33 +08:00
+ + _diffCount ;
2022-06-15 11:24:57 -04:00
}
}
}
}
}
2022-10-24 18:39:33 +08:00
return _diffCount ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
//o------------------------------------------------------------------------------------------------o
//| Function - UltimaMap::ApplyTerrainDiff()
//o------------------------------------------------------------------------------------------------o
//| Purpose - Apply patches from diff files to map loaded by UOX3
//o------------------------------------------------------------------------------------------------o
auto UltimaMap : : ApplyTerrainDiff ( const std : : string & difflPath , const std : : string & diffPath ) - > int
{
auto diffblock = std : : ifstream ( difflPath , std : : ios : : binary ) ;
_diffTerrain = 0 ;
if ( diffblock . is_open ( ) )
{
auto diff = std : : ifstream ( diffPath , std : : ios : : binary ) ;
if ( diff . is_open ( ) )
{
auto blocknum = std : : uint32_t ( 0 ) ;
auto data = std : : vector < std : : uint8_t > ( 196 , 0 ) ;
while ( diffblock . good ( ) & & ! diffblock . eof ( ) )
{
diffblock . read ( reinterpret_cast < char * > ( & blocknum ) , 4 ) ;
if ( diffblock . gcount ( ) = = 4 )
{
diff . read ( reinterpret_cast < char * > ( data . data ( ) ) , 196 ) ;
if ( diff . gcount ( ) = = 196 )
{
_terrain [ blocknum ] . LoadBlock ( data . data ( ) , tileInfo ) ;
_diffTerrain + + ;
2022-06-15 11:24:57 -04:00
}
}
}
}
}
2022-10-24 18:39:33 +08:00
return _diffTerrain ;
2022-06-15 11:24:57 -04:00
}
//=========================================================
2022-10-24 18:39:33 +08:00
auto UltimaMap : : CalcBlock ( int x , int y ) const - > int
{
2022-06-15 11:24:57 -04:00
// How many blocks is x across?
2022-10-24 18:39:33 +08:00
return ( ( x / 8 ) * ( _height / 8 ) ) + ( y / 8 ) ;
2022-06-15 11:24:57 -04:00
}
//=========================================================
2022-10-24 18:39:33 +08:00
auto UltimaMap : : CalcXYOffset ( int block ) const - > std : : pair < int , int >
{
auto x = ( block / ( _height / 8 ) ) * 8 ;
auto y = ( block % ( _height / 8 ) ) * 8 ;
return std : : make_pair ( x , y ) ;
2022-06-15 11:24:57 -04:00
}
//=========================================================
2022-10-24 18:39:33 +08:00
auto UltimaMap : : BlockAndIndexFor ( int x , int y ) const - > std : : tuple < int , int , int >
{
auto block = CalcBlock ( x , y ) ;
auto offset = CalcXYOffset ( block ) ;
return std : : make_tuple ( block , x - offset . first , y - offset . second ) ;
2022-06-15 11:24:57 -04:00
}
//=========================================================
2022-11-14 21:12:12 -05:00
auto UltimaMap : : ProcessEntry ( [[maybe_unused]] std : : size_t entry , std : : size_t index , std : : vector < std : : uint8_t > & data ) - > bool
2022-10-24 18:39:33 +08:00
{
auto count = data . size ( ) / 196 ;
2022-11-04 17:12:13 -04:00
size_t block = ( static_cast < int > ( index ) * 0xC4000 ) / 196 ;
2022-12-04 02:03:43 -05:00
for ( auto i = 0 ; i < static_cast < int > ( count ) ; + + i )
2022-10-24 18:39:33 +08:00
{
auto ptr = data . data ( ) + ( i * 196 ) ;
if ( block < _terrain . size ( ) )
{
2022-12-04 02:03:43 -05:00
LoadTerrainBlock ( block , ptr ) ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
+ + block ;
2022-06-15 11:24:57 -04:00
}
2022-10-24 18:39:33 +08:00
return true ;
2022-06-15 11:24:57 -04:00
}
//=========================================================
2022-10-24 18:39:33 +08:00
auto UltimaMap : : LoadTerrainBlock ( int blocknum , std : : uint8_t * data ) - > void
{
_terrain [ blocknum ] . LoadBlock ( data , tileInfo ) ;
2022-06-15 11:24:57 -04:00
}
//=========================================================
2022-10-24 18:39:33 +08:00
auto UltimaMap : : TerrainAt ( int x , int y ) const - > const Tile_st &
{
auto [ blocknum , xoffset , yoffset ] = BlockAndIndexFor ( x , y ) ;
return _terrain [ blocknum ] . TerrainTileAt ( xoffset , yoffset ) ;
2022-06-15 11:24:57 -04:00
}
//=========================================================
2022-10-24 18:39:33 +08:00
auto UltimaMap : : TerrainAt ( int x , int y ) - > Tile_st &
{
auto [ blocknum , xoffset , yoffset ] = BlockAndIndexFor ( x , y ) ;
return _terrain [ blocknum ] . TerrainTileAt ( xoffset , yoffset ) ;
2022-06-15 11:24:57 -04:00
}
//=========================================================
2022-10-24 18:39:33 +08:00
auto UltimaMap : : ArtAt ( int x , int y ) const - > const std : : vector < Tile_st > &
{
auto [ blocknum , xoffset , yoffset ] = BlockAndIndexFor ( x , y ) ;
return _art [ blocknum ] . ArtTileAt ( xoffset , yoffset ) ;
2022-06-15 11:24:57 -04:00
}
//=========================================================
2022-10-24 18:39:33 +08:00
auto UltimaMap : : ArtAt ( int x , int y ) - > std : : vector < Tile_st > &
{
auto [ blocknum , xoffset , yoffset ] = BlockAndIndexFor ( x , y ) ;
return _art [ blocknum ] . ArtTileAt ( xoffset , yoffset ) ;
2022-06-15 11:24:57 -04:00
}