Walking Shapeshifter

Hi @LL!
After 5 year break, I started D2 again and saw that Etal vanished.
That was where I last was working on Teleporting Shapeshifter, what worked after some telling me Etal can’t do it.
Now in Kolbot I see similar ways the shaping and teleporting is handled. But very fast you can see a problem, especially when you turn teleport off! Bot keeps constantly shifting, sometimes even right in front of a fana mob. No wonder still no shape bots around. :smirk:
So I started working on this issue and got it solved for me for now. The code is ugly and needs someone who actually knows what to do and where. :laughing:
I never learned this, so I mostly look at code and trial and error my way through it while bot is running^^
1.
I got the bot to use cta hand as precast without swapping between slots(currently no check for better skill, I need skilltab number for corresponding skills to check).
This a must imo for any melee and is not handled for all skills.
2.
I got bot to stay in shape until he need to do something he can’t do while shaped!
3.
I changed the skill hand usage to always use rightclick not left(this needs a code to click on empty tile behind the targeted unit or empty tile in front of hero and holdclick, so every other monster in the path will get auto attacked.)
4.
I need turned of teleport for this testing, to use this with teleport I need help with distance calls and area clearing, to find right balance between tele and walk(original is tele to 10 and walk everything at 5, if I read the code right)
I would prefer something like teleport only for area changes or more then 30-40.

the main thing I did was adding this at the right positions(I think^^).

if(me.getState(139) || me.getState(140)){
					Misc.unShift();
					}

if(!me.getState(139) || !me.getState(140)){
				Misc.shapeShift(Config.Wereform);
				Attack.weaponSwitch(Attack.getPrimarySlot());
				}

It woks, but my guess is someone can write something global to handle it, like the teleport funktion it self. My code had to go all over the place and I have not tested Teleporting for now(started this 3 days ago).
Any help will be appreciated.

Regards Hama

1 Like

So I think I finally found the best solution and that was in pather.js

useTeleport: function () {
					if((me.getSkill(223,0) || me.getSkill(228,0)) &&  (me.getState(139) || me.getState(140))){
					Misc.unShift();
					}
		return this.teleport && !Config.NoTele && !me.getState(139) && !me.getState(140) && !me.inTown && ((me.classid === 1 && me.getSkill(54, 1)) || me.getStat(97, 54));
	},

and these changes in precast.js

