@ -28,6 +28,7 @@
# include <string>
# include <string>
# include <sstream>
# include <sstream>
# include <iostream>
# include <iostream>
# include <vector>
# include <char/char.hpp>
# include <char/char.hpp>
# include "pc.hpp"
# include "pc.hpp"
@ -37,6 +38,7 @@
# include "json.hpp" // The header-only library for JSON parsing
# include "json.hpp" // The header-only library for JSON parsing
//helpers (Store adepted functions from different areas in rathena
//helpers (Store adepted functions from different areas in rathena
//#include "config_helpers.hpp"
//#include "config_helpers.hpp"
# include "char_creation_helpers.hpp"
# include "char_creation_helpers.hpp"
# include "helper_skills.hpp"
# include "helper_skills.hpp"
@ -56,7 +58,7 @@ SkillDB* skills = nullptr;
// YAML DB Objects of all touched infrastucture
// YAML DB Objects of all touched infrastucture
BotStatPointDatabase bot_statpoint_db ;
BotStatPointDatabase bot_statpoint_db ;
BotJobDatabase bot_job_db ;
BotJobDatabase bot_job_db ;
// SkillTreeDatabase skill_tree_db;
// Bot SkillTreeDatabase bot_ skill_tree_db;
// Advanced subnet check [LuzZza]
// Advanced subnet check [LuzZza]
struct s_subnet {
struct s_subnet {
@ -77,7 +79,10 @@ struct online_login_data* login_get_online_user(uint32 account_id) {
*/
*/
TIMER_FUNC ( periodic_cleanup_timer ) {
TIMER_FUNC ( periodic_cleanup_timer ) {
bot_account_cleanup ( ) ; // Call the cleanup function
// Warning!!!: This will auto delete all bots after a certain time, even in the middle of sessions.
// Bots will not be logged out upon deletion.
//bot_account_cleanup(); // Call the cleanup function only if configured
return 0 ; // Return 0 to keep the timer going
return 0 ; // Return 0 to keep the timer going
}
}
@ -101,7 +106,7 @@ void setup_periodic_cleanup_timer() {
* 2 : Error while writing into bot_accounts table
* 2 : Error while writing into bot_accounts table
* 3 : Registration denied
* 3 : Registration denied
*/
*/
int brokk_mmo_auth_new ( const char * userid , const char * pass , const char sex , const char* last_ip , const bool auto_generated , int creator_id = 0 , const char * creator_name = " Brokk " ) {
int brokk_mmo_auth_new ( const char * userid , const char * pass , const char sex , const bool auto_generated , int creator_id = 0 , const char * creator_name = " Brokk " ) {
static int num_regs = 0 ; // bot registration counter
static int num_regs = 0 ; // bot registration counter
static t_tick new_reg_tick = 0 ;
static t_tick new_reg_tick = 0 ;
t_tick tick = gettick ( ) ;
t_tick tick = gettick ( ) ;
@ -141,6 +146,7 @@ int brokk_mmo_auth_new(const char* userid, const char* pass, const char sex, con
safestrncpy ( acc . email , " bot@brokk.ai " , sizeof ( acc . email ) ) ; // Default email for bots
safestrncpy ( acc . email , " bot@brokk.ai " , sizeof ( acc . email ) ) ; // Default email for bots
acc . expiration_time = 0 ; // Bots don't expire
acc . expiration_time = 0 ; // Bots don't expire
safestrncpy ( acc . lastlogin , " " , sizeof ( acc . lastlogin ) ) ;
safestrncpy ( acc . lastlogin , " " , sizeof ( acc . lastlogin ) ) ;
const char * last_ip = " 127.0.0.1 " ; //Allways localhost because bots will never be created elsewhere
safestrncpy ( acc . last_ip , last_ip , sizeof ( acc . last_ip ) ) ;
safestrncpy ( acc . last_ip , last_ip , sizeof ( acc . last_ip ) ) ;
safestrncpy ( acc . birthdate , " " , sizeof ( acc . birthdate ) ) ;
safestrncpy ( acc . birthdate , " " , sizeof ( acc . birthdate ) ) ;
safestrncpy ( acc . pincode , " " , sizeof ( acc . pincode ) ) ;
safestrncpy ( acc . pincode , " " , sizeof ( acc . pincode ) ) ;
@ -241,7 +247,9 @@ int brokk_mmo_auth_delete_num(uint32 account_id) {
struct mmo_account acc ;
struct mmo_account acc ;
struct mmo_bot_account bot_acc ;
struct mmo_bot_account bot_acc ;
struct mmo_charakter charakter ;
struct mmo_charakter charakter ;
struct bot_skill skill ;
std : : vector < uint32 > char_ids_to_delete ;
std : : vector < uint32 > char_ids_to_delete ;
std : : vector < bot_skill > skills_to_delete ;
// Check if the account exists
// Check if the account exists
if ( ! login_accounts - > load_num ( login_accounts , & acc , account_id ) ) {
if ( ! login_accounts - > load_num ( login_accounts , & acc , account_id ) ) {
@ -257,17 +265,18 @@ int brokk_mmo_auth_delete_num(uint32 account_id) {
return 1 ; // Bot account does not exist
return 1 ; // Bot account does not exist
}
}
// Delete login account and corresponding bot account
// Step 1: Account Data (login table)
if ( ! login_accounts - > remove ( login_accounts , acc . account_id ) ) {
if ( ! login_accounts - > remove ( login_accounts , acc . account_id ) ) {
ShowError ( " Failed to delete login account (account_id: %d) \n " , account_id ) ;
ShowError ( " Failed to delete login account (account_id: %d) \n " , account_id ) ;
return 1 ; // Deletion failed
return 1 ; // Deletion failed
}
}
// Step 2: Bot-Account Data (bot_accounts table)
if ( ! bot_accounts - > remove ( bot_accounts , bot_acc . account_id ) ) {
if ( ! bot_accounts - > remove ( bot_accounts , bot_acc . account_id ) ) {
ShowError ( " Failed to delete bot account (account_id: %d) \n " , account_id ) ;
ShowError ( " Failed to delete bot account (account_id: %d) \n " , account_id ) ;
return 1 ; // Deletion failed
return 1 ; // Deletion failed
}
}
// Attempt to delete charakters of the bot (if any )
// Step 3: Character Data (char table )
// First pass: Collect char_ids to delete based on config
// First pass: Collect char_ids to delete based on config
CharakterDBIterator * iter_chars = charakters - > iterator ( charakters ) ; // Create the iterator
CharakterDBIterator * iter_chars = charakters - > iterator ( charakters ) ; // Create the iterator
@ -281,13 +290,38 @@ int brokk_mmo_auth_delete_num(uint32 account_id) {
}
}
iter_chars - > destroy ( iter_chars ) ; // Destroy the iterator after use
iter_chars - > destroy ( iter_chars ) ; // Destroy the iterator after use
ShowDebug ( " DelMarco \n " ) ;
// Second pass: Delete the collected charakters
// Second pass: Delete the collected charakters
for ( const auto & char_id : char_ids_to_delete ) {
for ( const auto & char_id : char_ids_to_delete ) {
ShowDebug ( " DelPolo1 \n " ) ;
ShowInfo ( " Deleting charakter with ID %d. \n " , char_id ) ;
ShowInfo ( " Deleting charakter with ID %d. \n " , char_id ) ;
if ( ! charakters - > remove ( charakters , char_id ) ) {
if ( ! charakters - > remove ( charakters , char_id ) ) {
ShowError ( " Failed to delete charakter (char_id: %s) \n " , char_id ) ;
ShowError ( " Failed to delete charakter (char_id: %s) \n " , char_id ) ;
continue ; // Deletion failed
continue ; // Deletion failed
}
}
ShowDebug ( " DelPolo2 \n " ) ;
// Step 3B: Attempt to delete skills of the char (if any)
// First pass: Collect skill_ids to delete based on config
SkillDBIterator * iter_skills = skills - > iterator ( skills , char_id ) ; // Create the iterator
while ( iter_skills - > next ( iter_skills , char_id , & skill ) ) {
std : : string id_str = convert_skill_id_to_str ( skill . skill_id ) ;
//ShowDebug("Skill %s found. Schedule for deletion...\n", id_str.c_str());
skills_to_delete . push_back ( skill ) ;
}
iter_skills - > destroy ( iter_skills ) ; // Destroy the iterator after use
ShowDebug ( " DelPolo3 \n " ) ;
// Second pass: Delete the collected skills
for ( const auto & skill_entry : skills_to_delete ) {
//ShowInfo("Deleting skill with ID %d.\n", char_id);
if ( ! skills - > remove ( skills , char_id , skill_entry . skill_id ) ) {
ShowError ( " Failed to delete skill (skill_id: %s) \n " , skill_entry . skill_id ) ;
continue ; // Deletion failed
}
else {
ShowNotice ( " Deleting of skill %s from char_id %d was successful \n " , convert_skill_id_to_str ( skill_entry . skill_id ) , char_id ) ;
}
}
ShowDebug ( " DelPolo4 \n " ) ;
}
}
ShowNotice ( " Bot account deletion completed (account: %s, id: %d) \n \n " , acc . userid , acc . account_id ) ;
ShowNotice ( " Bot account deletion completed (account: %s, id: %d) \n \n " , acc . userid , acc . account_id ) ;
@ -449,6 +483,8 @@ void brokk_set_defaults() {
void bot_account_cleanup ( ) {
void bot_account_cleanup ( ) {
ShowStatus ( " Start bot deletion according to settings... \n " ) ;
struct mmo_bot_account bot_acc ;
struct mmo_bot_account bot_acc ;
BotAccountDBIterator * iter_bots = bot_accounts - > iterator ( bot_accounts ) ;
BotAccountDBIterator * iter_bots = bot_accounts - > iterator ( bot_accounts ) ;
std : : vector < uint32 > account_ids_to_delete ;
std : : vector < uint32 > account_ids_to_delete ;
@ -467,11 +503,12 @@ void bot_account_cleanup() {
// Second pass: Delete the collected accounts
// Second pass: Delete the collected accounts
for ( const auto & account_id : account_ids_to_delete ) {
for ( const auto & account_id : account_ids_to_delete ) {
ShowInfo ( " Deleting bot account with ID %d. \n " , account_id ) ;
//ShowInfo("Deleting bot account with ID %d.\n", account_id);
brokk_mmo_auth_delete_num ( account_id ) ; // Delete from `login`, `bot_accounts` and 'char' tables
brokk_mmo_auth_delete_num ( account_id ) ; // Delete from `login`, `bot_accounts` and 'char' tables
}
}
Show Notice ( " Bot account destruction completed successfully. \n \n " ) ;
Show Status ( " Bot account destruction completed successfully. \n \n " ) ;
}
}
/*
/*
* initializes dbs for all used non - yaml databases
* initializes dbs for all used non - yaml databases
@ -547,175 +584,114 @@ void set_last_login(char last_login[24]) {
}
}
/**
/**
* Create a new charakter and save it in db / sql .
* Create a new character and save it in the database .
* @ param account_id : int for account , the charakter belongs to
* @ param charakter : Pre - configured mmo_charakter object with all necessary fields populated .
* @ param char_name : string for charakter name
* @ param slot : int which charakter slot to put it in ( char_num in db )
* @ param < multiple stat fields > : stats of the charakter ( str , agi , vit , etc )
* @ param hair_style : int for hair_style id
* @ param hair_color : int for hair_color id *
* @ param start_job : short for job class
* @ param sex : string for gender of character
* @ return :
* @ return :
* - 1 : success
* 0 : error
* 0 : unregistered id ( invalid sex or failure to create in db )
* > 0 : new char id
* 1 : incorrect char_name ( char_name too short or already exists )
* 2 : Error while writing into char table
* 3 : Registration denied ( limit reached )
*/
*/
int brokk_create_character ( uint32 account_id , const char * char_name , int slot , int base_level , int job_level , int str , int agi , int vit , int int_ , int dex , int luk , int hair_style , int hair_color , short start_job , char sex , const bool auto_generated ) {
bool brokk_create_character ( mmo_charakter & charakter , int & char_id , const bool auto_generated ) {
static int num_regs = 0 ; // cha r registration counter
static int num_regs = 0 ; // Character registration counter
static t_tick new_reg_tick = 0 ;
static t_tick new_reg_tick = 0 ;
t_tick tick = gettick ( ) ;
t_tick tick = gettick ( ) ;
struct mmo_charakter charakter ;
struct mmo_account acc ;
// Check if the account exists
// Check if the account exists
if ( ! login_accounts - > load_num ( login_accounts , & acc , account_id ) ) {
mmo_account acc ;
ShowNotice ( " Attempt to create char for non-existent account (account_id: %s) \n " , account_id ) ;
if ( ! login_accounts - > load_num ( login_accounts , & acc , charakter . account_id ) ) {
return 0 ; // Account does not exist
ShowNotice ( " Attempt to create character for non-existent account (account_id: %u) \n " , charakter . account_id ) ;
return false ; // Account does not exist
}
}
// char r egistration flood protection
// R egistration flood protection
if ( new_reg_tick = = 0 )
if ( ! auto_generated ) {
new_reg_tick = gettick ( ) ;
if ( new_reg_tick = = 0 )
if ( auto_generated = = false ) {
new_reg_tick = gettick ( ) ;
if ( DIFF_TICK ( tick , new_reg_tick ) < 0 & & num_regs > = brokk_config . allowed_bot_creations ) {
if ( DIFF_TICK ( tick , new_reg_tick ) < 0 & & num_regs > = brokk_config . allowed_bot_creations ) {
ShowNotice ( " Chara k ter registration denied (registration limit exceeded)\n " ) ;
ShowNotice ( " Chara c ter registration denied (registration limit exceeded)\n " ) ;
return 3 ;
return false ;
}
}
}
}
// Ensure valid sex input (M/F for bots)
// Validate character's sex input (must be 'M' or 'F')
if ( sex ! = ' M ' & & sex ! = ' F ' )
if ( charakter . sex ! = ' M ' & & charakter . sex ! = ' F ' ) {
return 0 ; // Unregistered ID
ShowNotice ( " Invalid character sex (char_name: %s, sex: %c) \n " , charakter . name , charakter . sex ) ;
return false ; // Unregistered ID
// Check if the char already exists
}
if ( charakters - > load_str ( charakters , & charakter , char_name ) ) {
ShowNotice ( " Attempt to create an already existing charakter (CharName: %s, sex: %c) \n " , char_name , sex ) ;
// Check if the character already exists
return 1 ; // Char exists
mmo_charakter existing_char ;
}
if ( charakters - > load_str ( charakters , & existing_char , charakter . name ) ) {
ShowNotice ( " Attempt to create an already existing character (char_name: %s, sex: %c) \n " , charakter . name , charakter . sex ) ;
//TODO Herausfinden welche char Level und stats wann plausibel sind.
char_id = 1 ;
// -> Plausibility checks aus map.cpp extrahieren
return false ; // Character exists
//TODO2 Homogene Base-Level grenzen herausfinden (bei welchem Base-Level ist man welches Job-Level bei Renewal
}
// Create charakter
std : : string char_dump = dump_mmo_charakter ( charakter ) ;
// Clear and populate charakter structure
//ShowDebug(char_dump.c_str());
memset ( & charakter , ' \0 ' , sizeof ( charakter ) ) ;
charakter . char_id = - 1 ; // Assigned by char db
// Assign values from parameters
charakter . account_id = account_id ;
charakter . char_num = slot ;
safestrncpy ( charakter . name , char_name , sizeof ( charakter . name ) ) ;
charakter . str = str ;
charakter . agi = agi ;
charakter . vit = vit ;
charakter . int_ = int_ ;
charakter . dex = dex ;
charakter . luk = luk ;
charakter . hair = hair_style ;
charakter . hair_color = hair_color ;
charakter . class_ = start_job ;
charakter . sex = sex ;
// Default values for new character creation
charakter . base_level = base_level ;
charakter . job_level = job_level ;
charakter . base_exp = bot_job_db . get_baseExp ( start_job , base_level ) ;
charakter . job_exp = bot_job_db . get_jobExp ( start_job , job_level ) ;
charakter . zeny = 1000000 ;
charakter . pow = 0 ;
charakter . sta = 0 ;
charakter . wis = 0 ;
charakter . spl = 0 ;
charakter . con = 0 ;
charakter . crt = 0 ;
charakter . max_hp = 40 * ( 100 + vit ) / 100 ; // Default calculation for max HP
charakter . hp = charakter . max_hp ;
charakter . max_sp = 11 * ( 100 + int_ ) / 100 ; // Default calculation for max SP
charakter . sp = charakter . max_sp ;
charakter . max_ap = 0 ; // Default AP for new characters
charakter . ap = 0 ;
// Calculate Status Points from current level
charakter . status_point = bot_statpoint_db . get_table_point ( base_level ) ;
charakter . skill_point = 0 ;
charakter . trait_point = bot_statpoint_db . get_trait_table_point ( base_level ) ; ;
charakter . option = 0 ;
charakter . karma = 0 ;
charakter . manner = 0 ;
charakter . party_id = 0 ;
charakter . guild_id = 0 ;
charakter . pet_id = 0 ;
charakter . homun_id = 0 ;
charakter . elemental_id = 0 ;
charakter . body = 0 ;
charakter . weapon = 0 ;
charakter . shield = 0 ;
charakter . head_top = 0 ;
charakter . head_mid = 0 ;
charakter . head_bottom = 0 ;
charakter . robe = 0 ;
safestrncpy ( charakter . last_map , " morocc " , sizeof ( charakter . last_map ) ) ; // Default spawn map
charakter . last_x = 159 ; // Default spawn position x
charakter . last_y = 91 ; // Default spawn position y
charakter . last_instanceid = 0 ;
safestrncpy ( charakter . save_map , " morocc " , sizeof ( charakter . save_map ) ) ; // Default save point map
charakter . save_x = 156 ; // Default save point position x
charakter . save_y = 45 ; // Default save point position y
/*TODO Meta Profiles hier laden : Für payon_citizen
* safestrncpy ( charakter . save_map , " payon " , sizeof ( charakter . save_map ) ) ; // Default save point map
* charakter . save_x = 161 ; // Default save point position x
* charakter . save_y = 57 ; // Default save point position y
*/
charakter . partner_id = 0 ;
charakter . online = 0 ;
charakter . fame = 0 ;
charakter . rename = 0 ;
charakter . delete_date = 0 ;
charakter . moves = 0 ;
charakter . unban_time = 0 ;
charakter . font = 0 ;
charakter . uniqueitem_counter = 0 ;
charakter . hotkey_rowshift = 0 ;
charakter . hotkey_rowshift2 = 0 ;
charakter . clan_id = 0 ;
charakter . title_id = 0 ;
charakter . show_equip = 0 ;
charakter . inventory_slots = 100 ; // Default inventory slots
charakter . body_direction = 0 ;
charakter . disable_call = 0 ;
// Set default timestamp for last login to current time (or keep it empty for new character)
memset ( charakter . last_login , ' \0 ' , sizeof ( charakter . last_login ) ) ; // Clear the memory
set_last_login ( charakter . last_login ) ;
//#ifdef VIP_ENABLE
//#endif
// Create the account in the database
if ( ! charakters - > create ( charakters , & charakter ) )
return 0 ; // Charakter creation failed
ShowNotice ( " Bot charakter creation successful (name: %s, char_id: %d, sex: %c) \n " , charakter . name , charakter . char_id , charakter . sex ) ;
// Create the character in the database
if ( ! charakters - > create ( charakters , & charakter ) ) {
ShowError ( " Failed to create character (char_name: %s) \n " , charakter . name ) ;
return false ; // Character creation failed
}
// Log success
ShowNotice ( " Character creation successful (name: %s, char_id: %d, sex: %c) \n " , charakter . name , charakter . char_id , charakter . sex ) ;
// Registration rate limit logic
// Update registration limit
if ( DIFF_TICK ( tick , new_reg_tick ) > 0 ) {
if ( DIFF_TICK ( tick , new_reg_tick ) > 0 ) {
num_regs = 0 ;
num_regs = 0 ;
new_reg_tick = tick + brokk_config . time_allowed * 1000 ;
new_reg_tick = tick + brokk_config . time_allowed * 1000 ;
}
}
+ + num_regs ;
+ + num_regs ;
//ShowInfo("Bot character created: %s (account: %s, char_name: %d)\n", charakter.account_id, charakter.name);
Sleep ( 10 ) ;
return - 1 ;
if ( ! charakters - > load_str ( charakters , & existing_char , charakter . name ) ) {
ShowError ( " Attempt to load newly created character failed (char_name: %s, sex: %c) \n " , charakter . name , charakter . sex ) ;
return false ; // Character does not exists
}
char_id = existing_char . char_id ;
return true ; // Success -> return new char_id
}
/**
* Add a skill to a charakters bundle in the database .
* @ param skill : Pre - configured bot_skill object with all necessary fields populated .
* @ return :
* - 1 : success
* 1 : unregistered id ( invalid char_id )
* 2 : Error while writing into skill table
*/
int brokk_teach_skills ( bot_skill_bundle & skill_bundle , int & char_id ) {
int skill_count = 0 ;
// Check if the character already exists
mmo_charakter existing_char ;
if ( ! charakters - > load_num ( charakters , & existing_char , char_id ) ) {
ShowError ( " Attempt to add an skill to non-existing character (char_id: %d) \n " , char_id ) ;
return 1 ; // Character does not exist
}
std : : string char_name = existing_char . name ;
for ( auto & skill : skill_bundle . skills ) {
// Create entry in the skill database
if ( ! skills - > create ( skills , & skill ) ) {
ShowError ( " Failed to create skill entry (char_id: %d, skill_id: %d) \n " , skill . char_id , skill . skill_id ) ;
return 2 ; // skill entry creation failed
}
// Log success single skill
ShowNotice ( " Skill %s added to character char_id: %d) \n " , convert_skill_id_to_str ( skill . skill_id ) , skill . char_id ) ;
skill_count + + ;
}
// Log success
ShowStatus ( " Successfully applied %d Skills to character (name: %s, char_id: %d) \n " , skill_count , char_name . c_str ( ) , char_id ) ;
return - 1 ; // Success
}
}
void BrokkServer : : finalize ( ) {
void BrokkServer : : finalize ( ) {
@ -730,7 +706,7 @@ void BrokkServer::finalize() {
// brokklog_final();
// brokklog_final();
// Attempt to delete the bot account on shutdown
// Attempt to delete the bot account on shutdown
bot_account_cleanup ( ) ;
//bot_account_cleanup();
if ( db ) { // destroy account engine
if ( db ) { // destroy account engine
db - > destroy ( db ) ;
db - > destroy ( db ) ;
@ -768,7 +744,10 @@ void BrokkServer::finalize() {
void BrokkServer : : handle_shutdown ( ) {
void BrokkServer : : handle_shutdown ( ) {
ShowStatus ( " Shutting down... \n " ) ;
ShowStatus ( " Shutting down... \n " ) ;
// Attempt to delete the bot account on shutdown
bot_account_cleanup ( ) ;
flush_fifos ( ) ;
flush_fifos ( ) ;
}
}
@ -785,6 +764,7 @@ bool BrokkServer::initialize(int argc, char* argv[]) {
// Initialize Yaml-DBs
// Initialize Yaml-DBs
bot_read_yaml_dbs ( ) ;
bot_read_yaml_dbs ( ) ;
init_bot_skill_tree_db ( ) ;
// read brokk-server configuration
// read brokk-server configuration
brokk_set_defaults ( ) ;
brokk_set_defaults ( ) ;
@ -796,8 +776,8 @@ bool BrokkServer::initialize(int argc, char* argv[]) {
return false ;
return false ;
}
}
/**/
//debug: display skills of gm acc
//debug skills von gm acc aufzählen
/*
SkillDBIterator * iter_skills = skills - > iterator ( skills , 150000 ) ;
SkillDBIterator * iter_skills = skills - > iterator ( skills , 150000 ) ;
struct bot_skill skill ;
struct bot_skill skill ;
while ( iter_skills - > next ( iter_skills , 150000 , & skill ) ) {
while ( iter_skills - > next ( iter_skills , 150000 , & skill ) ) {
@ -806,7 +786,21 @@ bool BrokkServer::initialize(int argc, char* argv[]) {
}
}
// Destroy the iterator after use
// Destroy the iterator after use
iter_skills - > destroy ( iter_skills ) ;
iter_skills - > destroy ( iter_skills ) ;
*/
/*
//Demo-Skill tree
//TODO Eintragen in Job-Profil -> welche Skills gelernt werden sollen und Mechanik bauen für plausibles auto-skill erlernen
std : : shared_ptr < bot_skill_tree > tree = bot_skill_tree_db . find ( JOB_MAGE ) ;
for ( const auto & skill : tree - > skills ) {
ShowDebug ( " Skill Found in tree: %s \n " , convert_skill_id_to_str ( skill . first ) ) ;
if ( skill . first = = MG_SAFETYWALL ) {
ShowDebug ( " skill max lvl : %d \n " , skill . second - > max_lv ) ;
for ( const auto needed_skill : skill . second - > need ) {
ShowDebug ( " requires skill %s on level %d \n " , convert_skill_id_to_str ( needed_skill . first ) , needed_skill . second ) ;
}
}
} */
// initialize logging
// initialize logging
//if (brokk_config.log_brokk)
//if (brokk_config.log_brokk)
@ -847,7 +841,6 @@ bool BrokkServer::initialize(int argc, char* argv[]) {
const char * userid = userid_str . c_str ( ) ;
const char * userid = userid_str . c_str ( ) ;
const std : : string pass = bot [ " pass " ] ;
const std : : string pass = bot [ " pass " ] ;
const char sex = bot [ " sex " ] . get < std : : string > ( ) [ 0 ] ; // Extract single char from string
const char sex = bot [ " sex " ] . get < std : : string > ( ) [ 0 ] ; // Extract single char from string
const std : : string last_ip = bot [ " last_ip " ] ;
// Debug: Print the entire bot entry
// Debug: Print the entire bot entry
//ShowInfo("Processing bot: %s\n", bot.dump(4).c_str());
//ShowInfo("Processing bot: %s\n", bot.dump(4).c_str());
@ -860,7 +853,7 @@ bool BrokkServer::initialize(int argc, char* argv[]) {
//ShowStatus("Processing bot: userid=%s, pass=%s, sex=%c\n", userid, pass.c_str(), sex);
//ShowStatus("Processing bot: userid=%s, pass=%s, sex=%c\n", userid, pass.c_str(), sex);
// Call brokk_mmo_auth_new to handle account creation
// Call brokk_mmo_auth_new to handle account creation
if ( ! brokk_mmo_auth_new ( userid , pass . c_str ( ) , sex , last_ip . c_str ( ) , true ) ) {
if ( ! brokk_mmo_auth_new ( userid , pass . c_str ( ) , sex , true ) ) {
ShowError ( " Failed to create bot account (userid: %s) \n " , userid ) ;
ShowError ( " Failed to create bot account (userid: %s) \n " , userid ) ;
continue ; // Skip to the next bot account
continue ; // Skip to the next bot account
}
}
@ -874,110 +867,141 @@ bool BrokkServer::initialize(int argc, char* argv[]) {
}
}
uint32 account_id = acc . account_id ;
uint32 account_id = acc . account_id ;
// Iterate over each character for this bot account
// Iterate over each character for this bot account
if ( bot . contains ( " characters " ) ) {
const auto & characters = bot [ " characters " ] ;
//TODO ähnlichen Test für skills einbauen
for ( const auto & character : characters ) {
if ( bot . contains ( " characters " ) ) {
const std : : string char_name = character [ " name " ] ;
const auto & json_characters = bot [ " characters " ] ;
const int slot = character [ " slot " ] ;
//ShowDebug("StartChar Parsing");
for ( const auto & json_character : json_characters ) { //Iterate every declared character and try to create it
//ShowDebug("char_json:\n%s", character.dump().c_str());
mmo_charakter new_char { } ;
//Step1 Meta-Data about character (allways have to be present/not bound to profile)
const std : : string char_name = json_character [ " name " ] ;
safestrncpy ( new_char . name , char_name . c_str ( ) , NAME_LENGTH ) ;
std : : string sex_str = json_character [ " sex " ] ;
new_char . sex = sex_str [ 0 ] ;
new_char . char_num = json_character [ " slot " ] ;
new_char . zeny = json_character [ " zeny " ] ;
new_char . inventory_slots = 100 ;
// Decode Job Value
std : : string job_id = json_character [ " start_job " ] ;
new_char . class_ = convert_jobid_to_number ( job_id . c_str ( ) ) ;
if ( new_char . class_ = = - 1 ) {
job_id = " JOB_NOVICE " ;
new_char . class_ = JOB_NOVICE ;
}
// Step2: build data of character
new_char . account_id = account_id ;
new_char . char_id = - 1 ;
prepare_character_build_data ( new_char , json_character , bot_job_db ) ;
const int base_level = character [ " base_level " ] ;
// Step3: appearance of character
const int job_level = character [ " job_level " ] ;
prepare_character_appearance_data ( new_char , json_character ) ;
const int hair_style = character [ " hair_style " ] ;
// Step4: location data of character
const int hair_color = character [ " hair_color " ] ;
prepare_character_location_data ( new_char , json_character ) ;
//TODO: Clothing/Style Randomizer hier einbauen
//Decode Job Value (is given as the ID not the number behind the ID for readability)
// All char table related data is collected and can be saved to allow further steps (skills/items/equip)
const std : : string job_id = character [ " start_job " ] ;
int new_char_id = 0 ;
const int start_job = convert_jobid_to_number ( job_id . c_str ( ) ) ;
try {
if ( start_job = = - 1 ) {
if ( ! brokk_create_character ( new_char , new_char_id , true ) ) {
const int start_job = JOB_NOVICE ;
if ( new_char_id < 1 ) {
ShowError ( " Failed to create character: %s \n " , new_char . name ) ;
continue ;
}
else {
ShowNotice ( " Atempt to create existing character : % s (id: %d) \n " , new_char . name , new_char_id ) ;
continue ;
}
} // otherwise character is correctly and newly created
}
catch ( const std : : exception & e ) {
ShowError ( " Character creation for '%s 'failed: %s \n " , new_char . name , e . what ( ) ) ;
continue ;
}
}
std : : shared_ptr < bot_job_info > job = bot_job_db . find ( start_job ) ;
//TODO Ab hier debuggen warum bei EvaExample bei neuanlage crashed
// Step5: Skills
// Prepare skills inside a skill bundle
bot_skill_bundle skill_bundle { } ;
if ( base_level > bot_job_db . get_maxBaseLv ( start_job ) or job_level > bot_job_db . get_maxJobLv ( start_job ) )
prepare_skill_bundle ( skill_bundle , new_char_id , json_character ) ;
{
//ShowNotice("Error in bot data. Inplausible baselevel (max=%s) or joblevel (max=%s) (account: %s, charname: $s, baselevel: %d, joblevel: %d)\n", bot_job_db.get_maxBaseLv(start_job), bot_job_db.get_maxJobLv(start_job), userid, char_name, base_level, job_level);
ShowNotice ( " Unplausible Base-level/Job-level " ) ;
continue ; // Inplausible data
}
// Use job_id as reference for stat_builds
// All skill table related data is collected and can be saved
const std : : string build_profile = character [ " char_build_profile " ] ;
try {
// Prep with default
if ( ! brokk_teach_skills ( skill_bundle , new_char_id ) ) {
int str = 1 ;
ShowError ( " Failed to create skills entry for: %s \n " , new_char . name ) ;
int agi = 1 ;
int vit = 1 ;
int int_ = 1 ;
int dex = 1 ;
int luk = 1 ;
if ( build_profile = = " CUSTOM " ) {
// When a CUSTOM build is entered, stats key must be present
if ( ! character . contains ( " stats " ) ) {
// character params in json are malformed. Stats for CUSTOM build are missing
ShowNotice ( " Error: Could not create character %s . Stats are missing. " , char_name ) ;
continue ;
continue ;
}
}
const auto & char_stats = character [ " stats " ] ;
str = char_stats [ " str " ] ;
agi = char_stats [ " agi " ] ;
vit = char_stats [ " vit " ] ;
int_ = char_stats [ " int " ] ;
dex = char_stats [ " dex " ] ;
luk = char_stats [ " luk " ] ;
}
}
else {
catch ( const std : : exception & e ) {
// Open the JSON file
ShowError ( " skill creation for '%s 'failed: %s \n " , new_char . name , e . what ( ) ) ;
std : : string job_profile_file_path = " conf/bot_profiles/ " ;
continue ;
job_profile_file_path + = job_id . c_str ( ) ;
}
job_profile_file_path + = " _profiles.json " ;
std : : ifstream stat_profile_file ( job_profile_file_path ) ;
if ( ! stat_profile_file . is_open ( ) ) {
ShowError ( " Failed to open %s \n " , job_profile_file_path . c_str ( ) ) ;
return false ;
}
// Parse the JSON file
ShowNotice ( " Skills successfully teached to character (name: %s, char_id: %d, sex: %c) \n " , new_char . name , new_char . char_id , new_char . sex ) ;
json json_stat_profiles ;
try {
stat_profile_file > > json_stat_profiles ;
}
//Step4: Items
catch ( json : : parse_error & e ) {
//TODO Testweise folgende ItemIDs einbauen für Debug:
ShowError ( " Error parsing %s for job: %s \n " , job_profile_file_path . c_str ( ) , job_id . c_str ( ) ) ;
// 1950, 2627 , 4040
return false ;
//ShowNotice("Items successfully handed out to character (name: %s, char_id: %d, sex: %c)\n", new_char.name, new_char.char_id, new_char.sex);
}
// Close file after done with it
//Step5: Equipment
stat_profile_file . close ( ) ;
//ShowNotice("Gear/Weapons successfully equiped (name: %s, char_id: %d, sex: %c)\n", new_char.name, new_char.char_id, new_char.sex);
// Read profile data and convert to stats
ShowStatus ( " Bot-Character creation and administration completed (name: %s, char_id: %d, sex: %c) \n " , new_char . name , new_char . char_id , new_char . sex ) ;
if ( ! json_stat_profiles . contains ( build_profile ) ) {
ShowError ( " Error build profile %s does not exists. Skipping char... \n " , build_profile . c_str ( ) ) ;
/*****
return false ;
* Validating / Applying skill build
* * * * *
// DEBUG: check skill plausibility
const auto & skill_bundle = character [ " skills " ] ;
ShowDebug ( " Skill bundle: %s \n " , skill_bundle . dump ( 4 ) . c_str ( ) ) ; // Ensure `skill_bundle` is structured as expected
for ( const auto & skill : skill_bundle . items ( ) ) {
ShowDebug ( " Skill: %s " , skill . key ( ) . c_str ( ) ) ;
std : : unordered_map < uint16 , uint16 > required_skill ;
//skill >> required_skill;
std : : string skill_str = skill . key ( ) ;
int skill_id = convert_skill_str_to_id ( skill_str . c_str ( ) ) ;
if ( skill_id < 0 ) { // Assuming negative IDs are invalid
ShowError ( " Invalid skill ID for skill string: %s \n " , skill_str . c_str ( ) ) ;
continue ; // Skip this iteration
}
}
const auto & stats = json_stat_profiles [ build_profile ] ;
std : : unordered_map < uint16 , uint16 > parsed_skill_bundle ;
str = stats [ " str " ] ;
for ( const auto & skill : skill_bundle . items ( ) ) {
agi = stats [ " agi " ] ;
uint16 skill_id = convert_skill_str_to_id ( skill . key ( ) . c_str ( ) ) ;
vit = stats [ " vit " ] ;
uint16 level = skill . value ( ) ; // Assuming the value represents the skill level
int_ = stats [ " int " ] ;
parsed_skill_bundle [ skill_id ] = level ;
dex = stats [ " dex " ] ;
}
luk = stats [ " luk " ] ;
}
// DEBUG: Show character details
bool skill_plausible = check_skill_requirements ( start_job , skill_id , parsed_skill_bundle ) ;
//ShowStatus("Creating character: name=%s, slot=%d, start_job=%d\n", char_name.c_str(), slot, start_job);
if ( skill_plausible ) {
ShowDebug ( " all requirements met for skill %s \n " , skill . key ( ) ) ;
}
else {
ShowDebug ( " some requirements not met for skill %s , Cancel creation process? \n " , skill . key ( ) ) ;
continue ;
}
} */
// Create the character for this account
// Create the character for this account
// TODO rebuild to:
// if (!brokk_create_character(new_char, skill_build_data, item_data, equip_data true))
/*
if ( ! brokk_create_character ( account_id , char_name . c_str ( ) , slot , base_level , job_level , str , agi , vit , int_ , dex , luk , hair_style , hair_color , start_job , sex , true ) )
if ( ! brokk_create_character ( account_id , char_name . c_str ( ) , slot , base_level , job_level , str , agi , vit , int_ , dex , luk , hair_style , hair_color , start_job , sex , true ) )
{
{
ShowError ( " Failed to create charakter (char_name: %s) \n " , char_name ) ;
ShowError ( " Failed to create charakter (char_name: %s) \n " , char_name ) ;
continue ; // Skip to the next charakter
continue ; // Skip to the next charakter
}
} */
}
}
}
}
@ -988,7 +1012,7 @@ bool BrokkServer::initialize(int argc, char* argv[]) {
}
}
// Other initialization logic
// Other initialization logic
setup_periodic_cleanup_timer ( ) ; // Set up the cleanup timer
//setup_periodic_cleanup_timer(); // Set up the cleanup timer
ShowStatus ( " The brokk-server is " CL_GREEN " ready " CL_RESET " (Server is listening on the port %u). \n \n " , brokk_config . brokk_port ) ;
ShowStatus ( " The brokk-server is " CL_GREEN " ready " CL_RESET " (Server is listening on the port %u). \n \n " , brokk_config . brokk_port ) ;
//brokk_log(0, "brokk server", 100, "brokk server started");
//brokk_log(0, "brokk server", 100, "brokk server started");