2021-04-28 22:48:54 -03:00
|
|
|
-- Canary - Database (Schema)
|
2021-04-26 21:04:01 -03:00
|
|
|
|
|
|
|
|
-- Table structure `server_config`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `server_config` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`config` varchar(50) NOT NULL,
|
|
|
|
|
`value` varchar(256) NOT NULL DEFAULT '',
|
|
|
|
|
CONSTRAINT `server_config_pk` PRIMARY KEY (`config`)
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
feat(pvp): add Expert PvP world type and combat rules (#4033)
Add Expert PvP world type and combat rules
This commit adds Expert Open PvP support to Canary as an explicit world type through worldType = expert-pvp.
The implementation introduces a dedicated ExpertPvp component for Expert specific combat, relation, field, movement, collision, and marking rules. Existing combat, spell, tile, player, game, and protocol code remain as thin integration points, while the Expert PvP decisions live under src creatures players components pvp.
This keeps the new behavior isolated from the existing world types and avoids spreading Expert PvP specific rules across unrelated systems.
The existing PvP world type handling was also clarified. retro-pvp is now the explicit Retro Open PvP value, while pvp remains supported as a compatibility alias for retro-pvp. no-pvp and pvp-enforced remain outside the Expert PvP decision path.
Main world type changes
• Adds worldType expert-pvp
• Makes retro-pvp the explicit Retro Open PvP config value
• Keeps pvp as a compatibility alias for retro-pvp
• Changes the default config value from pvp to retro-pvp
• Removes the old toggleServerIsRetroPVP config option
• Updates Lua helpers so IsRetroPVP reads the world type string
• Adds IsExpertPVP for Lua scripts
• Keeps no-pvp and pvp-enforced behavior outside the Expert PvP component
The ExpertPvp component centralizes relation classification and decision making for the new world type. It evaluates PvP mode, actor and target relation, combat action type, field ownership, side effects, player collision, and viewer specific situation marks.
The component covers relations such as self, access players, party allies, guild allies, war enemies, direct attackers, protected ally attackers, direct targets, skulled targets, neutral players, monsters, player summons, and NPCs.
Main Expert PvP rules included
• Dove mode behavior
• White Hand behavior
• Yellow Hand behavior
• Red Fist behavior
• Direct combat decisions
• Rune target decisions
• Area spell decisions
• Summon combat decisions
• Field step decisions
• Field damage decisions
• Player walkthrough decisions
• Pathfinding probe decisions
• Viewer specific field visual decisions
• Viewer relative creature situation marks
Combat integration now asks ExpertPvp before allowing Expert PvP relevant actions. This applies to direct attacks, runes, aggressive area spells, mana and health combat, conditions, dispels, default combat actions, and field damage.
When Expert PvP handles an action, it can allow or block the action and apply the correct side effects. These side effects include fight state, PZ lock behavior, skull actions, square feedback, and unjustified kill tracking where applicable.
Secure mode behavior is handled through the Expert PvP relation rules instead of the older broad secure mode check. This allows secure mode retaliation without applying unjustified protection zone locks in cases where the Expert PvP relation allows the response.
Magic Wall and Wild Growth now carry Expert PvP cast time context. When Expert PvP is enabled, these fields are created as safe field variants and receive owner context so the server can evaluate relation dependent behavior later.
Magic Wall and Wild Growth changes
• Stores the field owner context when the rune is cast
• Stores the owner PvP mode at cast time
• Tracks owner targets and attackers at cast time
• Uses safe visual field items as the base item in Expert PvP
• Resolves viewer specific appearance through protocol serialization
• Evaluates collision and pathfinding from the field context
• Evaluates field stepping side effects through ExpertPvp
• Prevents Expert PvP owned safe fields from being removed like regular no-pvp safe fields
• Keeps normal no-pvp behavior for non Expert PvP worlds
Tile and pathfinding logic now consult ExpertPvp for Expert owned fields. This allows Magic Wall and Wild Growth to appear or behave differently depending on the viewer and the PvP relation, while still using the existing movement and tile query paths as the final authority.
Player walkthrough and body blocking were updated so Expert PvP can decide whether a player can walk through another player outside legacy safe zones. Party, guild, war, attacker, protected ally, and target relations are used to keep collision behavior aligned with Expert PvP hand modes.
PvP situation tracking was added so player relations can affect persistent creature marks. The server can now send viewer relative creature marks for the current client profile and refresh visible marks when relevant state changes.
Situation mark updates happen when needed for events such as party changes, guild changes, attacked player tracking, player removal, and visible relation changes.
Protocol changes
• Adds ExpertPvpModeByte as a protocol feature flag
• Enables Expert PvP mode byte support for the Tibia 11.00 profile
• Keeps Tibia 11.00 on the verified four byte Set Tactics layout
• Keeps current 15.25 on its verified three byte tactics layout
• Defaults unsupported profiles safely to Dove mode
• Avoids appending speculative PvP mode bytes to the current 15.25 profile
• Sends Expert PvP controls only when the protocol profile supports them
• Sends viewer relative creature marks only through supported packet layouts
The current 15.25 profile keeps its verified tactics payload layout and does not receive a speculative extra PvP byte. This prevents client desync or crash risk. Unsupported profiles are forced safely to Dove when Expert PvP is enabled but the protocol cannot represent the mode.
Player state now includes a dedicated PvP component. The selected Expert PvP mode is stored on the player and persisted to the database.
Persistence and database changes
• Adds PlayerPvp component
• Adds player getPvpMode and setPvpMode support
• Saves expert_pvp_mode during player save
• Loads expert_pvp_mode during player load
• Adds players.expert_pvp_mode to schema.sql
• Bumps database version to 59
• Adds migration 59 for the players.expert_pvp_mode column
• Skips the migration safely if the column already exists
Lua API support was expanded so scripts can inspect PvP state and attach field context where needed.
Lua API changes
• Adds Player getPvpMode
• Adds Player hasAttacked
• Adds Item setExpertPvpFieldContext
• Updates generated Lua API documentation
• Updates Magic Wall and Wild Growth scripts to attach Expert PvP field context
The PR also updates blessing and death loss behavior to use the new Retro PvP world type detection instead of the removed toggleServerIsRetroPVP config. This keeps existing Retro PvP behavior while moving the decision to the explicit world type model.
Additional behavior covered
• Party relation handling
• Guild relation handling
• War enemy relation handling
• Skull relation handling
• Aggressor relation handling
• Protected ally relation handling
• Field ownership behavior
• Viewer specific field visuals
• Body blocking and player collision
• Situation marks and persistent creature marks
• Defensive PZ lock behavior
• Secure mode retaliation behavior
• Blessing cost and Twist of Fate behavior under Retro PvP detection
Out of scope
• Frag sharing
• player_kills.weight schema changes
• Debug commands
• Unrelated PvP features
• Broad behavior changes to existing world types
Documentation and tests
• Adds Expert PvP implementation roadmap documentation
• Adds Expert PvP porting plan documentation
• Links the new documentation from the systems overview
• Documents the behavioral contract
• Documents the implementation roadmap
• Documents the in game regression matrix
• Adds Expert PvP unit coverage
• Adds protocol profile coverage for Expert PvP mode support
• Adds regression scenarios for all world types
Validation performed
• Built canary target
• Built canary_ut target
• Built canary_it target
• Expert PvP and protocol profile tests passed with 49 of 49 tests
• Full unit binary passed with 311 of 311 tests
• Integration binary passed with 40 of 40 tests
• Manual scenarios were exercised during implementation
• Tested secure mode retaliation
• Tested defensive PZ lock behavior
• Tested Magic Wall and Wild Growth cast time relations
• Tested viewer specific visuals and collision
• Tested situation marks
Test configuration
• Platform Windows x64
• Compiler Microsoft Visual C plus plus 19.44
• Protocol coverage Tibia 11.00 and current 15.25 profiles
Known validation note
Two isolated CTest invocations terminated during global teardown after their test bodies passed. The same behavior reproduces on the main baseline. Running the unit suite in one process passes all 311 tests.
Overall this commit adds Expert Open PvP as a gated world type with dedicated relation based combat and field rules. It keeps existing world types protected from Expert PvP behavior, persists the selected PvP mode, supports protocol safe PvP mode handling, updates Lua APIs and documentation, and adds regression coverage for the new rules.
2026-08-10 18:42:55 -03:00
|
|
|
INSERT INTO `server_config` (`config`, `value`) VALUES ('db_version', '59'), ('motd_hash', ''), ('motd_num', '0'), ('players_record', '0');
|
2021-04-26 21:04:01 -03:00
|
|
|
|
|
|
|
|
-- Table structure `accounts`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `accounts` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
|
|
|
`name` varchar(32) NOT NULL,
|
2026-03-31 14:10:36 +02:00
|
|
|
`password` VARCHAR(255) NOT NULL,
|
2021-04-28 22:48:54 -03:00
|
|
|
`email` varchar(255) NOT NULL DEFAULT '',
|
|
|
|
|
`premdays` int(11) NOT NULL DEFAULT '0',
|
feat: loyalty system (#1213)
This commit implements the Loyalty System based on the code from pull request #425 (Thanks @marcosvf132). The Loyalty System functionality is inspired by the loyalty system in Tibia (https://tibia.fandom.com/wiki/Loyalty_System).
Enhances the loyalty system with new configuration options, accurate tracking of premium days, and support for customizable bonuses. The Loyalty System introduces several new configuration keys that can be customized:
• loyaltyEnabled: Determines whether the loyalty system is enabled or not (default: true).
• loyaltyPointsPerCreationDay: Sets the number of loyalty points awarded per day of account creation (default: 1).
• loyaltyPointsPerPremiumDaySpent: Sets the number of loyalty points awarded per premium day spent (default: 0).
• loyaltyPointsPerPremiumDayPurchased: Sets the number of loyalty points awarded per premium day purchased (default: 0).
• loyaltyBonusPercentageMultiplier: Allows for customization of loyalty bonus strength (default: 1.0).
By default, the loyaltyPointsPerCreationDay is set to 1, providing 1 loyalty point per day since the account was created. This conservative default setting ensures a slow accumulation of loyalty points, similar to the original Tibia loyalty system. Server administrators can adjust these settings as needed.
To accurately track premium days spent, a new column was added to the accounts table, which stores the total number of premium days purchased on the account.
The implementation includes support for awarding loyalty points at the moment of VIP purchase. If a server uses a different mechanism for VIP, they can adapt the loyalty system accordingly.
The loyaltyBonusPercentageMultiplier allows administrators to adjust the strength of bonuses. The default settings are relatively mild, so this option provides flexibility. For example, to award a 10 skill bonus at around magic level or skill 120, the multiplier should be set to 4.0.
To ensure accurate calculations, a new library 'absl' was introduced. This enables precise calculation of bonuses as loyalty points are multiplied by the bonus percentage. This is necessary because only the current level's "tries" (or mana spent) are tracked, and calculations may exceed the limits of uint64_t.
2023-07-07 12:59:35 -07:00
|
|
|
`premdays_purchased` int(11) NOT NULL DEFAULT '0',
|
2021-04-28 22:48:54 -03:00
|
|
|
`lastday` int(10) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`type` tinyint(1) UNSIGNED NOT NULL DEFAULT '1',
|
|
|
|
|
`coins` int(12) UNSIGNED NOT NULL DEFAULT '0',
|
2023-05-20 16:26:33 -03:00
|
|
|
`coins_transferable` int(12) UNSIGNED NOT NULL DEFAULT '0',
|
[Enhancement] rework for enable choosing of a custom datapack name (#572)
With this modification, we will be able to focus on just one repository (the canary), and archive otservbr-global repository.
The intention is that we can have two datapacks in the same repository, being able to easily switch from one to the other, just change in config.lua the "dataPackDirectory" from "data-otservbr-global" to "data-canary" or vice versa.
The main purpose is to facilitate our development, at the same time that the community will be able to contribute in a single repository, but keeping the choice of using a "clean" datapack.
I made some more modifications, such as removing the unused C++ gamestore, I also removed the "allowPickupable" tag, which was duplicated, and I made some other adjustments.
Folder structure changes
Now we have the following structure:
• data = this will be the "core" folder, it is where the files that are absolutely necessary for the executable to open correctly, such as libs, xmls, etc. Here we will have files that both the global and the canary datapack will share with each other
• data-otservbr-global = here will be the global datapack files, some libs and folders that are only for the global server, such as scripts, monsters, npcs, world.
• data-canary = a "clean" datapack as far as possible, with only the scripts and files necessary for the server to work.
• NOTE: The "data" folder is actually the "core" of the server, we didn't rename it to avoid having to make changes to the sites and login.php, since they read the "data/xml". The other two folders, data-otservbr-global and data-canary can be changed in config.lua, which one you want the executable to read, by default we'll point to the global one, as that's what most use. If you want to start a custom server with "as few files and scripts as possible", then switch to "data-canary".
We also added a boolean in config.lua that allows choosing another name for the datapack, by default we will also keep this disabled, since we will only maintain support for these two datapacks, it is up to each one to know what they are doing in case they want to change it.
So, in the end, we have the reorganization in the folders:

Note that we made few real changes to the files, the abundance of modified files is due to moving from one folder to another and also adding the global datapack to this repository (with an abundance of files). If you want to migrate your datapack to the global one, you should know what you're doing, if you don't know, just pass your modifications to the "new files" or get in touch on our discord group so we can help you: https://discord.gg/X3mSnMH8jg
2022-11-18 22:32:44 -03:00
|
|
|
`tournament_coins` int(12) UNSIGNED NOT NULL DEFAULT '0',
|
2021-04-28 22:48:54 -03:00
|
|
|
`creation` int(11) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`recruiter` INT(6) DEFAULT 0,
|
2024-12-31 13:03:35 -03:00
|
|
|
`house_bid_id` int(11) NOT NULL DEFAULT '0',
|
2021-04-28 22:48:54 -03:00
|
|
|
CONSTRAINT `accounts_pk` PRIMARY KEY (`id`),
|
2026-03-31 14:10:36 +02:00
|
|
|
CONSTRAINT `accounts_unique` UNIQUE (`name`),
|
|
|
|
|
INDEX `accounts_email` (`email`),
|
|
|
|
|
INDEX `accounts_password` (`password`)
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `coins_transactions`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `coins_transactions` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
|
|
|
`account_id` int(11) UNSIGNED NOT NULL,
|
|
|
|
|
`type` tinyint(1) UNSIGNED NOT NULL,
|
2023-08-26 16:27:42 +02:00
|
|
|
`coin_type` tinyint(1) UNSIGNED NOT NULL DEFAULT '1',
|
2021-04-28 22:48:54 -03:00
|
|
|
`amount` int(12) UNSIGNED NOT NULL,
|
|
|
|
|
`description` varchar(3500) NOT NULL,
|
|
|
|
|
`timestamp` timestamp DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
INDEX `account_id` (`account_id`),
|
|
|
|
|
CONSTRAINT `coins_transactions_pk` PRIMARY KEY (`id`),
|
|
|
|
|
CONSTRAINT `coins_transactions_account_fk`
|
2021-04-26 21:04:01 -03:00
|
|
|
FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `players`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `players` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
|
|
|
`name` varchar(255) NOT NULL,
|
|
|
|
|
`group_id` int(11) NOT NULL DEFAULT '1',
|
|
|
|
|
`account_id` int(11) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`level` int(11) NOT NULL DEFAULT '1',
|
|
|
|
|
`vocation` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`health` int(11) NOT NULL DEFAULT '150',
|
|
|
|
|
`healthmax` int(11) NOT NULL DEFAULT '150',
|
|
|
|
|
`experience` bigint(20) NOT NULL DEFAULT '0',
|
|
|
|
|
`lookbody` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`lookfeet` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`lookhead` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`looklegs` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`looktype` int(11) NOT NULL DEFAULT '136',
|
|
|
|
|
`lookaddons` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`maglevel` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`mana` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`manamax` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`manaspent` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`soul` int(10) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`town_id` int(11) NOT NULL DEFAULT '1',
|
|
|
|
|
`posx` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`posy` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`posz` int(11) NOT NULL DEFAULT '0',
|
2024-11-09 22:18:08 -03:00
|
|
|
`conditions` mediumblob NOT NULL,
|
2021-04-28 22:48:54 -03:00
|
|
|
`cap` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`sex` int(11) NOT NULL DEFAULT '0',
|
2023-09-05 18:38:05 -07:00
|
|
|
`pronoun` int(11) NOT NULL DEFAULT '0',
|
2021-04-28 22:48:54 -03:00
|
|
|
`lastlogin` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`lastip` int(10) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`save` tinyint(1) NOT NULL DEFAULT '1',
|
|
|
|
|
`skull` tinyint(1) NOT NULL DEFAULT '0',
|
|
|
|
|
`skulltime` bigint(20) NOT NULL DEFAULT '0',
|
feat(pvp): add Expert PvP world type and combat rules (#4033)
Add Expert PvP world type and combat rules
This commit adds Expert Open PvP support to Canary as an explicit world type through worldType = expert-pvp.
The implementation introduces a dedicated ExpertPvp component for Expert specific combat, relation, field, movement, collision, and marking rules. Existing combat, spell, tile, player, game, and protocol code remain as thin integration points, while the Expert PvP decisions live under src creatures players components pvp.
This keeps the new behavior isolated from the existing world types and avoids spreading Expert PvP specific rules across unrelated systems.
The existing PvP world type handling was also clarified. retro-pvp is now the explicit Retro Open PvP value, while pvp remains supported as a compatibility alias for retro-pvp. no-pvp and pvp-enforced remain outside the Expert PvP decision path.
Main world type changes
• Adds worldType expert-pvp
• Makes retro-pvp the explicit Retro Open PvP config value
• Keeps pvp as a compatibility alias for retro-pvp
• Changes the default config value from pvp to retro-pvp
• Removes the old toggleServerIsRetroPVP config option
• Updates Lua helpers so IsRetroPVP reads the world type string
• Adds IsExpertPVP for Lua scripts
• Keeps no-pvp and pvp-enforced behavior outside the Expert PvP component
The ExpertPvp component centralizes relation classification and decision making for the new world type. It evaluates PvP mode, actor and target relation, combat action type, field ownership, side effects, player collision, and viewer specific situation marks.
The component covers relations such as self, access players, party allies, guild allies, war enemies, direct attackers, protected ally attackers, direct targets, skulled targets, neutral players, monsters, player summons, and NPCs.
Main Expert PvP rules included
• Dove mode behavior
• White Hand behavior
• Yellow Hand behavior
• Red Fist behavior
• Direct combat decisions
• Rune target decisions
• Area spell decisions
• Summon combat decisions
• Field step decisions
• Field damage decisions
• Player walkthrough decisions
• Pathfinding probe decisions
• Viewer specific field visual decisions
• Viewer relative creature situation marks
Combat integration now asks ExpertPvp before allowing Expert PvP relevant actions. This applies to direct attacks, runes, aggressive area spells, mana and health combat, conditions, dispels, default combat actions, and field damage.
When Expert PvP handles an action, it can allow or block the action and apply the correct side effects. These side effects include fight state, PZ lock behavior, skull actions, square feedback, and unjustified kill tracking where applicable.
Secure mode behavior is handled through the Expert PvP relation rules instead of the older broad secure mode check. This allows secure mode retaliation without applying unjustified protection zone locks in cases where the Expert PvP relation allows the response.
Magic Wall and Wild Growth now carry Expert PvP cast time context. When Expert PvP is enabled, these fields are created as safe field variants and receive owner context so the server can evaluate relation dependent behavior later.
Magic Wall and Wild Growth changes
• Stores the field owner context when the rune is cast
• Stores the owner PvP mode at cast time
• Tracks owner targets and attackers at cast time
• Uses safe visual field items as the base item in Expert PvP
• Resolves viewer specific appearance through protocol serialization
• Evaluates collision and pathfinding from the field context
• Evaluates field stepping side effects through ExpertPvp
• Prevents Expert PvP owned safe fields from being removed like regular no-pvp safe fields
• Keeps normal no-pvp behavior for non Expert PvP worlds
Tile and pathfinding logic now consult ExpertPvp for Expert owned fields. This allows Magic Wall and Wild Growth to appear or behave differently depending on the viewer and the PvP relation, while still using the existing movement and tile query paths as the final authority.
Player walkthrough and body blocking were updated so Expert PvP can decide whether a player can walk through another player outside legacy safe zones. Party, guild, war, attacker, protected ally, and target relations are used to keep collision behavior aligned with Expert PvP hand modes.
PvP situation tracking was added so player relations can affect persistent creature marks. The server can now send viewer relative creature marks for the current client profile and refresh visible marks when relevant state changes.
Situation mark updates happen when needed for events such as party changes, guild changes, attacked player tracking, player removal, and visible relation changes.
Protocol changes
• Adds ExpertPvpModeByte as a protocol feature flag
• Enables Expert PvP mode byte support for the Tibia 11.00 profile
• Keeps Tibia 11.00 on the verified four byte Set Tactics layout
• Keeps current 15.25 on its verified three byte tactics layout
• Defaults unsupported profiles safely to Dove mode
• Avoids appending speculative PvP mode bytes to the current 15.25 profile
• Sends Expert PvP controls only when the protocol profile supports them
• Sends viewer relative creature marks only through supported packet layouts
The current 15.25 profile keeps its verified tactics payload layout and does not receive a speculative extra PvP byte. This prevents client desync or crash risk. Unsupported profiles are forced safely to Dove when Expert PvP is enabled but the protocol cannot represent the mode.
Player state now includes a dedicated PvP component. The selected Expert PvP mode is stored on the player and persisted to the database.
Persistence and database changes
• Adds PlayerPvp component
• Adds player getPvpMode and setPvpMode support
• Saves expert_pvp_mode during player save
• Loads expert_pvp_mode during player load
• Adds players.expert_pvp_mode to schema.sql
• Bumps database version to 59
• Adds migration 59 for the players.expert_pvp_mode column
• Skips the migration safely if the column already exists
Lua API support was expanded so scripts can inspect PvP state and attach field context where needed.
Lua API changes
• Adds Player getPvpMode
• Adds Player hasAttacked
• Adds Item setExpertPvpFieldContext
• Updates generated Lua API documentation
• Updates Magic Wall and Wild Growth scripts to attach Expert PvP field context
The PR also updates blessing and death loss behavior to use the new Retro PvP world type detection instead of the removed toggleServerIsRetroPVP config. This keeps existing Retro PvP behavior while moving the decision to the explicit world type model.
Additional behavior covered
• Party relation handling
• Guild relation handling
• War enemy relation handling
• Skull relation handling
• Aggressor relation handling
• Protected ally relation handling
• Field ownership behavior
• Viewer specific field visuals
• Body blocking and player collision
• Situation marks and persistent creature marks
• Defensive PZ lock behavior
• Secure mode retaliation behavior
• Blessing cost and Twist of Fate behavior under Retro PvP detection
Out of scope
• Frag sharing
• player_kills.weight schema changes
• Debug commands
• Unrelated PvP features
• Broad behavior changes to existing world types
Documentation and tests
• Adds Expert PvP implementation roadmap documentation
• Adds Expert PvP porting plan documentation
• Links the new documentation from the systems overview
• Documents the behavioral contract
• Documents the implementation roadmap
• Documents the in game regression matrix
• Adds Expert PvP unit coverage
• Adds protocol profile coverage for Expert PvP mode support
• Adds regression scenarios for all world types
Validation performed
• Built canary target
• Built canary_ut target
• Built canary_it target
• Expert PvP and protocol profile tests passed with 49 of 49 tests
• Full unit binary passed with 311 of 311 tests
• Integration binary passed with 40 of 40 tests
• Manual scenarios were exercised during implementation
• Tested secure mode retaliation
• Tested defensive PZ lock behavior
• Tested Magic Wall and Wild Growth cast time relations
• Tested viewer specific visuals and collision
• Tested situation marks
Test configuration
• Platform Windows x64
• Compiler Microsoft Visual C plus plus 19.44
• Protocol coverage Tibia 11.00 and current 15.25 profiles
Known validation note
Two isolated CTest invocations terminated during global teardown after their test bodies passed. The same behavior reproduces on the main baseline. Running the unit suite in one process passes all 311 tests.
Overall this commit adds Expert Open PvP as a gated world type with dedicated relation based combat and field rules. It keeps existing world types protected from Expert PvP behavior, persists the selected PvP mode, supports protocol safe PvP mode handling, updates Lua APIs and documentation, and adds regression coverage for the new rules.
2026-08-10 18:42:55 -03:00
|
|
|
`expert_pvp_mode` tinyint(1) UNSIGNED NOT NULL DEFAULT '0',
|
2021-04-28 22:48:54 -03:00
|
|
|
`lastlogout` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`blessings` tinyint(2) NOT NULL DEFAULT '0',
|
|
|
|
|
`blessings1` tinyint(4) NOT NULL DEFAULT '0',
|
|
|
|
|
`blessings2` tinyint(4) NOT NULL DEFAULT '0',
|
|
|
|
|
`blessings3` tinyint(4) NOT NULL DEFAULT '0',
|
|
|
|
|
`blessings4` tinyint(4) NOT NULL DEFAULT '0',
|
|
|
|
|
`blessings5` tinyint(4) NOT NULL DEFAULT '0',
|
|
|
|
|
`blessings6` tinyint(4) NOT NULL DEFAULT '0',
|
|
|
|
|
`blessings7` tinyint(4) NOT NULL DEFAULT '0',
|
|
|
|
|
`blessings8` tinyint(4) NOT NULL DEFAULT '0',
|
|
|
|
|
`onlinetime` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`deletion` bigint(15) NOT NULL DEFAULT '0',
|
|
|
|
|
`balance` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`offlinetraining_time` smallint(5) UNSIGNED NOT NULL DEFAULT '43200',
|
2022-11-28 22:37:23 -03:00
|
|
|
`offlinetraining_skill` tinyint(2) NOT NULL DEFAULT '-1',
|
2021-04-28 22:48:54 -03:00
|
|
|
`stamina` smallint(5) UNSIGNED NOT NULL DEFAULT '2520',
|
|
|
|
|
`skill_fist` int(10) UNSIGNED NOT NULL DEFAULT '10',
|
|
|
|
|
`skill_fist_tries` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_club` int(10) UNSIGNED NOT NULL DEFAULT '10',
|
|
|
|
|
`skill_club_tries` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_sword` int(10) UNSIGNED NOT NULL DEFAULT '10',
|
|
|
|
|
`skill_sword_tries` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_axe` int(10) UNSIGNED NOT NULL DEFAULT '10',
|
|
|
|
|
`skill_axe_tries` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_dist` int(10) UNSIGNED NOT NULL DEFAULT '10',
|
|
|
|
|
`skill_dist_tries` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_shielding` int(10) UNSIGNED NOT NULL DEFAULT '10',
|
|
|
|
|
`skill_shielding_tries` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_fishing` int(10) UNSIGNED NOT NULL DEFAULT '10',
|
|
|
|
|
`skill_fishing_tries` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_critical_hit_chance` int(10) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_critical_hit_chance_tries` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_critical_hit_damage` int(10) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_critical_hit_damage_tries` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_life_leech_chance` int(10) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_life_leech_chance_tries` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_life_leech_amount` int(10) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_life_leech_amount_tries` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_mana_leech_chance` int(10) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_mana_leech_chance_tries` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_mana_leech_amount` int(10) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_mana_leech_amount_tries` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_criticalhit_chance` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_criticalhit_damage` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_lifeleech_chance` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_lifeleech_amount` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_manaleech_chance` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`skill_manaleech_amount` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
2024-05-07 16:08:01 -03:00
|
|
|
`manashield` INT UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`max_manashield` INT UNSIGNED NOT NULL DEFAULT '0',
|
2023-10-31 21:20:01 -07:00
|
|
|
`xpboost_stamina` smallint(5) UNSIGNED DEFAULT NULL,
|
|
|
|
|
`xpboost_value` tinyint(4) UNSIGNED DEFAULT NULL,
|
2021-04-28 22:48:54 -03:00
|
|
|
`marriage_status` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`marriage_spouse` int(11) NOT NULL DEFAULT '-1',
|
|
|
|
|
`bonus_rerolls` bigint(21) NOT NULL DEFAULT '0',
|
2022-04-24 13:36:35 -03:00
|
|
|
`prey_wildcard` bigint(21) NOT NULL DEFAULT '0',
|
|
|
|
|
`task_points` bigint(21) NOT NULL DEFAULT '0',
|
2021-04-28 22:48:54 -03:00
|
|
|
`quickloot_fallback` tinyint(1) DEFAULT '0',
|
|
|
|
|
`lookmountbody` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
|
|
|
|
`lookmountfeet` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
|
|
|
|
`lookmounthead` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
|
|
|
|
`lookmountlegs` tinyint(3) unsigned NOT NULL DEFAULT '0',
|
|
|
|
|
`lookfamiliarstype` int(11) unsigned NOT NULL DEFAULT '0',
|
|
|
|
|
`isreward` tinyint(1) NOT NULL DEFAULT '1',
|
|
|
|
|
`istutorial` tinyint(1) NOT NULL DEFAULT '0',
|
[Enhancement] rework for enable choosing of a custom datapack name (#572)
With this modification, we will be able to focus on just one repository (the canary), and archive otservbr-global repository.
The intention is that we can have two datapacks in the same repository, being able to easily switch from one to the other, just change in config.lua the "dataPackDirectory" from "data-otservbr-global" to "data-canary" or vice versa.
The main purpose is to facilitate our development, at the same time that the community will be able to contribute in a single repository, but keeping the choice of using a "clean" datapack.
I made some more modifications, such as removing the unused C++ gamestore, I also removed the "allowPickupable" tag, which was duplicated, and I made some other adjustments.
Folder structure changes
Now we have the following structure:
• data = this will be the "core" folder, it is where the files that are absolutely necessary for the executable to open correctly, such as libs, xmls, etc. Here we will have files that both the global and the canary datapack will share with each other
• data-otservbr-global = here will be the global datapack files, some libs and folders that are only for the global server, such as scripts, monsters, npcs, world.
• data-canary = a "clean" datapack as far as possible, with only the scripts and files necessary for the server to work.
• NOTE: The "data" folder is actually the "core" of the server, we didn't rename it to avoid having to make changes to the sites and login.php, since they read the "data/xml". The other two folders, data-otservbr-global and data-canary can be changed in config.lua, which one you want the executable to read, by default we'll point to the global one, as that's what most use. If you want to start a custom server with "as few files and scripts as possible", then switch to "data-canary".
We also added a boolean in config.lua that allows choosing another name for the datapack, by default we will also keep this disabled, since we will only maintain support for these two datapacks, it is up to each one to know what they are doing in case they want to change it.
So, in the end, we have the reorganization in the folders:

Note that we made few real changes to the files, the abundance of modified files is due to moving from one folder to another and also adding the global datapack to this repository (with an abundance of files). If you want to migrate your datapack to the global one, you should know what you're doing, if you don't know, just pass your modifications to the "new files" or get in touch on our discord group so we can help you: https://discord.gg/X3mSnMH8jg
2022-11-18 22:32:44 -03:00
|
|
|
`forge_dusts` bigint(21) NOT NULL DEFAULT '0',
|
|
|
|
|
`forge_dust_level` bigint(21) NOT NULL DEFAULT '100',
|
2023-02-06 15:01:01 -03:00
|
|
|
`randomize_mount` tinyint(1) NOT NULL DEFAULT '0',
|
2023-02-13 02:06:07 -03:00
|
|
|
`boss_points` int NOT NULL DEFAULT '0',
|
improve: migrate RSA backend from OpenSSL to Mbed TLS (#3938)
This change migrates the RSA login path away from direct OpenSSL usage and introduces a pluggable RSA backend model. RSAManager now delegates RSA operations through the new backend interface while preserving the existing Tibia login protocol contract.
The new Mbed TLS-based backend keeps compatibility with the current raw 128-byte RSA login block behavior. The goal is to reduce the crypto dependency surface, simplify future backend maintenance, and keep the login flow isolated from direct OpenSSL implementation details.
The migration also updates the build configuration and supporting files so the RSA login path is linked through Mbed TLS. This includes CMake configuration, Docker build dependencies, precompiled headers, and security module setup.
The implementation maintains strict compatibility requirements. RSA decryption is still used only during the first login packet and does not affect the normal gameplay tick path. Local benchmark results showed that the initial Mbed TLS implementation was slower than the old OpenSSL raw RSA path, primarily due to blinding RNG, verification, and mutex overhead.
The backend was then optimized by keeping Mbed TLS key parsing and validation while using a validated key with raw CRT modular exponentiation. This reduced the overhead and kept the behavior compatible with the existing login protocol.
Main points covered by this change
• Replace direct OpenSSL RSA login usage with a pluggable backend interface
• Add an Mbed TLS-based RSA backend
• Preserve raw 128-byte RSA login block compatibility
• Update CMake and Docker dependencies for the new backend
• Remove direct OpenSSL includes from the RSA login flow
• Avoid copying or swapping Mbed TLS RSA contexts directly
• Publish the active RSA key through an immutable pointer owned key object
• Remove the global backend mutex from the expensive RSA decrypt operation
• Add RSA backend equivalence tests and regression coverage
• Add documentation explaining the migration motivation, compatibility requirements, performance tradeoffs, and future work
Local benchmark notes:
• Old OpenSSL raw RSA path was around 0.22 to 0.25 milliseconds per operation
• Initial Mbed TLS private RSA implementation was around 1.05 to 1.62 milliseconds per operation
• Optimized Mbed TLS backend was reduced to around 0.82 milliseconds per operation
Overall, this keeps the login protocol unchanged while moving the RSA implementation to a cleaner backend structure based on Mbed TLS.
2026-05-06 08:45:24 -03:00
|
|
|
`comment` varchar(255) NOT NULL DEFAULT '',
|
2025-01-28 14:33:54 -03:00
|
|
|
`animus_mastery` mediumblob DEFAULT NULL,
|
2021-04-28 22:48:54 -03:00
|
|
|
INDEX `account_id` (`account_id`),
|
|
|
|
|
INDEX `vocation` (`vocation`),
|
|
|
|
|
CONSTRAINT `players_pk` PRIMARY KEY (`id`),
|
|
|
|
|
CONSTRAINT `players_unique` UNIQUE (`name`),
|
|
|
|
|
CONSTRAINT `players_account_fk`
|
2021-04-26 21:04:01 -03:00
|
|
|
FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `account_bans`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `account_bans` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`account_id` int(11) UNSIGNED NOT NULL,
|
|
|
|
|
`reason` varchar(255) NOT NULL,
|
|
|
|
|
`banned_at` bigint(20) NOT NULL,
|
|
|
|
|
`expires_at` bigint(20) NOT NULL,
|
|
|
|
|
`banned_by` int(11) NOT NULL,
|
|
|
|
|
INDEX `banned_by` (`banned_by`),
|
|
|
|
|
CONSTRAINT `account_bans_pk` PRIMARY KEY (`account_id`),
|
|
|
|
|
CONSTRAINT `account_bans_account_fk`
|
2021-04-26 21:04:01 -03:00
|
|
|
FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
|
|
|
|
ON UPDATE CASCADE,
|
2021-04-28 22:48:54 -03:00
|
|
|
CONSTRAINT `account_bans_player_fk`
|
2021-04-26 21:04:01 -03:00
|
|
|
FOREIGN KEY (`banned_by`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
|
|
|
|
ON UPDATE CASCADE
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `account_ban_history`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `account_ban_history` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
|
|
|
`account_id` int(11) UNSIGNED NOT NULL,
|
|
|
|
|
`reason` varchar(255) NOT NULL,
|
|
|
|
|
`banned_at` bigint(20) NOT NULL,
|
|
|
|
|
`expired_at` bigint(20) NOT NULL,
|
|
|
|
|
`banned_by` int(11) NOT NULL,
|
|
|
|
|
INDEX `account_id` (`account_id`),
|
|
|
|
|
INDEX `banned_by` (`banned_by`),
|
|
|
|
|
CONSTRAINT `account_bans_history_account_fk`
|
2021-04-26 21:04:01 -03:00
|
|
|
FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
|
|
|
|
ON UPDATE CASCADE,
|
2021-04-28 22:48:54 -03:00
|
|
|
CONSTRAINT `account_bans_history_player_fk`
|
2021-04-26 21:04:01 -03:00
|
|
|
FOREIGN KEY (`banned_by`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
|
|
|
|
ON UPDATE CASCADE,
|
2021-04-28 22:48:54 -03:00
|
|
|
CONSTRAINT `account_ban_history_pk` PRIMARY KEY (`id`)
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `account_viplist`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `account_viplist` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`account_id` int(11) UNSIGNED NOT NULL COMMENT 'id of account whose viplist entry it is',
|
|
|
|
|
`player_id` int(11) NOT NULL COMMENT 'id of target player of viplist entry',
|
|
|
|
|
`description` varchar(128) NOT NULL DEFAULT '',
|
|
|
|
|
`icon` tinyint(2) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`notify` tinyint(1) NOT NULL DEFAULT '0',
|
|
|
|
|
INDEX `account_id` (`account_id`),
|
|
|
|
|
INDEX `player_id` (`player_id`),
|
|
|
|
|
CONSTRAINT `account_viplist_unique` UNIQUE (`account_id`, `player_id`),
|
|
|
|
|
CONSTRAINT `account_viplist_account_fk`
|
2021-04-26 21:04:01 -03:00
|
|
|
FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`)
|
|
|
|
|
ON DELETE CASCADE,
|
2021-04-28 22:48:54 -03:00
|
|
|
CONSTRAINT `account_viplist_player_fk`
|
2021-04-26 21:04:01 -03:00
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
2024-05-24 08:57:04 -03:00
|
|
|
-- Table structure `account_vipgroup`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `account_vipgroups` (
|
2024-05-29 17:08:03 -03:00
|
|
|
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
|
2024-05-24 08:57:04 -03:00
|
|
|
`account_id` int(11) UNSIGNED NOT NULL COMMENT 'id of account whose vip group entry it is',
|
|
|
|
|
`name` varchar(128) NOT NULL,
|
|
|
|
|
`customizable` BOOLEAN NOT NULL DEFAULT '1',
|
2025-07-15 23:58:18 +02:00
|
|
|
CONSTRAINT `account_vipgroups_pk` PRIMARY KEY (`id`, `account_id`),
|
|
|
|
|
CONSTRAINT `account_vipgroups_accounts_fk`
|
|
|
|
|
FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
2024-05-24 08:57:04 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
--
|
|
|
|
|
-- Trigger
|
|
|
|
|
--
|
|
|
|
|
DELIMITER //
|
|
|
|
|
CREATE TRIGGER `oncreate_accounts` AFTER INSERT ON `accounts` FOR EACH ROW BEGIN
|
2024-05-29 17:08:03 -03:00
|
|
|
INSERT INTO `account_vipgroups` (`account_id`, `name`, `customizable`) VALUES (NEW.`id`, 'Enemies', 0);
|
|
|
|
|
INSERT INTO `account_vipgroups` (`account_id`, `name`, `customizable`) VALUES (NEW.`id`, 'Friends', 0);
|
|
|
|
|
INSERT INTO `account_vipgroups` (`account_id`, `name`, `customizable`) VALUES (NEW.`id`, 'Trading Partner', 0);
|
2024-05-24 08:57:04 -03:00
|
|
|
END
|
|
|
|
|
//
|
|
|
|
|
DELIMITER ;
|
|
|
|
|
|
|
|
|
|
-- Table structure `account_vipgrouplist`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `account_vipgrouplist` (
|
|
|
|
|
`account_id` int(11) UNSIGNED NOT NULL COMMENT 'id of account whose viplist entry it is',
|
|
|
|
|
`player_id` int(11) NOT NULL COMMENT 'id of target player of viplist entry',
|
2024-05-29 17:08:03 -03:00
|
|
|
`vipgroup_id` int(11) UNSIGNED NOT NULL COMMENT 'id of vip group that player belongs',
|
2024-05-24 08:57:04 -03:00
|
|
|
INDEX `account_id` (`account_id`),
|
|
|
|
|
INDEX `player_id` (`player_id`),
|
|
|
|
|
INDEX `vipgroup_id` (`vipgroup_id`),
|
|
|
|
|
CONSTRAINT `account_vipgrouplist_unique` UNIQUE (`account_id`, `player_id`, `vipgroup_id`),
|
|
|
|
|
CONSTRAINT `account_vipgrouplist_player_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE,
|
|
|
|
|
CONSTRAINT `account_vipgrouplist_vipgroup_fk`
|
|
|
|
|
FOREIGN KEY (`vipgroup_id`, `account_id`) REFERENCES `account_vipgroups` (`id`, `account_id`)
|
|
|
|
|
ON DELETE CASCADE
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
2023-02-13 02:06:07 -03:00
|
|
|
-- Table structure `boosted_boss`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `boosted_boss` (
|
|
|
|
|
`boostname` TEXT,
|
|
|
|
|
`date` varchar(250) NOT NULL DEFAULT '',
|
|
|
|
|
`raceid` varchar(250) NOT NULL DEFAULT '',
|
2024-05-29 17:08:03 -03:00
|
|
|
`looktypeEx` int(11) NOT NULL DEFAULT 0,
|
|
|
|
|
`looktype` int(11) NOT NULL DEFAULT 136,
|
|
|
|
|
`lookfeet` int(11) NOT NULL DEFAULT 0,
|
|
|
|
|
`looklegs` int(11) NOT NULL DEFAULT 0,
|
|
|
|
|
`lookhead` int(11) NOT NULL DEFAULT 0,
|
|
|
|
|
`lookbody` int(11) NOT NULL DEFAULT 0,
|
|
|
|
|
`lookaddons` int(11) NOT NULL DEFAULT 0,
|
|
|
|
|
`lookmount` int(11) DEFAULT 0,
|
2023-02-13 02:06:07 -03:00
|
|
|
PRIMARY KEY (`date`)
|
2024-05-29 17:08:03 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
INSERT INTO `boosted_boss` (`boostname`, `date`, `raceid`) VALUES ('default', 0, 0);
|
2023-02-13 02:06:07 -03:00
|
|
|
|
2021-04-26 21:04:01 -03:00
|
|
|
-- Table structure `boosted_creature`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `boosted_creature` (
|
|
|
|
|
`boostname` TEXT,
|
|
|
|
|
`date` varchar(250) NOT NULL DEFAULT '',
|
|
|
|
|
`raceid` varchar(250) NOT NULL DEFAULT '',
|
2024-05-29 17:08:03 -03:00
|
|
|
`looktype` int(11) NOT NULL DEFAULT 136,
|
|
|
|
|
`lookfeet` int(11) NOT NULL DEFAULT 0,
|
|
|
|
|
`looklegs` int(11) NOT NULL DEFAULT 0,
|
|
|
|
|
`lookhead` int(11) NOT NULL DEFAULT 0,
|
|
|
|
|
`lookbody` int(11) NOT NULL DEFAULT 0,
|
|
|
|
|
`lookaddons` int(11) NOT NULL DEFAULT 0,
|
|
|
|
|
`lookmount` int(11) DEFAULT 0,
|
2021-04-28 22:48:54 -03:00
|
|
|
PRIMARY KEY (`date`)
|
2024-05-29 17:08:03 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
2021-04-26 21:04:01 -03:00
|
|
|
|
2024-05-29 17:08:03 -03:00
|
|
|
INSERT INTO `boosted_creature` (`boostname`, `date`, `raceid`) VALUES ('default', 0, 0);
|
2021-04-26 21:04:01 -03:00
|
|
|
|
|
|
|
|
-- Tabble Structure `daily_reward_history`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `daily_reward_history` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
|
|
|
`daystreak` smallint(2) NOT NULL DEFAULT 0,
|
|
|
|
|
`player_id` int(11) NOT NULL,
|
|
|
|
|
`timestamp` int(11) NOT NULL,
|
|
|
|
|
`description` varchar(255) DEFAULT NULL,
|
|
|
|
|
INDEX `player_id` (`player_id`),
|
|
|
|
|
CONSTRAINT `daily_reward_history_pk` PRIMARY KEY (`id`),
|
|
|
|
|
CONSTRAINT `daily_reward_history_player_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
[Client Feature] Forge System (Fiendish and Influenced Creatures from 12.80) (#543)
Implementation of the Forge
New features:
• Added talkactions for use in forge system;
Talkactions "/adddusts, /removedusts, /getdusts, /setdusts"
Talkaction to teleport to fiendish creature "/fiendish" and for influenced "/influenced"
Talkaction to set monster fiendish "/setfiendish", need to look to monster direction and use talkaction
Added in "/m" talkaction the param for create monster fiendish/influenced, example:
"/m rat, 1" create an influenced Rat with level 1 (allowed is 1-5)
"/m rat, fiendish" create a Rat with fiendish status
Talkaction to open forge "/openforge"
• Added spell to find fiendish "exiva moe res"
NOTE: The system is, as far as possible, the same as the global one, there is still a lot of information about the system that nobody knows.
2022-12-09 00:20:54 -03:00
|
|
|
-- Tabble Structure `forge_history`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `forge_history` (
|
|
|
|
|
`id` int NOT NULL AUTO_INCREMENT,
|
|
|
|
|
`player_id` int NOT NULL,
|
|
|
|
|
`action_type` int NOT NULL DEFAULT '0',
|
|
|
|
|
`description` text NOT NULL,
|
|
|
|
|
`is_success` tinyint NOT NULL DEFAULT '0',
|
|
|
|
|
`bonus` tinyint NOT NULL DEFAULT '0',
|
|
|
|
|
`done_at` bigint NOT NULL,
|
|
|
|
|
`done_at_date` datetime DEFAULT NOW(),
|
|
|
|
|
`cost` bigint UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`gained` bigint UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
CONSTRAINT `forge_history_pk` PRIMARY KEY (`id`),
|
2026-01-08 17:49:17 -03:00
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`) ON DELETE CASCADE,
|
|
|
|
|
UNIQUE KEY `unique_player_done_at` (`player_id`, `done_at`)
|
2023-02-13 02:06:07 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
2021-04-26 21:04:01 -03:00
|
|
|
|
|
|
|
|
-- Table structure `global_storage`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `global_storage` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`key` varchar(32) NOT NULL,
|
|
|
|
|
`value` text NOT NULL,
|
|
|
|
|
CONSTRAINT `global_storage_unique` UNIQUE (`key`)
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `guilds`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `guilds` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
[Enhancement] rework for enable choosing of a custom datapack name (#572)
With this modification, we will be able to focus on just one repository (the canary), and archive otservbr-global repository.
The intention is that we can have two datapacks in the same repository, being able to easily switch from one to the other, just change in config.lua the "dataPackDirectory" from "data-otservbr-global" to "data-canary" or vice versa.
The main purpose is to facilitate our development, at the same time that the community will be able to contribute in a single repository, but keeping the choice of using a "clean" datapack.
I made some more modifications, such as removing the unused C++ gamestore, I also removed the "allowPickupable" tag, which was duplicated, and I made some other adjustments.
Folder structure changes
Now we have the following structure:
• data = this will be the "core" folder, it is where the files that are absolutely necessary for the executable to open correctly, such as libs, xmls, etc. Here we will have files that both the global and the canary datapack will share with each other
• data-otservbr-global = here will be the global datapack files, some libs and folders that are only for the global server, such as scripts, monsters, npcs, world.
• data-canary = a "clean" datapack as far as possible, with only the scripts and files necessary for the server to work.
• NOTE: The "data" folder is actually the "core" of the server, we didn't rename it to avoid having to make changes to the sites and login.php, since they read the "data/xml". The other two folders, data-otservbr-global and data-canary can be changed in config.lua, which one you want the executable to read, by default we'll point to the global one, as that's what most use. If you want to start a custom server with "as few files and scripts as possible", then switch to "data-canary".
We also added a boolean in config.lua that allows choosing another name for the datapack, by default we will also keep this disabled, since we will only maintain support for these two datapacks, it is up to each one to know what they are doing in case they want to change it.
So, in the end, we have the reorganization in the folders:

Note that we made few real changes to the files, the abundance of modified files is due to moving from one folder to another and also adding the global datapack to this repository (with an abundance of files). If you want to migrate your datapack to the global one, you should know what you're doing, if you don't know, just pass your modifications to the "new files" or get in touch on our discord group so we can help you: https://discord.gg/X3mSnMH8jg
2022-11-18 22:32:44 -03:00
|
|
|
`level` int(11) NOT NULL DEFAULT '1',
|
2021-04-28 22:48:54 -03:00
|
|
|
`name` varchar(255) NOT NULL,
|
|
|
|
|
`ownerid` int(11) NOT NULL,
|
|
|
|
|
`creationdata` int(11) NOT NULL,
|
|
|
|
|
`motd` varchar(255) NOT NULL DEFAULT '',
|
|
|
|
|
`residence` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`balance` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
[Enhancement] rework for enable choosing of a custom datapack name (#572)
With this modification, we will be able to focus on just one repository (the canary), and archive otservbr-global repository.
The intention is that we can have two datapacks in the same repository, being able to easily switch from one to the other, just change in config.lua the "dataPackDirectory" from "data-otservbr-global" to "data-canary" or vice versa.
The main purpose is to facilitate our development, at the same time that the community will be able to contribute in a single repository, but keeping the choice of using a "clean" datapack.
I made some more modifications, such as removing the unused C++ gamestore, I also removed the "allowPickupable" tag, which was duplicated, and I made some other adjustments.
Folder structure changes
Now we have the following structure:
• data = this will be the "core" folder, it is where the files that are absolutely necessary for the executable to open correctly, such as libs, xmls, etc. Here we will have files that both the global and the canary datapack will share with each other
• data-otservbr-global = here will be the global datapack files, some libs and folders that are only for the global server, such as scripts, monsters, npcs, world.
• data-canary = a "clean" datapack as far as possible, with only the scripts and files necessary for the server to work.
• NOTE: The "data" folder is actually the "core" of the server, we didn't rename it to avoid having to make changes to the sites and login.php, since they read the "data/xml". The other two folders, data-otservbr-global and data-canary can be changed in config.lua, which one you want the executable to read, by default we'll point to the global one, as that's what most use. If you want to start a custom server with "as few files and scripts as possible", then switch to "data-canary".
We also added a boolean in config.lua that allows choosing another name for the datapack, by default we will also keep this disabled, since we will only maintain support for these two datapacks, it is up to each one to know what they are doing in case they want to change it.
So, in the end, we have the reorganization in the folders:

Note that we made few real changes to the files, the abundance of modified files is due to moving from one folder to another and also adding the global datapack to this repository (with an abundance of files). If you want to migrate your datapack to the global one, you should know what you're doing, if you don't know, just pass your modifications to the "new files" or get in touch on our discord group so we can help you: https://discord.gg/X3mSnMH8jg
2022-11-18 22:32:44 -03:00
|
|
|
`points` int(11) NOT NULL DEFAULT '0',
|
2021-04-28 22:48:54 -03:00
|
|
|
CONSTRAINT `guilds_pk` PRIMARY KEY (`id`),
|
|
|
|
|
CONSTRAINT `guilds_name_unique` UNIQUE (`name`),
|
|
|
|
|
CONSTRAINT `guilds_owner_unique` UNIQUE (`ownerid`),
|
|
|
|
|
CONSTRAINT `guilds_ownerid_fk`
|
|
|
|
|
FOREIGN KEY (`ownerid`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `guild_wars`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `guild_wars` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
|
|
|
`guild1` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`guild2` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`name1` varchar(255) NOT NULL,
|
|
|
|
|
`name2` varchar(255) NOT NULL,
|
2024-03-01 09:40:53 -03:00
|
|
|
`status` tinyint(2) UNSIGNED NOT NULL DEFAULT '0',
|
2021-04-28 22:48:54 -03:00
|
|
|
`started` bigint(15) NOT NULL DEFAULT '0',
|
|
|
|
|
`ended` bigint(15) NOT NULL DEFAULT '0',
|
2024-03-01 09:40:53 -03:00
|
|
|
`frags_limit` smallint(4) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`payment` bigint(13) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`duration_days` tinyint(3) UNSIGNED NOT NULL DEFAULT '0',
|
2021-04-28 22:48:54 -03:00
|
|
|
INDEX `guild1` (`guild1`),
|
|
|
|
|
INDEX `guild2` (`guild2`),
|
|
|
|
|
CONSTRAINT `guild_wars_pk` PRIMARY KEY (`id`)
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `guildwar_kills`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `guildwar_kills` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
|
|
|
`killer` varchar(50) NOT NULL,
|
|
|
|
|
`target` varchar(50) NOT NULL,
|
|
|
|
|
`killerguild` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`targetguild` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`warid` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`time` bigint(15) NOT NULL,
|
|
|
|
|
INDEX `warid` (`warid`),
|
|
|
|
|
CONSTRAINT `guildwar_kills_pk` PRIMARY KEY (`id`),
|
|
|
|
|
CONSTRAINT `guildwar_kills_warid_fk`
|
|
|
|
|
FOREIGN KEY (`warid`) REFERENCES `guild_wars` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `guild_invites`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `guild_invites` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`player_id` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`guild_id` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`date` int(11) NOT NULL,
|
|
|
|
|
INDEX `guild_id` (`guild_id`),
|
|
|
|
|
CONSTRAINT `guild_invites_pk` PRIMARY KEY (`player_id`, `guild_id`),
|
|
|
|
|
CONSTRAINT `guild_invites_player_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE,
|
|
|
|
|
CONSTRAINT `guild_invites_guild_fk`
|
|
|
|
|
FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `guild_ranks`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `guild_ranks` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
|
|
|
`guild_id` int(11) NOT NULL COMMENT 'guild',
|
|
|
|
|
`name` varchar(255) NOT NULL COMMENT 'rank name',
|
|
|
|
|
`level` int(11) NOT NULL COMMENT 'rank level - leader, vice, member, maybe something else',
|
|
|
|
|
INDEX `guild_id` (`guild_id`),
|
|
|
|
|
CONSTRAINT `guild_ranks_pk` PRIMARY KEY (`id`),
|
|
|
|
|
CONSTRAINT `guild_ranks_fk`
|
|
|
|
|
FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
--
|
|
|
|
|
-- Trigger
|
|
|
|
|
--
|
|
|
|
|
DELIMITER //
|
|
|
|
|
CREATE TRIGGER `oncreate_guilds` AFTER INSERT ON `guilds` FOR EACH ROW BEGIN
|
2024-05-24 08:57:04 -03:00
|
|
|
INSERT INTO `guild_ranks` (`name`, `level`, `guild_id`) VALUES ('The Leader', 3, NEW.`id`);
|
|
|
|
|
INSERT INTO `guild_ranks` (`name`, `level`, `guild_id`) VALUES ('Vice-Leader', 2, NEW.`id`);
|
|
|
|
|
INSERT INTO `guild_ranks` (`name`, `level`, `guild_id`) VALUES ('Member', 1, NEW.`id`);
|
2021-04-26 21:04:01 -03:00
|
|
|
END
|
|
|
|
|
//
|
|
|
|
|
DELIMITER ;
|
|
|
|
|
|
|
|
|
|
-- Table structure `guild_membership`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `guild_membership` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`player_id` int(11) NOT NULL,
|
|
|
|
|
`guild_id` int(11) NOT NULL,
|
|
|
|
|
`rank_id` int(11) NOT NULL,
|
|
|
|
|
`nick` varchar(15) NOT NULL DEFAULT '',
|
|
|
|
|
INDEX `guild_id` (`guild_id`),
|
|
|
|
|
INDEX `rank_id` (`rank_id`),
|
|
|
|
|
CONSTRAINT `guild_membership_pk` PRIMARY KEY (`player_id`),
|
|
|
|
|
CONSTRAINT `guild_membership_player_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
|
|
|
|
ON UPDATE CASCADE,
|
|
|
|
|
CONSTRAINT `guild_membership_guild_fk`
|
|
|
|
|
FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
|
|
|
|
ON UPDATE CASCADE,
|
|
|
|
|
CONSTRAINT `guild_membership_rank_fk`
|
|
|
|
|
FOREIGN KEY (`rank_id`) REFERENCES `guild_ranks` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
|
|
|
|
ON UPDATE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `houses`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `houses` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
|
|
|
`owner` int(11) NOT NULL,
|
2023-09-23 18:54:14 -03:00
|
|
|
`new_owner` int(11) NOT NULL DEFAULT '-1',
|
2021-04-28 22:48:54 -03:00
|
|
|
`paid` int(10) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`warnings` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`name` varchar(255) NOT NULL,
|
|
|
|
|
`rent` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`town_id` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`size` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`guildid` int(11),
|
|
|
|
|
`beds` int(11) NOT NULL DEFAULT '0',
|
2024-12-31 13:03:35 -03:00
|
|
|
`bidder` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`bidder_name` varchar(255) NOT NULL DEFAULT '',
|
|
|
|
|
`highest_bid` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`internal_bid` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`bid_end_date` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`state` smallint(5) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`transfer_status` tinyint(1) DEFAULT '0',
|
2021-04-28 22:48:54 -03:00
|
|
|
INDEX `owner` (`owner`),
|
|
|
|
|
INDEX `town_id` (`town_id`),
|
|
|
|
|
CONSTRAINT `houses_pk` PRIMARY KEY (`id`)
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
--
|
|
|
|
|
-- trigger
|
|
|
|
|
--
|
|
|
|
|
DELIMITER //
|
2024-05-24 08:57:04 -03:00
|
|
|
CREATE TRIGGER `ondelete_players` BEFORE DELETE ON `players` FOR EACH ROW BEGIN
|
|
|
|
|
UPDATE `houses` SET `owner` = 0 WHERE `owner` = OLD.`id`;
|
2021-04-26 21:04:01 -03:00
|
|
|
END
|
|
|
|
|
//
|
|
|
|
|
DELIMITER ;
|
|
|
|
|
|
|
|
|
|
-- Table structure `house_lists`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `house_lists` (
|
2023-09-27 19:00:33 -07:00
|
|
|
`house_id` int NOT NULL,
|
|
|
|
|
`listid` int NOT NULL,
|
2023-10-20 14:18:49 -03:00
|
|
|
`version` bigint NOT NULL DEFAULT '0',
|
2023-09-27 19:00:33 -07:00
|
|
|
`list` text NOT NULL,
|
|
|
|
|
PRIMARY KEY (`house_id`, `listid`),
|
|
|
|
|
KEY `house_id_index` (`house_id`),
|
|
|
|
|
KEY `version` (`version`),
|
|
|
|
|
CONSTRAINT `houses_list_house_fk` FOREIGN KEY (`house_id`) REFERENCES `houses` (`id`) ON DELETE CASCADE
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
|
|
|
|
|
|
2021-04-26 21:04:01 -03:00
|
|
|
-- Table structure `ip_bans`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `ip_bans` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`ip` int(11) NOT NULL,
|
|
|
|
|
`reason` varchar(255) NOT NULL,
|
|
|
|
|
`banned_at` bigint(20) NOT NULL,
|
|
|
|
|
`expires_at` bigint(20) NOT NULL,
|
|
|
|
|
`banned_by` int(11) NOT NULL,
|
|
|
|
|
INDEX `banned_by` (`banned_by`),
|
|
|
|
|
CONSTRAINT `ip_bans_pk` PRIMARY KEY (`ip`),
|
|
|
|
|
CONSTRAINT `ip_bans_players_fk`
|
|
|
|
|
FOREIGN KEY (`banned_by`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
|
|
|
|
ON UPDATE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `market_history`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `market_history` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
|
|
|
`player_id` int(11) NOT NULL,
|
|
|
|
|
`sale` tinyint(1) NOT NULL DEFAULT '0',
|
|
|
|
|
`itemtype` int(10) UNSIGNED NOT NULL,
|
|
|
|
|
`amount` smallint(5) UNSIGNED NOT NULL,
|
2022-10-05 12:34:46 -03:00
|
|
|
`price` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
2021-04-28 22:48:54 -03:00
|
|
|
`expires_at` bigint(20) UNSIGNED NOT NULL,
|
|
|
|
|
`inserted` bigint(20) UNSIGNED NOT NULL,
|
|
|
|
|
`state` tinyint(1) UNSIGNED NOT NULL,
|
2022-10-27 20:01:38 -03:00
|
|
|
`tier` tinyint UNSIGNED NOT NULL DEFAULT '0',
|
2021-04-28 22:48:54 -03:00
|
|
|
INDEX `player_id` (`player_id`,`sale`),
|
|
|
|
|
CONSTRAINT `market_history_pk` PRIMARY KEY (`id`),
|
|
|
|
|
CONSTRAINT `market_history_players_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `market_offers`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `market_offers` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
|
|
|
`player_id` int(11) NOT NULL,
|
|
|
|
|
`sale` tinyint(1) NOT NULL DEFAULT '0',
|
|
|
|
|
`itemtype` int(10) UNSIGNED NOT NULL,
|
|
|
|
|
`amount` smallint(5) UNSIGNED NOT NULL,
|
|
|
|
|
`created` bigint(20) UNSIGNED NOT NULL,
|
|
|
|
|
`anonymous` tinyint(1) NOT NULL DEFAULT '0',
|
2022-10-05 12:34:46 -03:00
|
|
|
`price` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
2022-10-27 20:01:38 -03:00
|
|
|
`tier` tinyint UNSIGNED NOT NULL DEFAULT '0',
|
2021-04-28 22:48:54 -03:00
|
|
|
INDEX `sale` (`sale`,`itemtype`),
|
|
|
|
|
INDEX `created` (`created`),
|
|
|
|
|
INDEX `player_id` (`player_id`),
|
|
|
|
|
CONSTRAINT `market_offers_pk` PRIMARY KEY (`id`),
|
|
|
|
|
CONSTRAINT `market_offers_players_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `players_online`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `players_online` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`player_id` int(11) NOT NULL,
|
2025-07-15 23:58:18 +02:00
|
|
|
CONSTRAINT `players_online_pk` PRIMARY KEY (`player_id`),
|
|
|
|
|
CONSTRAINT `players_online_players_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=MEMORY DEFAULT CHARSET=utf8;
|
|
|
|
|
|
feat: add livestream broadcasting system (#3965)
Works with: https://github.com/opentibiabr/login-server/pull/31 (https://github.com/opentibiabr/login-server/commit/467af8d72fe623288ec877ce3de59d200dcc8029)
Add the game server side of the livestream system, allowing players to broadcast gameplay to read-only viewers and exposing active casters for external login services.
Livestream system:
- Add LivestreamManager to manage caster sessions, viewers, passwords, bans, mutes, kicks, and livestream chat.
- Add player-facing livestream talkactions through data/scripts/talkactions/player/livestream_system.lua.
- Support commands such as !livestream on, !livestream off, !livestream password, !livestream ban, and !livestream status.
- Add read-only viewer login through the normal protocol bootstrap while preserving client 15 compatibility.
- Integrate livestream state into Player and ProtocolGame.
Viewer restrictions:
- Keep livestream viewers read-only.
- Block viewer input that would move, fight, use items, send gameplay actions, or mutate the caster state.
- Preserve the normal player flow for non-livestream sessions.
Configuration:
- Add livestream configuration options to config.lua.dist.
- Wire livestream settings into the config loader.
- Add startup/runtime integration needed by the game server.
Database:
- Add active_livestream_casters so external login services can list active casters.
- Add migration data-otservbr-global/migrations/58.lua.
- Update schema.sql.
- Bump the database version to 58.
Login contract:
- External login services must use the descriptor @livestream.
- The livestream session key format is:
@livestream
<password>
Client 15 integration:
- Document the login.php flow for @livestream.
- List active casters from active_livestream_casters.
- Return a character list built from active casters.
- Return a clear login error when no casters are active or livestream is disabled.
- Return the expected livestream session key format for viewer login.
Compatibility:
- Keeps normal login, protocol bootstrap, and player gameplay behavior unchanged outside livestream mode.
2026-05-22 16:53:29 -03:00
|
|
|
-- Table structure `active_livestream_casters`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `active_livestream_casters` (
|
|
|
|
|
`caster_id` int(11) NOT NULL,
|
|
|
|
|
`livestream_status` tinyint(1) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`livestream_viewers` int(11) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
CONSTRAINT `active_livestream_casters_pk` PRIMARY KEY (`caster_id`),
|
|
|
|
|
CONSTRAINT `active_livestream_casters_players_fk`
|
|
|
|
|
FOREIGN KEY (`caster_id`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
2021-04-26 21:04:01 -03:00
|
|
|
-- Table structure `player_charm`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `player_charms` (
|
2025-06-08 16:12:15 -03:00
|
|
|
`player_id` int(11) NOT NULL,
|
|
|
|
|
`charm_points` SMALLINT NOT NULL DEFAULT '0',
|
|
|
|
|
`minor_charm_echoes` SMALLINT NOT NULL DEFAULT '0',
|
|
|
|
|
`max_charm_points` SMALLINT NOT NULL DEFAULT '0',
|
|
|
|
|
`max_minor_charm_echoes` SMALLINT NOT NULL DEFAULT '0',
|
|
|
|
|
`charm_expansion` BOOLEAN NOT NULL DEFAULT FALSE,
|
|
|
|
|
`UsedRunesBit` INT NOT NULL DEFAULT '0',
|
|
|
|
|
`UnlockedRunesBit` INT NOT NULL DEFAULT '0',
|
|
|
|
|
`charms` BLOB NULL,
|
|
|
|
|
`tracker list` BLOB NULL,
|
|
|
|
|
CONSTRAINT `player_charms_players_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
2025-07-15 23:58:18 +02:00
|
|
|
ON DELETE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE = InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `player_deaths`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `player_deaths` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`player_id` int(11) NOT NULL,
|
|
|
|
|
`time` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`level` int(11) NOT NULL DEFAULT '1',
|
|
|
|
|
`killed_by` varchar(255) NOT NULL,
|
|
|
|
|
`is_player` tinyint(1) NOT NULL DEFAULT '1',
|
|
|
|
|
`mostdamage_by` varchar(100) NOT NULL,
|
|
|
|
|
`mostdamage_is_player` tinyint(1) NOT NULL DEFAULT '0',
|
|
|
|
|
`unjustified` tinyint(1) NOT NULL DEFAULT '0',
|
|
|
|
|
`mostdamage_unjustified` tinyint(1) NOT NULL DEFAULT '0',
|
2025-07-12 20:09:51 -03:00
|
|
|
`participants` TEXT NOT NULL,
|
2021-04-28 22:48:54 -03:00
|
|
|
INDEX `player_id` (`player_id`),
|
|
|
|
|
INDEX `killed_by` (`killed_by`),
|
|
|
|
|
INDEX `mostdamage_by` (`mostdamage_by`),
|
|
|
|
|
CONSTRAINT `player_deaths_players_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `player_depotitems`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `player_depotitems` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`player_id` int(11) NOT NULL,
|
|
|
|
|
`sid` int(11) NOT NULL COMMENT 'any given range eg 0-100 will be reserved for depot lockers and all > 100 will be then normal items inside depots',
|
|
|
|
|
`pid` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`itemtype` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`count` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`attributes` blob NOT NULL,
|
|
|
|
|
CONSTRAINT `player_depotitems_unique` UNIQUE (`player_id`, `sid`),
|
|
|
|
|
CONSTRAINT `player_depotitems_players_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `player_hirelings`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `player_hirelings` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`id` INT NOT NULL PRIMARY KEY auto_increment,
|
|
|
|
|
`player_id` INT NOT NULL,
|
|
|
|
|
`name` varchar(255),
|
|
|
|
|
`active` tinyint unsigned NOT NULL DEFAULT '0',
|
|
|
|
|
`sex` tinyint unsigned NOT NULL DEFAULT '0',
|
|
|
|
|
`posx` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`posy` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`posz` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`lookbody` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`lookfeet` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`lookhead` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`looklegs` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`looktype` int(11) NOT NULL DEFAULT '136',
|
|
|
|
|
FOREIGN KEY(`player_id`) REFERENCES `players`(`id`)
|
|
|
|
|
ON DELETE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `player_inboxitems`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `player_inboxitems` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`player_id` int(11) NOT NULL,
|
|
|
|
|
`sid` int(11) NOT NULL,
|
|
|
|
|
`pid` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`itemtype` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`count` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`attributes` blob NOT NULL,
|
|
|
|
|
CONSTRAINT `player_inboxitems_unique` UNIQUE (`player_id`, `sid`),
|
|
|
|
|
CONSTRAINT `player_inboxitems_players_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `player_items`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `player_items` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`player_id` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`pid` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`sid` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`itemtype` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`count` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`attributes` blob NOT NULL,
|
|
|
|
|
INDEX `player_id` (`player_id`),
|
|
|
|
|
INDEX `sid` (`sid`),
|
|
|
|
|
CONSTRAINT `player_items_players_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
2023-08-22 00:03:34 -03:00
|
|
|
ON DELETE CASCADE,
|
2023-08-19 09:13:21 -07:00
|
|
|
CONSTRAINT `player_items_pk`
|
|
|
|
|
PRIMARY KEY (`player_id`, `pid`, `sid`)
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
2023-07-10 17:44:44 -03:00
|
|
|
-- Table structure `player_wheeldata`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `player_wheeldata` (
|
|
|
|
|
`player_id` int(11) NOT NULL,
|
|
|
|
|
`slot` blob NOT NULL,
|
|
|
|
|
INDEX `player_id` (`player_id`),
|
|
|
|
|
CONSTRAINT `player_wheeldata_players_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
2023-08-22 00:03:34 -03:00
|
|
|
ON DELETE CASCADE,
|
2023-08-19 09:13:21 -07:00
|
|
|
CONSTRAINT `player_wheeldata_pk`
|
|
|
|
|
PRIMARY KEY (`player_id`)
|
2023-07-10 17:44:44 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
2021-04-26 21:04:01 -03:00
|
|
|
-- Table structure `player_kills`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `player_kills` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`player_id` int(11) NOT NULL,
|
|
|
|
|
`time` bigint(20) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`target` int(11) NOT NULL,
|
2025-07-15 23:58:18 +02:00
|
|
|
`unavenged` tinyint(1) NOT NULL DEFAULT '0',
|
|
|
|
|
CONSTRAINT `player_kills_players_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `player_namelocks`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `player_namelocks` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`player_id` int(11) NOT NULL,
|
|
|
|
|
`reason` varchar(255) NOT NULL,
|
|
|
|
|
`namelocked_at` bigint(20) NOT NULL,
|
|
|
|
|
`namelocked_by` int(11) NOT NULL,
|
|
|
|
|
INDEX `namelocked_by` (`namelocked_by`),
|
|
|
|
|
CONSTRAINT `player_namelocks_unique` UNIQUE (`player_id`),
|
|
|
|
|
CONSTRAINT `player_namelocks_players_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
|
|
|
|
ON UPDATE CASCADE,
|
|
|
|
|
CONSTRAINT `player_namelocks_players2_fk`
|
|
|
|
|
FOREIGN KEY (`namelocked_by`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
|
|
|
|
ON UPDATE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `player_prey`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `player_prey` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`player_id` int(11) NOT NULL,
|
2022-04-24 13:36:35 -03:00
|
|
|
`slot` tinyint(1) NOT NULL,
|
|
|
|
|
`state` tinyint(1) NOT NULL,
|
|
|
|
|
`raceid` varchar(250) NOT NULL,
|
|
|
|
|
`option` tinyint(1) NOT NULL,
|
|
|
|
|
`bonus_type` tinyint(1) NOT NULL,
|
|
|
|
|
`bonus_rarity` tinyint(1) NOT NULL,
|
|
|
|
|
`bonus_percentage` varchar(250) NOT NULL,
|
|
|
|
|
`bonus_time` varchar(250) NOT NULL,
|
|
|
|
|
`free_reroll` bigint(20) NOT NULL,
|
2023-08-22 00:03:34 -03:00
|
|
|
`monster_list` BLOB NULL,
|
2025-07-15 23:58:18 +02:00
|
|
|
CONSTRAINT `player_prey_pk` PRIMARY KEY (`player_id`, `slot`),
|
|
|
|
|
CONSTRAINT `player_prey_players_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
2022-04-24 13:36:35 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `player_taskhunt`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `player_taskhunt` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`player_id` int(11) NOT NULL,
|
2022-04-24 13:36:35 -03:00
|
|
|
`slot` tinyint(1) NOT NULL,
|
|
|
|
|
`state` tinyint(1) NOT NULL,
|
|
|
|
|
`raceid` varchar(250) NOT NULL,
|
|
|
|
|
`upgrade` tinyint(1) NOT NULL,
|
|
|
|
|
`rarity` tinyint(1) NOT NULL,
|
|
|
|
|
`kills` varchar(250) NOT NULL,
|
|
|
|
|
`disabled_time` bigint(20) NOT NULL,
|
|
|
|
|
`free_reroll` bigint(20) NOT NULL,
|
2023-08-22 00:03:34 -03:00
|
|
|
`monster_list` BLOB NULL,
|
2025-07-15 23:58:18 +02:00
|
|
|
CONSTRAINT `player_taskhunt_pk` PRIMARY KEY (`player_id`, `slot`),
|
|
|
|
|
CONSTRAINT `player_taskhunt_players_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
2023-02-13 02:06:07 -03:00
|
|
|
-- Table structure `player_bosstiary`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `player_bosstiary` (
|
|
|
|
|
`player_id` int NOT NULL,
|
|
|
|
|
`bossIdSlotOne` int NOT NULL DEFAULT 0,
|
|
|
|
|
`bossIdSlotTwo` int NOT NULL DEFAULT 0,
|
2023-08-22 00:03:34 -03:00
|
|
|
`removeTimes` int NOT NULL DEFAULT 1,
|
2025-07-15 23:58:18 +02:00
|
|
|
`tracker` blob NOT NULL,
|
|
|
|
|
CONSTRAINT `player_bosstiary_players_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
2023-02-13 02:06:07 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
2021-04-26 21:04:01 -03:00
|
|
|
-- Table structure `player_rewards`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `player_rewards` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`player_id` int(11) NOT NULL,
|
|
|
|
|
`sid` int(11) NOT NULL,
|
|
|
|
|
`pid` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`itemtype` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`count` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`attributes` blob NOT NULL,
|
|
|
|
|
CONSTRAINT `player_rewards_unique` UNIQUE (`player_id`, `sid`),
|
|
|
|
|
CONSTRAINT `player_rewards_players_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `player_spells`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `player_spells` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`player_id` int(11) NOT NULL,
|
|
|
|
|
`name` varchar(255) NOT NULL,
|
|
|
|
|
INDEX `player_id` (`player_id`),
|
|
|
|
|
CONSTRAINT `player_spells_players_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
2023-08-22 00:03:34 -03:00
|
|
|
ON DELETE CASCADE,
|
2023-08-19 09:13:21 -07:00
|
|
|
CONSTRAINT `player_spells_pk` PRIMARY KEY (`player_id`, `name`)
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `player_stash`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `player_stash` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`player_id` INT(16) NOT NULL,
|
|
|
|
|
`item_id` INT(16) NOT NULL,
|
2023-08-22 00:03:34 -03:00
|
|
|
`item_count` INT(32) NOT NULL,
|
2025-07-15 23:58:18 +02:00
|
|
|
CONSTRAINT `player_stash_pk` PRIMARY KEY (`player_id`, `item_id`),
|
|
|
|
|
CONSTRAINT `player_stash_players_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `player_storage`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `player_storage` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`player_id` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`key` int(10) UNSIGNED NOT NULL DEFAULT '0',
|
|
|
|
|
`value` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
CONSTRAINT `player_storage_pk` PRIMARY KEY (`player_id`, `key`),
|
|
|
|
|
CONSTRAINT `player_storage_players_fk`
|
|
|
|
|
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
2021-04-26 21:04:01 -03:00
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `store_history`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `store_history` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
|
|
|
`account_id` int(11) UNSIGNED NOT NULL,
|
|
|
|
|
`mode` smallint(2) NOT NULL DEFAULT '0',
|
|
|
|
|
`description` varchar(3500) NOT NULL,
|
[Enhancement] rework for enable choosing of a custom datapack name (#572)
With this modification, we will be able to focus on just one repository (the canary), and archive otservbr-global repository.
The intention is that we can have two datapacks in the same repository, being able to easily switch from one to the other, just change in config.lua the "dataPackDirectory" from "data-otservbr-global" to "data-canary" or vice versa.
The main purpose is to facilitate our development, at the same time that the community will be able to contribute in a single repository, but keeping the choice of using a "clean" datapack.
I made some more modifications, such as removing the unused C++ gamestore, I also removed the "allowPickupable" tag, which was duplicated, and I made some other adjustments.
Folder structure changes
Now we have the following structure:
• data = this will be the "core" folder, it is where the files that are absolutely necessary for the executable to open correctly, such as libs, xmls, etc. Here we will have files that both the global and the canary datapack will share with each other
• data-otservbr-global = here will be the global datapack files, some libs and folders that are only for the global server, such as scripts, monsters, npcs, world.
• data-canary = a "clean" datapack as far as possible, with only the scripts and files necessary for the server to work.
• NOTE: The "data" folder is actually the "core" of the server, we didn't rename it to avoid having to make changes to the sites and login.php, since they read the "data/xml". The other two folders, data-otservbr-global and data-canary can be changed in config.lua, which one you want the executable to read, by default we'll point to the global one, as that's what most use. If you want to start a custom server with "as few files and scripts as possible", then switch to "data-canary".
We also added a boolean in config.lua that allows choosing another name for the datapack, by default we will also keep this disabled, since we will only maintain support for these two datapacks, it is up to each one to know what they are doing in case they want to change it.
So, in the end, we have the reorganization in the folders:

Note that we made few real changes to the files, the abundance of modified files is due to moving from one folder to another and also adding the global datapack to this repository (with an abundance of files). If you want to migrate your datapack to the global one, you should know what you're doing, if you don't know, just pass your modifications to the "new files" or get in touch on our discord group so we can help you: https://discord.gg/X3mSnMH8jg
2022-11-18 22:32:44 -03:00
|
|
|
`coin_type` tinyint(1) NOT NULL DEFAULT '0',
|
2021-04-28 22:48:54 -03:00
|
|
|
`coin_amount` int(12) NOT NULL,
|
|
|
|
|
`time` bigint(20) UNSIGNED NOT NULL,
|
|
|
|
|
`timestamp` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
`coins` int(11) NOT NULL DEFAULT '0',
|
|
|
|
|
INDEX `account_id` (`account_id`),
|
|
|
|
|
CONSTRAINT `store_history_pk` PRIMARY KEY (`id`),
|
|
|
|
|
CONSTRAINT `store_history_account_fk`
|
2021-04-26 21:04:01 -03:00
|
|
|
FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `tile_store`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `tile_store` (
|
2021-04-28 22:48:54 -03:00
|
|
|
`house_id` int(11) NOT NULL,
|
|
|
|
|
`data` longblob NOT NULL,
|
|
|
|
|
INDEX `house_id` (`house_id`),
|
|
|
|
|
CONSTRAINT `tile_store_account_fk`
|
|
|
|
|
FOREIGN KEY (`house_id`) REFERENCES `houses` (`id`)
|
|
|
|
|
ON DELETE CASCADE
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
|
|
|
|
-- Table structure `towns`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `towns` (
|
|
|
|
|
`id` int NOT NULL AUTO_INCREMENT,
|
|
|
|
|
`name` varchar(255) NOT NULL,
|
|
|
|
|
`posx` int NOT NULL DEFAULT '0',
|
|
|
|
|
`posy` int NOT NULL DEFAULT '0',
|
|
|
|
|
`posz` int NOT NULL DEFAULT '0',
|
|
|
|
|
PRIMARY KEY (`id`),
|
|
|
|
|
UNIQUE KEY `name` (`name`)
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
|
2021-04-26 21:04:01 -03:00
|
|
|
|
2023-07-08 06:28:46 -07:00
|
|
|
-- Table structure `account_sessions`
|
|
|
|
|
CREATE TABLE IF NOT EXISTS `account_sessions` (
|
|
|
|
|
`id` VARCHAR(191) NOT NULL,
|
|
|
|
|
`account_id` INTEGER UNSIGNED NOT NULL,
|
|
|
|
|
`expires` BIGINT UNSIGNED NOT NULL,
|
|
|
|
|
|
|
|
|
|
PRIMARY KEY (`id`)
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
2024-05-29 17:08:03 -03:00
|
|
|
-- Table structure `kv_store`
|
2023-09-07 19:37:29 -07:00
|
|
|
CREATE TABLE IF NOT EXISTS `kv_store` (
|
|
|
|
|
`key_name` varchar(191) NOT NULL,
|
|
|
|
|
`timestamp` bigint NOT NULL,
|
|
|
|
|
`value` longblob NOT NULL,
|
|
|
|
|
PRIMARY KEY (`key_name`)
|
|
|
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
|
|
|
|
2021-04-26 21:04:01 -03:00
|
|
|
-- Create Account god/god
|
|
|
|
|
INSERT INTO `accounts`
|
2021-04-28 22:48:54 -03:00
|
|
|
(`id`, `name`, `email`, `password`, `type`) VALUES
|
2026-01-17 20:34:13 +01:00
|
|
|
(1, 'god', '@god', '21298df8a3277357ee55b01df9530b535cf08ec1', 6);
|
2021-04-26 21:04:01 -03:00
|
|
|
|
|
|
|
|
-- Create player on GOD account
|
|
|
|
|
-- Create sample characters
|
|
|
|
|
INSERT INTO `players`
|
|
|
|
|
(`id`, `name`, `group_id`, `account_id`, `level`, `vocation`, `health`, `healthmax`, `experience`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `maglevel`, `mana`, `manamax`, `manaspent`, `town_id`, `conditions`, `cap`, `sex`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`) VALUES
|
2021-04-28 22:48:54 -03:00
|
|
|
(1, 'Rook Sample', 1, 1, 2, 0, 155, 155, 100, 113, 115, 95, 39, 129, 2, 60, 60, 5936, 1, '', 410, 1, 12, 155, 12, 155, 12, 155, 12, 93),
|
|
|
|
|
(2, 'Sorcerer Sample', 1, 1, 8, 1, 185, 185, 4200, 113, 115, 95, 39, 129, 0, 90, 90, 0, 8, '', 470, 1, 10, 0, 10, 0, 10, 0, 10, 0),
|
|
|
|
|
(3, 'Druid Sample', 1, 1, 8, 2, 185, 185, 4200, 113, 115, 95, 39, 129, 0, 90, 90, 0, 8, '', 470, 1, 10, 0, 10, 0, 10, 0, 10, 0),
|
|
|
|
|
(4, 'Paladin Sample', 1, 1, 8, 3, 185, 185, 4200, 113, 115, 95, 39, 129, 0, 90, 90, 0, 8, '', 470, 1, 10, 0, 10, 0, 10, 0, 10, 0),
|
|
|
|
|
(5, 'Knight Sample', 1, 1, 8, 4, 185, 185, 4200, 113, 115, 95, 39, 129, 0, 90, 90, 0, 8, '', 470, 1, 10, 0, 10, 0, 10, 0, 10, 0),
|
feat: add Way of the Monk quest and monk-related content (#3794)
feat: add Way of the Monk quest, monster updates, and core data improvements
This commit introduces the complete implementation of the Way of the Monk quest, along with multiple updates to monsters, bosses, items, and core gameplay data.
Quest:
• Added full quest definition for Way of the Monk, including mission flow, shrine tracking, and storage handling.
• Registered the new quest module in the quest catalog.
• Introduced new storage keys related to monk quest progression and items.
• Added a sample monk player migration (DB version 55) for testing purposes.
• Added Blue Valley to the towns list to support quest locations.
Monsters and Bosses:
• Added new monster Tame Terror Bird with complete stats, behaviors, and loot.
• Reworked Mitmah Vanguard boss with updated events, attributes, attacks, defenses, elemental modifiers, loot, and lifecycle hooks.
• Expanded loot tables for bosses such as The Brainstealer and The Monster, including monk-related items and potions.
Items and Loot:
• Updated frazzlemaw and guzzlemaw loot to drop traditional sai instead of sai.
• Added monk-related item IDs to destruction scripts and Dawnport cleanup logic.
Gameplay:
• Added Monk’s Apparition to the Soul War quest apparition list.
• Introduced a new combat formula for fist fighting skill.
• Removed legacy fist fighting attack speed configuration from server settings.
Workflow:
• Improved GitHub Actions workflow to ensure reusable checks run on the correct branch.
2026-02-12 23:03:25 -03:00
|
|
|
(6, 'Monk Sample', 1, 1, 8, 9, 185, 185, 4200, 113, 115, 95, 39, 129, 0, 90, 90, 0, 8, '', 470, 1, 10, 0, 10, 0, 10, 0, 10, 0),
|
|
|
|
|
(7, 'GOD', 6, 1, 2, 0, 155, 155, 100, 113, 115, 95, 39, 75, 0, 60, 60, 0, 8, '', 410, 1, 10, 0, 10, 0, 10, 0, 10, 0);
|