Thread: [RUSE] Making a boss/NPC from scratch!

Results 1 to 10 of 10
  1. #1 [RUSE] Making a boss/NPC from scratch! 
    Registered Member Text's Avatar
    Join Date
    Nov 2012
    Posts
    302
    Thanks given
    61
    Thanks received
    27
    Rep Power
    21
    Hello Rune-Server, today I made my first NPC from scratch, and I decided to turn it into a slightly larger tutorial! I'm going to be covering a pretty large surface with this tutorial, ranging from client commands, the NPCDef class, to NPC definitions on the server-side and CombatStrategies!

    What I'll be showing you:
    • Tools and Commands
    • Designing the NPC
    • Creating a CombatStrategy
    • Advanced CombatStrategy



    So let's get down and dirty, with step 1:

    Tools and Commands
    [SPOIL]For this tutorial, I used quite a few debugging tools and commands to help me on my way.
    Dump NPC defs by Linus - BEWARE, this will take some renaming. Just change entityDef to npc in Ruse, you should also remove the recolor features (That's what I did at least, if you can figure out how it works in Ruse be my guest lol)
    RSMV (RS Model Viewer) - You can find this just about anywhere, not gonna link lol
    The data from your cache - If you can't unpack this, search up like 474 model dats, should find what you need.
    Also, this command in your client:
    Code:
    		case "modelinf":
    			sendConsoleMessage("Model ID: " + ItemDef.forID(Integer.parseInt(args[1])).modelID, true);
    			sendConsoleMessage("Wear: " + ItemDef.forID(Integer.parseInt(args[1])).maleEquip1, true);
    			sendConsoleMessage("Zoom: " + ItemDef.forID(Integer.parseInt(args[1])).modelZoom, true);
    			sendConsoleMessage("RotX: " + ItemDef.forID(Integer.parseInt(args[1])).rotationX, true);
    			sendConsoleMessage("RotY: " + ItemDef.forID(Integer.parseInt(args[1])).rotationY, true);
    			break;
    All of these things should give you everything you need to identify model IDs, dump NPC defs so they can be added to NPCDef class, and create your own custom NPC!

    PS, use modelinf in the console to get the model of armor or weps to equip your NPC/boss
    [/SPOIL]

    Designing the NPC
    [SPOIL]This isn't a very complicated task, and it's all up to personal preference, for this segment, I'll just provide you with the NPCDef case of my first NPC.

    What I did was review the dump.txt that was written to my desktop by Linus's dump method, then in RSMV I checked out the array of models of a humanoid NPC I picked (In my case, it was NPC 200 since he isn't ingame and I really doubt I'll ever use him). After looking at all of the models in RSMV, I labeled which ones were which. I don't think the order REALLY matters, but then again this was my first attempt with this and I haven't done much experimenting.

    NPCDef case for my NPC: Rex Goliath
    Code:
    		case 200:
    			npc.name = "Rex Goliath";
    			npc.walkAnim = 1660;
    			npc.standAnim = 11973;
    			npc.models = new int[9];
    			npc.models[0] = 230; //HEAD
    			npc.models[1] = 246; //JAW
    			npc.models[2] = 49352; //CHEST
    			npc.models[3] = 10313; //CAPE
    			npc.models[4] = 49347; //ARM
    			npc.models[5] = 49349; //HAND
    			npc.models[6] = 5409; //WEP
    			npc.models[7] = 49351; //LEG
    			npc.models[8] = 49348; //BOOT
    			npc.actions = new String[5];
    			npc.actions[0] = "Examine";
    			npc.actions[1] = "Attack";
    			npc.actions[2] = null;
    			npc.actions[3] = null;
    			npc.actions[4] = null;
    
    
    			break;
    As you review these models in RSMV, you'll notice the wep slot has the model for a whip. This is why I set his walk and stand anims to what I did, if he's wielding a standard wep like a scimitar or sword, you'll need a different stand anim.

    Notice the examine button is before the attack button, that's switched if you're a high enough level to attack him with a left click. actions[0] should always be examine when making a combat capable NPC.

    Then, on the server-side, you'll need to change his npc definition in /src/data/def/json/npc_definitions.json
    Search for "id": 200 and replace that case with this:
    Code:
    {
    "id": 200,
    "name": "Rex Goliath",
    "examine": "A mighty warrior!",
    "combat": 138,
    "size": 1,
    "attackable": true,
    "aggressive": true,
    "retreats": false,
    "poisonous": false,
    "respawn": 10,
    "maxHit": 970,
    "hitpoints": 10000,
    "attackSpeed": 7,
    "attackAnim": 11968,
    "defenceAnim": 11974,
    "deathAnim": 2304,
    "attackBonus": 500,
    "defenceMelee": 350,
    "defenceRange": 350,
    "defenceMage": 150
    },
    Most of this is self explanatory, but remember this is the constitution system so hitpoints and maxHit are multiplied by 10. I chose attackSpeed 7 for this NPC because it seemed like a reasonable number, you can experiment with faster and slower enemies. Beware that this will be overridden when you create the CombatStrategy in the next step![/SPOIL]

    Creating the CombatStrategy
    [SPOIL]Creating the CombatStrategy for Rex Goliath is a simple, yet daunting task. For those who have never used the CombatStrategy class in Ruse before, please check out my other tutorial on making a simple Combat Stone Here

    Let's start with the basic CombatStrategy class, first create a new class in com.ruse.world.content.combat.strategy.impl, we'll call it RexGoliath to keep things simple. Then, you're going to implement CombatStrategy like this:
    Code:
    package com.ruseps.world.content.combat.strategy.impl;
    
    import com.ruseps.world.content.combat.CombatContainer;
    import com.ruseps.world.content.combat.CombatType;
    import com.ruseps.world.content.combat.strategy.CombatStrategy;
    import com.ruseps.world.entity.impl.Character;
    
    public class RexGoliath implements CombatStrategy{
    Hopefully you're using Eclipse, because this is going to throw an error. Hover over the class name and implement the methods.
    Your class should now look like this:
    Code:
    package com.ruseps.world.content.combat.strategy.impl;
    
    import com.ruseps.world.content.combat.CombatContainer;
    import com.ruseps.world.content.combat.CombatType;
    import com.ruseps.world.content.combat.strategy.CombatStrategy;
    import com.ruseps.world.entity.impl.Character;
    
    public class Example implements CombatStrategy{
    
    	@Override
    	public boolean canAttack(Character entity, Character victim) {
    		// TODO Auto-generated method stub
    		return false;
    	}
    
    	@Override
    	public CombatContainer attack(Character entity, Character victim) {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public boolean customContainerAttack(Character entity, Character victim) {
    		// TODO Auto-generated method stub
    		return false;
    	}
    
    	@Override
    	public int attackDelay(Character entity) {
    		// TODO Auto-generated method stub
    		return 0;
    	}
    
    	@Override
    	public int attackDistance(Character entity) {
    		// TODO Auto-generated method stub
    		return 0;
    	}
    
    	@Override
    	public CombatType getCombatType() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    }
    Now, after looking at the code, hovering over the different methods you're blindly overriding and figuring out what they're for, you're going to set up the boss.

    Somewhere in the top, you'll need to declare his main attack animation, and since he wields a whip, it will look like this:
    Code:
    Animation attackAnim = new Animation(11968);
    After this, we need to give him a basic attack, since we'll be adding other cases in the next step.
    Looking at the customContainerAttack method, it's safe to assume that'll go here. Keeping it simple, we'll start his animation then we'll create a CombatBuilder() and declare his hook, his victim, his hit amount, the delay, the type of attack, and if it should check the accuracy or not inside of a CombatContainer(). Simple, right? More like too simple for a CombatStrategy at this point!
    Code:
    	@Override
    	public boolean customContainerAttack(Character entity, Character victim) {
    		NPC rex = (NPC)entity;
    		rex.performAnimation(attackAnim);
    		rex.getCombatBuilder().setContainer(new CombatContainer(rex, victim, 1, 6, CombatType.MELEE, true));
    		return false;
    	}
    Then we should set up the other methods, so they return SOMETHING, though these values are pretty generic.

    Code:
    	@Override
    	public int attackDelay(Character entity) {
    		// TODO Auto-generated method stub
    		return entity.getAttackSpeed();
    	}
    
    	@Override
    	public int attackDistance(Character entity) {
    		// TODO Auto-generated method stub
    		return 2;
    	}
    
    	@Override
    	public CombatType getCombatType() {
    		// TODO Auto-generated method stub
    		return CombatType.MIXED;
    	}
    You should now have a class that looks like this:
    Code:
    package com.ruseps.world.content.combat.strategy.impl;
    
    import com.ruseps.model.Animation;
    import com.ruseps.world.content.combat.CombatContainer;
    import com.ruseps.world.content.combat.CombatType;
    import com.ruseps.world.content.combat.strategy.CombatStrategy;
    import com.ruseps.world.entity.impl.Character;
    import com.ruseps.world.entity.impl.npc.NPC;
    
    public class RexGoliath implements CombatStrategy{
    
    	Animation attackAnim = new Animation(11968);
    	
    	@Override
    	public boolean canAttack(Character entity, Character victim) {
    		// TODO Auto-generated method stub
    		return false;
    	}
    
    	@Override
    	public CombatContainer attack(Character entity, Character victim) {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public boolean customContainerAttack(Character entity, Character victim) {
    		NPC rex = (NPC)entity;
    		rex.performAnimation(attackAnim);
    		rex.getCombatBuilder().setContainer(new CombatContainer(rex, victim, 1, 6, CombatType.MELEE, true));
    		return false;
    	}
    
    	@Override
    	public int attackDelay(Character entity) {
    		// TODO Auto-generated method stub
    		return entity.getAttackSpeed();
    	}
    
    	@Override
    	public int attackDistance(Character entity) {
    		// TODO Auto-generated method stub
    		return 2;
    	}
    
    	@Override
    	public CombatType getCombatType() {
    		// TODO Auto-generated method stub
    		return CombatType.MIXED;
    	}
    
    }
    Now there's nothing left to do but add the CombatStrategy hook in com.ruseps.world.content.combat.strategy.CombatStr ategies like this:
    Code:
    STRATEGIES.put(200, new RexGoliath());//NPC id, strategy
    [/SPOIL]

    Advanced CombatStrategies!
    [SPOIL]I created a PvP style boss while writing this tutorial, and here's the source code! I'll explain what it does, but not in too much detail since the tutorial already explains MOST of it. There's a random int generated between 1 and 10, and if it rolls 2, he'll "eat a shark", doing the eat anim and gaining 20 hp, while also saying a random line from an array of forcedChat strings. Otherwise, he'll do the normal attack we wrote just before. If he heals, it subtracts from healsLeft, so he can't heal infinitely, I have it set where he can only heal 7 times. His attack distance is also significantly higher, so people can't run as easily

    Code:
    package com.ruseps.world.content.combat.strategy.impl;
    
    import java.util.Random;
    
    import com.ruseps.engine.task.Task;
    import com.ruseps.engine.task.TaskManager;
    import com.ruseps.model.Animation;
    import com.ruseps.model.Graphic;
    import com.ruseps.model.Locations;
    import com.ruseps.model.Projectile;
    import com.ruseps.world.content.combat.CombatContainer;
    import com.ruseps.world.content.combat.CombatType;
    import com.ruseps.world.content.combat.strategy.CombatStrategy;
    import com.ruseps.world.entity.impl.Character;
    import com.ruseps.world.entity.impl.npc.NPC;
    
    public class RexGoliath implements CombatStrategy {
    
    	Animation attackAnim = new Animation(11968);
    	int healsAllowed = 7;
    	String[] chat = { "Not so fast!", "I still have " + healsAllowed + " sharks left!", "Food left?" };
    
    	// Graphic fireGfx = new Graphic(393);
    
    	@Override
    	public boolean canAttack(Character entity, Character victim) {
    		// TODO Auto-generated method stub
    		return true;
    	}
    
    	@Override
    	public CombatContainer attack(Character entity, Character victim) {
    
    		return null;
    	}
    
    	@Override
    	public boolean customContainerAttack(Character entity, Character victim) {
    		NPC rex= (NPC) entity;
    		if (Locations.goodDistance(rex.getPosition().getX(), rex.getPosition().getY(), victim.getPosition().getX(),
    				victim.getPosition().getY(), 14)) {
    			rex.setChargingAttack(true);
    			Random rand = new Random();
    			switch (rand.nextInt(10)) {
    			case 2:
    				if (healsAllowed >= 1) {
    					rex.performAnimation(new Animation(829));
    					rex.setConstitution(rex.getConstitution() + 50);
    					rex.forceChat(chat[rand.nextInt(chat.length)]);
    					healsAllowed--;
    				}
    				break;
    			}
    			rex.getCombatBuilder().setContainer(new CombatContainer(rex, victim, 1, 6, CombatType.MELEE, true));
    			rex.performAnimation(attackAnim);
    			// victim.
    		}
    		return false;
    	}
    
    	@Override
    	public int attackDelay(Character entity) {
    		// TODO Auto-generated method stub
    		return entity.getAttackSpeed();
    	}
    
    	@Override
    	public int attackDistance(Character entity) {
    		// TODO Auto-generated method stub
    		return 7;
    	}
    
    	@Override
    	public CombatType getCombatType() {
    		// TODO Auto-generated method stub
    		return CombatType.MIXED;
    	}
    
    }
    [/SPOIL]

    Thanks for the read, guys! Hope you found this useful. Sorry it's so messy, I did my best to organize it but it's a lot for one post haha.
    TL;DR: I put the finished classes at the end of the last two parts, and the NPCDef and server definitions in part two lol

    Edit: Afterthought, seems the healsAllowed doesn't work, iunno
    Attached image
    Reply With Quote  
     

  2. Thankful users:


  3. #2  
    Banned

    Join Date
    May 2016
    Age
    55
    Posts
    1,137
    Thanks given
    565
    Thanks received
    600
    Rep Power
    0
    very basic stuff.
    Reply With Quote  
     

  4. #3  
    Unfortunately we’re all human. Except me


    Join Date
    Aug 2011
    Posts
    926
    Thanks given
    539
    Thanks received
    439
    Rep Power
    601
    nice tutorial I'm sure someone will find that useful
    Reply With Quote  
     

  5. #4  
    Registered Member Plasmetic's Avatar
    Join Date
    Nov 2015
    Posts
    273
    Thanks given
    20
    Thanks received
    30
    Rep Power
    20
    Thanks for the contribution. Pretty basic yeah, though basic stuff is useful to newer developers. Good job.
    Reply With Quote  
     

  6. #5  
    Registered Member Text's Avatar
    Join Date
    Nov 2012
    Posts
    302
    Thanks given
    61
    Thanks received
    27
    Rep Power
    21
    Quote Originally Posted by Plasmetic View Post
    Thanks for the contribution. Pretty basic yeah, though basic stuff is useful to newer developers. Good job.
    I figured someone would find it useful, because you don't often see custom NPCs in servers, unless they're newer revision bosses or something xD

    OT: Someone neg repped me for this ;-;
    Attached image
    Reply With Quote  
     

  7. Thankful user:


  8. #6  
    Registered Member Plasmetic's Avatar
    Join Date
    Nov 2015
    Posts
    273
    Thanks given
    20
    Thanks received
    30
    Rep Power
    20
    Quote Originally Posted by Text View Post
    I figured someone would find it useful, because you don't often see custom NPCs in servers, unless they're newer revision bosses or something xD

    OT: Someone neg repped me for this ;-;
    I tried to give positive Karma for it, it might've negged you instead. Sorry if it did.
    Reply With Quote  
     

  9. #7  
    Registered Member Text's Avatar
    Join Date
    Nov 2012
    Posts
    302
    Thanks given
    61
    Thanks received
    27
    Rep Power
    21
    Quote Originally Posted by Plasmetic View Post
    I tried to give positive Karma for it, it might've negged you instead. Sorry if it did.
    Wasn't you, don't worry haha
    Attached image
    Reply With Quote  
     

  10. Thankful user:


  11. #8  
    Registered Member

    Join Date
    May 2016
    Age
    26
    Posts
    281
    Thanks given
    162
    Thanks received
    64
    Rep Power
    96
    Quote Originally Posted by Text View Post
    Wasn't you, don't worry haha
    I tried to rep you but I need to
    Quote Originally Posted by RuneServer
    ... spread some Reputation around before giving it to Text again.
    apparently
    Reply With Quote  
     

  12. #9  
    Registered Member
    Join Date
    Jul 2017
    Posts
    158
    Thanks given
    5
    Thanks received
    5
    Rep Power
    10
    I am having trouble moving shops around to different spots. could you help me by anychance?



    skype:blacktune9876543

    Quote Originally Posted by LukaFurlan View Post
    nice tutorial I'm sure someone will find that useful
    I am having trouble moving shops around to different locations. could you help me out by any chance?


    skype: blacktune9876543
    Reply With Quote  
     

  13. #10  
    Registered Member
    Join Date
    Mar 2018
    Posts
    19
    Thanks given
    2
    Thanks received
    1
    Rep Power
    11
    thank you
    Reply With Quote  
     


Thread Information
Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)


User Tag List

Similar Threads

  1. Replies: 2
    Last Post: 05-11-2013, 04:16 PM
  2. Make a Working Login,Logout, and Member page from scratch
    By Ken in forum Website Development
    Replies: 22
    Last Post: 12-06-2009, 06:21 AM
  3. [317]Make Server From Scratch [PAYING]
    By CarbonAngel in forum Requests
    Replies: 5
    Last Post: 10-02-2009, 03:43 PM
  4. Making models from scratch!
    By Mr. Linksys in forum Models
    Replies: 11
    Last Post: 07-03-2009, 12:28 AM
  5. Making a server from scratch
    By ~ Zymus ~ in forum Help
    Replies: 8
    Last Post: 02-19-2009, 03:39 AM
Posting Permissions
  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •