Page 1 of 4

AI Switcher

Posted: Fri Apr 19, 2013 7:04 pm
by Xanathar
Hi all
here is the first release of the AI switcher : http://grimrock.nexusmods.com/mods/254/

Demo in this post from Leki: viewtopic.php?f=14&t=5230&start=100#p58291

Sample dungeon contained in zip, with web and poison shooting spider - really almost the same AI code of Leki ancient ghoul, put on a spider to give you an example :)

Sorry but now I'm in a hurry, later today I'll update this post with more details :oops: I wanted to release it, however, as I'm not so sure I'm able to do it later ;)


Readme.txt dumped here in a hurry:

SETUP
=====

0) unzip or copy the ai folder in your mod directory.

IF YOU'RE USING LOG FRAMEWORK OR GRIMWIDGETS:
--------------------------------------------
1) You must be on the latest version of Log Framework
2) In init.lua, immediately *after* the import of grimwidgets/framework line add:

import "mod_assets/ai/aiswitcher.lua"


IF YOU'RE NOT USING LOG FRAMEWORK OR GRIMWIDGETS:
-------------------------------------------------
1) At the beginning of init.lua, immediately after either the 'import "assets/scripts/standard_assets.lua"' line add:

import "mod_assets/ai/aiswitcher.lua"

2) After this, add a scripting entity to your dungeon with this code:

spawn("aiswitcher_engine", 1, 1, 1, 1):open()



Either way... You're Done :)



DEFINING MONSTERS
=================
To define a monster for AI switching, use defineAiSwitchMonster instead of defineObject.
You need to change the monster definition this way:

1) All hooks must be strings containing code, instead of functions. In 99% of the cases you just need to add [[ before the code and ]] after (but before the comma).
2) You need a new "brains" subtable which will contain the alternate definitions. You can override every property in brains (as a handy helper, if you override the animations, these will be merged with the original definition).
3) Each element of the "brains" subtable must contain a "condition". Condion can be a function in string form or a table of <condition-name>, <minvalue>, <maxvalue>. condition-name can as now be "distance" to check the distance of the monster to the party, "directdistance", which checks the distance but only if the monster is in the same row or column of the party, and "health" which checks the monster health. If a function in string form is specified, the function receives the monster as an argument and should return true when the condition is satisfied.
4) Elements of "brains" are always checked in sequence (so the first satisfied condition wins). If no condition is satisfied, the default is the brain of the monster (the one outside the brains table).
5) Do NOT add items to monsters with AI switch using the standard editor, as those are lost after an AI change.

EXTRA-HOOKS
===========
A couple of extra hooks are provided for the modder convenience at the monster declaration level:
- onAiSwitch(self, oldindex, newindex): Happens when the AI is about to be switched. oldindex and newindex are indices in the brains array, with 0 being the one of the outer (default) brain.
- onPartyProjectileHit: same as party.onProjectileHit. This is included here, as a lot of monster customizations involve
shooting a projectile as a form of attack


Example:

Code: Select all

