Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 07/30/23 in Posts

  1. 1. rathena/src/map/script.hpp Search: HAT_EF_MAX Replace: /* Custom Hateffects */ HAT_EF_arcane_aura_A, HAT_EF_arcane_aura_B, HAT_EF_gluttony_aura_A, HAT_EF_gluttony_aura_B, HAT_EF_MAX = 9999 2. rathena/src/map/script_constants.hpp Search: export_constant(HAT_EF_EFST_C_20TH_ANNIVERSARY_HAT); Replace: export_constant(HAT_EF_EFST_C_20TH_ANNIVERSARY_HAT); /* Custom Hateffects */ export_constant(HAT_EF_arcane_aura_A); export_constant(HAT_EF_arcane_aura_B); export_constant(HAT_EF_gluttony_aura_A); export_constant(HAT_EF_gluttony_aura_B); 3. Compile you Server. 4. Copy in you Data/texture/effect/(arcane_aura) and (gluttony_aura) Data(Example_Auras).zip 5. Data/luafiles514/lua files/hateffectinfo/hateffectinfo.lub Search: HAT_EF_efst_C_20th_Anniversary_Hat = 176 } Replace: HAT_EF_efst_C_20th_Anniversary_Hat = 176, HAT_EF_arcane_aura_A = 177, HAT_EF_arcane_aura_B = 178, HAT_EF_gluttony_aura_A = 179, HAT_EF_gluttony_aura_B = 180 } resourceFileName: route effect(Data/effect/name you effect folder/name you str file.str) IsIgnoreRiding: if true when mounting a mount or asking for hateffect will not go up, it will ignore this action isRenderBeforeCharacter: If true when using hateffect it will be over the character. hatEffectPos: Position the Y anchor (up and down) of the hateffect hatEffectPosX: Positions hateffect X anchor (left right) isAdjustPositionWhenShrinkState: always true isAdjustSizeWhenShrinkState: always true Search: [HatEFID.HAT_EF_efst_C_20th_Anniversary_Hat] = { resourceFileName = "efst_C_20th_Anniversary_Hat\\20th_f.str", hatEffectPos = -6, hatEffectPosX = 0, isIgnoreRiding = true, isAdjustPositionWhenShrinkState = true, isAdjustSizeWhenShrinkState = true } } Replace: [HatEFID.HAT_EF_efst_C_20th_Anniversary_Hat] = { resourceFileName = "efst_C_20th_Anniversary_Hat\\20th_f.str", hatEffectPos = -6, hatEffectPosX = 0, isIgnoreRiding = true, isAdjustPositionWhenShrinkState = true, isAdjustSizeWhenShrinkState = true }, [HatEFID.HAT_EF_arcane_aura_A] = { resourceFileName = "arcane_aura\\arcane_aura_particle.str", hatEffectPos = -1, hatEffectPosX = 0, isRenderBeforeCharacter = false, isIgnoreRiding = false, isAdjustPositionWhenShrinkState = true, isAdjustSizeWhenShrinkState = true }, [HatEFID.HAT_EF_arcane_aura_B] = { resourceFileName = "arcane_aura\\arcane_aura.str", hatEffectPos = -2, hatEffectPosX = 0.2, isRenderBeforeCharacter = true, isIgnoreRiding = true, isAdjustPositionWhenShrinkState = true, isAdjustSizeWhenShrinkState = true }, [HatEFID.HAT_EF_gluttony_aura_A] = { resourceFileName = "gluttony_aura\\gluttony_aura_particle.str", hatEffectPos = -1, hatEffectPosX = 0, isRenderBeforeCharacter = false, isIgnoreRiding = false, isAdjustPositionWhenShrinkState = true, isAdjustSizeWhenShrinkState = true }, [HatEFID.HAT_EF_gluttony_aura_B] = { resourceFileName = "gluttony_aura\\gluttony_aura.str", hatEffectPos = -2, hatEffectPosX = 0.2, isRenderBeforeCharacter = true, isIgnoreRiding = true, isAdjustPositionWhenShrinkState = true, isAdjustSizeWhenShrinkState = true } } 6. Add Script NPC: rathena\npc\custom\hateffect.txt (Use command @efc in game) - script HATEFFECT -1,{ OnHatEffect: if(getgmlevel()>= 80){ input .@number; if (.@number < 1) end; if (.@number >= 301) end; for(.@i = 1; .@i < 300; ++.@i) hateffect .@i,false; hateffect .@number,true; end; } OnInit: bindatcmd "efc",strnpcinfo(3)+"::OnHatEffect"; end; } 7. Add npc in rathena\npc\scripts_custom.conf npc: npc/custom/hateffect.txt 8. (OPTIONAL) Add Hateffect in item: Example: - Id: 2301 AegisName: Cotton_Shirt Name: Cotton Shirt Type: Armor Buy: 10 Weight: 100 Defense: 1 Locations: Armor: true ArmorLevel: 1 Refineable: true Script: | hateffect HAT_EF_arcane_aura_A,true; hateffect HAT_EF_arcane_aura_B,true; UnEquipScript: | hateffect HAT_EF_arcane_aura_A,false; hateffect HAT_EF_arcane_aura_B,false; Update: My project all Auras. (09/27/2023) - Pack Auras: My Project All Auras Too my project Ragnarok Online Pre-Renewal(Offline) and guide for easy update. - Data Folder + Server: Google Drive or MediaFire - Client RO: Google Drive or MediaFire Guide for start server and Play: 0. Dowloand Client RO and Update. 1. Download Data Folder + Server 2. Copy all files C:/MyServer/Client (In folder Ragnarok Onmline). 3. Run C:/MyServer/UwAmp/UwAmp.exe 4. Start Server C:/MyServer/rathena/runserver.exe Enjoy!!! Gluttony Aura: Arcane Aura: Credits: LCDTheOG Fros
    1 point
  2. Heya, These script commands are an alternative for those who do not want to use yaml for making barter shops. The shops can be reloaded by reloading the script, using the barter_clear command. The NPC location is defined just like a regular NPC and then using callshop <npc barter name>, just like regular shop types (which is already possible without this diff, but I thought I'd mention it anyway). Removes all items from a barter shop barter_clear <npc name>; Add item, not extended barter_add <npc name>,<item id>,<amount>,<req item id>,<req amount>; Add item, extended barter_add_ex <npc name>,<item id>,<amount>,<zeny>{,<req item id>,<req amount>,<req refine>}*; Here's a script example: prontera,150,188,0 script Barter NPC 77,{ mes "[Barter NPC]"; next; switch(select("Normal barter shop.:Extended barter shop.:")) { case 1: mes "[Barter NPC]"; mes "..."; close2; callshop "barter_test_npc"; end; case 2: mes "[Barter NPC]"; mes "..."; close2; callshop "barter_test_npc_ex"; end; } end; OnInit: barter_clear "barter_test_npc"; barter_add "barter_test_npc", 504, 10, 501, 20; barter_add "barter_test_npc", 504, 10, 502, 10; barter_add "barter_test_npc", "White_Potion", 10, "Yellow_Potion", 3; barter_clear "barter_test_npc_ex"; barter_add_ex "barter_test_npc_ex", "Zeny_Knife", 5, 5000, "Knife", 1, 9; barter_add_ex "barter_test_npc_ex", "Zeny_Knife", 5, 5000, "Knife", 1, 9, "White_Potion", 10, 0; barter_add_ex "barter_test_npc_ex", "Zeny_Knife", 5, 5000, "Knife", 1, 9, "White_Potion", 10, 0, "White_Potion", 10, 0; end; } prontera,152,188,0 script Barter NPC2 77,{ callshop "barter_test_npc"; end; } And here's the diff file: diff --git a/src/map/npc.cpp b/src/map/npc.cpp index d227467ed..37f50d94d 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -842,6 +842,26 @@ void BarterDatabase::loadingFinished(){ BarterDatabase barter_db; +struct npc_data* npc_create_dummy_barter_npc(const char *npcname) { + struct npc_data* nd = npc_create_npc(-1, 0, 0); + + npc_parsename(nd, npcname, nullptr, nullptr, __FILE__ ":" QUOTE(__LINE__)); + + nd->class_ = -1; + nd->speed = 200; + + nd->bl.type = BL_NPC; + nd->subtype = NPCTYPE_BARTER; + + nd->u.barter.extended = false; + + map_addiddb(&nd->bl); + + strdb_put(npcname_db, npcname, nd); + + return nd; +} + /** * Returns the viewdata for normal NPC classes. * @param class_: NPC class ID diff --git a/src/map/npc.hpp b/src/map/npc.hpp index 0a0c104e6..82ad2cf3d 100644 --- a/src/map/npc.hpp +++ b/src/map/npc.hpp @@ -1479,6 +1479,8 @@ enum e_npcv_status : uint8 { NPCVIEW_INVISIBLE = 0x29, NPCVIEW_CLOAK = 0x30, }; + +struct npc_data* npc_create_dummy_barter_npc(const char* npcname); struct view_data* npc_get_viewdata(int class_); int npc_chat_sub(struct block_list* bl, va_list ap); int npc_event_dequeue(map_session_data* sd,bool free_script_stack=true); diff --git a/src/map/script.cpp b/src/map/script.cpp index 5aeebe228..6742ab8c4 100644 --- a/src/map/script.cpp +++ b/src/map/script.cpp @@ -26916,6 +26916,154 @@ BUILDIN_FUNC(preg_match) { #endif } +/*========================================== + * Removes all items from a barter shop + * barter_clear <npc name>; + *------------------------------------------*/ +BUILDIN_FUNC(barter_clear) +{ + const char* npcname = script_getstr(st, 2); + std::shared_ptr<s_npc_barter> barter = barter_db.find(npcname); + + if (barter != nullptr) { + barter->items.clear(); + } + + return SCRIPT_CMD_SUCCESS; +} + +/*========================================== + * Add an item to the barter shop + * Not extended: + * barter_add <npc name>,<item id>,<amount>,<req item id>,<req amount>; + * + * Extended: + * barter_add_ex <npc name>,<item id>,<amount>,<zeny>{,<req item id>,<req amount>,<req refine>}*; + *------------------------------------------*/ +BUILDIN_FUNC(barter_add) +{ + const char* npcname = script_getstr(st, 2); + std::shared_ptr<s_npc_barter> barter = barter_db.find(npcname); + struct npc_data* nd = npc_name2id(npcname); + const char* command = script_getfuncname(st); + + if (barter == nullptr) { + barter = std::make_shared<s_npc_barter>(); + barter->name = npcname; + barter_db.put(npcname, barter); + } + + if (nd == nullptr) { + nd = npc_create_dummy_barter_npc(npcname); + } + + int index = barter->items.size(); + + std::shared_ptr<s_npc_barter_item> item = std::make_shared<s_npc_barter_item>(); + item->index = index; + barter->items[index] = item; + + if (strcmpi(command, "barter_add_ex") == 0) { + nd->u.barter.extended = true; + + if (script_isstring(st, 3)) { + const char* name = script_getstr(st, 3); + + std::shared_ptr<item_data> id = item_db.searchname(name); + + if (id == nullptr) { + ShowError("buildin_barter_add: Nonexistant item %s\n", name); + return SCRIPT_CMD_FAILURE; + } + + item->nameid = id->nameid; + } + else { + item->nameid = script_getnum(st, 3); + } + + item->stock = script_getnum(st, 4); + item->stockLimited = false; + item->price = script_getnum(st, 5); + + int offset = 6; + + while (script_hasdata(st, offset) && script_hasdata(st, offset + 1) && script_hasdata(st, offset + 2)) { + std::shared_ptr<s_npc_barter_requirement> requirement = std::make_shared<s_npc_barter_requirement>(); + + requirement->index = (uint16)item->requirements.size(); + + if (script_isstring(st, offset)) { + const char* name = script_getstr(st, offset); + + std::shared_ptr<item_data> id = item_db.searchname(name); + + if (id == nullptr) { + ShowError("buildin_barter_add: Nonexistant item %s\n", name); + return SCRIPT_CMD_FAILURE; + } + + requirement->nameid = id->nameid; + } + else { + requirement->nameid = script_getnum(st, offset); + } + + requirement->amount = script_getnum(st, offset + 1); + requirement->refine = script_getnum(st, offset + 2); + item->requirements[requirement->index] = requirement; + offset += 3; + } + } + else { + nd->u.barter.extended = false; + + if (script_isstring(st, 3)) { + const char* name = script_getstr(st, 3); + + std::shared_ptr<item_data> id = item_db.searchname(name); + + if (id == nullptr) { + ShowError("buildin_barter_add: Nonexistant item %s\n", name); + return SCRIPT_CMD_FAILURE; + } + + item->nameid = id->nameid; + } + else { + item->nameid = script_getnum(st, 3); + } + + item->stock = script_getnum(st, 4); + item->stockLimited = false; + + std::shared_ptr<s_npc_barter_requirement> requirement = std::make_shared<s_npc_barter_requirement>(); + + requirement->index = 0; + + if (script_isstring(st, 5)) { + const char* name = script_getstr(st, 5); + + std::shared_ptr<item_data> id = item_db.searchname(name); + + if (id == nullptr) { + ShowError("buildin_barter_add: Nonexistant item %s\n", name); + return SCRIPT_CMD_FAILURE; + } + + requirement->nameid = id->nameid; + } + else { + requirement->nameid = script_getnum(st, 5); + } + + requirement->amount = script_getnum(st, 6); + item->requirements[0] = requirement; + } + + return SCRIPT_CMD_SUCCESS; +} + /// script command definitions /// for an explanation on args, see add_buildin_func struct script_function buildin_func[] = { @@ -27623,6 +27771,10 @@ struct script_function buildin_func[] = { BUILDIN_DEF(isdead, "?"), BUILDIN_DEF(macro_detector, "?"), + BUILDIN_DEF(barter_clear, "s"), + BUILDIN_DEF(barter_add, "svi*"), + BUILDIN_DEF2(barter_add, "barter_add_ex", "svii*"), + #include "../custom/script_def.inc" {NULL,NULL,NULL}, Quick notes: There isn't a whole lot of error handling. Do... not use an existing NPC name for the barter name if you don't want to crash, but otherwise, should be fine! There is no handling for stocks. You can add parameters to it in the script command if you feel like it, but I've personally never used this option so I just didn't add it. barter.diff
    1 point
  3. Unfortunately, hat effects were implemented on the map_session_data (player) on the emulator, while it should have been on the unit_data structure instead, which is shared by all object types. So you'll need a lot of modifications to get this working on monsters. If you apply the changes below, you'll be able to add a hat effect with this command: monster "prontera", 154, 182, "--ja--", 1002, 1; hateffect 12, true, $@mobid; Changes: diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 991b5b1b8..f2fece16d 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -1733,7 +1733,7 @@ int clif_spawn( struct block_list *bl, bool walking ){ if (sd->status.robe) clif_refreshlook(bl,bl->id,LOOK_ROBE,sd->status.robe,AREA); clif_efst_status_change_sub(bl, bl, AREA); - clif_hat_effects(sd,bl,AREA); + clif_hat_effects(bl, bl, true, AREA); } break; case BL_MOB: @@ -1745,6 +1745,7 @@ int clif_spawn( struct block_list *bl, bool walking ){ clif_specialeffect(&md->bl,EF_BABYBODY2,AREA); if ( md->special_state.ai == AI_ABR || md->special_state.ai == AI_BIONIC ) clif_summon_init(*md); + clif_hat_effects(bl, bl, true, AREA); } break; case BL_NPC: @@ -1756,6 +1757,7 @@ int clif_spawn( struct block_list *bl, bool walking ){ clif_specialeffect(&nd->bl,EF_BABYBODY2,AREA); clif_efst_status_change_sub(bl, bl, AREA); clif_progressbar_npc_area(nd); + clif_hat_effects(bl, bl, true, AREA); } break; case BL_PET: @@ -5104,7 +5106,7 @@ void clif_getareachar_unit( map_session_data* sd,struct block_list *bl ){ if ( tsd->status.robe ) clif_refreshlook(&sd->bl,bl->id,LOOK_ROBE,tsd->status.robe,SELF); clif_efst_status_change_sub(&sd->bl, bl, SELF); - clif_hat_effects(sd,bl,SELF); + clif_hat_effects(&sd->bl, bl, true, SELF); } break; case BL_MER: // Devotion Effects @@ -5122,6 +5124,7 @@ void clif_getareachar_unit( map_session_data* sd,struct block_list *bl ){ clif_specialeffect_single(bl,EF_BABYBODY2,sd->fd); clif_efst_status_change_sub(&sd->bl, bl, SELF); clif_progressbar_npc(nd, sd); + clif_hat_effects(&sd->bl, bl, true, SELF); } break; case BL_MOB: @@ -5139,6 +5142,7 @@ void clif_getareachar_unit( map_session_data* sd,struct block_list *bl ){ clif_monster_hp_bar(md, sd->fd); } #endif + clif_hat_effects(&sd->bl, bl, true, SELF); } break; case BL_PET: @@ -21184,53 +21188,46 @@ void clif_navigateTo(map_session_data *sd, const char* mapname, uint16 x, uint16 /// Send hat effects to the client (ZC_HAT_EFFECT). /// 0A3B <Length>.W <AID>.L <Status>.B { <HatEffectId>.W } -void clif_hat_effects( map_session_data* sd, struct block_list* bl, enum send_target target ){ +void clif_hat_effects(struct block_list* src, struct block_list* bl, bool enable, enum send_target target ){ #if PACKETVER_MAIN_NUM >= 20150507 || PACKETVER_RE_NUM >= 20150429 || defined(PACKETVER_ZERO) - map_session_data *tsd; - struct block_list* tbl; - - if( target == SELF ){ - tsd = BL_CAST(BL_PC,bl); - tbl = &sd->bl; - }else{ - tsd = sd; - tbl = bl; - } - - nullpo_retv( tsd ); - - if( tsd->hatEffects.empty() || map_getmapdata(tbl->m)->getMapFlag(MF_NOCOSTUME) ){ + struct unit_data* ud; + + if (!src || !bl || !(ud = unit_bl2ud(bl))) return; - } - + + if (ud->hatEffects.empty() || map_getmapdata(src->m)->getMapFlag(MF_NOCOSTUME)) { + return; + } + struct PACKET_ZC_EQUIPMENT_EFFECT* p = (struct PACKET_ZC_EQUIPMENT_EFFECT*)packet_buffer; - - p->packetType = HEADER_ZC_EQUIPMENT_EFFECT; - p->packetLength = (int16)( sizeof( struct PACKET_ZC_EQUIPMENT_EFFECT ) + sizeof( int16 ) * tsd->hatEffects.size() ); - p->aid = tsd->bl.id; - p->status = 1; - - for( size_t i = 0; i < tsd->hatEffects.size(); i++ ){ - p->effects[i] = tsd->hatEffects[i]; - } - - clif_send( p, p->packetLength, tbl, target ); + + p->packetType = HEADER_ZC_EQUIPMENT_EFFECT; + + p->packetLength = (int16)( sizeof( struct PACKET_ZC_EQUIPMENT_EFFECT ) + sizeof( int16 ) * ud->hatEffects.size() ); + p->aid = bl->id; + p->status = enable; + + for (size_t i = 0; i < ud->hatEffects.size(); i++) { + p->effects[i] = ud->hatEffects[i]; + } + + clif_send(p, p->packetLength, src, target); #endif } -void clif_hat_effect_single( map_session_data* sd, uint16 effectId, bool enable ){ +void clif_hat_effect_single( struct block_list* bl, uint16 effectId, bool enable ){ #if PACKETVER_MAIN_NUM >= 20150507 || PACKETVER_RE_NUM >= 20150429 || defined(PACKETVER_ZERO) - nullpo_retv( sd ); - - struct PACKET_ZC_EQUIPMENT_EFFECT* p = (struct PACKET_ZC_EQUIPMENT_EFFECT*)packet_buffer; - - p->packetType = HEADER_ZC_EQUIPMENT_EFFECT; - p->packetLength = (int16)( sizeof( struct PACKET_ZC_EQUIPMENT_EFFECT ) + sizeof( int16 ) ); - p->aid = sd->bl.id; - p->status = enable; - p->effects[0] = effectId; - - clif_send( p, p->packetLength, &sd->bl, AREA ); + nullpo_retv(bl); + + struct PACKET_ZC_EQUIPMENT_EFFECT* p = (struct PACKET_ZC_EQUIPMENT_EFFECT*)packet_buffer; + + p->packetType = HEADER_ZC_EQUIPMENT_EFFECT; + p->packetLength = (int16)( sizeof( struct PACKET_ZC_EQUIPMENT_EFFECT ) + sizeof( int16 ) ); + p->aid = bl->id; + p->status = enable; + p->effects[0] = effectId; + + clif_send( p, p->packetLength, bl, AREA ); #endif } diff --git a/src/map/clif.hpp b/src/map/clif.hpp index 1bf10b262..f6ba450b2 100644 --- a/src/map/clif.hpp +++ b/src/map/clif.hpp @@ -801,8 +801,8 @@ void clif_item_repair_list(map_session_data *sd, map_session_data *dstsd, int lv void clif_item_repaireffect(map_session_data *sd, int idx, int flag); void clif_item_damaged(map_session_data* sd, unsigned short position); void clif_item_refine_list(map_session_data *sd); -void clif_hat_effects( map_session_data* sd, struct block_list* bl, enum send_target target ); -void clif_hat_effect_single( map_session_data* sd, uint16 effectId, bool enable ); +void clif_hat_effects(struct block_list* src, struct block_list* bl, bool enable, enum send_target target); +void clif_hat_effect_single(struct block_list* bl, uint16 effectId, bool enable); void clif_item_skill(map_session_data *sd,uint16 skill_id,uint16 skill_lv); diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 1cb25fad6..c2e9b2cc2 100755 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -2220,10 +2220,6 @@ bool pc_authok(map_session_data *sd, uint32 login_id2, time_t expiration_time, i // Initialize BG queue sd->bg_queue_id = 0; -#if PACKETVER_MAIN_NUM >= 20150507 || PACKETVER_RE_NUM >= 20150429 || defined(PACKETVER_ZERO) - sd->hatEffects = {}; -#endif - sd->catch_target_class = PET_CATCH_FAIL; // Check EXP overflow, since in previous revision EXP on Max Level can be more than 'official' Max EXP diff --git a/src/map/pc.hpp b/src/map/pc.hpp index c37cd4fb5..3f4ceb943 100644 --- a/src/map/pc.hpp +++ b/src/map/pc.hpp @@ -922,10 +922,6 @@ public: short setlook_head_top, setlook_head_mid, setlook_head_bottom, setlook_robe; ///< Stores 'setlook' script command values. -#if PACKETVER_MAIN_NUM >= 20150507 || PACKETVER_RE_NUM >= 20150429 || defined(PACKETVER_ZERO) - std::vector<int16> hatEffects; -#endif - struct{ int tid; uint16 skill_id; diff --git a/src/map/script.cpp b/src/map/script.cpp index 027587945..72a1382f1 100644 --- a/src/map/script.cpp +++ b/src/map/script.cpp @@ -24268,39 +24268,31 @@ BUILDIN_FUNC(recalculatestat) { BUILDIN_FUNC(hateffect){ #if PACKETVER_MAIN_NUM >= 20150507 || PACKETVER_RE_NUM >= 20150429 || defined(PACKETVER_ZERO) - map_session_data* sd; - - if( !script_rid2sd(sd) ) - return SCRIPT_CMD_FAILURE; - - int16 effectID = script_getnum(st,2); - bool enable = script_getnum(st,3) ? true : false; - - if( effectID <= HAT_EF_MIN || effectID >= HAT_EF_MAX ){ - ShowError( "buildin_hateffect: unsupported hat effect id %d\n", effectID ); - return SCRIPT_CMD_FAILURE; - } - - auto it = util::vector_get( sd->hatEffects, effectID ); - - if( enable ){ - if( it != sd->hatEffects.end() ){ - return SCRIPT_CMD_SUCCESS; - } - - sd->hatEffects.push_back( effectID ); - }else{ - if( it == sd->hatEffects.end() ){ - return SCRIPT_CMD_SUCCESS; - } - - util::vector_erase_if_exists( sd->hatEffects, effectID ); - } - - if( !sd->state.connect_new ){ - clif_hat_effect_single( sd, effectID, enable ); - } - + int16 effectID = script_getnum(st,2); + bool enable = script_getnum(st,3) ? true : false; + + // This is unecessary and annoying half the time + //if( effectID <= HAT_EF_MIN || effectID >= HAT_EF_MAX ){ + // ShowError( "buildin_hateffect: unsupported hat effect id %d\n", effectID ); + // return SCRIPT_CMD_FAILURE; + //} + + struct block_list* bl; + bool send = true; + + if (script_hasdata(st, 4)) { + bl = map_id2bl(script_getnum(st, 4)); + } + else { + bl = map_id2bl(st->rid); + map_session_data* sd = BL_CAST(BL_PC, bl); + + if (sd && sd->state.connect_new) { + send = false; + } + } + + unit_hateffect(bl, effectID, enable, send); #endif return SCRIPT_CMD_SUCCESS; } @@ -27566,7 +27558,7 @@ struct script_function buildin_func[] = { BUILDIN_DEF(adopt,"vv"), BUILDIN_DEF(getexp2,"ii?"), BUILDIN_DEF(recalculatestat,""), - BUILDIN_DEF(hateffect,"ii"), + BUILDIN_DEF(hateffect,"ii?"), BUILDIN_DEF(getrandomoptinfo, "i"), BUILDIN_DEF(getequiprandomoption, "iii?"), BUILDIN_DEF(setrandomoption,"iiiii?"), diff --git a/src/map/unit.cpp b/src/map/unit.cpp index f90529926..f57fcde6c 100644 --- a/src/map/unit.cpp +++ b/src/map/unit.cpp @@ -2964,6 +2964,9 @@ void unit_dataset(struct block_list *bl) ud->attackabletime = ud->canact_tick = ud->canmove_tick = gettick(); +#if PACKETVER_MAIN_NUM >= 20150507 || PACKETVER_RE_NUM >= 20150429 || defined(PACKETVER_ZERO) + ud->hatEffects = {}; +#endif } /** @@ -3461,10 +3464,6 @@ int unit_free(struct block_list *bl, clr_type clrtype) sd->qi_display.clear(); -#if PACKETVER_MAIN_NUM >= 20150507 || PACKETVER_RE_NUM >= 20150429 || defined(PACKETVER_ZERO) - sd->hatEffects.clear(); -#endif - if (sd->achievement_data.achievements) achievement_free(sd); @@ -3645,6 +3644,14 @@ int unit_free(struct block_list *bl, clr_type clrtype) break; } } + + + if (ud) { +#if PACKETVER_MAIN_NUM >= 20150507 || PACKETVER_RE_NUM >= 20150429 || defined(PACKETVER_ZERO) + ud->hatEffects.clear(); +#endif + } + map_deliddb(bl); @@ -3656,6 +3663,39 @@ int unit_free(struct block_list *bl, clr_type clrtype) return 0; } + +void unit_hateffect(struct block_list* bl, int16 effectID, bool enable, bool send) +{ + struct unit_data* ud; + map_session_data* sd; + + if (!bl || !(ud = unit_bl2ud(bl))) + return; + + sd = BL_CAST(BL_PC, bl); + auto it = util::vector_get(ud->hatEffects, effectID); + + if (enable) { + if (it != ud->hatEffects.end()) { + return; + } + + ud->hatEffects.push_back(effectID); + } + else { + if (it == ud->hatEffects.end()) { + return; + } + + util::vector_erase_if_exists(ud->hatEffects, effectID); + } + + if (send || !enable) { + clif_hat_effect_single(bl, effectID, enable); + } +} + + static TIMER_FUNC(unit_shadowscar_timer) { block_list *bl = map_id2bl(id); diff --git a/src/map/unit.hpp b/src/map/unit.hpp index cfd932615..0964d7438 100644 --- a/src/map/unit.hpp +++ b/src/map/unit.hpp @@ -65,6 +65,9 @@ struct unit_data { int32 group_id; std::vector<int> shadow_scar_timer; +#if PACKETVER_MAIN_NUM >= 20150507 || PACKETVER_RE_NUM >= 20150429 || defined(PACKETVER_ZERO) + std::vector<int16> hatEffects; +#endif }; struct view_data { @@ -115,6 +118,7 @@ bool unit_run(struct block_list *bl, map_session_data *sd, enum sc_type type); int unit_calc_pos(struct block_list *bl, int tx, int ty, uint8 dir); TIMER_FUNC(unit_delay_walktoxy_timer); TIMER_FUNC(unit_delay_walktobl_timer); +void unit_hateffect(struct block_list* bl, int16 effectID, bool enable, bool send); // Causes the target object to stop moving. int unit_stop_walking(struct block_list *bl,int type); You'll be able to use hat effects on NPCs as well. Goodluck. Edit: Updated diff to fix an error with the script function. hateffects.diff
    1 point
  4. You are probably using outdated cursors.act and cursors.spr cursor.rar
    1 point
×
×
  • Create New...