Jump to content

Tokei

Members
  • Posts

    662
  • Joined

  • Last visited

  • Days Won

    90

Everything posted by Tokei

  1. Heya, You're right, this is definitely the wrong thread ;P. There are many ways of doing this, so here goes. for (int aid = 0; aid <= 7; aid++) { var action = act[aid]; for (int fid = 0; fid < action.Frames.Count; fid++) { var frame = action[fid]; for (int lid = 0; lid < frame.Layers.Count; lid++) { var layer = frame[lid]; layer.OffsetX = 2; layer.OffsetY = -82; } } }
  2. Well, first thing first, you should download the latest version. As for lzma.dll: Microsoft Visual Studio C++ 2005 (x86), https://www.microsoft.com/en-us/download/details.aspx?id=26347
  3. The script engine was never finished. It does work, but there is no documentation for it so it's not like anyone can use it. It was meant for myself for some testing. Though, you can use this: var scale = 0.5f; var centerOffset = new GRF.Graphics.Point(319f, 291f); for (int i = 1; i < str.Layers.Count; i++) { var layer = str.Layers[i]; for (int k = 0; k < layer.KeyFrames.Count; k++) { var keyFrame = layer.KeyFrames[k]; keyFrame.Scale(scale); // The offset shown is not the real XY value. The center is rebased by the centerOffset, so some math is needed var center = keyFrame.Offset - centerOffset; center = scale * center; keyFrame.Offset = center + centerOffset; } }
  4. You have many ways of doing it. You could use a loop with an array, but this one is pretty straightfoward: if (countitem(A)) { .@itemid = A; } else if (countitem(B)) { .@itemid = B; } else if (countitem(C)) { .@itemid = C; } if (!.@itemid) { mes "Hello, Good day huh?"; close; } mes "Oh you want this juice?": mes "let me have a look that " + getitemname(.@itemid); next; mes "Nice!, thanks for showing me,"; mes "you can have this juice !"; getitem 7709, 1; close;
  5. A bit of a random reply, but for future reference, you can simply use Scripts > Merge layers (new sprites). That will create a single layer for all your frames.
  6. Heya, This topic is actually very complex and it has tons of exceptions. It also depends of the client version since they do have different behaviors. When the clif_damage packet is sent, the important value is "sdelay", "amotion", "animation motion" or "attack motion". This is the duration of the attack animation shown by the monster. This value is defined in your mob db file under AttackMotion. The AttackMotion is the speed at which the mob displays its attack animation and it can go between 0 and 500. It works as you think it does (ish): An AttackMotion motion of 100 would be 100 * AttackMotion / 500 = 1/5th of the normal duration. Meanwhile 600 AttackMotion would be capped to 500, giving you the full attack animation duration. Now you would think the animation duration is given by the AttackMotion, but that's just bullshit. That's not the case at all. The damage number shown isn't related to that. The real animation duration that the client reads is given by the Act file itself by the action index 16. If you take Willow as an example, it has 7 frames at 100 ms each, so it has a total duration of 700 ms. Now there's another special "feature" going on here. The damage number will be shown at "frames count - 1". So in the case of Condor, the damage animation will be shown at frame 7. So while the animation duration is indeed 9 x 75 = 675 ms, the damage number will be shown at 7 x 75 = 525 ms. To be clear, it is shown the moment the frame appears and not when it ends, so that's why it's not 8 x 75 but 7 x 75. As for Condor, there is yet again another special "feature" going on. The damage number will be shown earlier if the "atk" sound is triggered. In the case of Willow, the attack sound is at frame 3, so while the animation duration is 700 ms, the damage will actually be shown at 3 x 100 = 300 ms. Now that's why the attack isn't displayed at the end of the animation as you'd expect it to be. The character stops moving on the client once the damage number is shown. More on the server-side of things: The damage will be inflicted after the AttackMotion timer server-side. Once AttackMotion runs out, the player movement will be stopped, that position will be saved and then a clif_updatestatus will be sent for the new HP value. So as you can imagine, there is absolutely no way that the position in the client and the position on the server would be the same considering all this. The server can't know the Act file true damage animation duration vs attack animation duration. Overall, quite the blunder Gravity made, yet again. And that's just what I've found out through the years. I'm sure there is plenty more weirdness going on there, like how player ranged melee attacks are 4/3 of the AttackMotion on some clients, creating even more position lag issues. Anyway, to fix your issue, change the "atk" sound and it will work out, but fixing that for all mobs doesn't seem very realistic to me. Edit: Please keep in mind most of the above is only related to monsters; players have different behavior in regards to AttackMotion.
  7. Thor files are a bit different because you can have files outside of the "data" folder, so the pathing needs to be fixed. Therefore, when adding a file to a thor file, you need to add the "root" as the base folder: add "root\data\" "C:\whatever.txt" There are some conversions behind the scene to make a thor file compatible with a grf file, otherwise it's troublesome to display it properly in the editor. There are also no issues ignoring that warning, the "root" folder is more or less ignored when saving either way.
  8. Added the options in 1.8.5.3 : help options options /UseGrfMerging=true /TargetGrf=test.grf Drag and drop is a Windows problem. Windows Explorer must have the same privilege as the program you're using for drag and drop to work. I'm assuming your Windows Explorer is running with user privileges, so that means you're running GRF Editor with admin privileges. So to fix the issue, stop running GRF Editor with admin privileges.
  9. This should be fixed now, sorry about that: 1.8.5.3
  10. I added the encryption commands (setKey, encrypt, decrypt) to it in 1.8.5.1. Here's an example: -open test.thor -setKey mykey.grfkey -encrypt -save Where the mykey.grfkey is the file version of your password. You can generate this file via Tool > GRF Encryption:
  11. Well, it seems there's a problem with the custom decompression library you're using...? Not sure what's up there, but you'll probably want to change it to the default compression library. If you have issues loading the default compression library, you'll need to install some VC++ libraries: For Gravity Official Zlib Library (cps.dll), you'll have to install VC++ 2010 (x86). For LZMA Library (by Curiosity, lzma.dll), you'll have to install VC++ 2005 (x86). Same issue as above (most likely). lzma.dll requires VC++ 2005 (x86). You only appear to have x64, which is not compatible.
  12. Functions don't get unloaded when you reload a script. So the script engine thinks that Class_Mastery is a function since it was previously defined here: function script Class_Mastery { But you're using it as a constant variable... everywhere. Either change the names around, like F_Class_Mastery, or remove the function altogether. It feels like you're using this function on an item script, so changing it to F_Class_Mastery would be enough. (Also, you might want to use proper formatting, it's very hard to read.)
  13. If they aren't in your data.grf, then your data.grf isn't the latest. You have a few options available. The easiest option is to download one of the "latest" kRO full client on rAthena, this thread appears to be the most active one: Then use Ragnarok.exe to patch your game afterwards. If your "latest" kRO full client above didn't bother to add the official Gravity patcher (Ragnarok.exe), then you can use the one from Ai4rei here: http://nn.ai4rei.net/dev/rsu/#download (use kRO RAG) and patch the data.grf directly with it. By the looks of it though, the thread above provided the rsu patcher directly so might as well use that. The harder option is to go on https://ro.gnjoy.com and download the official RO game (though I think you have to register first, which may be a problem? Not sure, haven't done that in a while).
  14. Missing LUB files most likely. Seeing as the error title is "package item", I'm assuming there's something wrong with this file: data\luafiles514\lua files\selectpackage\selectpackageitem.lub That'd be my guess.
  15. Ah, that's my bad, I apparently didn't remove the player check in the script function. Change it to: BUILDIN_FUNC(hateffect){ #if PACKETVER_MAIN_NUM >= 20150507 || PACKETVER_RE_NUM >= 20150429 || defined(PACKETVER_ZERO) 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; }
  16. Hello, the final GRF size is the problem here and your texture GRF being 800MB on its own doesn't mean much without knowing the size of the base GRF. That error is shown if the file table offset in the final GRF goes past the 4GB size limit. There's not much I can tell without more information on your end though. Perhaps your GRFs are compacted using the "redirect indexes" option, which makes them seem smaller than they really are. When merging, if the conditions aren't perfect, the GRFs will be unpacted first and then merged together which can trigger the 4GB limit more easily. It's either that or the base GRF size is near 3.4+GB. None of that is helpful at the end of the day though, it seems like you will have to make a new GRF alongside instead of trying to keep compressing/removing stuff in it. There's really not much to do once you reach the size limit and the obvious solution is simply to have another GRF in your RO folder to save a lot of future headaches.
  17. 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
  18. Heya, There isn't anything you can do from the STR file itself. I remember ez2streffect.bson allowing you to change that behavior, but I believe you can't add custom skills in there. So that won't do. Your atlernative is to use hat effects, with "isRenderBeforeCharacter = true" (mini-guide below). Though that requires a lot more source edits on your end since there is currently no support for that behavior (and it's not that well known apparently?). To be clear, yes this can be used on a targeted cell and not only on top of your character. It creates a dummy hidden NPC on the cell and then show a hat effect on that NPC instead. Here's the end result: Mini-guide: Add the effect via data\luafiles514\lua files\hateffectinfo\hateffectinfo.lub using a "reasonable" ID (some IDs just don't work, who knows why). For example: [100] = { resourceFileName = "new_earthdrive\\new_earthdrive_bottom\\new_earthdrive_bottom.str", hatEffectPos = -4, hatEffectPosX = 0, isRenderBeforeCharacter = true, isIgnoreRiding = true, isAdjustPositionWhenShrinkState = false, isAdjustSizeWhenShrinkState = false }, Apply these changes: diff --git a/db/re/skill_db.yml b/db/re/skill_db.yml index cfd23900c..fbb59d834 100644 --- a/db/re/skill_db.yml +++ b/db/re/skill_db.yml @@ -46484,3 +46484,11 @@ Body: Duration1: 10000 Cooldown: 60000 Status: Emergency_Move + - Id: 10100 + Name: NPC_HATEFFECT_POS + Description: Hateffect Pos + MaxLevel: 1 + TargetType: Self + DamageFlags: + NoDamage: true + diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 991b5b1b8..1540d9083 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -5449,6 +5449,26 @@ void clif_getareachar_skillunit(struct block_list *bl, struct skill_unit *unit, if (bl->type == BL_PC) fd = ((TBL_PC*)bl)->fd; + if (unit->group->skill_id == NPC_HATEFFECT_POS) { + // Comment below if you want the effect to show up after using @refresh (not default behavior for skills, that's only the case for ground units) + if (target == SELF) { + return; + } + + struct npc_data npc; + + memset(&npc, 0, sizeof(struct npc_data)); + + npc.bl = unit->bl; + npc.bl.type = BL_NPC; + npc.name[0] = '\0'; + npc.vd.class_ = 139; + + clif_set_unit_idle(&npc.bl, false, target, bl); + clif_hat_effects2(bl, &unit->bl, unit->group->skill_lv, true, target); + return; + } + if (unit->group->state.guildaura) return; @@ -5564,6 +5584,14 @@ void clif_skill_delunit(struct skill_unit *unit) nullpo_retv(unit); + if (unit->group && unit->group->skill_id == NPC_HATEFFECT_POS) { + WBUFW(buf, 0) = 0x80; + WBUFL(buf, 2) = unit->bl.id; + WBUFB(buf, 6) = CLR_OUTSIGHT; + clif_send(buf, packet_len(0x80), &unit->bl, ALL_SAMEMAP); + return; + } + WBUFW(buf, 0)=0x120; WBUFL(buf, 2)=unit->bl.id; clif_send(buf,packet_len(0x120),&unit->bl,AREA); @@ -21218,6 +21246,25 @@ void clif_hat_effects( map_session_data* sd, struct block_list* bl, enum send_ta #endif } +/// Send hat effects to the client (ZC_HAT_EFFECT). +/// 0A3B <Length>.W <AID>.L <Status>.B { <HatEffectId>.W } +void clif_hat_effects2(struct block_list* src, struct block_list* effect_bl, uint16 effect_id, bool enable, enum send_target target) { +#if PACKETVER_MAIN_NUM >= 20150507 || PACKETVER_RE_NUM >= 20150429 || defined(PACKETVER_ZERO) + unsigned char buf[13]; + + if (!effect_bl || !src) + return; + + WBUFW(buf, 0) = 0xa3b; + WBUFW(buf, 2) = 13; + WBUFL(buf, 4) = effect_bl->id; + WBUFB(buf, 8) = enable; + WBUFL(buf, 9) = effect_id; + + clif_send(buf, 13, src, target); +#endif +} + void clif_hat_effect_single( map_session_data* sd, uint16 effectId, bool enable ){ #if PACKETVER_MAIN_NUM >= 20150507 || PACKETVER_RE_NUM >= 20150429 || defined(PACKETVER_ZERO) nullpo_retv( sd ); diff --git a/src/map/clif.hpp b/src/map/clif.hpp index 1bf10b262..c8f47b049 100644 --- a/src/map/clif.hpp +++ b/src/map/clif.hpp @@ -802,6 +802,7 @@ 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_effects2(struct block_list* src, struct block_list* effect_bl, uint16 effect_id, bool enable, enum send_target target); void clif_hat_effect_single( map_session_data* sd, uint16 effectId, bool enable ); void clif_item_skill(map_session_data *sd,uint16 skill_id,uint16 skill_lv); diff --git a/src/map/script.cpp b/src/map/script.cpp index 027587945..a261e64ec 100644 --- a/src/map/script.cpp +++ b/src/map/script.cpp @@ -26896,6 +26896,36 @@ BUILDIN_FUNC(getfamerank) { return SCRIPT_CMD_SUCCESS; } +BUILDIN_FUNC(showhateffectpos) { + int hat_effect_id = script_getnum(st, 2); + int x = script_getnum(st, 3); + int y = script_getnum(st, 4); + int duration = script_getnum(st, 5); + struct block_list* bl; + + if (script_hasdata(st, 6)) { + bl = map_id2bl(script_getnum(st, 6)); + } + else { + bl = map_id2bl(st->oid); + } + + if (!bl) { + return SCRIPT_CMD_FAILURE; + } + + std::shared_ptr<s_skill_unit_group> group = skill_unitsetting(bl, NPC_HATEFFECT_POS, hat_effect_id, x, y, duration); + + if (group != NULL) { + script_pushint(st, group->group_id); + } + else { + script_pushint(st, -1); + } + + return SCRIPT_CMD_SUCCESS; +} + BUILDIN_FUNC(isdead) { map_session_data *sd; @@ -27680,6 +27710,7 @@ struct script_function buildin_func[] = { BUILDIN_DEF(getfame, "?"), BUILDIN_DEF(getfamerank, "?"), BUILDIN_DEF(isdead, "?"), + BUILDIN_DEF(showhateffectpos, "iiii?"), BUILDIN_DEF(macro_detector, "?"), #include <custom/script_def.inc> diff --git a/src/map/skill.cpp b/src/map/skill.cpp index 611aff452..c9a695768 100755 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -15058,6 +15058,12 @@ std::shared_ptr<s_skill_unit_group> skill_unitsetting(struct block_list *src, ui case WH_FLAMETRAP: limit += 3000 * (sd ? pc_checkskill(sd, WH_ADVANCED_TRAP) : 5); break; + case NPC_HATEFFECT_POS: + limit = flag; + interval = flag + 1000; + flag = 0; + val2 = skill_lv; + break; } // Init skill unit group @@ -15702,6 +15708,9 @@ int skill_unit_onplace_timer(struct skill_unit *unit, struct block_list *bl, t_t case UNT_DUMMYSKILL: switch (sg->skill_id) { + case NPC_HATEFFECT_POS: + // don't do anything for this skill + break; case SG_SUN_WARM: //SG skills [Komurka] case SG_MOON_WARM: case SG_STAR_WARM: { @@ -20500,6 +20509,9 @@ int skill_delunit(struct skill_unit* unit) tsc->getSCE(SC__MANHOLE)->val4 = 0; // Remove the Unit ID } break; + case NPC_HATEFFECT_POS: + clif_hat_effects2(&unit->bl, &unit->bl, unit->group->skill_lv, false, ALL_SAMEMAP); + break; } clif_skill_delunit(unit); @@ -20734,6 +20746,9 @@ int skill_delunitgroup_(std::shared_ptr<s_skill_unit_group> group, const char* f } } break; + case NPC_HATEFFECT_POS: + clif_hat_effects2(&group->unit->bl, &group->unit->bl, group->skill_lv, false, ALL_SAMEMAP); + break; } if (src->type==BL_PC && group->state.ammo_consume) diff --git a/src/map/skill.hpp b/src/map/skill.hpp index c22e0ad70..04dc782d9 100644 --- a/src/map/skill.hpp +++ b/src/map/skill.hpp @@ -2494,6 +2494,8 @@ enum e_skill { ABR_NET_REPAIR, ABR_NET_SUPPORT, ABR_INFINITY_BUSTER, + + NPC_HATEFFECT_POS = 10100, }; /// The client view ids for land skills. Call the effect from the source with something like this (100 being your effect ID): case NPC_CUSTOM_SKILL: // skill related stuff... skill_unitsetting(src, NPC_HATEFFECT_POS, 100, x, y, 2000); break; or if you want to test first with the script command .@effect_id = 100; .@x = 152; .@y = 187; .@duration = 2000; showhateffectpos .@effect_id, .@x, .@y, .@duration; The downside of this method is that the hat effects always loop. So you have to know in advance the duration of the effect. You also probably want to add some empty frames at the end of your STR animation for some buffer and prevent the loop from showing up at all. Best solution I can think of, goodluck! hateffectpos.diff
  19. Well, the error itself isn't too helpful. 0x8b3 is clif_showscript. So one of the possible cause is a script sending "showscript" (a script command) to a player too many times, probably in an infinity loop would be my guess. Though, the error message only shows the last packet that exceeded the length of the connection buffer, so a prior packet could be responsible too. It's hard to know for sure. If the error is somewhat new, then you should know if this rings a bell or not. If you still can't figure it out, then you could dump the last packet in your console (in socket.cpp): ShowDump(s->wdata + s->wdata_size, len); ShowError("WFIFOSET: Maximum write buffer size for client connection %d exceeded, most likely caused by packet 0x%04x (len=%" PRIuPTR ", ip=%lu.%lu.%lu.%lu).\n", fd, WFIFOW(fd,0), len, CONVIP(s->client_addr)); Then you can see what the string used by showscript was and track down the issue a bit more easily. If nothing else, then you'd have to dump the entire write butter, but hopefully you won't have to do that. Goodluck!
  20. Well your links are not uploaded properly, so I can't see. Though, the gif format doesn't allow transparency. Most people will simply pick a black background as it is what would yield the best results.
  21. Well, ground units (Land Protector and traps) do disappear by themselves when you change map. That is the default behavior and it's handled by this code in pc_setpos: if (battle_config.clear_unit_onwarp&BL_PC) skill_clear_unitgroup(&sd->bl); You can copy this code in pc_dead if you want to do make ground units disappear on player death as well.
  22. That's not really possible without rewritting most of the emulator. Everything is made with the assumption that the account ID is unique to a player. A simple example would be a script function like "rid2name". Which name should that return, since they both players have the same rid (the rid is the account ID, to be clear)? Plus, that's the easy part. Imagine using a storage on two characters in the same account; you'd be able to dupe items left and right and that's just one scenario.
  23. Well, it looks like it managed to read the GRF fine so someone probably just changed the header for whatever reason. It gives you that error because that's not what is expected at all from the GRF format. You can hex the file manually and change the start to "Master of Magic\0". You might be able to just save the GRF again as well and it will fix the issue...? It managed to load it anyway, so you could just keep using the GRF normally.
  24. The error says: "The entry is either corrupted or encrypted". If you want to read the file, decrypt the content first.
  25. This is a barter shop, not a normal shop. You should have a more readable format below with "barter_clear" and "barter_add", though those are custom functions (found here if interested). rAthena went with a yaml approach for these types of shops, so you'll have to convert those yourself. You can find an example in npc/re/merchants/barters/refine.yml. The tool can't produce a yaml output because it would need to convert item IDs to aegis names, and that's just a nightmare nobody wants to spend time on.
×
×
  • Create New...