Jump to content

Winterfox

Members
  • Posts

    248
  • Joined

  • Last visited

  • Days Won

    19

Posts posted by Winterfox

  1. You could try to achieve this effect using autobonus by setting a short amount for the duration the script will last.

    *autobonus <bonus script>,<rate>,<duration>{,<flag>,{<other script>}};
    *autobonus2 <bonus script>,<rate>,<duration>{,<flag>,{<other script>}};
    *autobonus3 <bonus script>,<rate>,<duration>,<skill id>,{<other script>};
    *autobonus3 <bonus script>,<rate>,<duration>,"<skill name>",{<other script>};
    
    These commands are meant to be used in item scripts only! See 'petautobonus' for pet usage.
    
    What these commands do is 'attach' a script to the player which will get
    executed on attack (or when attacked in the case of autobonus2).
    
    Rate is the trigger rate of the script (1000 = 100%).
    
    Duration is the time in milliseconds that the bonus will last for since the script has triggered.
    
    Skill ID/skill name the skill which will be used as trigger to start the bonus. (autobonus3)
    
    The optional argument 'flag' is used to classify the type of attack where the script
    can trigger (it shares the same flags as the bAutoSpell bonus script):
    
    Range criteria:
    	BF_SHORT:  Trigger on melee attack
    	BF_LONG:   Trigger on ranged attack
    	Default:   BF_SHORT+BF_LONG
    Attack type criteria:
    	BF_WEAPON: Trigger on weapon skills
    	BF_MAGIC:  Trigger on magic skills
    	BF_MISC:   Trigger on misc skills
    	Default:   BF_WEAPON
    Skill criteria:
    	BF_NORMAL: Trigger on normal attacks
    	BF_SKILL:  Trigger on skills
    	default:   If the attack type is BF_WEAPON (only) BF_NORMAL is used,
    		   otherwise BF_SKILL+BF_NORMAL is used.
    
    The difference between the optional argument 'other script' and the 'bonus script' is that,
    the former one triggers only when attacking(or attacked) and the latter one runs on
    status calculation as well, which makes sure, within the duration, the "bonus" that get
    lost on status calculation is restored. So, 'bonus script' is technically supposed to accept
    "bonus" command only. And we usually use 'other script' to show visual effects.
    
    In all cases, when the script triggers, the attached player will be the one
    who holds the bonus. There is currently no way of knowing within this script
    who was the other character (the attacker in autobonus2, or the target in
    autobonus and autobonus3).
    
    //Grants a 1% chance of starting the state "all stats +10" for 10 seconds when
    //using weapon or misc attacks (both melee and ranged skills) and shows a special
    //effect when the bonus is active.
    	autobonus "{ bonus bAllStats,10; }",10,10000,BF_WEAPON|BF_MISC,"{ specialeffect2 EF_FIRESPLASHHIT; }";

     

  2. Poring Slot


    In this game, you can place bets on one of 5 slots. Each slot has a different chance to be picked, but also gives a higher reward, the lesser the chance. 
    After enough bets are placed, a player can pay a fee to spin the wheel. After a certain amount of time, one slot is picked and the winners can get their prize.

    This script is resistant to server restarts and script reloads. It always keeps track of all currently placed bets and prizes a player has.
    If the player is offline during a spin but wins, he gets a notification on the next login that he has pending prizes.

    The following things are customizable via config variables:

    • Price per spin.
    • Amount of bets before a spin can be started.
    • The item used as currency for the game.
    • The minimum amount for a bet.
    • The sprite, name, color, bonus on win and position of each slot selection.
    • The position and type of each slot.

    Updates and bug fixes are free and will be available here for all customers.
    Costumers can contact me via discord for support. My username there is hope2812.


    • Submitter
    • Submitted
      09/09/23
    • Category
    • Video
    • Content Author
      Winterfox

     

  3. You can use the time labels:

    OnClock<hour><minute>:
    OnMinute<minute>:
    OnHour<hour>:
    On<weekday><hour><minute>:
    OnDay<month><day>:
    
    This will execute when the server clock hits the specified date or time. Hours
    and minutes are given in military time. ('0105' will mean 01:05 AM). Weekdays
    are Sun,Mon,Tue,Wed,Thu,Fri,Sat. Months are 01 to 12, days are 01 to 31.
    Remember the zero.

    This would run the event every 24 hours at 14 o'clock:

    OnHour14:
      goto l_start;
      end;
  4. I think your problem is the falltrough after the call of an OnBarDead label. This leads to one OnBarDead label calling all succeeding setcell calls that make the cells walkable.

    If for example OnBarDead1 gets called, it falls through all labels until it hits the end command at the end of the file, effectivly making all non-walkable cells walkable instead of only the ones you targeted with your label.

  5. If you have logging enabled, you can check the picklog table for rows where type is S.

    // 0x00000010 - (S) Log NPC transactions (buy/sell)

    For details, check log_athena.conf. The logging part is directly at the beginning of the file.

  6. Autoplay


    This is a command that basically turns a character into a bot.
    Once a player with the proper permissions uses this command, the character will start to walk around the map and attack all mobs it sees automatically.
    Warps are ignored and most functions like chatting etc. are disabled while in autoplay mode.
    Autoplay is disabled automatically when the character dies while it is active.

    The following things are configurable:

    • The radius the character searches for mobs around itself.
    • The minimum path length the character walks per move.
    • The maximum path length the character walks per move.
    • The timeout when a character fails to attack a mob.
    • The timeout when a character fails to move.
    • The minimal group level to use the command.

    Updates and bug fixes are free and will be available here for all customers.
    Costumers can contact me via discord for support. My username there is hope2812.


    • Submitter
    • Submitted
      09/10/23
    • Category
    • Video
    • Content Author
      Winterfox

     

  7. 4 hours ago, jamesandrew said:

    Thanks for the explanation. Very helpful!
     

    So... If I want to use unlimited quantity for 1010 and 1011 can I use marketshop and change the quantity to -1 ?

    //=Ore Exchanger
    //============================================================
    -	marketshop	market_refine_prt_in	-1,1010:-1:-1,1011:-1:-1
    -	marketshop	market_refine_payon	-1,1010:-1:-1,1011:-1:-1
    -	marketshop	market_refine_morocc_in	-1,1010:-1:-1,1011:-1:-1
    -	marketshop	market_refine_alberta_in	-1,1010:-1:-1,1011:-1:-1
    -	marketshop	market_refine_yuno_in01	-1,1010:-1:-1,1011:-1:-1
    -	marketshop	market_refine_ein_in01	-1,1010:-1:-1,1011:-1:-1
    -	marketshop	market_refine_lhz_in02	-1,1010:-1:-1,1011:-1:-1
    
    prt_in,63,69,3	script	Dietrich#ns_prt	4_M_02,{
    	mes "[" + strnpcinfo(1) + "]";
    	mes "We sell and exchange various ores used in smelting.";
    	next;
    	switch( select( "View basic smelting ores", "View advanced smelting ores", "Cancel" ) ) {
    	case 1:
    		mes "[" + strnpcinfo(1) + "]";
    		mes "Phracon and Emveretarcon are available for use in smelting low-level weapons.";
    		close2;
    		callshop "market_refine_" + strnpcinfo(4);
    		end;
    	case 2:
    		mes "[" + strnpcinfo(1) + "]";
    		mes "We are purifying Elunium Stone and Oridecon Stone, or exchanging Coins.";
    		close2;
    		callshop "barter_refine_1";
    		end;
    	case 3:
    		mes "[" + strnpcinfo(1) + "]";
    		mes "If you lack the materials used for smelting, come anytime.";
    		close;
    	}
    	end;
    
    OnInit:
    	setunittitle getnpcid(0), "<Ore Refiner>";
    	end;
    }

    Exactly.  npcshopupdate uses the same arguments for stocks as the marketshop itemlist, as it is also explained in the script documentation:

    "marketshop" can have limited quantity of an item in stock.
    Use -1 in the stock field to have unlimited stock in a marketshop.


     

    • Upvote 1
  8. If you want to update the stock programmatically, for example on a certain event, you can use npcshopupdate.

    *npcshopupdate "<name>",<item_id>,<price>{,<stock>}
    
    Update an entry from a shop. If the price is 0 it won't be changed. May also be used for
    marketshop to update the stock quantity. For unlimited stock, use -1.
    For other shop types, the stock value has no effect.

    Which means to reset the stock of item 1010 in the market_refine_prt_in shop, you would do it like this:

    npcshopupdate("market_refine_prt_in", 1010, 0, 999999);

    If you want to simply change the stock for testing purposes, you could edit the shop in the market table in the database.

    In your NPCs case, if you check line 588 in the file npc/merchants/refine.txt, you will see the NPC refine_barter_init.
    Which uses above-mentioned npcshopupdate to update the stocks of the NPCs in your post when the script gets loaded.

    So if you only care about resetting the stock of those, reloading only the script where the shops are defined should suffice.
    You can use this command to do this:

    @reloadnpcfile npc/merchants/refine.txt

     

    • Upvote 1
  9. You can generate the navigation information of the npcs for the client by running navigenerator in the server root directory.
    Afterward, you can find the clientside files in the folder generated/clientside and copy that into your client root directory.

  10. -	script	FREEZE	FAKE_NPC,{
    	OnInit:
    		.@group = 99;
    		bindatcmd("freeze", strnpcinfo(3) + "::OnFreeze", .@group);
    		bindatcmd("unfreeze", strnpcinfo(3) + "::OnUnfreeze", .@group);
    	end;
    	
    	OnFreeze:
    		.@mode = 1;
    	OnUnfreeze:
    		getmapunits(BL_PC, .@atcmd_parameters$[0], .@players);
    		freeloop(1);
    		for(.@i = 0; .@i < getarraysize(.@players); .@i++)
    			pcblockmove(.@players[.@i], .@mode);
    		freeloop(0);
    }

     

    • Love 1
  11. -	script	FREEZE	FAKE_NPC,{
    	OnInit:
    		bindatcmd("freeze", strnpcinfo(3) + "::OnFreeze");
    		bindatcmd("unfreeze", strnpcinfo(3) + "::OnUnfreeze");
    	end;
    	
    	OnFreeze:
    		.@mode = 1;
    	OnUnfreeze:
    		getmapunits(BL_PC, .@atcmd_parameters$[0], .@players);
    		freeloop(1);
    		for(.@i = 0; .@i < getarraysize(.@players); .@i++)
    			pcblockmove(.@players[.@i], .@mode);
    		freeloop(0);
    }

     

  12. I didn't test it, but this should do what you want.
     

    -	script	FREEZE	FAKE_NPC,{
    	OnInit:
    		bindatcmd("freeze", strnpcinfo(3) + "::OnFreeze");
    		bindatcmd("unfreeze", strnpcinfo(3) + "::OnUnfreeze");
    	end;
    	
    	OnFreeze:
    		.@mode = 1;
    	OnUnfreeze:
    		getmapunits(BL_PC, getarg(0), .@players);
    		freeloop(1);
    		for(.@i = 0; .@i < getarraysize(.@players); .@i++)
    			pcblockmove(.@players[.@i], .@mode);
    		freeloop(0);
    }

     

  13. On 9/6/2023 at 8:12 PM, jamesandrew said:

    I'm making a simple fishing script.
    The rules are:
    -  Must equip a fishing rod (2764)
    - 5 seconds cast time
    - Get one reward per cast
    - Rewards rate are: Red Herb 40%; Yellow Herb 30%; White Herb 20%, Blue Herb 10%, Yggdrasil Berry 0.01%
     

    prt_fild00,278,237,0	script	Fishing School	10065,{
    set .@Rod,2764; //Fishing rod
    if (isequipped(.@Rod)){
    	specialeffect EF_BUBBLE,"Fishing School";
    	soundeffect "_attack_axe.wav",0;
    	dispbottom "[Fishing] Casting...";
    	set .@fcast,5;
    	progressbar "ffffff",.@fcast;
    	if (rand(1,10) <= 4) ||(rand(1,10) <= 3) || (rand(1,10) <= 2) || (rand(1,10) <= 1){
    		setarray .@Catch[0],507,508,509,510;// Red 40%, Yellow 30%, White 20%, Blue Herb 10%
    		set .@CatchRand,.@Catch[rand(getarraysize(.@Catch))];
    		getitem .@CatchRand,1;
    		specialeffect2 610;
    		soundeffectall "see_otter_damage.wav",0,strcharinfo(3);
    		dispbottom("[Fishing] You got "+ getitemname(.@CatchRand) +".");
    		}
    	else {
    		dispbottom "[Fishing] Nothing was caught...";
    		specialeffect2 611;
    		end;}
    			if (rand(1,100) == 1){
    				setarray .@Rare[0],607; //Yggdrasil Berry 0.01%
    				set .@RareCatch, .@Rare[rand(getarraysize(.@Rare))];
    				getitem .@RareCatch,1;
    				dispbottom("[Fishing] Congratulations you got "+ getitemname(.@RareCatch) +".");
    				specialeffect2 68;
    				end;}
    			else {
    				end;}
    	}
    else {
    	dispbottom "[Fishing] You need a Fishing Rod.";
    	end;
    	}
    }

    are these rands correct?

    Your pick code throws 4 dice with 10 eyes and checks if at least one fits, and then picks an item randomly.
    Which means your script decides if it should give loot or not (Which contradicts your 4. Rule) but in case it drops an item, it gives every item an equal chance to be dropped.

    Except Yggrasil Berry, which gets a 1% chance to be dropped regardless of if there was already a drop, which also contradicts your 4. Rule.
    Here is what I would do to change your script to make it fit your given rules:
     

    prt_fild00,278,237,0	script	Fishing School	10065,{
    	if (!isequipped(.rod)) {
    		dispbottom("[Fishing] You need a Fishing Rod.");
    		end;
    	}
    
    	specialeffect(EF_BUBBLE, "Fishing School");
    	soundeffect("_attack_axe.wav", 0);
    	dispbottom("[Fishing] Casting...");
    	progressbar("ffffff", .cast_delay);
    
    	.@pick = rand(1, .catch_weight_sum);
    	for(.@i = 0; .@i < getarraysize(.catches); .@i += 2) {
    		.@pick -= .catches[.@i + 1];
    		if(.@pick <= 0) {
    			.@catch = .catches[.@i];
    			break;
    		}
    	}
    
    	getitem(.@catch, 1);
    	specialeffect2(610);
    	soundeffectall("see_otter_damage.wav", 0, strcharinfo(3));
    	dispbottom("[Fishing] You got "+ getitemname(.@catch) + ".");
    	end;
    
        OnInit:
    		.rod = 2764;
    		.cast_delay = 5;
    		
    		// Red Herb 40%; Yellow Herb 30%; White Herb 20%, Blue Herb 10%, Yggdrasil Berry 0.01%
    		setarray(.catches, 507, 4000, 508, 3000, 509, 2000, 510, 1000, 607, 1);
    
    		for(.@i = 0; .@i < getarraysize(.catches); .@i += 2)
    			.catch_weight_sum = .catches[.@i + 1];
    }

     

    • Upvote 1
  14. 1 hour ago, namerpus18 said:

    I am sorry, I also tried that method but the thing is inside the quote should be a <condition> can be any expression similar to the <condition> in the 'if' command. I am not quite sure if doing for inside it is really possible. Thank you

    OnInit:
    questinfo(QTYPE_QUEST),QMARK_YELLOW, "checkquest (11114,HUNTING) == 2 || checkquest (11115,HUNTING) == 2 || checkquest (11116,HUNTING) == 2 || checkquest (11117,HUNTING) == 2 || checkquest (11118,HUNTING) == 2 || checkquest (11119,HUNTING) == 2 || checkquest (11120,HUNTING) == 2 || checkquest (11121,HUNTING) == 2 || checkquest (11122,HUNTING) == 2 || checkquest (11123,HUNTING) == 2";

     

    You are right, it doesn't seem like you can put anything inside the condition argument of the questinfo function that doesn't return a value directly.
    It simply evaluates if the result of the script in the conditions string results in true or false, when certain events like the completion of a quest trigger a reevaluation. 

    That means you can only use functions that the script engine knows and that return a value. 
    So what you can do alternatively is to build the condition string dynamically. 

    prontera,150,193,4	script	DEMO	124,{
    	OnInit:
    		setarray(.@quests, 11114, 11115, 11116, 11117, 11118, 11119, 11120, 11121, 11122, 11123);
    		for(.@i = 0; .@i < getarraysize(.@quests); .@i++)
    			.@condition$[.@i] = "checkquest(" + .@quests[.@i] + ", HUNTING) == 2";
    
    		questinfo(QTYPE_QUEST, QMARK_YELLOW,  implode(.@condition$, "||"));
    }

     

    • Love 1
  15. -	script	SKILL_DEMO	FAKE_NPC,{
    	OnInit:
    		monster("prontera", 150, 170, "Helper A", 1002, 1);
    		.@mob_a = $@mobid[0];
    		unitblockmove(.@mob_a, 1);
    
    		getunitdata(.@mob_a, .@mob_a_data);
    		.@pos_x = .@mob_a_data[UMOB_X];
    		.@pos_y = .@mob_a_data[UMOB_Y];
    
    		monster("prontera", 140, 160, "Helper B", 1002, 1);
    		.@mob_b = $@mobid[0];
    
    		while(.@pos_x != .@target_x || .@pos_y != .@target_y) {
    			getunitdata(.@mob_b, .@mob_b_data);
    			.@target_x = .@mob_b_data[UMOB_X];
    			.@target_y = .@mob_b_data[UMOB_Y];
    
    			if(.@pos_x != .@target_x) .@pos_x += (.@pos_x < .@target_x) ? 1 : -1;
    			if(.@pos_y != .@target_y) .@pos_y += (.@pos_y < .@target_y) ? 1 : -1;
    
    			unitskillusepos(.@mob_a, "MG_THUNDERSTORM", 10, .@pos_x, .@pos_y, -5, false, 0, true);
    			sleep(1000);
    		}
    }

     

  16. 25 minutes ago, namerpus18 said:

    Good Day everyone,

     I just need some help, if someone can help me shorten this script. My methods are too limited and i cant find a way to shorten it.

    Does it improve if i manage to optimize this script? I feel that this script alone takes a lot of checking.

    Thank you so much,

    if(getmonsterinfo(killedrid, MOB_MVPEXP) > 1 && isbegin_quest(19000) > 0 || isbegin_quest(19001) > 0 || isbegin_quest(19002) > 0 || isbegin_quest(19003) > 0 || isbegin_quest(19004) > 0 || isbegin_quest(19005) > 0 || isbegin_quest(19006) > 0 || isbegin_quest(19007) > 0 || isbegin_quest(19008) > 0 || isbegin_quest(19009) > 0 || isbegin_quest(19010) > 0 || isbegin_quest(19011) > 0 || isbegin_quest(19012) > 0 || isbegin_quest(19013) > 0 || isbegin_quest(19014) > 0 || isbegin_quest(19015) > 0 || isbegin_quest(19016) > 0 || isbegin_quest(19017) > 0 || isbegin_quest(19018) > 0 || isbegin_quest(19019) > 0 )	{
      ....
    }

     

    It is hard to really optimize the script without knowing the whole code. But to make the snippet you have more manageable, you could organize your code like this:
     

    for(.@i = 0; .@i < 20; .@i++) {
        if(isbegin_quest(19000 + .@i) > 0) {
            .@has_quest = 1;
            break;
        }
     }
    
    if(getmonsterinfo(killedrid, MOB_MVPEXP) > 1 && .@has_quest)	{
    
    }

     

  17. 4 hours ago, jamesandrew said:

    I've just tested it. It does work but it's very easy to abuse by swapping weapons 😞
    Thanks though

     

    ----edit
    Is it possible to use specialeffect2 from this list rathena/doc/effect_list.txt at master · rathena/rathena (github.com) to make your character act like auto attacking mobs?

    I am not sure if there is an effect that makes it look like a character attacks.

    Another idea I had would be to spawn an invisible mob below the ore NPC when the player meets the requirements, and then to set him up to attack that mob and lock him in this state until he killed the ore mob.
    When the ore mob is dead, you can hide the npc for the player for a certain amount of time.

    For the part of making a player attack a mob and blocking movement, you could check the commands: unitattack and, setpcblock that could help you with that. In general, the unit commands could be of help to you.
    For the part about visibility of ores, you could use the on touch area of the npc and combine that with cloakonnpc or cloakonnpcself to control which players can see the npc right now.

  18. You could attach the checks on a label that gets triggered when the mob that represents an ore gets killed.

    Here is a small example:

    -	script	MINING	FAKE_NPC,{
    	OnInit:
    		// Config
    		setarray(.mining_utils, 28116);
    
    		setarray(.minerals, 3742, 3743, 1083);
    
    		.mineral_0_name$ = "Bronze";
    		setarray(.mineral_0_maps$, "prontera");
    		setarray(.mineral_0_amounts, 10);
    		setarray(.mineral_0_areas_x_1, 150);
    		setarray(.mineral_0_areas_x_2, 163);
    		setarray(.mineral_0_areas_y_1, 175);
    		setarray(.mineral_0_areas_y_2, 137);
    		setarray(.mineral_0_items, 502, 10, 1, 5, 503, 40, 1, 5, 504, 50, 1, 5);
    
    		.mineral_1_name$ = "Silver";
    		setarray(.mineral_1_maps$, "prontera");
    		setarray(.mineral_1_amounts, 10);
    		setarray(.mineral_1_areas_x_1, 150);
    		setarray(.mineral_1_areas_x_2, 163);
    		setarray(.mineral_1_areas_y_1, 150);
    		setarray(.mineral_1_areas_y_2, 200);
    		setarray(.mineral_1_items, 505, 10, 1, 5, 506, 40, 1, 5, 507, 50, 1, 5);
    
    		.mineral_2_name$ = "Gold";
    		setarray(.mineral_2_maps$, "prontera");
    		setarray(.mineral_2_amounts, 10);
    		setarray(.mineral_2_areas_x_1, 150);
    		setarray(.mineral_2_areas_x_2, 163);
    		setarray(.mineral_2_areas_y_1, 175);
    		setarray(.mineral_2_areas_y_2, 137);
    		setarray(.mineral_2_items, 508, 10, 1, 5, 509, 40, 1, 5, 510, 50, 1, 5);
    
    		// Config End
    		for(.@i = 0; .@i < getarraysize(.minerals); .@i++) {
    			.@name$ = getd(".mineral_" + .@i + "_name$");
    			.@items = getd(".mineral_" + .@i + "_items");
    
    			.@items_size = getarraysize(getd(".mineral_" + .@i + "_items"));
    			.@item_sum = 0;
    			for(.@x = 0; .@x < .@items_size; .@x += 4)
    				.@item_sum += getd(".mineral_" + .@i + "_items[" + (.@x + 1) + "]");
    
    			setd(".mineral_" + .@i + "_item_sum", .@item_sum);
    
    			.@maps_size = getarraysize(getd(".mineral_" + .@i + "_maps$"));
    			for(.@y = 0; .@y < .@maps_size; .@y++) {
    				.@maps$ = getd(".mineral_" + .@i + "_maps$[" + .@y + "]");
    				.@amounts = getd(".mineral_" + .@i + "_amounts[" + .@y + "]");
    				.@areas_x_1 = getd(".mineral_" + .@i + "_areas_x_1[" + .@y + "]");
    				.@areas_x_2 = getd(".mineral_" + .@i + "_areas_x_2[" + .@y + "]");
    				.@areas_y_1 = getd(".mineral_" + .@i + "_areas_y_1[" + .@y + "]");
    				.@areas_y_2 = getd(".mineral_" + .@i + "_areas_y_2[" + .@y + "]");
    
    				areamonster(.@maps$, .@areas_x_1, .@areas_x_2, .@areas_y_1, .@areas_y_2, .@name$, .minerals[.@i], .@amounts, "MINING::OnMined");
    			}
    		}
    	end;
    
    	OnMined:
    		.@mineral = inarray(.minerals, killedrid);
    		.@mineral_name$ = getd(".mineral_" + .@mineral + "_name$");
    		.@util = getequipid(EQI_HAND_R);
    
    		if(inarray(.mining_utils, .@util) == -1) {
    			dispbottom("Using your " + getitemname(.@util) + " destroyed any useful resource from " + .@mineral_name$ + ".");
    			end;
    		}
    
    		.@mineral_item_sum = getd(".mineral_" + .@mineral + "_item_sum");
    		.@mineral_items_size = getarraysize(getd(".mineral_" + .@i + "_items"));
    
    		.@pick = rand(1, .@mineral_item_sum);
    		for(.@i = 0; .@i < .@mineral_items_size; .@i += 4) {
    			.@pick -=  getd(".mineral_" + .@mineral + "_items[" + (.@i + 1) + "]");
    
    			if(.@pick <= 0)
    				break;
    		}
    
    		.@item = getd(".mineral_" + .@mineral + "_items[" + .@i + "]");
    		.@item_min_amount = getd(".mineral_" + .@mineral + "_items[" + (.@i + 2) + "]");
    		.@item_max_amount = getd(".mineral_" + .@mineral + "_items[" + (.@i + 3) + "]");
    
    		getitem(.@item, rand(.@item_min_amount, .@item_max_amount));
    }

    This will spawn different minerals (in this example represented by purple ore and plants), which give different items on kill etc. once a mineral gets killed, it checks if an item from the .mining_utils array is equipped and if not gives the player the message, that using the wrong item destroyed any useful resources otherwise it will roll which and how many of an item the player gets.

    • Upvote 1
  19. The easiest way would be to create a custom mob that looks like a mineral. You could for example copy Purple Ore (id: 3742) and add the items you want the player to get by mining as drop.
    You just need to remember to add your custom mob to mob_avail,yml to tell rathena to make the client use the sprite of the original mob for your custom one.

    • Upvote 1
×
×
  • Create New...