Jump to content

Tokei

Members
  • Posts

    700
  • Joined

  • Last visited

  • Days Won

    109

Posts posted by Tokei

  1. You'd still need to modify your source to do that. You can be more restrictive as well and attach more "parameters". killerid won't work as it isn't added to the script yet. So something like...

    	if (src && src->type == BL_PC && bl->type == BL_MOB && damage > 0) {
    		struct mob_data *md = (struct mob_data *)bl;
    		mapreg_setreg(reference_uid(add_str("$@attacked_mid"), 0), md->id);
    		mapreg_setreg(reference_uid(add_str("$@attacked_gid"), 0), md->bl.id);
    		npc_event_do_id("MyNPC::OnEvent", src->id);
    	}
    OnEvent:
    	switch($@attacked_mid) {
    		case 1002:
    			if (rand(100) < 5) {
    				getitem 501, 1;
    			}
    			
    			break;
    	}
    	
    	end;

     

    • Love 1
  2. It's possible, but it's also... very intensive for your server and I would highly recommend against it.

    In battle.cpp, in battle_calc_damage, add the NPC call:

    	if (bl->type == BL_PC) {
    		npc_event_do_id("MyNPC::OnEvent", bl->id);
    	}

    And with the matching script:

    -	script	MyNPC	-1,{
    	end;
    OnEvent:
    	//callfunc("F_Function");
    	dispbottom "You have attacked.";
    	end;
    }

     

    It would be much better to add code in the source for what you want to do instead.

  3. Well, the question is hard to answer because there is nothing wrong with the script. The announcements are clearly wrong, and it doesn't account for server reboots where the rates would be reset to Friday's rates, but besides that... it works as you'd expect. What issue do you have in particular?

  4. Well you can get the full command used with something like:

    OnNavigate:
    	.@cmd$ = implode(.@atcmd_parameters$, " ");
    
    	if (isloggedin(getcharid(3, .@cmd$)) != 1) {
    		message strcharinfo(0), "Target player '" + .@cmd$ + "' is offline or do not exist.";
    	}
    
    	sleep2 1;
    	unitwalkto getcharid(3), getcharid(3, .@cmd$);
    	end;

    Though, unitwalkto is very limited and will most likely fail in most scenarios.

    • Upvote 1
  5. Well, they are misaligned in the RSW file because RSM models are centered using a bounding box, while RSM2 are not centered by their bounding box. So to align them within the RSW file, you need to calculate the difference between the two.

    • Calculate the bounding box for the RSM2 file, calculate the offset between the center of it with the location in the RSW.
    • Calculate the bounding box for the RSM file, add the previous offset to the RSW file to re-align the model­.

    But technically speaking, the converted RSM model is working as intended.

    • Upvote 1
    • Love 1
  6. 1 hour ago, Emistry said:

    true, but its not really an ideal solution.

    why? although the emulator is kinda updated but the emulator still assume array value 0 still exists.

    
    .array[4001] = 999999;
    debugmes ".array size = " + getarraysize(.array); // output: .array size = 4002

    this meant, your current array total size is 4002, which wasted the memory the allocated for the total of 4001 data from index 0 to 4000, and you dont even need it.

    dont forgot that card_id could be above 5 digits or even 6 digits ID nowadays, which will end up wasting even more than we expected..

     

    Heya,

    I just wanted to add there that this is actually incorrect (unless there was a major update on rAthena I'm not aware of). The script engine does not allocate memory for the 0 to 4000 values in your example. Technically speaking, arrays are emulated and not actually arrays in the source. When you use ".array[4001]", the engine does the following:

    • ".array" is a string that gets indexed. The string is given a unique number, say 9048. From then on, everytime the string ".array" is used, it will be refered to as 9048. This is called the id.
    • 4001 is the index.
    • uid (id and index): Both of the values above combined as one (32bit for the id, 32bit for the index, making up 64bit for the uid).

    The uid with its value is then stored in a big collection for the whole NPC script. This big collection also contains the values of other non-array variables such as ".temp = 20;". They are all stored in the same place. If you had written the variable as ".array_4001", it would have created a new unique value for the string such as 9049 and the index would have been 0. As you need to index the string everytime you create a new variable, using setd with a big amount of variables is usually not a good practice. Using .array[4001] is handled better source wise.

    Quick note, but this is also why .@var = 5 is identical to .@var[0] = 5 and both would return the same value. They have the same uid.

    What rAthena also does when you use an index greater than 0 is that it starts keeping track of the array keys (members). So say you used .array[4001], it will keep track that 4001 is a member of the array for the .array variable.

    As for getarraysize(), it should be used very carefully and never in the condition of the for loop. getarraysize() does the following:

    • Checks if the .array value exists in the big collection. If not, adds 0 as a member of the array. (This is more of a hack, as it's impossible to know otherwise if [0] is part of the array or not.)
    • Go through all the members of the array and find the highest key, then does + 1.

    So in your case, using getarraysize(.array) would indeed return 4002 as 4001 is the only member of the array. Using arrays instead of getd/setd would be much faster (and cleaner) in your script sample as a result:

    prontera,155,181,5	script	Card Buyer	757,{
    	mes "["+strnpcinfo(1)+"]";
    	mes "You have any card to sell ? <3";
    	next;
    	getinventorylist;
    	for (.@i = 0; .@i < @inventorylist_count; .@i++) {
    		.@price = .card[@inventorylist_id[.@i]];
    		if (.@price)
    			.@menu$ = .@menu$ + getitemname(@inventorylist_id[.@i]) + " ^FF0000"+F_InsertComma(.@price)+" Zeny^000000";
    		.@menu$ = .@menu$ + ":";
    	}
    	.@i = select(.@menu$) - 1;
    	clear;
    	.@price = .card[@inventorylist_id[.@i]];
    	mes "["+strnpcinfo(1)+"]";
    	mes "Sell "+getitemname(@inventorylist_id[.@i])+" for ^FF0000"+F_InsertComma(.@price)+" Zeny^000000?";
    	if (select("Confirm", "Cancel") == 1) {
    		delitem @inventorylist_id[.@i], 1;
    		Zeny += .@price;
    		clear;
    		mes "["+strnpcinfo(1)+"]";
    		mes "You have sold "+getitemname(@inventorylist_id[.@i])+" for ^FF0000"+F_InsertComma(.@price)+" Zeny^000000.";
    	}
    	close;
    function	AddCard	{
    	.@price = getarg(0, 0);
    	.@getargcount = getargcount();
    	
    	for (.@i = 1; .@i <= .@getargcount; .@i++)
    		.card[getarg(.@i, 0)] = .@price;
    	return;
    }
    
    OnInit:
    	// AddCard( <zeny>, <card_id>...);
    	AddCard( 10000, 4001, 4002, 4003, 4004);
    	AddCard(100000, 4011, 4012, 4013, 4014);
    	AddCard(500000, 4021, 4022, 4023, 4024, 4025);
    	AddCard(999999, 4031, 4032, 4033, 4034, 4035, 4036);
    	end;
    }

    Edit: This of course doesn't hold true if you would start iterating through the whole array with for (.@i = 0; .@i < getarraysize(.array); .@i++). This would give horrendous performance. We use the array there as a dictionary rather than a list.

    • Upvote 3
  7. You have a few ways of doing that. Your script doesn't cover all possible abusable ways even with logout. It is possible to cancel a script without logging out. One trick is to "abuse" the addtimer behavior. While a script is running, the timed event will not run until the current script is finished (it is queued). As for the logging out issue, you can simply use OnPCLogoutEvent. One drawback from this is that you need to delete the timer as otherwise it will revert whenever you exit the NPC. So I added another menu option to confirm your style, " ~ I want this style". I'd probably remove the " ~ Revert to original" if I were you as it's not needed at all. Cancelling will do that for you and that way you can keep 4 menu options and keep things clean.

    prontera,76,96,1	script	Stylist#custom_stylist	122,{
    	setarray .@Styles[1],
    		getbattleflag("max_cloth_color"),
    		getbattleflag("max_hair_style"),
    		getbattleflag("max_hair_color");
    	setarray .@Look[1],
    		LOOK_CLOTHES_COLOR,
    		LOOK_HAIR,
    		LOOK_HAIR_COLOR;
    	set .@s, select(" ~ Cloth color: ~ Hairstyle: ~ Hair color");
    	set .@Revert, getlook(.@Look[.@s]);
    	set .@Style,1;
    	
    	@stylist_look_type = .@Look[.@s];
    	@stylist_look_value = getlook(@stylist_look_type);
    	addtimer 1, strnpcinfo(0) + "::OnPCLogoutEvent";
    	
    	while(1) {
    		setlook .@Look[.@s], .@Style;
    		message strcharinfo(0),"This is style #"+.@Style+".";
    		set .@menu$, " ~ Next (^0055FF"+((.@Style!=.@Styles[.@s])?.@Style+1:1)+"^000000): ~ Previous (^0055FF"+((.@Style!=1)?.@Style-1:.@Styles[.@s])+"^000000): ~ Jump to...: ~ I want this style";
    		switch(prompt(.@menu$)) {
    		case 1:
    			set .@Style, ((.@Style != .@Styles[.@s]) ? .@Style+1 : 1);
    			break;
    		case 2:
    			set .@Style, ((.@Style != 1) ? .@Style-1 : .@Styles[.@s]);
    			break;
    		case 3:
    			message strcharinfo(0),"Choose a style between 1 - "+.@Styles[.@s]+".";
    			input .@Style,0,.@Styles[.@s];
    			if (!.@Style)
    				set .@Style, rand(1,.@Styles[.@s]);
    			break;
    		case 4:
    			// You have to set the values to 0 and remove the timer event once the colors are chosen and confirmed
    			// Your code currently doesn't have a way out of your loops, so I added this one.
    			@stylist_look_type = @stylist_look_value = 0;
    			deltimer strnpcinfo(0) + "::OnPCLogoutEvent";
    			end;
    		default:
    			set .@Style, .@Revert;
    			setlook .@Look[.@s], .@Revert;
    			end;
    		}
    	}
    	
    	end;
    OnPCLogoutEvent:
    	if (@stylist_look_type != 0) {
    		setlook @stylist_look_type, @stylist_look_value;
    	}
    	
    	deltimer strnpcinfo(0) + "::OnPCLogoutEvent";
    	end;
    }

     

    • Upvote 1
  8. Heya,

    The Reins of Mount has special exceptions in the source. By default, while you are on a mount, you cannot use any item, and this includes the Reins of Mount itself. That is why there is an exception made for the item, and why you need to add an exception for your custom item as well.

    In pc.cpp, look for "ITEMID_REINS_OF_MOUNT" in the pc_useitem function. Change 

    if( nameid != ITEMID_REINS_OF_MOUNT && sd->sc.data[SC_ALL_RIDING] )

    to

    if( nameid != ITEMID_REINS_OF_MOUNT && nameid != 33014 && sd->sc.data[SC_ALL_RIDING] )

    (Or in any other way you'd prefer, this is the most straightforward one I suppose.)

    You may also want to look at other exceptions from ITEMID_REINS_OF_MOUNT and apply them too for yours. Goodluck!

  9. Well, that's because of how you described your event. You want the rates to change on the hour at 00, but you want the event to start when the goal is reached. Both of these are impossible as the event has to end on the hour as well. So you have to choose, if the event starts at say... 3:44, does it end the next day at 4:00 or 3:00? That's how I understood it.

    If... you want the event to run for 24 hours and announce at non-00 intervals from when the goal is first reached, that's a different story entirely.

    As for the first time the script is loaded, that's normal. I was too lazy to resolve that point and since it would only happen once, I didn't care much for that.

  10. Heya,

    Well normally you'd just do a initnpctimer, but since your event needs to run for 24 hours, you can't really expect it to work correctly as a lot can happen in those 24 hours. You need a different approach in that case to survive a server restart/crash or a script reload.

    //===== rAthena Script =======================================
    //= Floating Server Rates
    //===== By: ==================================================
    //= Lupus
    //===== Current Version: =====================================
    //= 1.0
    //===== Compatible With: =====================================
    //= rAthena Project
    //===== Description: =========================================
    //= It's a simply example of setbattleflag
    //= This script will change your server rates from 1x to 1.5x every 6 hours
    //= Note: It doesn't affect Card granted drops, MVP & Treasure Chests drops ^_-
    //=       It also doesn't affect CARD drops, because they are just 0.01%
    //===== Additional Comments: =================================
    //= You can make incredible scripts with 'setbattleflag'!
    //============================================================
    
    prontera,123,209,6	script	Broker#FloatingRates	84,{
    	if ($floating_rates_hours_left > 0) {
    		.@seconds_left = 3600 - (gettime(2) * 60 + gettime(1));
    		.@hours_left = ($floating_rates_hours_left - 1) * 3600;
    		.@time_left = .@seconds_left + .@hours_left;
    		
    		.@dun_d = .@time_left / 86400;
    		.@dun_h = (.@time_left / 3600) % 24;
    		.@dun_m = (.@time_left / 60) % 60;
    		.@dun_s = .@time_left % 60;
    		
    		if (.@dun_d > 0) {
    			.@remaining$ = .@dun_d + " day" + (.@dun_d > 1 ? "s" : "") + " and ";
    		}
    		
    		.@remaining$ = .@remaining$ + (.@dun_h < 10 ? "0" : "")+.@dun_h+":"+(.@dun_m < 10 ? "0" : "")+.@dun_m+":"+(.@dun_s < 10 ? "0" : "")+.@dun_s;
    		
    		mes "[Broker]";
    		mes "The event will end in";
    		mes .@remaining$;
    		mes "Current rates are: "+($@brate/100)+"."+($@brate-$@brateminus)+"x "+($@jrate/100)+"."+($@jrate-$@jrateminus)+"x";
    		close;
    	}
    	
    	mes "[Broker]";
    	mes "Our server's current fund is:";
    	mes "" + callfunc("F_InsertComma",$fr_zeny) + " Zeny";
    	next;
    	mes "[Broker]";
    	mes "Would you like to make a donation?";
    	next;
    	
    	switch(select("Yes:No")) {
    		case 1:
    Change_Amount:			
    			mes "[Broker]";
    			mes "Please input your donation amount.";
    			next;
    			input .@fr_zeny;
    			
    			if (.@fr_zeny < 1) {
    				mes "[Broker]";
    				mes "Input number greater than 0.";
    				end;		
    			}
    			
    			mes "[Broker]";
    			mes "Please confirm Zeny transfer..";
    			next;
    			
    			switch(select("Cancel:Change Amount:Confirm")) {
    				case 1:
    					end;
    				case 2:
    					.@fr_zeny = 0;
    					next;
    					goto Change_Amount;
    					end;
    				case 3:
    					if (Zeny < .@fr_zeny) {
    						mes "[Broker]";
    						mes "Sorry, but you don't have enough";
    						mes "zeny to proceed on payment.";
    						end;
    					}
    					
    					mes "[Broker]";
    					mes "Zeny has succesfully transfered.";
    					Zeny -= .@fr_zeny;
    					$fr_zeny += .@fr_zeny;
    					
    					if ($fr_zeny >= .fr_targetdonation) {
    						$fr_zeny = 0;
    						
    						// Up to you whether you want to add an extra hour or not, as otherwise the event will be below 24 hours.
    						$floating_rates_hours_left = 25;
    						donpcevent strnpcinfo(0) + "::OnMinute00";
    					}
    					
    					end;
    			}
    			
    			break;
    		case 2:
    			break;
    	}
    	
    	end;
    OnInit:
    	.fr_targetdonation = 5000;
    OnMinute00:
    	if (gettime(2) == 0) {
    		$floating_rates_hours_left--;
    	}
    	
    	if ($floating_rates_hours_left < 0) {
    		end;
    	}
    	else if ($floating_rates_hours_left == 0) {
    		$floating_rates_hours_left = -1;
    		.@default_brate = 100;
    		.@default_jrate = 100;
    		
    		if (getbattleflag("base_exp_rate") != .@default_brate) {
    			setbattleflag("base_exp_rate", .@default_brate);
    		}
    		
    		if (getbattleflag("job_exp_rate") != .@default_jrate) {
    			setbattleflag("job_exp_rate", .@default_jrate);
    		}
    		
    		announce "Event is over, rates were changed back to: "+(.@default_brate/100)+"x "+(.@default_jrate/100)+"x ",bc_all,0xFF6060;
    		end;
    	}
    	
    	$@brate = rand(500,800);
    	$@jrate = rand(500,599);
    	//$@drate = rand(100,150);
    	//Base exp
    	setbattleflag("base_exp_rate",$@brate);
    	//Job exp
    	setbattleflag("job_exp_rate",$@jrate);
    	$@brateminus = ($@brate/100) * 100;
    	$@jrateminus = ($@jrate/100) * 100;
    	announce "Current rates are: "+($@brate/100)+"."+($@brate-$@brateminus)+"x "+($@jrate/100)+"."+($@jrate-$@jrateminus)+"x ",bc_all,0xFF6060;
    	
    	if ($floating_rates_hours_left == 1) {
    		announce "There is one hour left!",bc_all,0xFF6060;
    	}
    	
    	end;
    }

     

    • Upvote 1
  11. Heya,

    The issue is from your char-server. "intif" is for "interserver" and "interface", intif_parse_StorageReceived (which is for all storages, including inventory, etc) is a packet the char-server sends to the map-server, type 3 is TABLE_STORAGE. Long story short, it means it failed to load the storage data for your character. The char-server logs should give you more information about the issue, though. The... fact that you aren't seeing more information is strange. It's not an invalid storage index as you'd get an error such as "Invalid storage with id #". So this only leaves an invalid SQL query. Your storage table doesn't seem to match what the char-server is expecting. Make sure your storage table matches with what rAthena is using. You should have received an SQL error, though.

    • Like 2
  12. 3 hours ago, Radian said:

    Hey @Tokei how are you doing?

    Im just having issues with encrypted files atm while using a 2018-06-20eRagexeRE client date exe

    What im getting is queryRegionInfo or the client cant read when its encrypted i tried running it without encryption and its working fine.

    I made new GRF's change the cpp.dll name into something else, create new patch of client and still not working. Any idea what mistake i made on encrypting it?

    Newer clients reference cps.dll twice; so keep the name to cps.dll instead of changing it to cpp.dll.

    • Love 1
  13. Hm, well the map-server is indeed the one struggling there. The easy solution is to upgrade your CPU to something better, but... you'd have to figure out what's draining so much power from the emulator. It feels rather high for such a population. The usual culprits are SQL usage (which doesn't appear to be case here? mysqld would show a spike there too) or bad scripts/instances. It'll be almost impossible to pinpoint your issue from the forums though.

    • MVP 1
  14. Heya,

    This setting has no impact on the map-server. The character saving process is handled on the char-server, not the map-server. Anything SQL related is handled on the char-server to prevent "lagging" the map-server (and should be kept this way).

    I wouldn't recommend increasing this value either. Anything past 5 minutes (300 seconds) can make you more vulnerable to "rollbacks" if the map-server crashes. If your character data hasn't been saved for more than X minutes, that can be annoying to deal with.

  15. 10 hours ago, tibbersx said:

    @Tokei having same problem. also cannot extract a certain Act/Spr file then something will pop up 
    "An  unhandled exception has been thrown

    Generic failure: a task in the thread pool has failed to finish properly. The current operation will be cancelled."

    You should open a new thread/question, as this is from 2017. Anyway, it simply means the entry is corrupted or encrypted, most likely encrypted.

  16. Heya,

    The ground unit IDs for skills are within the client itself, they are not found in lub files and you cannot add new ones. These IDs are mostly meant to display a visual effect on the client though. Therefore... if you want a custom ground skill to show an effect, you'll have to use a pre-existing ID from those currently defined in rAthena and work your way around that. Otherwise, if you want to display a custom effect, you'll have to use "dirty tricks". Either way, what you're looking for simply doesn't exist.

    But I'll say, what you've described so far is unclear. Most custom skills do not require an unit ID to begin with.

    • Upvote 1
×
×
  • Create New...