if (this.checkCTA()) {
			var slot = me.weaponswitch;
			
			Attack.weaponSwitch(this.haveCTA);
			if((me.getSkill(223,0) || me.getSkill(228,0)) &&  (me.getState(139) || me.getState(140))){
					Misc.unShift();
					}
			Skill.cast(155, 0); // Battle Command
			Skill.cast(149, 0); // Battle Orders

	
			this.BODuration = (20 + me.getSkill(149, 1) * 10 + (me.getSkill(138, 0) + me.getSkill(155, 0)) * 5) * 1000;
			this.BOTick = getTickCount();


			return true;
		}
	this.precastSkill = function (skillId) {
		var swap = me.weaponswitch;

		Attack.weaponSwitch(this.getBetterSlot(skillId));	
		
		Skill.cast(skillId, 0);
		if(me.getSkill(223,0) || me.getSkill(228,0)){
			if(!me.getState(139) || !me.getState(140)){ 
			Misc.shapeShift(Config.Wereform);}
			}
		

		Attack.weaponSwitch(Attack.getPrimarySlot());
		if(me.classid === 3){Skill.setSkill(Config.AttackSkill[2], 0);}
		return true;
	};
		case 5: // Druid

			
			if (me.getSkill(235, 0) && (!me.getState(151) || force)) {
				if((me.getSkill(223,0) || me.getSkill(228,0)) &&  (me.getState(139) || me.getState(140))){
					Misc.unShift();
					}
				this.precastSkill(235); // Cyclone Armor
			}

			if (Config.SummonRaven) {
				this.summon(221); // Raven
			}


			switch (Config.SummonAnimal) {
				
			case 1:
			case "Spirit Wolf":
				buffSummons = this.summon(227) || buffSummons; // Summon Spirit Wolf

				break;
			case 2:
			case "Dire Wolf":
				buffSummons = this.summon(237) || buffSummons; // Summon Dire Wolf

				break;
			case 3:
			case "Grizzly":
				buffSummons = this.summon(247) || buffSummons; // Summon Grizzly

				break;
			}

			switch (Config.SummonVine) {
			case 1:
			case "Poison Creeper":
				buffSummons = this.summon(222) || buffSummons; // Poison Creeper

				break;
			case 2:
			case "Carrion Vine":
				buffSummons = this.summon(231) || buffSummons; // Carrion Vine

				break;
			case 3:
			case "Solar Creeper":
				buffSummons = this.summon(241) || buffSummons; // Solar Creeper

				break;
			}

			switch (Config.SummonSpirit) {
			case 1:
			case "Oak Sage":
				buffSummons = this.summon(226) || buffSummons; // Oak Sage

				break;
			case 2:
			case "Heart of Wolverine":
				buffSummons = this.summon(236) || buffSummons; // Heart of Wolverine

				break;
			case 3:
			case "Spirit of Barbs":
				buffSummons = this.summon(246) || buffSummons; // Spirit of Barbs

				break;
			}
			
			if (me.getSkill(250, 0) && (!me.getState(144) || force)) {
				if((me.getSkill(223) || me.getSkill(228)) &&  (me.getState(139) || me.getState(140))){
					Misc.unShift();
					}
				Skill.cast(250, 0); // Hurricane
			}

			if (Config.SummonSpirit === 1 && me.getSkill(226, 1) && (!me.getState(149) || force)) {
				Skill.cast(226, 0); // Oak Sage
			}

			if (Config.SummonSpirit === 2 && me.getSkill(236, 1) && (!me.getState(148) || force)) {
				Skill.cast(236, 0); // Heart of Wolverine
			}

			if (Config.SummonSpirit === 3 && me.getSkill(246, 1) && (!me.getState(147) || force)) {
				Skill.cast(246, 0); // Spirit of Barbs
			}

			if (buffSummons) {
				this.precastCTA(force);
				}

			
			if(!me.getState(139) || !me.getState(140)){
				(me.getSkill(223,0) || me.getSkill(228,0))
					Misc.shapeShift(Config.Wereform);
			}
			
			

			break;

But since I made the changes I didn’t try botting with druid, only used it for manual play.
And for that it is a joy to play now, he changes for Bo, precast, rebuff summons and teleport. So you can use hotkeys while shapeshifted and after Bo he even changes back to wear form. this cause double shaping with bot if he need to teleport after buffing, at that point I lost interest in trying on my own without further help.
Obviously my solution is a bit raw, but I think this would make wearform script unnecessary. Just a simple rule in global attack script would be needed to handle shaping before attacks.

Biggest issue is shape-shifting is slow. To do a wereform druid with cta it needs to check current surrounding mob count before shifting to precast cta. Which alright thats not too bad i recently added me.getMobCount. However if there are too many mobs around so it skips precasting now you have a recursive situation because after every attack or every node moved to precast gets called again which then rebuilds the monster list and repeats until surrounding area is safe. If you were pathing that might be awhile so probably end up crashing. If you try to use teleport with wereform current teleporting method will need to be modded so he only teleports within x distance otherwise he’ll likely end up in the middle of a mob pack and get wrecked. Combining both of those what if you’re teleporting and get within x of mobs then start to move towards them but arent quite in the getMobCount range yet so it decides area is safe enough to unshift. Likely by the time he actuall finishes casting he’ll be surrounded and get wrecked.

1 Like

The way I’m trying to solve this will not unshape and teleport under distance < 20, so it will call the walk to function and mainly use teleport to get to areas and distance > 20. The mob count and distance to start walking are main problem I started to play around with this, but have no clue how to code, I mainly read code and paste or mod it to parts I found where I think they’re needed.
Had no crashes or recursion with these changes.