Jump to content

GmOcean

Community Contributors
  • Content Count

    371
  • Joined

  • Last visited

  • Days Won

    8

Everything posted by GmOcean

  1. Yeah, I thought about the breaking of all other scripts using the commands, but I figured it'd fit right in along with other deprecated commands in that sense.
  2. Well some may not consider this an overhaul, but really I think a few commands are in need of a small adjustment Namely the following: *getinventorylist;*getpartymember <party id>{,<type>};*getguildmember <guild id>{,<type>};*getmobdrops(<mob id>) These 4 commands all having something in common. 1. They produce array's using $@variables. ( *getinventorylist being the exception using @variables ). 2. They all produce a variable that deals with their array size. 3. They don't erase that array. What I'm suggesting is simple. 1. Produce .@(temp_scope) variables. 2. eliminate this variable entirely, or leave it for backwards compatibility. 3. Erase the array upon execution of command. This will allow the use of getarraysize(); for each of these commands, which imo should have been the norm. These are just my thoughts on the matter. Anyone else feel the same way?
  3. Well, if you want to add individual monsters to your script for achievements then it is very simple. In fact, it won't take away from your script much at all. Just in corporate this bit of code in to your script: This is for OnInit, as it will handle the variables used. OnInit:// Each element of the array can be set to the amount needed to be killed.// Allowing you to dynamically set each monster achievements, sort of .// Example, if I wanted a regular monster achievement for 500 kills just add this:// .mob_master[500] = 500; // 500 kills will be another achievement. Listed as: 'Monster_Name Master' '500'..mob_master[10000] = 10000;.mob_master[20000] = 20000;.mob_master[30000] = 30000;end; This is for OnNPCKillEvent, as it will deal with calculating each monster's kills. OnNPCKillEvent:setd ""+ killedrid +"", getd(""+ killedrid +"") + 1;if( getd(""+ killedrid +"") == .mob_master[getd(""+ killedrid +"")] ){ .@prize = getd(""+ killedrid +""); announce ""+ strcharinfo(0) +" just achieved "+ getmonsterinfo( killedrid, 0 ) +" Master "+ getd(""+ killedrid +"") +"",bc_all; query_sql("INSERT INTO `achievement` VALUES (NULL, "+ getcharid(3) +","+ getcharid(0) +",'"+ escape_sql(strcharinfo(0)) +"','"+ getmonsterinfo( killedrid, 0 )+" Master', "+ getd(""+ killedrid +"") +")"); callsub OnRegularMaster, .@prize; // Call the label, with the value to be used for giving prizes.}end; Lastly, this is the prize section, they only get red potions for now, but that's because I didn't get into detail on what they should receive xD OnRegularMaster:switch( getarg(0) ){ case 10000: getitem 501,1; break; case 20000: getitem 501,2; break; case 30000: getitem 501,3; break; // More as needed.}end; That's it really O.o; Heck you could even just make it another NPC all together, since it uses your sql_database as it's placer. The only part I didn't do was the ranking system. I'll leave that to you =P So as an example, let's say I wanted an achievement for 1,000,000 kills of a mosnter. I'd just do the following ( This is a sample script ): - script monster_kills -1,{OnInit:.mob_master[1000000] = 1000000;end;OnNPCKillEvent:setd ""+ killedrid +"", getd(""+ killedrid +"") + 1;// Checks to see if the monsters I killed is equal to the array.// This works, because if 0->999,999 are all 0, then it won't do anything, since my kills will always be 1 or higher.// Meaning any element that has a value of 0 is disabled and will not be an achievement, which means you can even enable/disable some for events =P.if( getd(""+ killedrid +"") == .mob_master[getd(""+ killedrid +"")] ){ // announcement; // query_sql; // This will make me call the label with the given value as getarg(0). In this sample, case, it will send 1,000,000 as the number. callsub OnRegularMonster, getd(""+ killedrid +"");}end;OnRegularMonster:switch( getarg(0) ){ // This means I killed 1,000,000 monsters, and there is a reward for doing so. // If you do not add a case for the relative achievement, it just means they don't get a reward for doing it. // So, let's say they got an achievement for killing 10, and that's too easy, well we just don't make a case 10: and then they don't get a reward. // Still get the achievement though =P case 1000000: getitem 501,1; break;}end; O.o hope this helps. Make use of it if you want, or don't up to you.
  4. That would be awesome. Thank you
  5. Hi I'm requesting 2 script_commands that are pretty self explanatory: duplicatenpc & duplicateremove. I know this is possible since we are able to duplicate npcs for instances. But I want to do that outside of instances. I made an attempt myself, but sadly fell short (who am I kidding, far, very far) of what I believe is needed. *duplicateremove({"<npc_name>"}); *duplicatenpc("<source_npc_name>","<target_npc_name>","<hidden_name>","<map_name>",<x>,<y>,<dir>); So, seeing as how I failed miserably, I've come to ask you expert's to do this for me. I don't know if my attempt will prove useful but there it is in all it's pile of mess lol. If payment is required, then send me a PM and we can discuss terms there. Otherwise, I'd hope to get this done for free D: Please & Thank You!
  6. That would be under mob.c for AI controls More specifically this particular section of the above code: // Check for target change. if( md->attacked_id && mode&MD_CANATTACK ) { if( md->attacked_id == md->target_id ) { //Rude attacked check. if( !battle->check_range(&md->bl, tbl, md->status.rhw.range) && ( //Can't attack back and can't reach back. (!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0 && (battle_config.mob_ai&0x2 || (md->sc.data[SC_SPIDERWEB] && md->sc.data[SC_SPIDERWEB]->val1) || md->sc.data[SC_WUGBITE] || md->sc.data[SC_VACUUM_EXTREME] || md->sc.data[SC_THORNS_TRAP] || md->sc.data[SC__MANHOLE])) // Not yet confirmed if boss will teleport once it can't reach target. || !mob->can_reach(md, tbl, md->min_chase, MSS_RUSH) ) && md->state.attacked_count++ >= RUDE_ATTACKED_COUNT && !mob->skill_use(md, tick, MSC_RUDEATTACKED) // If can't rude Attack && can_move && unit->escape(&md->bl, tbl, rnd()%10 +1)) // Attempt escape { //Escaped md->attacked_id = 0; return true; } } else if( (abl = map->id2bl(md->attacked_id)) && (!tbl || mob->can_changetarget(md, abl, mode) || (md->sc.count && md->sc.data[SC__CHAOS]))) { int dist; if( md->bl.m != abl->m || abl->prev == NULL || (dist = distance_bl(&md->bl, abl)) >= MAX_MINCHASE // Attacker longer than visual area || battle->check_target(&md->bl, abl, BCT_ENEMY) <= 0 // Attacker is not enemy of mob || (battle_config.mob_ai&0x2 && !status->check_skilluse(&md->bl, abl, 0, 0)) // Cannot normal attack back to Attacker || (!battle->check_range(&md->bl, abl, md->status.rhw.range) // Not on Melee Range and ... && ( // Reach check (!can_move && DIFF_TICK(tick, md->ud.canmove_tick) > 0 && (battle_config.mob_ai&0x2 || (md->sc.data[SC_SPIDERWEB] && md->sc.data[SC_SPIDERWEB]->val1) || md->sc.data[SC_WUGBITE] || md->sc.data[SC_VACUUM_EXTREME] || md->sc.data[SC_THORNS_TRAP] || md->sc.data[SC__MANHOLE])) // Not yet confirmed if boss will teleport once it can't reach target. || !mob->can_reach(md, abl, dist+md->db->range3, MSS_RUSH) ) ) ) { // Rude attacked if (md->state.attacked_count++ >= RUDE_ATTACKED_COUNT && !mob->skill_use(md, tick, MSC_RUDEATTACKED) && can_move && !tbl && unit->escape(&md->bl, abl, rnd()%10 +1)) { //Escaped. //TODO: Maybe it shouldn't attempt to run if it has another, valid target? md->attacked_id = 0; return true; } } else if (!(battle_config.mob_ai&0x2) && !status->check_skilluse(&md->bl, abl, 0, 0)) { //Can't attack back, but didn't invoke a rude attacked skill... } else { //Attackable if (!tbl || dist < md->status.rhw.range || !check_distance_bl(&md->bl, tbl, dist) || battle->get_target(tbl) != md->bl.id) { //Change if the new target is closer than the actual one //or if the previous target is not attacking the mob. [Skotlex] md->target_id = md->attacked_id; // set target if (md->state.attacked_count) md->state.attacked_count--; //Should we reset rude attack count? md->min_chase = dist+md->db->range3; if(md->min_chase>MAX_MINCHASE) md->min_chase=MAX_MINCHASE; tbl = abl; //Set the new target } } } My guess, is before it attempts to say it was rude attacked you need to add a check to see if the mvp is in an icewall.state ( do we use this? ). Sadly, I'm no where near able to do that with src code :/ but i'm pretty positive this is the bit that needs to be edited to do what you want. D:
  7. Okay, first ' bug ' I found was a mistake on my part, just need to make 2 changes. 1: .@quest_menu$ = .@quest_menu$ +":"+ .@quest_name$[.@temp_variable];TO.@quest_menu$ = .@quest_menu$ + .@quest_name$[.@temp_variable] +":"; 2: .@quest_menu$ = .@quest_menu$ +":[^0000FF More Quests ^000000]";TO.@quest_menu$ = .@quest_menu$ +"[^0000FF More Quests ^000000]"; My apologizes. Was pretty tired when I wrote it originally. At any rate, it needs to be changed as such, or the menu options will be pushed down 1. It's a small simple fix. But would have caused a lot of problems when trying to create a quest. All the information would have been messed up @.@; As for tracking the quest takers, just use the labels: OnNPCKillEvent: & OnPCLogoutEvent: & OnPCDieEvent: Example of tracking when logging out: OnPCLogoutEvent:query_sql("UPDATE `database` SET `taker_id` VALUE '0' WHERE `taker_id` = '"+ getcharid(3) +"'");end; That would essentially erase their ID from the custom quest database's taker id, making the quest available again. Example of when the player dies: OnPCDieEvent:if( countstr( ""+ killerrid +"" ) >= 7 && killerrid != getcharid(3) ){ end; } // Player died in PvP Combat, and did not commit suicide. Shouldn't count against them.@quest_death++; // Player either was killed by a monster or committed suicide.if( @quest_death >= .quest_death_limit ){ // Player died too many times so remove all his quests. @quest_death = 0; deletearray @quests$; // This would be an example of the array which holds all the data for his quests. query_sql("UPDATE `database` SET `taker_id` VALUE '0' WHERE `taker_id` = '"+ getcharid(3) +"'"); dispbottom "You have died too many times to monsters. You have abandoned all of your quests.";}end; Finally example of tracking when he kills a monster: OnNPCKillEvent:for( .@i = 0; .@i < getarraysize( @quests$ ); .@i++ ){ explode( .@tmp_array$, @quests$[.@i] ); // .@tmp_array$[0] = Quest Name // .@tmp_array$[1] = Monster (Objective) name // .@tmp_array$[2] = Amount (kill, collect, etc...) // .@tmp_array$[3] = Total needed. (kill, collect, etc...) // Now we check to see if the monster we killed was a requirement for a quest the player has. if( killedrid == .@tmp_array$[1] ){ //The monster was a requirement so we add +1 kills. .@tmp_array$[2] = ""+ ( atoi( .@tmp_array$[2] ) + 1 ) +""; // Check the amount we killed against the amount we need to kill. if( .@tmp_array$[2] >= .@tmp_array$[3] ){ // We killed more or just enough so now we give player reward and remove quest. // Get reward. getitem(501,1); // remove quest from sql_database query_sql("DELETE * FROM `database` WHERE `quest_name` = '"+ .@tmp_array[0]$ +"'"); // Now that player got their reward, it's time to erase the quest from the player's tracker. @quests$[.@i] = ""; } }}// Nothing else to do here so we end it.end; To use my example of tracking when they kill a monster you need to store the quest information in a certain way when they accept the quest: @quests$[getarraysize(@quests$)] = ""+ .@name$ +":"+ .@mob_id +":"+ 0 +":"+ .@kill_required +""; This will store all the data of 1 quest into a single 'element' with in the array. Meaning that each player will be able to keep track of 2.1billion quests at a time. This method will work for tracking monster kills. However, for cooking / gathering tracking, that would probably just be handled by countitem(<item_id>);
  8. This is determined by the mobs rude status skill. If an MVP is unable to reach the player, by walking then they will eventually use their " rude " skill, which just so happens to be teleport. mob_skill_db.txt located in p(re)/folder Examples: 1039,Baphomet@AL_TELEPORT,idle,26,1,10000,0,0,yes,self,rudeattacked,,,,,,,,1039,Baphomet@AL_TELEPORT,walk,26,1,5000,0,5000,yes,self,rudeattacked,,,,,,,, You see that Baphomet like other MVPs will teleport away. So to prevent that from happening, just remove those 2 skills and they should stay there and get beat like the meanies they are D:
  9. Step 2: Of your requests, can easily be done like this: // Sets .@size to the amount of quests we were able to grab that fits our query.// Our query says to select all information from any quest that isn't taken yet.// This is determined by assuming if a quest is taken, the `taker_id` will be filled with that player's character id#..@size = query_sql("SELECT * FROM quest_database WHERE `taker_id`='0' AND `type`='hunting'", .@quest_name$, .@quest_id, .@poster_name$, .@obj1, .@amt1); // Etc, just add variables as you need them to match the table in your database..@select = 4; // We set this to 4 so we can use our loop below and not have to worry about anything else.while( .@select == 4 ){ // As long as player keeps selecting the 4th option in the menu it will repeat this loop. .@sel_quest = 0; // Set this to 0 here to reset the variable for use in the loop below. .@quest_menu$ = ""; // Again, set this variable to "" to reset the variable for use in the loop below. while( .@sel_quest != 3 ){ // This attempts to grab 3 different quests and present them as options for the player. .@temp_variable = rand( getarraysize( .@quest_name$ ) ); // Randomly select a quest. if( !compare( .@quest_menu$, .@quest_name$[.@temp_variable] ) ){ // Checks to see if we already chose this quest. // Since we didn't use this one before we put it in the menu. .@quest_menu$ = .@quest_menu$ +":"+ .@quest_name$[.@temp_variable]; .@sel_quest++; // Set to +1 to let loop know we selected a quest. } } // We finished selecting our quests, now we just add a 4th option to the menu saying more quests. .@quest_menu$ = .@quest_menu$ +":[^0000FF More Quests ^000000]"; // Then we present them with the menu and have them decide. .@select = select( .@quest_menu$ );}// If they selected a menu option that was not [More Quests], then they come here, other wise they stay in the loop.// Here we update the sql table with the player's character id# in the taker's position to say they accepted the quest.// This is also where you begin to set things up to track their progress. That's the basics for making the player choose a quest, that has been previously generated from a specified type.
  10. While, I don't quite like your " tone " depicted with your choice of words, I have commented it. * note - again this hasn't been tested * This won't help do everything you listed, but it will help give you an idea of how to generate quests and add them to sql.
  11. I agree with Playtester and csnv, while I myself are in the same position as yourself, I have recently increased the amount of work I do from script -> source code. A lot (~85%) of the stuff I write in src, doesn't work. But the 15% that did work, I am proud to say I did all on my own with little to no help aside from looking at source code for references, and the times I ask for it in source_support section ( very good place if you get stuck ). I can even go as far to say that after just 2-3 months of experimentation, I was able to make 2 working commands ( src code was moderately borrowed from existing ) with the plugin system. So believe me when I say, it's not some unreachable place or goal. With a little bit of time and some passionate effort, you can get there, because I know I'm still trying and slowly moving towards that position! Learners rally!!
  12. @Garr - Didn't see the .@j++ at the end. But yes, in order to fix this, he would need to run 2 separate loops, 1 to delete all items and the second to give them back bound. At least this is the simplest way to do it.
  13. Well, for one your using ' .@i ' in your loop. But in the commands delitem2 and getitembound2 your using ' .@j '. I'm going to assume your only testing this with 2 items in your inventory. If this is the case then only 1 item is going to be bound, since .@j has a value of zero and never get's increased. TL;DR: change all .@j to .@i or vice-versa
  14. Sorry my bad, I meant to use getmonsterinfo( .@i, 0); but I forgot to change it after I was done writing out the template. I updated my previous post. And again, I haven't tested whether or not it will fully work, I just know it doesn't have syntax errors.
  15. Perhaps something like this: - script sql_quest_generator -1,{OnHuntingCreate:freeloop(1); // Freeloop to prevent infinite loop error.while( .@hunting != .hunting_generate ){ // Loop through the below until a total of (.hunting_generate) amount of quests have been created. .@a = rand(.min_hunting_objective, .max_hunting_ojbective); // Select a random amount of objectives for this quest. .@name$ = "Hunting:"; // Start of the quest name. // Loop the below until the selected amount of objectives have been added to the proper variables. while( .@b != .@a ){ .@i = rand(1001,3000); // Selecting a random mob_id # from 1001 (Scorpion) -> 3000 ( Just going beyond what exists to add support for custom mobs ). if( !compare( .blacklist$, ""+ getmonsterinfo( .@i, 0 ) +"" ) ){ // Compares monster ID number to see if it is blacklisted or not. .@mob_objectives[.@b] = .@i; // Adds the monster as an objective. .@mob_obj_amount[.@b] = rand(.min_hunting_amount, .max_hunting_amount); // Adds a random amount to be killed to complete that objective. .@name$ = .@name$ + getmonsterinfo( .@i, 0 ); // Adds the monster's name as part of the quest name. .@b++; } } // We create an entry in our custom quest_database using just the Quest name for now. // This will serve as a pointer when adding in all the objectives later, since the amounts were dynamically chosen and not set in stone. query_sql("INSERT INTO quest_database `quest_name` = '"+ .@name$ +"'"); // Loop through this until ALL objectives & the amount needed to complete it, have been added to the quest we listed above. while( .@c < getarraysize( .@mob_objectives ) ){ // Adding in each objective and it's amount to the quest we just created above. query_sql("Update quest_database SET( `obj"+ .@c +"`, `amt"+ .@c +"'`) VALUES( '"+.@mob_objectives[.@c]+"', '"+.@mob_obj_amount[.@c]+"') WHERE `quest_name`='"+ .@name$ +"'"); .@c++; } // Set this variable +1 to say we have completed creating a quest. And to continue looping if not all of them have been created. .@hunting++;}// Freeloop(0) to let server know we are done looping and to stop trying to prevent infinite loops.freeloop(0);end;// This is where the settings go to configure the above to do what you want.OnInit:.hunting_generate = 3; // How many hunting quests to create and add to sql.// Minimum and Maximum amount of different monsters to be used as an objective..min_hunting_objective = 1;.max_hunting_objective = 5; // Note - This can not be higher than the number of objectives listed in your sql table. So if your sql table only supports 3, this can be no higher than 3.// Minimum and Maximum amount to be killed for each objective..min_hunting_amount = 5;.max_hunting_amount = 20;// Bonus, a custom command that when used, will attempt to create a (.hunting_generate) more quests and add them to the database.bindatcmd "huntgen", strnpcinfo(3)+"::OnHuntingCreate";end;} It's untested, but if it works, it should generate 3 hunting quests, with random amount of 1-5 different monsters to hunt, ranging from 5-20 of each to kill. And place them into a sql database.
  16. O.o I believe it's <ITEMLINK> what your looking for, but I'm not sure if we have it working here yet. All my attempts have failed. <URL> & <NAVI> works though.
  17. SRC modifications involving clif.c and clif.h deal with how the client interprets these sort of things. You'd need to manipulate what the packet is actually sending. You might also possibly need to hex the client as well, but I'm not too sure, nor am I capable of doing this.
  18. You could use, Annieruru's getmemberaid command. It can return all the AID's of users within X1,Y1,X2,Y2 range. So if you were to specify, all users with in 9 cells in any direction starting from the unit. You could have it just randomly choose 1 of those or make it do something else based on that information. Also, you can use a script to make the mob walk dynamically to it's location. It'd be pretty much checking the unit's location every X seconds, and reroute accordingly mid walk, thus eliminating the need to actually set predefined points into an array and making it travel there and reroute to the next predetermined point until it reaches it's destination.
  19. Okay, well I thought about various ways to get this to work, but sadly the only way to get it to work is through src modifications ( best way ) or src + scripts ( works, but wouldn't recommend ). Fastest, but also buggy method: 1. Increase party share range to 30 levels in party.conf 2. Edit party.conf and turn share bonus to +0%. 3. Through script you can make it so players who are in the party need to be within share range of the highest member and will only receive exp based on that. a. If highest member is level 79 then people level 49-79 can receive exp in the party. b. If highest member is level 80+ then only those who are within 1-10 levels may receive exp in the party. Known issues: 1. Player who kills the monster may receive 1-2% more or less exp from the monster. 2. Player's who are out of share range, may receive or lose 1-2% of the killed monster experience. This is because of how integers work in hercules, there is no decimal everything is whole numbers rounded down. Best way: Modify src to fit exactly what you want. More difficult, but definitely better.
  20. Just use the NEMO client patcher. It's by far the best, easiest and fastest way to make a working client for any server. http://herc.ws/board/topic/2905-nemo-client-patcher/
  21. Well, my information was off by a long shot xD
  22. If it needs to walk then you have to make a small algorithm for it. So that it will walk to X recalculate route, walk to Y, recalculate route and continue in this pattern until it reaches it's destination. Otherwise, you could just use unitwarp if the method of arrival doesn't matter so long as they get there.
  23. Currently not possible. from this topic: http://herc.ws/board/topic/4830-noitem-mapflag/?p=42296
  24. File Name: Instance Check Commands File Submitter: GmOcean File Submitted: 07 Nov 2014 File Category: Plugins Additional Instance Check Commands to go along with the existing instance_check_party. Commands: *instance_check_guild(<guild_id>{,<amount>{,<min>{,<max>}}});This function checks if a guild meets certain requirements, returning 1 ifall conditions are met and 0 otherwise. it will only check online characters.amount - number of online guild members (default is 1).min - minimum level of all characters in the guild (default is 1).max - maximum level of all characters int he guild (default is max level in conf).Example:if( instance_check_guild(getcharid(2), 2, 1, 150) ){ mes "Your guild meets the Memorial Dungeon requirements.", mes "All online members are between levels 1-150 and at least two are online."; close;} else { mes "Sorry, your guild does not meet requirements."; close;} *instance_check_ready(<IOT_TYPE>,<owner_id>{,amount{,min{,max}}});This function checks if the Char, Party, Guild, etc... meets certain requirements, returning 1 ifall conditions are met and 0 otherwise. It will only check online characters.IOT_TYPE: IOT_NONE - Not sure what this is, but will return 1 regardless of settings due to it being unknown. IOT_CHAR - Character ( Will only check for min or max level. Amount doesn't matter since only 1 character can enter IOT_CHAR instance ). IOT_PARTY - Party IOT_GUILD - Guildamount - number of online party members (default is 1).min - minimum level of all characters in the party (default is 1).max - maximum level of all characters in the party (default is max level in conf).Example:if( instance_check_ready(IOT_CHAR, getcharid(0), 1, 75) ){ mes "The player has met all the requirements to enter the instance.", mes "The player is at least level 75 and is online."; close;} else { mes "The player does not meet all the requirements or is offline."; close;}Example 2:if( instance_check_ready(IOT_PARTY, getcharid(1), 5, 10, 50) ){ mes "The party meets all the requirements to enter the instance.", mes "All online members are between the levels 10-50 and at least 5 members are online."; close;} else { mes "Sorry, your party does not meet all the requirements."; close;}Example 3:if( instance_check_ready(IOT_GUILD, getcharid(2), 36, 140, 150) ){ mes "The guild meets all the requirements to enter the instance."; mes "All online members are between the levels 140-150 and at least 36 of them are online."; close;} else { mes "Sorry, your guild does not meet the requirements."; close;} [Credits: malufett for providing the base for which these commands were derived from]. Click here to download this file
  25. While, I don't feel that RO has died or failed. I do agree with a few of the points made. Also, RO2 I hated it, tried it, didn't like it, deleted it. End of story there. But even now I can't bring myself to play RO as I used to back during subscription days when it was first released, before there was even a single 99 player. However, I do find quite a bit of joy in creating scripts and the like for ragnarok. Perhaps I've just moved on from playing to creating !! Call it my feeble attempt at trying to bring to RO what, in my opinion should have been there to begin with.
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.