Cvičenie 8
Edit2:
IWizard je pridaný naspäť do CreateSpell - pri vytváraní kúzla je potrebné mať referenciu na toho, kto ho vyčaroval, aby nedošlo ku kolízií
Note:
To, že ISpellBuilder definuje v každej metóde ako návratovú hodnotu nám umožňuje spraviť nasledovné:
builder.AddEffect("use cycle").AddEffect("for effects")
  .SetAnimation(animation).SetSpellCost(cost).CreateSpell()Ako na buildera:
- wizard (nemusí byť player) si vytvorí iba SpellDirector
- director si vytvorí zodpovedajúcich builderov
- director si načíta zo súboru kúzla (budúce cviko, zatiaľ si ich tam pridajte ručne
- director vie, ktorý builder sa má použiť
- director povie postupne builderovi všetky efekty, ktoré treba pridať do vytváraného kúzla (môže ich byť niekoľko)
- director povie builderovi, akú animáciu nastaviť (ak je to projectile)
- director spočíta cenu a povie ju builderovi (selfcast builder si ju zníži o nejaké percento)
- wizard dostane kúzlo, ktoré môže použiť (nie používať - na ďalšie použitie si treba znovu vytvoriť nové, inak by mohol existovať iba jeden projektil daného typu v hre)
Changelog:
- 
IMovable: double GetSpeed(double speed)fixed definition to properly reflect strategy pattern (originallydouble GetSpeed())
7.1 Gimme a plan
Player a Enemy majú niečo spoločné vo svete - sú to postavičky. Zatiaľ sme ich považovali iba za actorov, ale narozdiel od predmetov (kotlík, pec) by mali mať ešte niečo navyše - život a pohyb.
Vytvorte si rozhranie ISpeedStrategy ktoré bude mať jednu metódu: double GetSpeed(double speed). Vytvorte si triedy NormalSpeedStrategy a ModifiedSpeedStrategy.
Vytvorte si teda rozhranie ICharacter nech rozširuje IMovable. Vytvorte si abstraktnú triedu AbstractCharacter, ktorá bude implementovať ICharacter, IMovable a samozrejme rozširovať AbstractActor
nech ICharacter definuje nasledujúce metódy:
void ChangeHealth(int delta);
int GetHealth();
void Die();
void AddEffect(ICommand effect);
void RemoveEffect(ICommand effect);Do IMovable pridajte nasledujúce metódy:
void SetSpeedStrategy(ISpeedStrategy);
double GetSpeed(double speed);kde effect bude uložený do zoznamu a vykonaný počas update. Môžu tu byť veci, ako periodické dopĺňanie života / many, DoT efekty, spomalenie, zrýchlenie...
Triedu Move upravte Move tak, aby pracovala s desatinnými číslami. Speed sa nebude udávať v konštruktore, ale bude pýtaný od IMovable (keďže pozícia actora musí byť celé číslo, zabezpečte, aby sa rozdiel akumuloval a následne pripočítal keď dosiahne 1).
Obidve triedy SpeedStrategy implementujte tak, aby používali návrhový vzor strategy a tiež modifikujte AbstractCharacter tak, aby využíval spomínané triedy na nastavenie rýchlosti.
Upravte triedy Player a Enemy tak aby rozširovali AbstractCharacter. Enemy premenujte na Skeleton.
Pridajte si enum ActorOrientation ktorý bude obsahovať dve hodnoty: FacingLeft a FacingRight. Využite ho na určenie orientácie actora vo svete.
7.2 I smell magic in here
Vytvorte si:
- priečinok Spells
- rozhrania IWizard,ISpell,ISpellBuilder,ISpellDirector
- triedy
- ProjectileSpell : AbstractActor, IMovable, ISpell
- SelfCastSpell : ISpell
- ProjectileSpellBuilder : ISpellBuilder
- SelfCastSpellBuilder : ISpellBuilder
- 
SpellEffectFactory(implementujte factory method design pattern)
- SpellDirector : ISpellDirector
- SpellInfo
 
- enum SpellType
public Interface IWizard : IActor
{
    void ChangeMana(int delta);
    int GetMana();
    void Cast(ISpell spell);
}
public class ISpell
{
    ISpell AddEffect(ICommand effect);
    void AddEffects(IEnumerable<ICommand> effects);
    int GetCost();
    void Cast();
}
public interface ISpellBuilder
{
    ISpellBuilder AddEffect(string effectName);
    ISpellBuilder SetAnimation(Animation animation); //unused for self-cast spells
    ISpellBuilder SetSpellCost(int cost);
    ISpell CreateSpell(IWizard wizard);
}
public interface ISpellDirector
{
    ISpell Build(string spellName);
}
public class SpellInfo
{
    public string Name { get; set; }
    public SpellType SpellType { get; set; }
    public IEnumerable<string> EffectNames { get; set; }
    public string AnimationPath { get; set; }
    public int AnimationWidth { get; set; }
    public int AnimationHeight { get; set; }
}Nech ProjectileSpell a SelfCastSpell majú v sebe konštruktor v ktorom dostanú referenciu na toho, kto to vyčaroval a IEnumerable<ICommand> zoznam efektov.
Nech SpellType určuje, či sa jedná o self-cast alebo projektil.
Vytvorte si efekty (triedy, implementujúce ICommand): damage over time, speed change, heal, heal over time a samozrejme podľa chuti ďalšie.
Každý efekt má svoju cenu, výsledná cena kúzla bude súčet cien jednotlivých efektov (pre self-cast nech je táto cena upravená, napr. 70%).
Implementujte ProjectileSpellBuilder, SelfCastSpellBuilder a SpellDirector ako návrhový vzor builder a nech SpellDirector v sebe obsahuje dva slovníky: Dictionary<string, int> kde bude cena jednotlivých efektov a Dictionary<string, SpellInfo> kde budú uložené zoznamy efektov pre jednotlivké kúzla. Zatiaľ si tieto slovníky inicializujte ručne, nabudúce si ukážeme ako si ich načítať zo súboru.