views:

418

answers:

6

Hi,

I am currently writing a bot for a MMORPG. Though, currently I am stuck at trying to figure out how to nicely implement this. The design problem is related to casting the character spells in the correct order. Here is a simple example to what I need to archieve. It's not related to casting them, but doing it in the correct order. I would know how simply cast them randomly, by checking which skill has not yet been casted, but in right order as being shown in the GUI, not really.

note: the skill amount may differ, it's not always 3, maximum 10 though.

Charactername < foobar > has 3 skills.

Skill 1: Name ( random1 ) cooldown ( 1000 ms ) cast duration ( 500 ms )

Skill 2: Name ( random2 ) cooldown ( 1500 ms ) cast duration ( 700 ms )

Skill 3: Name ( random3 ) cooldown ( 2000 ms ) cast duration ( 900 ms )

I don't really know how I could implement this, if anyone has some thoughts, feel free to share. I do know that most of the people don't like the idea of cheating in games, I don't like it either, nor I am actually playing the game, but its an interesting field for me.

Thank you.

+1  A: 

Maybe you want a queue with scheduled tasks.

Havenard
+1  A: 

You're going to want to look into "scheduling algorithms." Here's a link to get you started.

http://www.ctl.ua.edu/math103/scheduling/scheduling_algorithms.htm

Essentially, you need to schedule optimally an infinite number of tasks 1, 2, and 3.

Stefan Kendall
+2  A: 

This is venturing into more "intelligent agent" territory. Consider having a plan database for your AI. Your cast-fireball-spell plan may have a prerequisite with the ignite-fire spell, which itself may have a prerequisite of the successful casing of the create-gas-bubble spell. Picking a plan would require satisfying all the preconditions, so if your AI can create a gas bubble but not ignite the bubble, then the plan fizzles, and they have to do something else (perhaps retry).

Shaggy Frog
+1 for the punnery. I like that.
Kawa
Would you believe me if I told you I didn't notice it until now? :D
Shaggy Frog
Rather than a plan database, what you would need is some simple form of STRIPS planning: http://web.media.mit.edu/~jorkin/goap.html
miquelramirez
A: 

Maybe from some event handler, you want to decide what spell to cast. Perhaps you can start with something like this spellcaster:

public class Caster
{
    private readonly ICastable[] _spells;
    private int _canCastAt;

    public Caster(ICastable[] spells)
    {
        _spells = spells;
        _canCastAt = -1;
    }

    public string GetNextSpellToCast(int currentTime)
    {
        if (currentTime < _canCastAt)
            return null;

        for (int i = 0; i < _spells.Length; i++)
        {
            int durationOfCast = _spells[i].AttemptCast(currentTime);

            if (durationOfCast > 0)
            {
                _canCastAt = currentTime + durationOfCast;
                return _spells[i].GetName();
            }
        }

        return null;
    }
}

The caster will cast spells:

public interface ICastable
{
    string GetName();
    int AttemptCast(int msCurrentTime);
}

You described a particular kind of spell:

public class ChanneledSpell : ICastable
{
    private readonly string _name;
    private readonly int _castDuration;
    private readonly int _castCooldown;
    private int _lastCast;

    public ChanneledSpell(string name, int castDuration, int castCooldown)
    {
        Debug.Assert(castDuration < castCooldown);  // a reasonable assumption the tests makes

        _name = name;
        _castDuration = castDuration;
        _castCooldown = castCooldown;
        _lastCast = -_castCooldown;
    }

    public string GetName()
    {
        return _name;
    }

    public int AttemptCast(int msCurrentTime)
    {
        if (msCurrentTime > _lastCast + _castCooldown)
        {
            _lastCast = msCurrentTime;
            return _castDuration;
        }

        return 0;
    }
}

I see this was marked C++, this answer is C# though I only used language constructs available in C++ so it should be a straightforward translation. What I couldn't translate so easily are some of the tests,

[TestFixture]
public class SpellTest
{
    [Test]
    public void TestCanCastOnStartup()
    {
        var sut = new ChanneledSpell(Some.String(), Some.PositiveNonzeroInteger(), Some.PositiveNonzeroInteger());

        int result = sut.AttemptCast(Some.PositiveNonzeroInteger());

        Assert.IsTrue(CastWasMade(result));
    }

    [Test]
    public void TestCantCastUntilCooldown()
    {
        int firstCast = Some.PositiveNonzeroInteger();
        int duration = Some.PositiveNonzeroInteger();
        int cooldown = duration + Some.PositiveNonzeroInteger();  // assuming spell duration is less then cooldown

        var sut = new ChanneledSpell(Some.String(), duration, cooldown);

        int ignored = sut.AttemptCast(firstCast);
        int secondCastAttempt = sut.AttemptCast(firstCast + cooldown - 1);
        int thirdCastAttempt = sut.AttemptCast(firstCast + cooldown + 1);

        Assert.IsFalse(CastWasMade(secondCastAttempt));
        Assert.IsTrue(CastWasMade(thirdCastAttempt));
    }

    [Test]
    public void TestReportsTimeOnCast()
    {
        int duration = Some.PositiveNonzeroInteger();
        int firstCastTime = Some.PositiveNonzeroInteger();

        var sut = new ChanneledSpell(Some.String(), duration, Some.PositiveNonzeroInteger());

        int firstCastAttempt = sut.AttemptCast(firstCastTime);

        Assert.AreEqual(duration, firstCastAttempt);
    }

    private bool CastWasMade(int result)
    {
        return result > 0;
    }
}
Frank Schwieterman
A: 

Hey, thanks everyone. Frank, thanks for the example, I don't mind if the example is written in another language. It helped me.

A: 

Look at OpenKore bot - the most advanced bot I've seen. It's a big opensource project, existing several years and many bot-AI-specifing problems were resolved in it. I think, you can get/learn some ideas from it. But OpenKore is written mostly in Perl.

zxcat