stan_stan
2015-03-08T19:27:14Z
Thanks Snarky.

I'll keep trying. [:thumbu:]
stan_stan
2015-03-08T22:48:57Z
Snarky. I finally did it [:dance:]

Now Sishunder is only summoned if the AI has at least 1 Kagetokage on hand.

Made something similar for Pahunder and Mahunder.


Also, added Batteryman AAA and Masked Chameleon

Batteryman and Masked Ch are only summoned if there's already 1 or more BmanAAA in the Graveyard.


I still don't know how to limit Hunders' effect to one per turn. I mean, Pahunder and Mahunder can swarm the field, on top of that Kagetogake effect is always activated.
Bateriemann
2015-03-09T01:46:40Z
Thank you Snarky!

i have a question: When i want to work with my own ai_tutorial.lua file and i want to work with a priority list then i have to make my own function PrioritySetup()?. When does the ai calls this function? Do i have to call this function at the start of the duel?

http://www.fotos-hochlad...iew/snarky2mcq85p9hg.jpg 
the "end" should be a "else".

Bateriemann
Bat
Snarky
  • Snarky
  • Advanced Member Topic Starter
2015-03-09T02:10:00Z
Originally Posted by: stan_stan 


I still don't know how to limit Hunders' effect to one per turn. I mean, Pahunder and Mahunder can swarm the field, on top of that Kagetogake effect is always activated.


You could add a limitation to their abilities by only activating them, if the AI controls x amount of cards. For example if you check for #AIMon()<2 and only use the effect then, they will only activate, if the AI controls less than 2 monsters. Or FieldCheck(4)<2, then they will only activate, if the AI controls 2 or less Level 4 monsters.

Do note, that the Hunders perform an additional normal summon, but they activate an effect to do so, so this normal summon is not handled by cards.summonable_cards, but rather by the activatable cards, and the normal summoned target is selected in OnSelectCard.

Originally Posted by: Bateriemann 


i have a question: When i want to work with my own ai_tutorial.lua file and i want to work with a priority list then i have to make my own function PrioritySetup()?. When does the ai calls this function? Do i have to call this function at the start of the duel?


You can include most of the priority stuff by adding require("ai.mod.AIOnDeckSelect"). And yes, once you have the requirement, you should be able to run AddPriority() in your start of duel function, as all it does is setting up variables.
PrioritySetup() might fail, if you call it without requiring all the other deck functions.

Also, you don't need to actually add your priorities to the same file. As seen in the Constellar and Dark World files, you can just as well put the priority list in other files, I'll probably relocate the priorities to their respective deck files at some point, since that seems to make more sense, and the deck selection became kinda cramped.
Quote:


http://www.fotos-hochlad...iew/snarky2mcq85p9hg.jpg 
the "end" should be a "else".



That doesn't really matter in this case.

if a then
  return b
else
  return c
end

if a then
  return b
end
return c

In this context, these do pretty much the same thing.
Snarky
  • Snarky
  • Advanced Member Topic Starter
2015-03-09T14:54:52Z
Added another chunk of information. Also, for anyone wanting to use the custom functions provided by the AI in their own AI: Instead of adding the required files one by one, you can just use this line:

require("ai.ai")

This links your AI file to the standard AI file, and in succession to all files the standard AI uses. Also, any function you don't add to your AI will be taken from the standard AI then. Don't feel like creating a new attack target logic? Just don't include an OnSelectBattleCommand function, it should use the one from the standard AI instead (there might be issues, because its partly handled in OnSelectCard, but I'm sure that can be sorted out).
francot514
2015-03-09T22:06:34Z
Good work youre doing here Snarky, this is a really complete information, and hope ai can be extended so far, to get story mode in ygopro.

Quote:

