Jump to content

Tokei

Members
  • Posts

    664
  • Joined

  • Last visited

  • Days Won

    90

Posts posted by Tokei

  1. Heya,

    • Did you check if the char-server has loaded properly first? The map-server will not connect to the char-server unless the char-server is loaded, so you might want to check that. It should be saying "Awaiting maps from map-server."
    • For inter-server connections, you should also use the localhost IP (127.0.0.1). This goes for map-server to char-server and char-server to login-server. Regardless of your server being public or not, inter-server connections should remain in a "closed" system.
    • But ultimately, since you're using your private IP to connect right now, it would seem to indicate there is also a problem with your port configuration. So make sure port 6121 is forwarded to 192.168.1.14 in your router configuration. Note that this step is only required if you plan to make your server public. You should make sure that the server can run locally first using the localhost IP.
  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

    • Upvote 1
    • Love 2
    • MVP 3
  3. Take a look at System\OngoingQuestInfoList_True.lub (or Sakray.lub, depending of your client version), for example:

    	[7858] = {
    		Title = "불온한 소리의 정체 조사",
    		IconName = "ico_ep.bmp",
    		Description = {
    			"리벨리온 대원 일부는 격벽 너머에서 들려오는 소리의 정체를 밝히기 위해 이미 움직였다. 루키는 소리의 근원이 괴물이라면 멋지게 해치워 달라고 했다."
    		},
    		Summary = "괴물 사냥",
    		RewardEXP = "800000",
    		RewardJEXP = "800000",
    		RewardItemList = {
    			{ ItemID = 25723, ItemNum = 15 }
    		}
    	},

     

  4. On 1/9/2023 at 11:27 AM, Geezy said:

    Hi, @Tokei!

    I've been having this error for generating maps in these settings:

    image.png.61b435dc80ee25cd6c4243e0afc1a6ed.png

     

    Error:

    image.png.5c6de761d5ed06537b92e5ae548c6e21.png

    Would you know what the problem might be?

    Thanks in advance!

    Make sure you are at the latest version: 1.8.4.6 (link in the download description page).

    5 hours ago, paaaaatch said:

    I don't know why I'm having this error. Can someone help me? Already re-installed GRF Editor.image.thumb.png.e234bcdc0308b7d326378a8ccf7dad7f.png

    Well, that means it found no *.gat files in your currently opened GRF. You're not showing what's in there, so I don't know.

  5. This script is... way more complicated than it has to be. The rand function is misused in two different places, which I'm guessing is the main problem you're having. First thing first:

    .@r > rand( 1, 1000 )

    ^ that's a big no-no. Randomized numbers for chances are always from [0-999], not [1-1000]. You then use rand(1000); or rand(0, 999), but the former is preferred for various reasons. Also, normally you put the rand first for clarity's sake, but that one is preference:

    if (rand(1000) < .@r)

    Declaring functions at the beginning is fine, but it's also unecessary and not used that much anymore. Use callsub instead, though... using local scope functions for this script is overkill.

    rAthena scripts prefer the no-space syntax for function arguments, but that one is up to you.

    As for the main problem you're having, that is because .@in is returning negative values because of rand( 1, getd( ".size_tot_"+ getarg(0) ) ) has invalid bounds and... well, because this is overly complicated so it's not really worth spending time deciphering what it does. I suggest a simpler approach:

    prontera,155,177,5	script	random	615,{
    	if (countitem(.rare_ticket)) {
    		mes "Rare Ticket";
    		.@r = .rate_chance_rare; // chance
    		.@ticket = .rare_ticket;
    	}
    	else if (countitem(.normal_ticket)) {
    		mes "Normal Ticket";
    		.@r = .rate_chance_normal; // chance
    		.@ticket = .normal_ticket;
    	}
    	else {
    		mes "random";
    		close;
    	}
    	
    	switch(select("Go.:No.:")) {
    		case 2:
    			close;
    	}
    	
    	delitem .@ticket, 1;
    	
    	if (rand(1000) < .@r) {
    		mes "random";
    		getitem .rare[rand(.rare_size)], 1;
    		close;
    	}
    	else {
    		mes "random";
    		getitem .normal[rand(.normal_size)], 1;
    		close;
    	}
    	
    	end;
    OnInit:
    	.normal_ticket = 501;
    	.rare_ticket = 502;
    	.rate_chance_rare = 500; // chance to get a rare costume with rare ticket (500 = 50%)
    	.rate_chance_normal = 100; // chance to get a rare costume with normal ticket (100 = 10%)
    	
    	// rare items
    	setarray .rare,5909,5912,5914,5915,5977,5979,5980,15280,15841,15843,15858;
    	.rare_size = getarraysize(.rare);
    	
    	// normal items
    	setarray .normal,50001;
    	.normal_size = getarraysize(.normal);
    	end;
    }

     

  6. 1 hour ago, Note Note said:

    Hi Tokei thanks for your grf editor!

    Im playing at a server with custom maps that are encrypted (like 1@exhn, etc etc). Was able to get the map in kro but there are custom lua files that makes me crash. Was wondering if its possible to bypass this? Thanks! 

    The lub files are irrelevant, just don't remove/modify/replace them.

  7. The separator used for menus is the colon, ":". So just change "%" to "%:".

    Though, this line:

    .@part = .@count[select(.@menu$)];

    doesn't make a whole lot of sense. Keep in mind that select returns the first value as 1 instead of 0, so you have to remove 1. What you probably wanted to write was the following.

    .@selected = select(.@menu$) - 1;
    .@itemid = .@item[.@selected];

    Also, not... an issue, but you'd probably want to change your variable names a bit by adding an 's' to your arrays otherwise it becomes very messy (and addding [0] is redundant).

    copyarray .@items, $@MobDrop_item, .@count;

    Also, might as well use sprintf for your drop rates, it makes your life easier. So something like this:

    	mes "Monster ID: "+getmonsterinfo(.@mob_id,MOB_NAME)+"'";
    	
    	if (getmobdrops(.@mob_id)) {	// 'getmobdrops' returns 1 on success
    		// immediately copy global temporary variables into scope variables,
    		// since we don't know when 'getmobdrops' will get called again for
    		// another mob, overwriting your global temporary variables
    		.@count = $@MobDrop_count;
    		copyarray .@items, $@MobDrop_item, .@count;
    		copyarray .@rates, $@MobDrop_rate, .@count;
    
    		mes getmonsterinfo(.@mob_id,MOB_NAME) + " - " + .@count + " drops found:";
    		
    		for (.@i = 0; .@i < .@count; .@i++) {
    			.@menu$ = .@menu$ + sprintf("%d (%s) %d.%02d%%", .@items[.@i], getitemname(.@items[.@i]), .@rates[.@i] / 100, .@rates[.@i] % 100) + ":";
    		}
    		
    		.@menu$ = .@menu$ + ":";
    	}
    	else {
    		mes "Unknown monster ID.";
    	}
    	
    	.@selected = select(.@menu$) - 1;
    	.@item = .@items[.@selected];
    	.@rate = .@rates[.@selected];

     

  8. On 11/30/2022 at 12:18 AM, KappaJus said:

    Snake Dungeon(jor_dun01, jor_dun02)

    Hmm, well I was able to make it into a flat map without any issues? Make sure you are using the latest version in the description.

  9. 10 hours ago, KappaJus said:

    Hi @Tokei

    I'm playing on a server that is currently on the latest episode (19.1) and I tried to use grf editor to make gray map. There are maps that are crashing when warping to a newer area and just wondering what could be the issue that I've encountered?

    Thank you.

    What is the map name?

  10. 15 minutes ago, Lily said:

    Heya! 

    Co-admin currently running into same issue as  ermit123 .  The pc recently was reinstalled/got a fresh install of windows.  .net framework is installed, Microsoft visual C++ from 2005 until 2022 is installed yet the following error continues to occur: Failed to load the decompression library (Files.lzma.dll).

    That usually means you're missing a VC++ library, though I don't remember which one it was compiled on. I'm guessing it's most likely VC++ 2010 (maybe 2008 as well). I'm guessing you picked x64 instead of x86 though.

  11. 5 hours ago, Thibazu said:

    Hello !
    First of all thanks a lot for creating this software it's wayyy more convenient than the other alternatives.
    I have a little question, would it be possible for the "Save as Gif" option to create Gifs with transparent background because when I set the opacity of the background to 0 the output gif has a solid background composed of the grid that's shown on the editor.

    Heya,

    Unfortunately, that is not really possible. The gif format doesn't support semi-transparency. One pixel color can be transparent (which is commonly the pink color in RO, or 0xff00ff). While... this is possible to support, it would also make any other semi-transparent pixel look horrible with shades of pink for any of your other semi-transparent layers (I'd show you an example, but I'm on phone right now). It's a limitation of the gif format, there's not much I can do there. That's why I didn't really bother with transparency support while saving gif images and instead opted of rendering the str as they are directly shown in the preview window. I would suggest simply changing the background to black to make these gifs as this is when you'll have the best output. Alternatively, you could change the background color to wherever you plan on displaying these gifs, but you'll quickly see white background isn't a great choice for most str. Saving those animations is just really troublesome.

    The only real "solution" I could come up with is saving the output as a series of PNG images (which I'm not sure is actually possible, but worth looking into). Though, that wouldn't really solve what you're trying to do, at least I don't think...?

  12. Heya,

    You can create a new script command:

    static int buildin_killmonsterarea_sub(struct block_list *bl,va_list ap)
    {
    	int   x1       = va_arg(ap, int);
    	int   y1       = va_arg(ap, int);
    	int   x2       = va_arg(ap, int);
    	int   y2       = va_arg(ap, int);
    
    	if (x1 <= bl->x && bl->x <= x2 &&
    		y2 <= bl->y && bl->y <= y1)
    		status_kill(bl);
    	return 0;
    }
    
    BUILDIN_FUNC(killmonsterarea)
    {
    	const char *mapname;
    	int16 m;
    	int x1, x2, y1, y2;
    
    	mapname=script_getstr(st,2);
    
    	if( (m = map_mapname2mapid(mapname))<0 )
    		return 0;
    
    	x1=script_getnum(st,3);
    	y1=script_getnum(st,4);
    	x2=script_getnum(st,5);
    	y2=script_getnum(st,6);
    
    	map_foreachinmap(buildin_killmonsterarea_sub,m,BL_MOB, x1, y1, x2, y2);
    	return SCRIPT_CMD_SUCCESS;
    }
          
    // def
    BUILDIN_DEF(killmonsterarea,"siiii"),

     

    • Upvote 1
  13. 9 hours ago, ez2on said:

    open and save an existing .str file, the Bias value is lost.

    I am not able to reproduce this issue. Str files do not have a bias value to begin with though, that's emulated. If the bias value isn't showing up, it could be that it simply failed to guess the value properly. Either way, I would need an example (with a file if possible) on how to reproduce.

    As for the second part, at 0x10c, the value should indeed be 0x00000000. That is the delay for texture animation. That value, "0x7f800000", means "Infinifty" which is usually the result of a division by 0. That's... a bug with the original str file. I saw it in your EZV file and I fixed the output to say "0" instead as it didn't make any sense to save the value as "Infinity" in a EZV file. As for the str file itself, it has no impact since the animation type is set to normal, and therefore the value isn't read at all. I will make a small change however and make sure this value (infinity) can't propagate anywhere either and fix it when loading the str file instead. I'll wait for more information on the bias issue above though.

  14. On 10/30/2022 at 2:02 PM, ez2on said:

    If you save it as ezv,A single frame has been changed.

    Hmm, I'm not able to reproduce your issue. Saving as ezv works fine on my end. I have uploaded a newer version (1.0.6) to save ezv as 0.95 instead of 0.94 to support tga images. But that doesn't appear to be related to your issue at all, so you'd have to give me a way to reproduce the problem.

    • Like 1
  15. Updated to 1.8.4.5:

    • Fixed a bunch of issues with the dark theme.
    • Fixed focussing in the tree view.
    • Added Str preview support.
    • Added support for RSW version 0x206.
    • Fixed another packed DLL issue regarding GRF encryption.
    • Extracting resources will now export all files.
    • Added more checks when saving GRFs beyond 4 GB.
    On 10/29/2022 at 9:25 PM, Pokye said:

    Thanks, working now. A doubt, this new version, was also fixed the problem of GRF above 4GB? I've seen some comments here reporting about this.

    I've added a "fix" for this issue, but like I said last time, it isn't an issue. GRF Editor will now prevent you from saving files past 4 GB of size. If your GRFs are reaching that size, you will need to use another GRF alongside for your client. There are no other solutions.

    5 hours ago, KeiKun said:

    Generating cps.dll gives this error.

    --------------          Message          --------------
    Field not found: 'Utilities.Services.EncodingService.ANSI'.
    --------------        Stack trace        --------------
       at GrfToWpfBridge.Application.DefaultErrorHandler._reportAnyManagedExceptions(String message, Exception exception, ErrorLevel errorLevel)
       at GrfToWpfBridge.Application.DefaultErrorHandler.Handle(Exception exception, ErrorLevel errorLevel)
       at GRFEditor.WPF.EncryptorDialog._buttonGenerateClientConf_Click(Object sender, RoutedEventArgs e)
       at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
       at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
       at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
       at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
       at System.Windows.Controls.Primitives.ButtonBase.OnClick()
       at System.Windows.Controls.Button.OnClick()
       at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
       at System.Windows.UIElement.OnMouseLeftButtonUpThunk(Object sender, MouseButtonEventArgs e)
       at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
       at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
       at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
       at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
       at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)
       at System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e)
       at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
       at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
       at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
       at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
       at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
       at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args)
       at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
       at System.Windows.Input.InputManager.ProcessStagingArea()
       at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
       at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
       at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
       at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
       at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
       at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
       at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
       at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
       at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
       at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
       at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
       at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
       at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
       at System.Windows.Window.ShowHelper(Object booleanBox)
       at System.Windows.Window.Show()
       at System.Windows.Window.ShowDialog()
       at GRFEditor.EditorMainWindow._menuItemEncryptor_Click(Object sender, RoutedEventArgs e)
       at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
       at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
       at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
       at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
       at System.Windows.Controls.MenuItem.InvokeClickAfterRender(Object arg)
       at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
       at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
       at System.Windows.Threading.DispatcherOperation.InvokeImpl()
       at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Windows.Threading.DispatcherOperation.Invoke()
       at System.Windows.Threading.Dispatcher.ProcessQueue()
       at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
       at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
       at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
       at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
       at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
       at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
       at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
       at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
       at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
       at System.Windows.Application.RunDispatcher(Object ignore)
       at System.Windows.Application.RunInternal(Window window)
       at System.Windows.Application.Run(Window window)
       at GRFEditor.GRFEditorMain.Main(String[] args)
    
    --------------         Exception         --------------
    System.MissingFieldException: Field not found: 'Utilities.Services.EncodingService.ANSI'.
       at ..(Byte[] , String , Byte[]& , Byte[] , Byte[] , String , )
       at Encryption.Ee322.b3c0cf5bc709dff2229e99124d1968b7(String c5c85cccb9b0fd3067387800c587f028, String outputClientPath, Byte[] f70c5dbd6c0e10ca9e06d246bbb58501c928f6a25037efd3ae810a02f3aa16ec, Byte[] cps, Byte[] client, Byte[]& newClient)
       at GRFEditor.WPF.EncryptorDialog._buttonGenerateClientConf_Click(Object sender, RoutedEventArgs e)

     

    EDIT:
    I went and use GRF Editor v1.8.4.1.zip, which doesn't have the problem.

    Should be fixed now.

    • Love 1
    • MVP 2
  16. Updated to 1.8.4.3 :

    • Added support for json and bson file formats (you can save as a bson file after editing).
      • Only common types are supported.
    • Fixed a bug with the lub decompiler regarding non-latin strings not being enclosed properly.
    • Upvote 1
  17. On 10/26/2022 at 8:06 AM, paaaaatch said:

    Can someone help me with this? I can't generate map because of this.

    image.png

    It's failing to save the file because you have the file opened in GRF Editor already. You can't write/modify a file that's being used by another program. So as the error says, the file is locked.

  18. 49 minutes ago, 15peaces said:

    But the RO client doesn't support grfs > 2GB at all (or did I miss something?), so why should the grf editor do? ^^

    The client can read up to uint32, so ~4GB. But you are indeed correct, GRF Editor shouldn't allow more than that either for obvious reasons. Though the check put in place for size limit is obviously not working, so I'd have to fix that.

    • Like 1
  19. Heya,

    A few comments first:

    • I assume that this script is going to be duplicated since you have multiple copies of it in your replay.
    • I made it into a floating script instead.
    • There are no handy methods to use for making a character walk towards a target with 1 cell distance (it will try to go on top of the target). If you want something more convenient, you'll have to use unitwalk with x/y coordinates, or make your own function. Though for a starting script, unitwalkto will do.
    • Since you can break the script by simply walking away, while unitwalkto is running, it will trigger the OnOpenChest event label for some unknown reason. So you need to check the distance again. Plus, by doing so, you also prevent other type of exploits like using close confine.
    • I added an ID next to the NPC name (World Boss Treasure#ID), which is used to prevent another exploit:
      • If two players talk to the treasure at the same time, they'll both be able to get the items from the treasure box, whether or not you disabled the NPC.
      • NPC variables (those starting with a .) are shared among all the duplicated NPCs. That's why I use an unique ID to track whether the box was already looted or not.
    -	script	World Boss Treasure#wb	1324,{
    	getmapxy(.@map$, .@npc_x, .@npc_y, 0);
    	getmapxy(.@map$, .@player_x, .@player_y, 1);
    	
    	.@distance = distance(.@npc_x, .@npc_y, .@player_x, .@player_y);
    	
    	if (.@distance > 1) {
    		unitwalkto getcharid(3), getnpcid(0), strnpcinfo(0) + "::OnOpenChest";
    		end;
    	}
    	
    	goto OnOpenChest;
    	end;
    OnOpenChest:
    	getmapxy(.@map$, .@npc_x, .@npc_y, 0);
    	getmapxy(.@map$, .@player_x, .@player_y, 1);
    	
    	.@distance = distance(.@npc_x, .@npc_y, .@player_x, .@player_y);
    	
    	if (.@distance > 1) {
    		end;
    	}
    	
    	progressbar "ffff00", 10;
    	.@id = atoi(strnpcinfo(2));
    	
    	// I presume you don't want multiple people to loot the same chest...?
    	if (.npc_disabled[.@id]) {
    		//dispbottom "This chest has been looted by someone else!";
    		end;
    	}
    	
    	specialeffect EF_COIN;
    	
    	.wb_treasure[.wb_treasure_size++] = getcharid(3);
    	
    	setarray .@catch, 30203, 30202, 607, 504; // List of Junk/Other
    	getitem .@catch[rand(getarraysize(.@catch))], 1;
    	
    	disablenpc strnpcinfo(0);
    	.npc_disabled[.@id] = true;
    	initnpctimer;
    	end;
    OnReward:
    	.@id = atoi(strnpcinfo(2));
    	.npc_disabled[.@id] = false;
    	deletearray .wb_treasure;
    	enablenpc strnpcinfo(0);
    	initnpctimer;
    	end;
    OnTimer7200000:
    	disablenpc strnpcinfo(0);
    	stopnpctimer;
    	end;
    }
    
    prontera,150,180,3	duplicate(World Boss Treasure#wb)	World Boss Treasure#1	1324
    prontera,152,180,3	duplicate(World Boss Treasure#wb)	World Boss Treasure#2	1324
  20. The simplest way to do that is via a status effect. You give the status when the player uses @pk, and when the status runs out, it removes the pk mode.

    int atcommand_pkmode( const int fd, struct map_session_data *sd, const char *command, const char *message ) {
     
    	nullpo_retr(-1, sd);
    
    	if (!sd->state.pk_mode) {
    		sd->state.pk_mode = 1;
    		sc_start(&sd->bl, &sd->bl, SC_PK_DISABLE, 100, 0, 60 * 60 * 10000);
    		clif_displaymessage(sd->fd, "You are now no longer in PK mode.");
    	} else {
    		sd->state.pk_mode = 0;
    		status_change_end(&sd->bl, SC_PK_DISABLE);
    		clif_displaymessage(sd->fd, "Returned to normal state.");
    	}
    
    	return 0;
    }

     

    And define the SC_PK_DISABLE status:

    diff --git a/db/re/status.yml b/db/re/status.yml
    index 96693fdce..40693394c 100644
    --- a/db/re/status.yml
    +++ b/db/re/status.yml
    @@ -8166,3 +8166,9 @@ Body:
           NoClearbuff: true
         End:
           Sub_Weaponproperty: true
    +  - Status: Pk_Disable
    +    #Icon: EFST_PK_DISABLE
    +    Flags:
    +      NoDispell: true
    +      NoBanishingBuster: true
    +      NoClearance: true
    diff --git a/src/map/script_constants.hpp b/src/map/script_constants.hpp
    index 25ce19a67..ddbd1c466 100644
    --- a/src/map/script_constants.hpp
    +++ b/src/map/script_constants.hpp
    @@ -1844,6 +1844,7 @@
     	export_constant(SC_M_LIFEPOTION);
     	export_constant(SC_S_MANAPOTION);
     	export_constant(SC_SUB_WEAPONPROPERTY);
    +	export_constant(SC_PK_DISABLE);
     
     #ifdef RENEWAL
     	export_constant(SC_EXTREMITYFIST2);
    diff --git a/src/map/status.cpp b/src/map/status.cpp
    index 42005bdae..4b6f462fb 100644
    --- a/src/map/status.cpp
    +++ b/src/map/status.cpp
    @@ -13351,6 +13351,11 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid)
     				pc_delabyssball( *sd, sd->abyssball );
     			}
     			break;
    +		case SC_PK_DISABLE:
    +			if (sd) {
    +				sd->state.pk_mode = 0;
    +			}
    +			break;
     	}
     
     	// Reset the options as needed
    diff --git a/src/map/status.hpp b/src/map/status.hpp
    index f103cd018..f2b79e058 100644
    --- a/src/map/status.hpp
    +++ b/src/map/status.hpp
    @@ -1230,7 +1230,7 @@ enum sc_type : int16 {
     	SC_S_MANAPOTION,
     
     	SC_SUB_WEAPONPROPERTY,
    -
    +	SC_PK_DISABLE,
     #ifdef RENEWAL
     	SC_EXTREMITYFIST2, //! NOTE: This SC should be right before SC_MAX, so it doesn't disturb if RENEWAL is disabled
     #endif

    (Also... shouldn't this message "You are now no longer in PK mode." be "You are now in PK mode." instead?)

    • Love 1
×
×
  • Create New...