Initial release of stylist UI (#6446)
Fixes #3037 Thanks to @Balferian and @aleos89 Co-authored-by: Aleos <aleos89@users.noreply.github.com>
This commit is contained in:
270
src/map/npc.cpp
270
src/map/npc.cpp
@@ -121,6 +121,271 @@ struct script_event_s{
|
||||
// Holds pointers to the commonly executed scripts for speedup. [Skotlex]
|
||||
std::map<enum npce_event, std::vector<struct script_event_s>> script_event;
|
||||
|
||||
const std::string StylistDatabase::getDefaultLocation(){
|
||||
return std::string(db_path) + "/stylist.yml";
|
||||
}
|
||||
|
||||
bool StylistDatabase::parseCostNode( std::shared_ptr<s_stylist_entry> entry, bool doram, const YAML::Node& node ){
|
||||
std::shared_ptr<s_stylist_costs> costs = doram ? entry->doram : entry->human;
|
||||
bool costs_exists = costs != nullptr;
|
||||
|
||||
if( !costs_exists ){
|
||||
costs = std::make_shared<s_stylist_costs>();
|
||||
}
|
||||
|
||||
if( this->nodeExists( node, "Price" ) ){
|
||||
uint32 price;
|
||||
|
||||
if( !this->asUInt32( node, "Price", price ) ){
|
||||
return false;
|
||||
}
|
||||
|
||||
if( price > MAX_ZENY ){
|
||||
this->invalidWarning( node["Price"], "stylist_parseCostNode: Price %u is too high, capping to MAX_ZENY...\n", price );
|
||||
price = MAX_ZENY;
|
||||
}
|
||||
|
||||
costs->price = price;
|
||||
}else{
|
||||
if( !costs_exists ){
|
||||
costs->price = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( this->nodeExists( node, "RequiredItem" ) ){
|
||||
std::string item;
|
||||
|
||||
if( !this->asString( node, "RequiredItem", item ) ){
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<item_data> id = item_db.search_aegisname( item.c_str() );
|
||||
|
||||
if( id == nullptr ){
|
||||
this->invalidWarning( node["RequiredItem"], "stylist_parseCostNode: Unknown item \"%s\"...\n", item.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
costs->requiredItem = id->nameid;
|
||||
}else{
|
||||
if( !costs_exists ){
|
||||
costs->requiredItem = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( this->nodeExists( node, "RequiredItemBox" ) ){
|
||||
std::string item;
|
||||
|
||||
if( !this->asString( node, "RequiredItemBox", item ) ){
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<item_data> id = item_db.search_aegisname( item.c_str() );
|
||||
|
||||
if( id == nullptr ){
|
||||
this->invalidWarning( node["RequiredItemBox"], "stylist_parseCostNode: Unknown item \"%s\"...\n", item.c_str() );
|
||||
return false;
|
||||
}
|
||||
|
||||
costs->requiredItemBox = id->nameid;
|
||||
}else{
|
||||
if( !costs_exists ){
|
||||
costs->requiredItemBox = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( !costs_exists ){
|
||||
if( doram ){
|
||||
entry->doram = costs;
|
||||
}else{
|
||||
entry->human = costs;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64 StylistDatabase::parseBodyNode( const YAML::Node &node ){
|
||||
if( !this->nodesExist( node, { "Look", "Options" } ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string look_str;
|
||||
|
||||
if( !this->asString( node, "Look", look_str ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64 constant;
|
||||
|
||||
if( !script_get_constant( ( "LOOK_" + look_str ).c_str(), &constant ) ){
|
||||
this->invalidWarning( node["Look"], "stylist_parseBodyNode: Invalid look %s.\n", look_str.c_str() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch( constant ){
|
||||
case LOOK_HEAD_TOP:
|
||||
case LOOK_HEAD_MID:
|
||||
case LOOK_HEAD_BOTTOM:
|
||||
case LOOK_HAIR:
|
||||
case LOOK_HAIR_COLOR:
|
||||
case LOOK_CLOTHES_COLOR:
|
||||
case LOOK_BODY2:
|
||||
break;
|
||||
default:
|
||||
this->invalidWarning( node["Look"], "stylist_parseBodyNode: Unsupported look value \"%s\"...\n", look_str.c_str() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<s_stylist_list> list = this->find( (uint32)constant );
|
||||
bool exists = list != nullptr;
|
||||
uint64 count = 0;
|
||||
|
||||
if( !exists ){
|
||||
list = std::make_shared<s_stylist_list>();
|
||||
list->look = (uint16)constant;
|
||||
}
|
||||
|
||||
for( const YAML::Node& optionNode : node["Options"] ){
|
||||
int16 index;
|
||||
|
||||
if( !this->asInt16( optionNode, "Index", index ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( index == 0 ){
|
||||
this->invalidWarning( optionNode["Index"], "stylist_parseBodyNode: Unsupported index value \"%hd\"...\n", index );
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<s_stylist_entry> entry = util::umap_find( list->entries, index );
|
||||
bool entry_exists = entry != nullptr;
|
||||
|
||||
if( !entry_exists ){
|
||||
entry = std::make_shared<s_stylist_entry>();
|
||||
entry->look = list->look;
|
||||
entry->index = index;
|
||||
|
||||
if( !this->nodesExist( optionNode, { "Value" } ) ){
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( this->nodeExists( optionNode, "Value" ) ){
|
||||
uint32 value;
|
||||
|
||||
switch( list->look ){
|
||||
case LOOK_HEAD_TOP:
|
||||
case LOOK_HEAD_MID:
|
||||
case LOOK_HEAD_BOTTOM: {
|
||||
std::string item;
|
||||
|
||||
if( !this->asString( optionNode, "Value", item ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<item_data> id = item_db.search_aegisname( item.c_str() );
|
||||
|
||||
if( id == nullptr ){
|
||||
this->invalidWarning( optionNode["Value"], "stylist_parseBodyNode: Unknown item \"%s\"...\n", item.c_str() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = id->nameid;
|
||||
} break;
|
||||
case LOOK_HAIR:
|
||||
if( !this->asUInt32( optionNode, "Value", value ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( value < MIN_HAIR_STYLE ){
|
||||
this->invalidWarning( optionNode["Value"], "stylist_parseBodyNode: hair style \"%u\" is too low...\n", value );
|
||||
return 0;
|
||||
}else if( value > MAX_HAIR_STYLE ){
|
||||
this->invalidWarning( optionNode["Value"], "stylist_parseBodyNode: hair style \"%u\" is too high...\n", value );
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case LOOK_HAIR_COLOR:
|
||||
if( !this->asUInt32( optionNode, "Value", value ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( value < MIN_HAIR_COLOR ){
|
||||
this->invalidWarning( optionNode["Value"], "stylist_parseBodyNode: hair color \"%u\" is too low...\n", value );
|
||||
return 0;
|
||||
}else if( value > MAX_HAIR_COLOR ){
|
||||
this->invalidWarning( optionNode["Value"], "stylist_parseBodyNode: hair color \"%u\" is too high...\n", value );
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case LOOK_CLOTHES_COLOR:
|
||||
if( !this->asUInt32( optionNode, "Value", value ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( value < MIN_CLOTH_COLOR ){
|
||||
this->invalidWarning( optionNode["Value"], "stylist_parseBodyNode: cloth color \"%u\" is too low...\n", value );
|
||||
return 0;
|
||||
}else if( value > MAX_CLOTH_COLOR ){
|
||||
this->invalidWarning( optionNode["Value"], "stylist_parseBodyNode: cloth color \"%u\" is too high...\n", value );
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case LOOK_BODY2:
|
||||
if( !this->asUInt32( optionNode, "Value", value ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( value < MIN_BODY_STYLE ){
|
||||
this->invalidWarning( optionNode["Value"], "stylist_parseBodyNode: body style \"%u\" is too low...\n", value );
|
||||
return 0;
|
||||
}else if( value > MAX_BODY_STYLE ){
|
||||
this->invalidWarning( optionNode["Value"], "stylist_parseBodyNode: body style \"%u\" is too high...\n", value );
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
entry->value = value;
|
||||
}
|
||||
|
||||
if( this->nodeExists( optionNode, "CostsHuman" ) ) {
|
||||
if( !this->parseCostNode( entry, false, optionNode["CostsHuman"] ) ){
|
||||
return 0;
|
||||
}
|
||||
}else{
|
||||
if( !entry_exists ){
|
||||
entry->human = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if( this->nodeExists( optionNode, "CostsDoram" ) ) {
|
||||
if( !this->parseCostNode( entry, true, optionNode["CostsDoram"] ) ){
|
||||
return 0;
|
||||
}
|
||||
}else{
|
||||
if( !entry_exists ){
|
||||
entry->doram = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if( !entry_exists ){
|
||||
list->entries[index] = entry;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
if( !exists ){
|
||||
this->put( (uint32)constant, list );
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
StylistDatabase stylist_db;
|
||||
|
||||
/**
|
||||
* Returns the viewdata for normal NPC classes.
|
||||
* @param class_: NPC class ID
|
||||
@@ -4785,6 +5050,8 @@ int npc_reload(void) {
|
||||
"\t-'" CL_WHITE "%d" CL_RESET "' Mobs Not Cached\n",
|
||||
npc_id - npc_new_min, npc_warp, npc_shop, npc_script, npc_mob, npc_cache_mob, npc_delay_mob);
|
||||
|
||||
stylist_db.reload();
|
||||
|
||||
//Re-read the NPC Script Events cache.
|
||||
npc_read_event_script();
|
||||
|
||||
@@ -4851,6 +5118,7 @@ void do_final_npc(void) {
|
||||
#if PACKETVER >= 20131223
|
||||
NPCMarketDB->destroy(NPCMarketDB, npc_market_free);
|
||||
#endif
|
||||
stylist_db.clear();
|
||||
ers_destroy(timer_event_ers);
|
||||
ers_destroy(npc_sc_display_ers);
|
||||
npc_clearsrcfile();
|
||||
@@ -4936,6 +5204,8 @@ void do_init_npc(void){
|
||||
"\t-'" CL_WHITE "%d" CL_RESET "' Mobs Not Cached\n",
|
||||
npc_id - START_NPC_NUM, npc_warp, npc_shop, npc_script, npc_mob, npc_cache_mob, npc_delay_mob);
|
||||
|
||||
stylist_db.load();
|
||||
|
||||
// set up the events cache
|
||||
npc_read_event_script();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user