Mm!! If i remember correct on the past there is a program called Puzzle Editor by francot514 where you are able to make puzlzle duels but also this program have some tools about ai scripting and there is an option to allow you to change the ai name though i never test it and it seems at this moment this Puzzle Editor have not anymore any ai scripting tool!!:(



What are you talking about Tea82??, my program did not was intended to allow ai scirpting only, tried to do it once, but after that in latest updates removed it, because create an ai editor will be a huge task for programming tool.. But the editor is still avaliable and very functional...
stan_stan
2015-03-10T01:48:02Z
Originally Posted by: Snarky 

Added another chunk of information. Also, for anyone wanting to use the custom functions provided by the AI in their own AI: Instead of adding the required files one by one, you can just use this line:

require("ai.ai")

This links your AI file to the standard AI file, and in succession to all files the standard AI uses. Also, any function you don't add to your AI will be taken from the standard AI then. Don't feel like creating a new attack target logic? Just don't include an OnSelectBattleCommand function, it should use the one from the standard AI instead (there might be issues, because its partly handled in OnSelectCard, but I'm sure that can be sorted out).



Snarky, it seems like the require("ai.ai") doesn't handle the summoning of monsters from the Extra Deck.

So, let's say that I want to add some Xyz monsters like Shark Knight and Ragnazero. Obviously, the AI needs info like if I have a a SS monster, if it's in attack position, etc.

So, instead of adding all that info, what should I do?

Snarky
  • Snarky
  • Advanced Member Topic Starter
2015-03-10T02:02:54Z
Originally Posted by: stan_stan 


Snarky, it seems like the require("ai.ai") doesn't handle the summoning of monsters from the Extra Deck.

So, let's say that I want to add some Xyz monsters like Shark Knight and Ragnazero. Obviously, the AI needs info like if I have a a SS monster, if it's in attack position, etc.

So, instead of adding all that info, what should I do?



All extra deck summoning is handled in OnSelectInitCommand. So if you use a custom one here, you will override the default AI summoning logic for that.

You can try to call the generic extra deck summoning logic separately, within your own OnSelectInit function. Something like this:

OnSelectInit(...

  --handle all your own stuff

  local result = SummonExtraDeck(cards) -- function handling a lot of generic extra deck cards
  if result then 
    return result[1],result[2]
  end
  return COMMAND_TO_NEXT_PHASE,1
end

Unfortunately, the AI is not modular enough, that you can implement all the parts by themselves at will. Many extra deck monsters are spread throughout different files, lots of functions you might want to include instead of remaking are within the main functions you will automatically override, if you declare new ones. Honestly, I am not sure, how to handle this the best way.
stan_stan
2015-03-10T02:21:55Z
Originally Posted by: Snarky 

Originally Posted by: stan_stan 


Snarky, it seems like the require("ai.ai") doesn't handle the summoning of monsters from the Extra Deck.

So, let's say that I want to add some Xyz monsters like Shark Knight and Ragnazero. Obviously, the AI needs info like if I have a a SS monster, if it's in attack position, etc.

So, instead of adding all that info, what should I do?



All extra deck summoning is handled in OnSelectInitCommand. So if you use a custom one here, you will override the default AI summoning logic for that.

You can try to call the generic extra deck summoning logic separately, within your own OnSelectInit function. Something like this:

OnSelectInit(...

  --handle all your own stuff

  local result = SummonExtraDeck(cards) -- function handling a lot of generic extra deck cards
  if result then 
    return result[1],result[2]
  end
  return COMMAND_TO_NEXT_PHASE,1
end

Unfortunately, the AI is not modular enough, that you can implement all the parts by themselves at will. Many extra deck monsters are spread throughout different files, lots of functions you might want to include instead of remaking are within the main functions you will automatically override, if you declare new ones. Honestly, I am not sure, how to handle this the best way.




Sounds complicated lol. But I'll keep trying. Thanks.
stan_stan
2015-03-10T20:32:44Z
Snarky, could you please tell me about this function? and if I understan correctly this language?

function SummonImpKing(c) -- how it decides if it's ok to summon Feral Imp
  return MP2Check()  -- I have no idea what this is suppossed to mean
  and (CardsMatchingFilter(AIDeck(),FilterRace,RACE_REPTILE)>0 -- the AI has 1 or more reptile cards in the deck
  and NotNegated(c) -- i read that is a negation check, but not sure how it works
  or Negated(c) and OppGetStrongestAttDef() < 2300 -- the Opp has a monster with less than 2300 in atk or def
  and OppHasStrongestMonster()) -- not sure about this
end


So, far I've managed to copy-paste the functions for Feral Imp and Shark Knight. But Shark K. randomly targets my monsters. I still need to figure out how it decides what monster will "absorb".
Snarky
  • Snarky
  • Advanced Member Topic Starter
2015-03-10T21:03:35Z
Originally Posted by: stan_stan 

Snarky, could you please tell me about this function? and if I understan correctly this language?


MP2Check -> Checks, if the AI can wait until MP2 to summon a monster, or if it needs to summon it right away. MP2Check checks for the current phase (obviously), if the BP is even allowed, and if the opponent controls stronger monsters. This is done, so the AI can attack with the materials before XYZing to maybe get more damage in.

Negated and NotNegated check, if a card is currently (not) negated, or is about to be negated when it hits the field. Simple as that. If the card is on the field, it checks for the EFFECT_DISABLED, if its in a different location, it will check for stuff like Skill Drain, Jinzo, Decree, Majesty's Fiend, stuff like that.

OppHasStrongestMonster -> checks, if the opponent currently controls the strongest monster on the field. Pretty straight forward.

The summoning condition in its entirety should summon Imp King, if it is not negated on the field and has valid targets in the deck, with the option to wait until MP2. Or it will summon him, if it will be negated on the field (Skill Drain maybe), and the opponent currently controls the strongest monster on the field but Imp King would be stronger. Not much sense to XYZ under Skill Drain, if not to get a monster with stronger ATK, right? If your monsters are stronger anyway, it would just waste an XYZ summon.

Quote:


So, far I've managed to copy-paste the functions for Feral Imp and Shark Knight. But Shark K. randomly targets my monsters. I still need to figure out how it decides what monster will "absorb".



Well, that is handled in OnSelectCard again. You can make this really easy for yourself:


function SharkKnightTarget(cards,min)              -- pass the minTargets count as well, just to be on the safe side. 
  return BestTargets(cards,min,TARGET_OTHER)  --Remember, the detach part targets 2 cards
end

Normally, you would use Add for the detach, but since it usually detaches all materials at once anyway, you don't need to bother. Just make sure, you return the correct count, otherwise, you'll get an error message. And, as usual, you need to call that function in OnSelectCard.
stan_stan
2015-03-10T21:24:16Z
^^^^
Got it! Thanks Snarky.

AccessDenied
2015-03-12T14:31:29Z
Thanks this helped explain alot of the YGOPro Network API to me. I can start coding again. After reading this I've started making Salvation a bot;

https://github.com/Salva...blob/master/server/ai.js 

I wrote like 300 lines of code in one day based on what you wrote. This tutorial has been a huge help!
stan_stan
2015-03-13T13:57:42Z
Snarky

Shark Knight now it targets the strongest SS monster I control, but I still get a script error message when SK is summoned, when it activates its effect and when it has to detach one card to avoid destruction.

I managed to make Sishunder use its effect but how do I make a priority list for the targets?

Also, I've tried to use Batteryman AAA's effect only to summon another BAAA from the grave, but no luck yet, the game crashes, so, for now, it's using it's effect to summon another copy from the hand or grave.

Also, the attack logic usually stops working after a few turns [:confu:] (I added the require("ai.ai") line and deleted OnSelectBattleCommand)

I thought I was getting good at this lol, this is way harder than I expected.

Michael Lawrence Dee
2015-05-12T01:38:49Z
Snarky, can you please bump this post when there is an update to the Tutorial and what part(s) are updated?
Now this is how I play:
Snarky
  • Snarky
  • Advanced Member Topic Starter
2015-05-12T04:42:38Z
I usually do, there were no further updates in quite a while, though.
Michael Lawrence Dee
2015-07-13T10:37:20Z
Umm... I'm not sure if it's already here but how do I make an AI Deck. Specifically my problem is detecting the .lua file. I have added my something like ai.decks.name in ai.lua. But I'm trying to make an Empty Jar FTK for a start also I'm planning to detect situations so it's able to surrender.

I'm basing my scripts from Spellbook.lua and ExodiaLib.lua

I have found Exodia surrender check but I don't know how to trigger it.

EDIT: My current script:


--
--        Empty Jar FTK
--        produced by Michael Lawrence Dee
--
--
function EmptyJarStartup(cards)
	AI.Chat("Testing...")
	local mset = cards.monster_setable_cards
	local stset = cards.st_setable_cards
	local activate = cards.activatable_cards
	local e1=Effect.GlobalEffect()
	e1:SetType(EFFECT_TYPE_FIELD+EFFECT_TYPE_CONTINUOUS)
	e1:SetCode(EVENT_ADJUST)
	e1:SetOperation(EJSurrenderCheck(e,tp,eg,ep,ev,re,r,rp))
	Duel.RegisterEffect(e1,0)
end
DECK_EMPTYJAR	= NewDeck("Empty Jar",38699854,EmptyJarStartup)

AntiSpellM={84636823,48229808}
AntiMon={24348804,83965310,82732705}
function EJSurrenderCheck(e,tp,eg,ep,ev,re,r,rp)
	
end

It's not yet complete since the surrender condition didn't apply in-game.
Now this is how I play:
Snarky
  • Snarky
  • Advanced Member Topic Starter
2015-07-13T17:28:06Z
I wouldn't start with the surrender, that should be more of a gimmick after the deck is already playing properly imo. To make the AI surrender, you can just call the "Surrender()" function at any point. For exodia, I run the SurrenderCheck() both in the OnSelectInit and OnSelectChain functions, as these are pretty much always called when the AI can actually do something.

I would not look at the Exodia deck for orientation (except for the surrender, as thats the only deck that uses it), I just took the base script of the Exodia AI and cramped it into a separate file. The script itself is quite outdated and doesn't interact all that well with the other decks.

If you want to use a deck as orientation, use the Spellbook or Boxer decks, those are a pretty good showcase on how I intended people to add their decks. The creator of the spellbook deck does have a little different coding style compared to me, but that is not necessarily a bad thing.
Quote:


I have added my something like ai.decks.name in ai.lua.


This line should look something like this:

    require("ai.decks.EmptyJar")
,
assuming your file is called EmptyJar.lua. You can also use requireoptional, it doesn't matter (require throws an error if the file is missing, requireoptional makes the script work regardless of the files existence). This is probably pretty obvious from the other lines that work just like that.

Note, that this takes the name of the script file, not the name of the deck file, those may differ. Also make sure, you use the "" and don't add the ".lua" at the end. If you use require instead of the optional, you can see, if you did it correctly, because it will only let you start the game, if you did it right.
Quote:


DECK_EMPTYJAR = NewDeck("Empty Jar",38699854,EmptyJarStartup)


This line adds your deck to the system. If you start the game in debug mode, the console should print a message, which deck the AI is playing. Make sure, it prints the correct name for your deck.
Michael Lawrence Dee
2015-07-14T11:19:22Z
Sorry. I was able to make the surrender now my new problem is an error about length of activatable_cards.
I'm pretty sure I checked the tutorial several times, so what went wrong.


--
--        Empty Jar FTK
--        produced by Michael Lawrence Dee
--
--
--NOTE: 0 - player
--		1 - AI
function EmptyJarStartup(cards)
	--local mset = cards.monster_setable_cards
	--local stset = cards.st_setable_cards
	--local activate = cards.activatable_cards
	local boechk = false --Book of Eclipse
	AI.Chat("Testing...")
	--check for surrender
	local e1=Effect.GlobalEffect()
	e1:SetType(EFFECT_TYPE_FIELD+EFFECT_TYPE_CONTINUOUS)
	e1:SetCode(EVENT_ADJUST)
	e1:SetOperation(function(e,tp,eg,ep,ev,re,r,rp)
		if Duel.IsExistingMatchingCard(negchk,1,LOCATION_ONFIELD,LOCATION_ONFIELD,1,nil) then
			Surrender()
			return
		end
		if Duel.IsExistingMatchingCard(asst,1,LOCATION_SZONE,LOCATION_SZONE,1,nil) then
			Surrender()
			return
		end
		if Duel.IsExistingMatchingCard(asm,1,LOCATION_MZONE,LOCATION_MZONE,1,nil) 
			and not Duel.IsExistingMatchingCard(jars,1,LOCATION_MZONE+LOCATION_HAND+LOCATION_DECK,0,1,nil) then
			Surrender()
			return
		end
	end)
	Duel.RegisterEffect(e1,0)
	
	--priority
	for i=1,#cards.activatable_cards do 
		local c = cards.activatable_cards[i]
		if c.id == 72892473 and Duel.GetFieldGroupCount(0,LOCATION_HAND,0)>Duel.GetFieldGroupCount(0,LOCATION_DECK,0) 
		and Duel.GetFieldGroupCount(1,LOCATION_HAND,0)<=Duel.GetFieldGroupCount(1,LOCATION_DECK,0) then -- Card Destruction
			return COMMAND_ACTIVATE,i
		end
	end
end
DECK_EMPTYJAR	= NewDeck("Empty Jar",38699854,EmptyJarStartup) --Check Book of Taiyou

function negchk(c) --check Anti-Effect Monsters
	if c:IsLocation(LOCATION_MZONE) then
		return c:IsCode(83965310) and c:IsControler(0) and c:IsFaceup() and not c:IsStatus(STATUS_DISABLED)
	elseif c:IsLocation(LOCATION_SZONE) then
		return (c:IsCode(24348804) or c:IsCode(82732705)) and c:IsFaceup() and not c:IsStatus(STATUS_DISABLED)
	end
	return false
end
function asst(c) --check Anti-Spell Traps
	return c:IsCode(61740673) and c:IsFaceup() and not c:IsStatus(STATUS_DISABLED)
end
function asm(c) --check Anti-Spell Monsters
	return (c:IsCode(84636823) or (c:IsCode(48229808) and c:IsControler(0))) and c:IsFaceup() and not c:IsStatus(STATUS_DISABLED)
end
function jars(c) --check Morphing Jar#2 / Cyber Jar / Level Jar / Night Assailant
	return (c:IsCode(34124316) or c:IsCode(79106360) or c:IsCode(16226786) or c:IsCode(511000585))
		and (c:IsFacedown() or not c:IsLocation(LOCATION_MZONE))
end

The one with "priority" comment.
Now this is how I play:
Snarky
  • Snarky
  • Advanced Member Topic Starter
2015-07-14T13:05:35Z
Your Startup function is only called at the start of the duel once, and it does not have any cards to list. It receives the deck as a parameter, which allows you to setup various functions and blacklists affecting this deck only. What you most likely want to do is define an "Init" function, which is called whenever the AI can do something in its main phase, maybe like this:



function EmptyJarStartup(deck) 
  -- check Boxer.lua or the tutorial template for a list of things you can setup here
  deck.Init = EmptyJarInit -- this links your own Init function to the deck
end

DECK_EMPTYJAR    = NewDeck("Empty Jar",38699854,EmptyJarStartup) -- Check Book of Taiyou

function EmptyJarInit(cards,to_bp_allowed,to_ep_allowed) 
  -- same parameters as "OnSelectInitCommand", check the ai-template.lua
  -- feel free to leave out the latter, it works just fine with only "cards"
  print("The AI can activate "..#cards.activatable_cards.." different effects.")
end 


This sets up your deck and tells the script to call your Init function whenever OnSelectInit is called by the system
Users browsing this topic