defineAiSwitchMonster{
	name = "spider",
	class = "Monster",
	model = "assets/models/monsters/spider.fbx",
	meshName = "spider_mesh",
	animations = {
		idle = "assets/animations/monsters/spider/spider_idle.fbx",
		moveForward = "assets/animations/monsters/spider/spider_walk.fbx",
		turnLeft = "assets/animations/monsters/spider/spider_turn_left.fbx",
		turnRight = "assets/animations/monsters/spider/spider_turn_right.fbx",
		attack = "assets/animations/monsters/spider/spider_bite.fbx",
		getHitFrontLeft = "assets/animations/monsters/spider/spider_get_hit_front_left.fbx",
		getHitFrontRight = "assets/animations/monsters/spider/spider_get_hit_front_right.fbx",
		getHitBack = "assets/animations/monsters/spider/spider_get_hit_back.fbx",
		getHitLeft = "assets/animations/monsters/spider/spider_get_hit_left.fbx",
		getHitRight = "assets/animations/monsters/spider/spider_get_hit_right.fbx",
		fall = "assets/animations/monsters/spider/spider_get_hit_front_left.fbx",
	},
	moveSound = "spider_walk",
	attackSound = "spider_attack",
	hitSound = "spider_hit",
	dieSound = "spider_die",
	hitEffect = "hit_goo",
	capsuleHeight = 0.2,
	capsuleRadius = 0.8,
	health = 160,
	sight = 6,
	attackPower = 23,
	accuracy = 10,
	movementCoolDown = 1,
	noRecoilInterval = { 0.1, 0.4 },
	exp = 175,
	healthIncrement = 30,
	attackPowerIncrement = 5,
	brain = "Melee",
	onDealDamage = [[function(self, champion, damage)
		if math.random() <= 0.3 then
			champion:setConditionCumulative("poison", 30)
		end
	end]],
	onDamage = [[function(self, amount, typed)
		if (typed == "poison") then
			return false
		end
	end]],	
	
	brains = 
	{
		{	-- will change to this brain when the monster is in line with the party, with distance equal to 2
			condition = { "directdistance", 2, 2 },
			animations = { attack = "mod_assets/animations/spider_shoot.fbx" },
			rangedAttack = "poison_bolt",
			brain = "Ranged",
			
			-- override ranged attack for this monster! Note the hook is a string
			onRangedAttack = [[function(self)
				local x, z = getForward(self.facing)
				shootProjectile("spider_web", self.level, self.x, self.y, self.facing, 9.0, 7.0, 0.1, -x, 0.7, z, 10, self, true);
				return false;
			end]],
			onPartyProjectileHit = [[function(champ, proj, damage, damtype)
				if (proj.name == "spider_web") then
					champ:setConditionCumulative("paralyzed", 60);
				end
			end]],					
		},
		{	-- will change to this brain when the monster is distance 2 to infinite from the party
			condition = { "distance", 2, 99999 },
			animations = { attack = "mod_assets/animations/spider_shoot.fbx" },
			rangedAttack = "poison_bolt",
			brain = "Ranged",
		},	
	},	
}

defineAnimationEvent{
	animation = "mod_assets/animations/spider_shoot.fbx",
	event = "ranged_attack",
	frame = 12,
}

cloneObject {
	name = "spider_web",
	baseObject = "rock",
	-- change the model here!
}

Re: AI Switcher

Posted: Fri Apr 19, 2013 8:14 pm
by Leki
File on Nexus does not published m8.

Re: AI Switcher

Posted: Fri Apr 19, 2013 8:40 pm
by odinsballs
Leki wrote:File on Nexus does not published m8.
nexus is set up in a way that you can upload the files and make all read me's and then hit publish file (so i wager xanathar forgot to hit the publish button wich then makes file visible in download list)

Re: AI Switcher

Posted: Fri Apr 19, 2013 9:10 pm
by Xanathar
Ok I'm an idiot.. me and Nexus are in a complicated relationship :lol:
Now it should work.

Just another point I kinda forgot in the worst announcement ever: if you are a framework user, the sentence "1) You must be on the latest version of Log Framework" might actually mean "the next version jkos is going to release when he can" :D (sorry jkos, I totally forgot that wasn't a public version yet).

Re: AI Switcher

Posted: Sat Apr 20, 2013 11:01 am
by Xanathar
Hi all,
I have a number of requests for little demos of this, if anyone has spare time :)
  • A "web" projectile and, maybe, a web particle screen effect (like the fireball one but suggesting a web thrown to the party)
  • Two retextured spiders, one "natural" the other more with vivid colors (this second for a phase spider concept)
  • Any one humanoid monster (skeleton, ogre, warden, what you want) retextured and positioned as a statue (texture and 1 frame fixed animation in a statue like position)
I think they would make nice concepts (not original at all I admit, these were discussed a lot in these forums :) ), but I have no skills on those areas (or, well, very little skills :) ).

Re: AI Switcher

Posted: Sat Apr 20, 2013 12:30 pm
by Damonya
I like your job
SpoilerShow
First spider (red)
Model = http://www.meteobell.com/Divers/JDR/Gri ... _low.model
Texture = http://www.meteobell.com/Divers/JDR/Gri ... l2_dif.dds

Second spider (green)
Model = http://www.meteobell.com/Divers/JDR/Gri ... dium.model
Texture = http://www.meteobell.com/Divers/JDR/Gri ... l3_dif.dds

Code: Select all

defineMaterial{
	name = "spider_low",
	diffuseMap = "mod_assets/textures/spider_level2_dif.tga",
	specularMap = "assets/textures/monsters/spider_spec.tga",
	normalMap = "assets/textures/monsters/spider_normal.tga",
	doubleSided = false,
	lighting = true,
	alphaTest = false,
	blendMode = "Opaque",
	textureAddressMode = "Wrap",
	glossiness = 40,
	depthBias = 0,
}


defineMaterial{
	name = "spider_medium",
	diffuseMap = "mod_assets/textures/spider_level3_dif.tga",
	specularMap = "assets/textures/monsters/spider_spec.tga",
	normalMap = "assets/textures/monsters/spider_normal.tga",
	doubleSided = false,
	lighting = true,
	alphaTest = false,
	blendMode = "Opaque",
	textureAddressMode = "Wrap",
	glossiness = 40,
	depthBias = 0,
}

--Spider LVL 2
cloneObject{
	name = "spider_low",
	baseObject = "spider",
	model = "mod_assets/models/spider_low.fbx",
	exp = 200,
	health = 190,
	attackPower = 28,
	
}
--Spider LVL 3
cloneObject{
	name = "spider_medium",
	baseObject = "spider",
	model = "mod_assets/models/spider_medium.fbx",
	exp = 225,
	health = 220,
	attackPower = 33,
	
}

Spider_web_rock
Model = http://www.meteobell.com/Divers/JDR/Gri ... _web.model

Code: Select all

defineMaterial{
	name = "spider_web_rock",
	diffuseMap = "assets/textures/props/spider_webs_dif.tga",
	specularMap = "assets/textures/items/rock_spec.tga",
	doubleSided = true,
	lighting = false,
	alphaTest = false,
	blendMode = "Translucent",
	textureAddressMode = "Wrap",
	glossiness = 20,
	depthBias = 0,
}

defineObject{
		name = "spider_web",
		class = "Item",
		uiName = "Spider Web",
		model = "mod_assets/models/spider_web.fbx",							
		skill = "throwing_weapons",
		ammoType = "rock",
		throwingWeapon = true,
		gfxIndex = 45,
		attackPower = 5,
		coolDownTime = 4,
		attackMethod = "throwAttack",
		attackSound = "swipe",
		impactSound = "impact_blunt",
		stackable = true,
		projectileRotationSpeed = 10,
		projectileRotationZ = -30,
		weight = 1.0,

}
Change like you want the spider_web feature. Here it's like a rock with only the web texture. It's not perfect. I did it very quickly. We can do better

Re: AI Switcher

Posted: Sat Apr 20, 2013 2:42 pm
by Xanathar
Wow that was QUICK!

Thanks!

Re: AI Switcher

Posted: Sat Apr 20, 2013 3:51 pm
by Damonya
Yes very quickly. Maybe, someone will do better.

For your web particle screen effect. Try this:
SpoilerShow

Code: Select all

  defineParticleSystem{
name = "web",
emitters = {
{
emissionRate = 10,
emissionTime = 5,
maxParticles = 100,
boxMin = {-1, 0,-1},
boxMax = { 1, 0, 1},
sprayAngle = {0,0},
velocity = {0,0},
texture = "assets/textures/props/spider_webs_dif.tga",
lifetime = {10,20},
color0 = {1, 1, 1},
opacity = 0.9,
fadeIn = 0.5,
fadeOut = 7,
size = {0,5, 1},
gravity = {0,0,0},
airResistance = 0.1,
rotationSpeed = 0,
blendMode = "Translucent",
objectSpace = false,
}
}
} 

defineObject{
name = "spider_web_emitter",
class = "LightSource",
lightPosition = vec(1.2, 0.2, 0),
lightRange = 6,
lightColor = vec(1, 1, 1),
brightness = 0,
castShadow = true,
particleSystem = "web",
placement = "floor",
editorIcon = 88,
}
For humanoid monster, I've never done it, so someone else.

Re: AI Switcher

Posted: Sat Apr 20, 2013 5:30 pm
by Grimfan
This is simply brilliant Xanathar (and Leki). While I won't be implementing this in my upcoming mod (playtesting it now) I certainly will be using this in the future (unless AH implements something like this in LOG2 before I can conclude my next one that is).

Still, crazy good work! :)

Re: AI Switcher

Posted: Sat Apr 20, 2013 10:29 pm
by Xanathar
Thanks Grimfan! :)

And using Damonya assets, I've uploaded to the Nexus page a new version of the sample dungeon with a more badass version of the shooting spider :)