Просмотр исходного кода

Game Objekte fertig implementiert

Kolja Strohm 4 лет назад
Родитель
Сommit
c2dd17c5d5
40 измененных файлов с 1378 добавлено и 173 удалено
  1. 6 6
      StickmanWorldOnline/Bariere.cpp
  2. 1 1
      StickmanWorldOnline/Base.cpp
  3. 12 0
      StickmanWorldOnline/BosheitRune.h
  4. 23 0
      StickmanWorldOnline/Brand.cpp
  5. 19 0
      StickmanWorldOnline/Brand.h
  6. 25 0
      StickmanWorldOnline/DrachenAuge.cpp
  7. 20 0
      StickmanWorldOnline/DrachenAuge.h
  8. 4 4
      StickmanWorldOnline/Drop.cpp
  9. 54 0
      StickmanWorldOnline/Effect.cpp
  10. 27 0
      StickmanWorldOnline/Effect.h
  11. 14 0
      StickmanWorldOnline/Enterhaken.h
  12. 9 9
      StickmanWorldOnline/Ereignis.h
  13. 25 12
      StickmanWorldOnline/GameObject.cpp
  14. 13 9
      StickmanWorldOnline/GameObject.h
  15. 89 7
      StickmanWorldOnline/Gegenstand.cpp
  16. 9 3
      StickmanWorldOnline/Gegenstand.h
  17. 13 0
      StickmanWorldOnline/Geist.h
  18. 48 12
      StickmanWorldOnline/Geschoss.cpp
  19. 10 1
      StickmanWorldOnline/Geschoss.h
  20. 12 0
      StickmanWorldOnline/Leben.h
  21. 12 0
      StickmanWorldOnline/LebenRune.h
  22. 2 28
      StickmanWorldOnline/Reader.cpp
  23. 15 0
      StickmanWorldOnline/Rolle.h
  24. 7 0
      StickmanWorldOnline/Schiene.cpp
  25. 13 0
      StickmanWorldOnline/Schild.h
  26. 12 0
      StickmanWorldOnline/Schuh.h
  27. 73 21
      StickmanWorldOnline/Spiel.cpp
  28. 612 0
      StickmanWorldOnline/Spieler.cpp
  29. 54 56
      StickmanWorldOnline/Spieler.h
  30. 20 0
      StickmanWorldOnline/StickmanWorldOnline.vcxproj
  31. 63 0
      StickmanWorldOnline/StickmanWorldOnline.vcxproj.filters
  32. 12 0
      StickmanWorldOnline/StrengthRune.h
  33. 15 0
      StickmanWorldOnline/Sturm.h
  34. 3 0
      StickmanWorldOnline/Team.cpp
  35. 12 0
      StickmanWorldOnline/TempoRune.h
  36. 1 1
      StickmanWorldOnline/Timer.cpp
  37. 1 1
      StickmanWorldOnline/Tunnel.cpp
  38. 4 1
      StickmanWorldOnline/Umlenkung.cpp
  39. 2 1
      StickmanWorldOnline/Variablen.h
  40. 12 0
      StickmanWorldOnline/WeisheitRune.h

+ 6 - 6
StickmanWorldOnline/Bariere.cpp

@@ -4,7 +4,7 @@
 
 
 Bariere::Bariere( int id, int x, int y, int breite, int height, int style, int verschiebungWeite, int autoSchaltungMaxTime, Team *team )
-    : GameObject( x, y, breite, height )
+    : GameObject( BARIERE, x, y, breite, height )
 {
     this->id = id;
     this->style = style;
@@ -85,7 +85,7 @@ void Bariere::tick( double time, Spiel* zSpiel)
     }
     if( hatStyle( Style::InVerschiebung ) )
     {
-        int last = (int)currentWeite;
+        float last = currentWeite;
         currentWeite += (float)time * 10;
         if( currentWeite >= verschiebungWeite )
         {
@@ -101,16 +101,16 @@ void Bariere::tick( double time, Spiel* zSpiel)
         if( hatStyle( Style::VerschiebungWaagerecht ) )
         {
             if( hatStyle( Style::NextVerschiebungLinksOben ) )
-                setX( getX() + last - (int)currentWeite );
+                setX( getX() + last - currentWeite );
             else
-                setX( getX() - last + (int)currentWeite );
+                setX( getX() - last + currentWeite );
         }
         else
         {
             if( hatStyle( Style::NextVerschiebungLinksOben ) )
-                setY( getX() + last - (int)currentWeite );
+                setY( getX() + last - currentWeite );
             else
-                setY( getX() - last + (int)currentWeite );
+                setY( getX() - last + currentWeite );
         }
     }
 }

+ 1 - 1
StickmanWorldOnline/Base.cpp

@@ -4,7 +4,7 @@
 
 
 Base::Base( int id, int x, int y, int width, int height, int maxTime, Team *team )
-    : GameObject( x, y, width, height )
+    : GameObject( BASE, x, y, width, height )
 {
     this->id = id;
     this->maxTime = maxTime;

+ 12 - 0
StickmanWorldOnline/BosheitRune.h

@@ -0,0 +1,12 @@
+#pragma once
+
+#include "Effect.h"
+
+class BosheitRuneEffect : public Effect
+{
+private:
+
+public:
+    BosheitRuneEffect( Spieler *zSpieler );
+    ~BosheitRuneEffect();
+};

+ 23 - 0
StickmanWorldOnline/Brand.cpp

@@ -0,0 +1,23 @@
+#include "Brand.h"
+#include "Spieler.h"
+
+
+BrandEffekt::BrandEffekt( Spieler *zVerursacher, Spieler *zOpfer )
+    : Effect( zOpfer, B_DURATION )
+{
+    this->zVerursacher = zVerursacher;
+    laufTempoDecrease = B_MOVEMENT_DECREASE <= zSpieler->getLaufTempo() ? B_MOVEMENT_DECREASE : zSpieler->getLaufTempo();
+    zSpieler->setLaufTempo( zSpieler->getLaufTempo() - laufTempoDecrease );
+}
+
+BrandEffekt::~BrandEffekt()
+{
+    zSpieler->setLaufTempo( zSpieler->getLaufTempo() + laufTempoDecrease );
+}
+
+bool BrandEffekt::tick( double time, Spiel *zSpiel )
+{
+    float damage = B_MIN_DPS * (float)time;
+    zSpieler->nimmSchaden( damage, zVerursacher, MITTE, zSpiel );
+    return Effect::tick( time, zSpiel );
+}

+ 19 - 0
StickmanWorldOnline/Brand.h

@@ -0,0 +1,19 @@
+#pragma once
+
+#include "Effect.h"
+
+#define B_MOVEMENT_DECREASE 1
+#define B_MIN_DPS 5
+#define B_DURATION 1
+
+class BrandEffekt : public Effect
+{
+private:
+    Spieler *zVerursacher;
+    float laufTempoDecrease;
+
+public:
+    BrandEffekt( Spieler *zVerursacher, Spieler *zOpfer );
+    ~BrandEffekt();
+    bool tick( double time, Spiel *zSpiel ) override;
+};

+ 25 - 0
StickmanWorldOnline/DrachenAuge.cpp

@@ -0,0 +1,25 @@
+#include "DrachenAuge.h"
+#include "Spieler.h"
+
+
+DrachenAugeEffect::DrachenAugeEffect( Spieler *zVerursacher, Spieler *zOpfer )
+    : Effect( zOpfer, DA_DURATION )
+{
+    this->zVerursacher = zVerursacher;
+    laufTempoDecrease = DA_MOVEMENT_DECREASE <= zSpieler->getLaufTempo() ? DA_MOVEMENT_DECREASE : zSpieler->getLaufTempo();
+    zSpieler->setLaufTempo( zSpieler->getLaufTempo() - laufTempoDecrease );
+}
+
+DrachenAugeEffect::~DrachenAugeEffect()
+{
+    zSpieler->setLaufTempo( zSpieler->getLaufTempo() + laufTempoDecrease );
+}
+
+bool DrachenAugeEffect::tick( double time, Spiel *zSpiel )
+{
+    float damage = DA_MIN_DPS * (float)time;
+    zSpieler->nimmSchaden( damage, zVerursacher, MITTE, zSpiel );
+    if( zVerursacher )
+        zVerursacher->heilung( DA_HEALPS * (float)time, zSpiel );
+    return Effect::tick( time, zSpiel );
+}

+ 20 - 0
StickmanWorldOnline/DrachenAuge.h

@@ -0,0 +1,20 @@
+#pragma once
+
+#include "Effect.h"
+
+#define DA_MOVEMENT_DECREASE 10
+#define DA_MIN_DPS 10
+#define DA_DURATION 10
+#define DA_HEALPS 4
+
+class DrachenAugeEffect : public Effect
+{
+private:
+    Spieler *zVerursacher;
+    float laufTempoDecrease;
+
+public:
+    DrachenAugeEffect( Spieler *zVerursacher, Spieler *zOpfer );
+    ~DrachenAugeEffect();
+    bool tick( double time, Spiel *zSpiel ) override;
+};

+ 4 - 4
StickmanWorldOnline/Drop.cpp

@@ -11,7 +11,7 @@ Drop::Drop( int id, int minX, int maxX, int minY, int maxY, int maxTime, int num
     this->minY = minY;
     this->maxY = maxY;
     this->maxTime = maxTime;
-    this->nextDrop = maxTime;
+    this->nextDrop = (float)maxTime;
     this->numDrops = numDrops;
     memcpy( wahrscheinlichkeit, wkeit, sizeof( float ) * ITEMANZAHL );
 }
@@ -46,7 +46,7 @@ void Drop::setMaxTime( int seconds )
 
 void Drop::doDrop( Spiel *zSpiel )
 {
-    nextDrop = maxTime;
+    nextDrop = (float)maxTime;
     Ereignis *e = new Ereignis( DROP_AKTION );
     e->addParameter( "Betroffener Drop", getThis() );
     zSpiel->throwEvent( e );
@@ -63,13 +63,13 @@ void Drop::doDrop( Spiel *zSpiel )
         int x = (int)( zSpiel->getRand() * ( maxX - minX - 100 ) + minX + 50 );
         int y = (int)( zSpiel->getRand() * ( maxY - minY - 100 ) + minY + 50 );
         if( x >= minX + 50 && x < maxX - 50 && y >= minY + 50 && y < maxY - 50 )
-            zSpiel->addGegenstand( new Gegenstand( zSpiel->getNextId(), (GegenstandTyp)typ, 1, x, y, 50, 50 ) );
+            zSpiel->addGegenstand( new Gegenstand( zSpiel->getNextId(), (GegenstandTyp)typ, x, y ) );
     }
 }
 
 void Drop::tick( double time, Spiel *zSpiel )
 {
-    nextDrop -= time;
+    nextDrop -= (float)time;
     if( nextDrop <= 0 )
         doDrop( zSpiel );
 }

+ 54 - 0
StickmanWorldOnline/Effect.cpp

@@ -0,0 +1,54 @@
+#include "Effect.h"
+
+
+Effect::Effect( Spieler *zSpieler, int maxTime )
+{
+    this->zSpieler = zSpieler;
+    timeLeft = maxTime;
+    ref = 1;
+}
+
+Effect::~Effect()
+{}
+
+bool Effect::tick( double time, Spiel *zSpiel )
+{
+    timeLeft -= time;
+    return timeLeft <= 0;
+}
+
+bool Effect::istSpielerBeweglich( Richtung r )
+{
+    return 1;
+}
+
+bool Effect::istSpielerVerwundbar( Richtung r )
+{
+    return 1;
+}
+
+bool Effect::istSpielerSichtbar( Team *zTeam )
+{
+    return 1;
+}
+
+void Effect::move( double time )
+{}
+
+bool Effect::istGegenstandErlaubt( GegenstandTyp typ )
+{
+    return 1;
+}
+
+Effect *Effect::getThis()
+{
+    ref++;
+    return this;
+}
+
+Effect *Effect::release()
+{
+    if( !--ref )
+        delete this;
+    return 0;
+}

+ 27 - 0
StickmanWorldOnline/Effect.h

@@ -0,0 +1,27 @@
+#pragma once
+
+#include "Gegenstand.h"
+
+class Spieler;
+class Spiel;
+class Team;
+
+class Effect
+{
+protected:
+    Spieler *zSpieler;
+    double timeLeft;
+    int ref;
+
+public:
+    Effect( Spieler *zSpieler, int maxTime );
+    virtual ~Effect();
+    virtual bool tick( double time, Spiel *zSpiel );
+    virtual bool istSpielerBeweglich( Richtung r );
+    virtual bool istSpielerVerwundbar( Richtung r );
+    virtual bool istSpielerSichtbar( Team *zTeam );
+    virtual void move( double time );
+    virtual bool istGegenstandErlaubt( GegenstandTyp typ );
+    Effect *getThis();
+    Effect *release();
+};

+ 14 - 0
StickmanWorldOnline/Enterhaken.h

@@ -0,0 +1,14 @@
+#pragma once
+
+#include "Effect.h"
+
+class EnterhakenEffect : public Effect
+{
+private:
+
+public:
+    EnterhakenEffect( Spieler *zSpieler, Richtung r );
+    ~EnterhakenEffect();
+    bool istSpielerBeweglich( Richtung r ) override;
+    void move( double time ) override;
+};

+ 9 - 9
StickmanWorldOnline/Ereignis.h

@@ -15,17 +15,17 @@ enum EreignisTyp
     GEGENSTAND_DROPED, // "Betroffener Gegenstand"
     INITIALISIERUNG, //
     SCHALTER_AKTIVIERT, // "Betroffener Schalter"
-    SPIELER_BENUTZT_GEGENSTAND,
+    SPIELER_BENUTZT_GEGENSTAND, // "Betroffener Spieler", "Betroffener Gegenstand"
     SPIELER_KEY_PRESSED, // "Betroffene Taste", "Ausführender Spieler"
-    SPIELER_BEKOMMT_ERFAHRUNG,
-    SPIELER_BEKOMMT_GEGENSTAND,
+    SPIELER_BEKOMMT_ERFAHRUNG, // "Betroffer Spieler", "Wert"
+    SPIELER_BEKOMMT_GEGENSTAND, // "Betroffener Spieler", "Betroffener Gegenstand", "Anzahl"
     SPIELER_KEY_RELEASED, // "Betroffene Taste", "Ausführender Spieler"
-    SPIELER_LEVEL_UP,
-    SPIELER_MACHT_SCHADEN,
-    SPIELER_NIMMT_SCHADEN,
-    SPIELER_STIRBT,
-    SPIELER_WIEDERBELEBT,
-    SPIELER_WIRD_GEHEILT,
+    SPIELER_LEVEL_UP, // "Betroffer Spieler"
+    SPIELER_MACHT_SCHADEN, // "Betroffer Spieler", "Wert"
+    SPIELER_NIMMT_SCHADEN, // "Betroffer Spieler", "Wert"
+    SPIELER_STIRBT, // "Betroffer Spieler"
+    SPIELER_WIEDERBELEBT, // "Betroffer Spieler"
+    SPIELER_WIRD_GEHEILT, // "Betroffer Spieler", "Wert"
     TIMER_RUNNS_OUT, // "Betroffener Timer"
     TIMER_BEGINNT, // "Betroffener Timer"
     TUNNEL_BENUTZT, // {"Betroffes Geschoss", "Betroffer Spieler"}, "Betroffer Tunnel"

+ 25 - 12
StickmanWorldOnline/GameObject.cpp

@@ -1,31 +1,44 @@
 #include "GameObject.h"
 
 
+Richtung invert( Richtung r )
+{
+    if( r == OBEN )
+        return UNTEN;
+    if( r == UNTEN )
+        return OBEN;
+    if( r == LINKS )
+        return RECHTS;
+    if( r == RECHTS )
+        return LINKS;
+    return r;
+}
+
 GameObject::GameObject( VariableTyp typ, int x, int y, int width, int height )
     : Variable( typ )
 {
-    this->x = x;
-    this->y = y;
-    w = width;
-    h = height;
+    this->x = (float)x;
+    this->y = (float)y;
+    w = (float)width;
+    h = (float)height;
 }
 
-void GameObject::setX( int x )
+void GameObject::setX( float x )
 {
     this->x = x;
 }
 
-void GameObject::setY( int y )
+void GameObject::setY( float y )
 {
     this->y = y;
 }
 
-void GameObject::setWidth( int width )
+void GameObject::setWidth( float width )
 {
     w = width;
 }
 
-void GameObject::setHeight( int height )
+void GameObject::setHeight( float height )
 {
     h = height;
 }
@@ -35,22 +48,22 @@ bool GameObject::intersectsWith( GameObject *zObj )
     return x < zObj->x + zObj->w && x + w > zObj->x && y < zObj->y + zObj->h && y + h > zObj->y;
 }
 
-int GameObject::getX() const
+float GameObject::getX() const
 {
     return x;
 }
 
-int GameObject::getY() const
+float GameObject::getY() const
 {
     return y;
 }
 
-int GameObject::getWidth() const
+float GameObject::getWidth() const
 {
     return w;
 }
 
-int GameObject::getHeight() const
+float GameObject::getHeight() const
 {
     return h;
 }

+ 13 - 9
StickmanWorldOnline/GameObject.h

@@ -7,9 +7,12 @@ enum Richtung
     OBEN,
     RECHTS,
     UNTEN,
-    LINKS
+    LINKS,
+    MITTE
 };
 
+Richtung invert( Richtung r );
+
 class GameObject : public Variable
 {
 protected:
@@ -17,13 +20,14 @@ protected:
 
 public:
     GameObject( VariableTyp typ, int x, int y, int width, int height );
-    void setX( int x );
-    void setY( int y );
-    void setWidth( int width );
-    void setHeight( int height );
+    void setX( float x );
+    void setY( float y );
+    void setWidth( float width );
+    void setHeight( float height );
     bool intersectsWith( GameObject *zObj );
-    int getX() const;
-    int getY() const;
-    int getWidth() const;
-    int getHeight() const;
+    float getX() const;
+    float getY() const;
+    float getWidth() const;
+    float getHeight() const;
+    float abstandZu( GameObject *zObj );
 };

+ 89 - 7
StickmanWorldOnline/Gegenstand.cpp

@@ -1,6 +1,94 @@
 #include "Gegenstand.h"
 
 
+bool consumable( GegenstandTyp typ )
+{
+    switch( typ )
+    {
+    case PFEIL:
+        return 1;
+    case LEBEN:
+        return 1;
+    case SCHILD:
+        return 0;
+    case SCHUH:
+        return 0;
+    case GEIST:
+        return 0;
+    case KUGEL:
+        return 1;
+    case ROLLE:
+        return 0;
+    case STURM:
+        return 0;
+    case DRACHENAUGE:
+        return 1;
+    case FEUERBALL:
+        return 1;
+    case ENTERHAKEN:
+        return 0;
+    case MINE:
+        return 1;
+    case RWEISHEIT:
+    case RSTRENGTH:
+    case RBOSHEIT:
+    case RLEBEN:
+    case RTEMPO:
+    default:
+        return 0;
+    }
+}
+
+
+float abklingzeit( GegenstandTyp typ )
+{
+    switch( typ )
+    {
+    case PFEIL:
+        return 5;
+    case LEBEN:
+        return 5;
+    case SCHILD:
+        return 100;
+    case SCHUH:
+        return 100;
+    case GEIST:
+        return 100;
+    case KUGEL:
+        return 5;
+    case ROLLE:
+        return 30;
+    case STURM:
+        return 30;
+    case DRACHENAUGE:
+        return 5;
+    case FEUERBALL:
+        return 5;
+    case ENTERHAKEN:
+        return 60;
+    case MINE:
+        return 5;
+    case RWEISHEIT:
+    case RSTRENGTH:
+    case RBOSHEIT:
+    case RLEBEN:
+    case RTEMPO:
+    default:
+        return 0;
+    }
+}
+
+bool storable( GegenstandTyp typ )
+{
+    return typ == RWEISHEIT || typ == RSTRENGTH || typ == RBOSHEIT || typ == RLEBEN || typ == RTEMPO;
+}
+
+bool brauchtRichtung( GegenstandTyp typ )
+{
+    return typ == PFEIL || typ == KUGEL || typ == DRACHENAUGE || typ == FEUERBALL || typ == ENTERHAKEN || typ == ROLLE || typ == STURM;
+}
+
+
 GegenstandTypVar::GegenstandTypVar( GegenstandTyp value )
     : Variable( GEGENSTAND_TYP )
 {
@@ -18,11 +106,10 @@ GegenstandTyp GegenstandTypVar::getValue() const
 }
 
 
-Gegenstand::Gegenstand( int id, GegenstandTyp typ, bool onMap = 0, int x = 0, int y = 0, int w = 50, int h = 50 )
+Gegenstand::Gegenstand( int id, GegenstandTyp typ, int x, int y, int w, int h )
     : GameObject( GEGENSTAND, x, y, w, h )
 {
     this->id = id;
-    this->onMap = onMap;
     this->typ = typ;
 }
 
@@ -34,9 +121,4 @@ int Gegenstand::getId() const
 GegenstandTyp Gegenstand::getTyp() const
 {
     return typ;
-}
-
-bool Gegenstand::isOnMap() const
-{
-    return onMap;
 }

+ 9 - 3
StickmanWorldOnline/Gegenstand.h

@@ -25,6 +25,14 @@ enum GegenstandTyp
     ITEMANZAHL
 };
 
+bool consumable( GegenstandTyp typ );
+
+float abklingzeit( GegenstandTyp typ );
+
+bool storable( GegenstandTyp typ );
+
+bool brauchtRichtung( GegenstandTyp typ );
+
 class GegenstandTypVar : public Variable
 {
 private:
@@ -40,12 +48,10 @@ class Gegenstand : public GameObject
 {
 private:
     GegenstandTyp typ;
-    bool onMap;
     int id;
 
 public:
-    Gegenstand( int id, GegenstandTyp typ, bool onMap = 0, int x = 0, int y = 0, int w = 50, int h = 50 );
+    Gegenstand( int id, GegenstandTyp typ, int x = 0, int y = 0, int w = 50, int h = 50 );
     int getId() const;
     GegenstandTyp getTyp() const;
-    bool isOnMap() const;
 };

+ 13 - 0
StickmanWorldOnline/Geist.h

@@ -0,0 +1,13 @@
+#pragma once
+
+#include "Effect.h"
+
+class GeistEffect : public Effect
+{
+private:
+
+public:
+    GeistEffect( Spieler *zSpieler );
+    ~GeistEffect();
+    bool istSpielerSichtbar( Team *zTeam ) override;
+};

+ 48 - 12
StickmanWorldOnline/Geschoss.cpp

@@ -30,14 +30,7 @@ Geschoss::~Geschoss()
 
 void Geschoss::invertDirection()
 {
-    if( richtung == OBEN )
-        richtung = UNTEN;
-    else if( richtung == RECHTS )
-        richtung = LINKS;
-    else if( richtung == UNTEN )
-        richtung = OBEN;
-    else if( richtung == LINKS )
-        richtung = RECHTS;
+    richtung = invert( richtung );
 }
 
 void Geschoss::addUmlenkung()
@@ -70,16 +63,18 @@ void Geschoss::tick( double zeit )
     switch( richtung )
     {
     case OBEN:
-        y -= zeit * speed;
+        y -= (float)zeit * speed;
         break;
     case UNTEN:
-        y += zeit * speed;
+        y += (float)zeit * speed;
         break;
     case RECHTS:
-        x += zeit * speed;
+        x += (float)zeit * speed;
         break;
     case LINKS:
-        x -= zeit * speed;
+        x -= (float)zeit * speed;
+        break;
+    case MITTE:
         break;
     }
 }
@@ -97,4 +92,45 @@ Spieler *Geschoss::zBesitzer() const
 Spieler *Geschoss::getBesitzer() const
 {
     return besitzer ? (Spieler *)besitzer->getThis() : 0;
+}
+
+Richtung Geschoss::getRichtung() const
+{
+    return richtung;
+}
+
+
+FeuerballTreffer::FeuerballTreffer( int id, int x, int y, Spieler *besitzer, int maxZeit )
+    : GameObject( FEUERBALL_TREFFER, x - 75, y - 75, 150, 150 )
+{
+    this->id = id;
+    this->besitzer = besitzer;
+    this->timeLeft = (float)maxZeit;
+    count = 0;
+}
+
+FeuerballTreffer::~FeuerballTreffer()
+{
+    besitzer->release();
+}
+
+void FeuerballTreffer::tick( double zeit )
+{
+    timeLeft -= (float)zeit;
+    count++;
+}
+
+bool FeuerballTreffer::isOver() const
+{
+    return timeLeft <= 0;
+}
+
+bool FeuerballTreffer::makeDamage() const
+{
+    return count % 2;
+}
+
+Spieler *FeuerballTreffer::zVerursacher() const
+{
+    return besitzer;
 }

+ 10 - 1
StickmanWorldOnline/Geschoss.h

@@ -8,9 +8,13 @@ enum GeschossTyp
     GESCHOSS_PFEIL,
     GESCHOSS_KUGEL,
     GESCHOSS_DRACHENAUGE,
-    GESCHOSS_FEUERBALL
+    GESCHOSS_FEUERBALL,
+    GESCHOSS_MINE
 };
 
+#define PFEIL_DAMAGE 100
+#define KUGEL_DAMAGE 100
+
 class Geschoss : public GameObject
 {
 private:
@@ -37,6 +41,7 @@ public:
     GeschossTyp getTyp() const;
     Spieler *zBesitzer() const;
     Spieler *getBesitzer() const;
+    Richtung getRichtung() const;
 };
 
 // size: 150x150
@@ -45,10 +50,14 @@ class FeuerballTreffer : public GameObject
 private:
     int id;
     Spieler *besitzer;
+    int count;
     float timeLeft;
 
 public:
     FeuerballTreffer( int id, int x, int y, Spieler *besitzer, int maxZeit );
     ~FeuerballTreffer();
     void tick( double zeit );
+    bool isOver() const;
+    bool makeDamage() const;
+    Spieler *zVerursacher() const;
 };

+ 12 - 0
StickmanWorldOnline/Leben.h

@@ -0,0 +1,12 @@
+#pragma once
+
+#include "Effect.h"
+
+class LebenEffect : public Effect
+{
+private:
+
+public:
+    LebenEffect( Spieler *zSpieler );
+    ~LebenEffect();
+};

+ 12 - 0
StickmanWorldOnline/LebenRune.h

@@ -0,0 +1,12 @@
+#pragma once
+
+#include "Effect.h"
+
+class LebenRuneEffect : public Effect
+{
+private:
+
+public:
+    LebenRuneEffect( Spieler *zSpieler );
+    ~LebenRuneEffect();
+};

+ 2 - 28
StickmanWorldOnline/Reader.cpp

@@ -592,41 +592,15 @@ void MapReader::ladeKarte( Spiel *zSpiel )
     {
         int spawnX;
         int spawnY;
-        int breite;
-        int height;
-        int leben;
-        int erfahrung;
-        int laufTempo;
-        int geschossTempo;
-        int armor;
-        int schadenBonus;
-        int lebensraub;
-        int lebensReg;
-        int abkVerringerung;
-        int level;
         mapFile.lese( (char *)& spawnX, 4 );
         mapFile.lese( (char *)& spawnY, 4 );
-        mapFile.lese( (char *)& breite, 4 );
-        mapFile.lese( (char *)& height, 4 );
-        mapFile.lese( (char *)& leben, 4 );
-        mapFile.lese( (char *)& erfahrung, 4 );
-        mapFile.lese( (char *)& laufTempo, 4 );
-        mapFile.lese( (char *)& geschossTempo, 4 );
-        mapFile.lese( (char *)& armor, 4 );
-        mapFile.lese( (char *)& schadenBonus, 4 );
-        mapFile.lese( (char *)& lebensraub, 4 );
-        mapFile.lese( (char *)& lebensReg, 4 );
-        mapFile.lese( (char *)& abkVerringerung, 4 );
-        mapFile.lese( (char *)& level, 4 );
         if( i < sts.spielerAnzahl )
         {
             if( i >= maxT )
                 team++;
             if( sts.teamSize.hat( team ) )
                 maxT += sts.teamSize.get( team );
-            zSpiel->addSpieler( new Spieler( i, zSpiel->getTeam( team ), spawnX, spawnY, breite, height,
-                                sts.spielerFarbe.get( i ), leben, erfahrung, laufTempo, geschossTempo,
-                                armor, schadenBonus, lebensraub, lebensReg, abkVerringerung, level ) );
+            zSpiel->addSpieler( new Spieler( i, zSpiel->getTeam( team ), spawnX, spawnY, sts.spielerFarbe.get( i ) ) );
         }
     }
     // Barieren
@@ -693,7 +667,7 @@ void MapReader::ladeKarte( Spiel *zSpiel )
         char *name = new char[ (int)len + 1 ];
         mapFile.lese( (char *)& name, len );
         name[ (int)len ] = 0;
-        zSpiel->addDrop( new Drop( minX, maxX, minY, maxY, maxTime, numDrops, name, wahrscheinlichkeit ) );
+        zSpiel->addDrop( new Drop( zSpiel->getNextId(), minX, maxX, minY, maxY, maxTime, numDrops, name, wahrscheinlichkeit ) );
         delete[] name;
     }
     // Schalter

+ 15 - 0
StickmanWorldOnline/Rolle.h

@@ -0,0 +1,15 @@
+#pragma once
+
+#include "Effect.h"
+
+class RolleEffect : public Effect
+{
+private:
+
+public:
+    RolleEffect( Spieler *zSpieler, Richtung r );
+    ~RolleEffect();
+    bool istSpielerBeweglich( Richtung r ) override;
+    bool istSpielerVerwundbar( Richtung r ) override;
+    void move( double time ) override;
+};

+ 7 - 0
StickmanWorldOnline/Schiene.cpp

@@ -0,0 +1,7 @@
+#include "Schiene.h"
+
+Schiene::Schiene( int id, int x, int y, int width, int height )
+    : GameObject( SCHIENE, x, y, width, height )
+{
+    this->id = id;
+}

+ 13 - 0
StickmanWorldOnline/Schild.h

@@ -0,0 +1,13 @@
+#pragma once
+
+#include "Effect.h"
+
+class SchildEffect : public Effect
+{
+private:
+
+public:
+    SchildEffect( Spieler *zSpieler );
+    ~SchildEffect();
+    bool istSpielerVerwundbar( Richtung r ) override;
+};

+ 12 - 0
StickmanWorldOnline/Schuh.h

@@ -0,0 +1,12 @@
+#pragma once
+
+#include "Effect.h"
+
+class SchuhEffect : public Effect
+{
+private:
+
+public:
+    SchuhEffect( Spieler *zSpieler );
+    ~SchuhEffect();
+};

+ 73 - 21
StickmanWorldOnline/Spiel.cpp

@@ -1,4 +1,6 @@
 #include "Spiel.h"
+#include "DrachenAuge.h"
+#include "Brand.h"
 
 #define TICK 0.03333333
 
@@ -273,7 +275,7 @@ void Spiel::nachricht( int accountId, int len, char *bytes )
             Spieler *tmp = spieler.z( i );
             if( tmp && tmp->getAccountId() == accountId )
             {
-                if( !tmp->setTastenStand( *bytes, 0 ) )
+                if( !tmp->setTastenStand( (unsigned char)*bytes, 0 ) )
                 {
                     saveMSG = 0;
                     break;
@@ -349,18 +351,20 @@ void Spiel::tick( double zeit )
     // spieler bewegungen
     for( auto s = spieler.getIterator(); s; s++ )
     {
-        s->tick( zeit );
+        s->move( zeit );
         if( s->getX() < 0 || s->getY() < 0 || s->getX() + s->getWidth() >= mapSize.x || s->getY() + s->getHeight() >= mapSize.y )
-            s->tick( -zeit );
+            s->move( -zeit );
         else
         {
             for( auto b = barieren.getIterator(); b; b++ )
             { // spieler - bariere intersection
                 if( b->hatStyle( Bariere::Style::Aktiv ) && ( b->zTeam() != s->zTeam() ) && b->intersectsWith( s ) )
-                    s->tick( -zeit );
+                    s->move( -zeit );
             }
         }
     }
+    for( auto s = spieler.getIterator(); s; s++ )
+        s->tick( zeit, this );
     // barieren bewegung
     for( auto b = barieren.getIterator(); b; b++ )
         b->tick( zeit, this );
@@ -397,7 +401,7 @@ void Spiel::tick( double zeit )
             case GESCHOSS_FEUERBALL:
                 if( intersectsWithBariere )
                 {
-                    feuer.add( new FeuerballTreffer( ++nextId, g->getX() - 70, g->getY() - 70, g->getBesitzer(), 10 ) );
+                    feuer.add( new FeuerballTreffer( ++nextId, (int)g->getX() - 70, (int)g->getY() - 70, g->getBesitzer(), 10 ) );
                     shots.remove( i );
                     i--;
                     removed = 1;
@@ -405,6 +409,21 @@ void Spiel::tick( double zeit )
                 else
                     g->invertDirection();
                 break;
+            case GESCHOSS_MINE:
+                for( auto s = spieler.getIterator(); s; s++ )
+                {
+                    if( s->abstandZu( g ) < 50 )
+                    {
+                        s->nimmSchaden( 100 - s->abstandZu( g ), g->zBesitzer(), MITTE, this );
+                        if( g->zBesitzer() )
+                            g->zBesitzer()->addTreffer( this );
+                        s->addGetroffen();
+                    }
+                }
+                shots.remove( i );
+                i--;
+                removed = 1;
+                break;
             }
         }
         if( !removed )
@@ -413,8 +432,8 @@ void Spiel::tick( double zeit )
             {
                 if( t->istAktiv() && t->intersectsWith( g ) )
                 {
-                    g->setX( g->getX() + t->getZielX() - t->getX() );
-                    g->setY( g->getY() + t->getZielY() - t->getY() );
+                    g->setX( g->getX() + (float)t->getZielX() - t->getX() );
+                    g->setY( g->getY() + (float)t->getZielY() - t->getY() );
                     g->addTunnel();
                     Ereignis *e = new Ereignis( TUNNEL_BENUTZT );
                     e->addParameter( "Betroffes Geschoss", g->getThis() );
@@ -480,32 +499,45 @@ void Spiel::tick( double zeit )
                     // geschoss - spieler intersection
                     for( auto s = spieler.getIterator(); s; s++ )
                     {
-                        if( s->istAmLeben() && s != g->zBesitzer() )
+                        if( s->istAmLeben() && s != g->zBesitzer() && g->intersectsWith( s ) )
                         {
                             switch( g->getTyp() )
                             {
                             case GESCHOSS_PFEIL:
+                            {
+                                s->nimmSchaden( PFEIL_DAMAGE, g->zBesitzer(), invert( g->getRichtung() ), this );
+                                break;
+                            }
                             case GESCHOSS_KUGEL:
                             {
-                                double schaden = 100 + ( g->zBesitzer() ? g->zBesitzer()->getSchadenBonus() : 0 );
-                                s->nimmSchaden( schaden );
-                                if( g->zBesitzer() )
-                                {
-                                    g->zBesitzer()->addGemachterSchaden( schaden );
-                                    if( !s->istAmLeben() )
-                                        g->zBesitzer()->addKill();
-                                }
+                                s->nimmSchaden( KUGEL_DAMAGE, g->zBesitzer(), invert( g->getRichtung() ), this );
                                 break;
                             }
                             case GESCHOSS_DRACHENAUGE:
-                                s->addEffekt( new DrachenAugeEffekt( g->zBesitzer(), s._, 10 ) );
+                                s->addEffekt( new DrachenAugeEffect( g->zBesitzer(), s._ ) );
                                 break;
                             case GESCHOSS_FEUERBALL:
-                                feuer.add( new FeuerballTreffer( ++nextId, g->getX() - 70, g->getY() - 70, g->getBesitzer(), 10 ) );
+                                feuer.add( new FeuerballTreffer( ++nextId, (int)g->getX() - 70, (int)g->getY() - 70, g->getBesitzer(), 10 ) );
+                                break;
+                            case GESCHOSS_MINE:
+                                for( auto s2 = spieler.getIterator(); s2; s2++ )
+                                {
+                                    if( s2->abstandZu( g ) < 50 )
+                                    {
+                                        s2->nimmSchaden( 100 - s->abstandZu( g ), g->zBesitzer(), MITTE, this );
+                                        if( g->zBesitzer() )
+                                            g->zBesitzer()->addTreffer( this );
+                                        s->addGetroffen();
+                                    }
+                                }
+                                break;
+                            }
+                            if( g->getTyp() != GESCHOSS_MINE )
+                            {
+                                if( g->zBesitzer() )
+                                    g->zBesitzer()->addTreffer( this );
+                                s->addGetroffen();
                             }
-                            if( g->zBesitzer() )
-                                g->zBesitzer()->addTreffer();
-                            s->addGetroffen();
                             shots.remove( i );
                             i--;
                             removed = 1;
@@ -515,6 +547,26 @@ void Spiel::tick( double zeit )
             }
         }
     }
+    // Feuer Ticks
+    for( int i = 0; i < feuer.getEintragAnzahl(); i++ )
+    {
+        FeuerballTreffer *f = feuer.z( i );
+        f->tick( zeit );
+        if( f->isOver() )
+        {
+            feuer.remove( i );
+            i--;
+            continue;
+        }
+        if( f->makeDamage() )
+        {
+            for( auto s = spieler.getIterator(); s; s++ )
+            {
+                if( s->abstandZu( f ) < f->getWidth() / 2 )
+                    s->addEffekt( new BrandEffekt( f->zVerursacher(), s ) );
+            }
+        }
+    }
     // Drop Ticks
     for( auto d = drops.getIterator(); d; d++ )
         d->tick( zeit, this );

+ 612 - 0
StickmanWorldOnline/Spieler.cpp

@@ -0,0 +1,612 @@
+#include "Spieler.h"
+#include "Spiel.h"
+#include "BosheitRune.h"
+#include "Enterhaken.h"
+#include "Geist.h"
+#include "Leben.h"
+#include "LebenRune.h"
+#include "Rolle.h"
+#include "Schild.h"
+#include "Schuh.h"
+#include "StrengthRune.h"
+#include "Sturm.h"
+#include "TempoRune.h"
+#include "WeisheitRune.h"
+
+
+Inventar::Inventar()
+{
+    for( int i = 0; i < INVENTORY_SLOTS; i++ )
+    {
+        slots[ i ] = KEIN_GEGENSTAND;
+        anzahl[ i ] = 0;
+        abklingzeit[ i ] = 0;
+    }
+    selected = 0;
+}
+
+void Inventar::addItem( GegenstandTyp typ, int anzahl )
+{
+    for( int i = 0; i < INVENTORY_SLOTS; i++ )
+    {
+        if( slots[ i ] == typ )
+        {
+            this->anzahl[ i ] += anzahl;
+            return;
+        }
+    }
+    for( int i = 0; i < INVENTORY_SLOTS; i++ )
+    {
+        if( slots[ i ] == KEIN_GEGENSTAND )
+        {
+            slots[ i ] = typ;
+            this->anzahl[ i ] = consumable( typ ) ? anzahl : 1;
+            return;
+        }
+    }
+}
+
+void Inventar::setSelected( int slot )
+{
+    selected = slot;
+    if( selected >= INVENTORY_SLOTS )
+        selected = INVENTORY_SLOTS - 1;
+}
+
+GegenstandTyp Inventar::useItem()
+{
+    if( slots[ selected ] != KEIN_GEGENSTAND && abklingzeit[ selected ] <= 0 )
+    {
+        if( consumable( slots[ selected ] ) )
+        {
+            if( !--anzahl[ selected ] )
+            {
+                GegenstandTyp typ = slots[ selected ];
+                slots[ selected ] = KEIN_GEGENSTAND;
+                return typ;
+            }
+        }
+        abklingzeit[ selected ] = ::abklingzeit( slots[ selected ] );
+        return slots[ selected ];
+    }
+    return KEIN_GEGENSTAND;
+}
+
+void Inventar::tick( double zeit )
+{
+    for( int i = 0; i < INVENTORY_SLOTS; i++ )
+    {
+        if( slots[ i ] != KEIN_GEGENSTAND && abklingzeit[ i ] > 0 )
+        {
+            abklingzeit[ i ] -= (float)zeit;
+            if( abklingzeit[ i ] < 0 )
+                abklingzeit[ i ] = 0;
+        }
+    }
+}
+
+bool Inventar::canAddItem( GegenstandTyp typ ) const
+{
+    if( !consumable( typ ) )
+    {
+        for( int i = 0; i < INVENTORY_SLOTS; i++ )
+        {
+            if( slots[ i ] == typ )
+                return 0;
+        }
+    }
+    for( int i = 0; i < INVENTORY_SLOTS; i++ )
+    {
+        if( slots[ i ] == KEIN_GEGENSTAND || ( slots[ i ] == typ && consumable( typ ) ) )
+            return 1;
+    }
+    return 0;
+}
+
+GegenstandTyp Inventar::selectedItem() const
+{
+    return slots[ selected ];
+}
+
+
+Spieler::Spieler( int id, Team *team, int spawnX, int spawnY, int farbe )
+    : GameObject( SPIELER, spawnX, spawnY, 40, 50 )
+{
+    klient = 0;
+    accountId = 0;
+    spielerNummer = id;
+    this->team = team;
+    amLeben = 1;
+    maxWiederbelebungsZeit = 2;
+    wiederbelebungsZeit = 0;
+    zuletztAufgehoben = KEIN_GEGENSTAND;
+    zuletztAktiviert = KEIN_GEGENSTAND;
+    this->leben = 300;
+    this->maxLeben = 300;
+    level = 1;
+    erfahrung = 0;
+    maxErfahrung = 5;
+    this->spawnX = spawnX;
+    this->spawnY = spawnY;
+    laufTempo = 30;
+    geschossTempo = 100;
+    armor = 0;
+    schadensBonus = 0;
+    lebensraub = 0;
+    lebensRegeneration = 1;
+    abklingZeitVerringerung = 0;
+    color = farbe;
+    kills = 0;
+    tode = 0;
+    treffer = 0;
+    getroffen = 0;
+    schadenGenommen = 0;
+    schadenGemacht = 0;
+    lebenGeheilt = 0;
+    erhalteneErfahrung = 0;
+    itemsAufgehoben = 0;
+    itemsVerwendet = 0;
+    tunnelBenutzt = 0;
+    schalterAktiviert = 0;
+    geschosseGeschossen = 0;
+    for( int i = 0; i < 256; i++ )
+        tastenStand[ i ] = 0;
+    ausrichtung = MITTE;
+}
+
+Spieler::~Spieler()
+{
+    if( klient )
+        klient->release();
+    if( team )
+        team->release();
+}
+
+bool Spieler::setTastenStand( unsigned char taste, bool pressed )
+{
+    bool ret = tastenStand[ (int)taste ] != pressed;
+    tastenStand[ (int)taste ] = pressed;
+    if( pressed )
+    {
+        if( taste == 'w' )
+            ausrichtung = OBEN;
+        if( taste == 'a' )
+            ausrichtung = LINKS;
+        if( taste == 's' )
+            ausrichtung = UNTEN;
+        if( taste == 'd' )
+            ausrichtung = RECHTS;
+    }
+    else
+    {
+        if( !tastenStand[ 'w' ] && !tastenStand[ 'a' ] && !tastenStand[ 's' ] && !tastenStand[ 'd' ] )
+            ausrichtung = MITTE;
+        else
+        {
+            if( ( ausrichtung == OBEN && taste == 'w' ) ||
+                ( ausrichtung == LINKS && taste == 'a' ) ||
+                ( ausrichtung == UNTEN && taste == 's' ) ||
+                ( ausrichtung == RECHTS && taste == 'd' ) )
+            {
+                if( tastenStand[ 'w' ] )
+                    ausrichtung = OBEN;
+                if( tastenStand[ 'a' ] )
+                    ausrichtung = LINKS;
+                if( tastenStand[ 's' ] )
+                    ausrichtung = UNTEN;
+                if( tastenStand[ 'd' ] )
+                    ausrichtung = RECHTS;
+            }
+        }
+    }
+    return ret;
+}
+
+void Spieler::setTeam( Team *team )
+{
+    if( this->team )
+        this->team->removeSpieler();
+    this->team->release();
+    this->team = team;
+    this->team->addSpieler();
+}
+
+void Spieler::setAccount( int id )
+{
+    this->accountId = id;
+}
+
+void Spieler::setKlient( Klient *klient )
+{
+    if( this->klient )
+        this->klient->release();
+    this->klient = klient;
+}
+
+void Spieler::addEffekt( Effect *e )
+{
+    effekte.add( e );
+}
+
+void Spieler::setLaufTempo( float pps )
+{
+    laufTempo = pps;
+}
+
+void Spieler::addErfahrung( float anz, Spiel *zSpiel )
+{
+    erfahrung += anz;
+    Ereignis *e = new Ereignis( SPIELER_BEKOMMT_ERFAHRUNG );
+    e->addParameter( "Betroffener Spieler", getThis() );
+    e->addParameter( "Wert", new Float( anz ) );
+    zSpiel->throwEvent( e );
+    if( erfahrung > maxErfahrung )
+    {
+        level++;
+        erfahrung -= (float)maxErfahrung;
+        maxErfahrung += ( maxErfahrung / level ) + 2;
+        maxLeben += 20;
+        heilung( 20, zSpiel );
+        if( level <= 10 )
+        {
+            laufTempo += 2;
+            geschossTempo += 2;
+        }
+        if( level <= 50 )
+        {
+            armor += 1;
+            abklingZeitVerringerung += 1;
+        }
+        if( level <= 75 )
+        {
+            schadensBonus += 1;
+            lebensraub += 1;
+        }
+        if( level <= 100 )
+            lebensRegeneration += 1;
+        Ereignis *e = new Ereignis( SPIELER_LEVEL_UP );
+        e->addParameter( "Betroffener Spieler", getThis() );
+        zSpiel->throwEvent( e );
+    }
+}
+
+// aktualisiert auch die team statistik
+void Spieler::addKill()
+{
+    team->addKill();
+    kills++;
+}
+
+void Spieler::addTreffer( Spiel *zSpiel )
+{
+    addErfahrung( 2, zSpiel );
+    treffer++;
+}
+
+void Spieler::addGetroffen()
+{
+    getroffen++;
+}
+
+void Spieler::move( double zeit )
+{
+    if( istAmLeben() )
+    {
+        if( tastenStand[ 'w' ] && istBeweglich( OBEN ) )
+            y -= laufTempo * (float)zeit;
+        if( tastenStand[ 'a' ] && istBeweglich( LINKS ) )
+            x -= laufTempo * (float)zeit;
+        if( tastenStand[ 's' ] && istBeweglich( UNTEN ) )
+            y += laufTempo * (float)zeit;
+        if( tastenStand[ 'd' ] && istBeweglich( RECHTS ) )
+            x += laufTempo * (float)zeit;
+        for( auto e = effekte.getIterator(); e; e++ )
+            e->move( zeit );
+    }
+}
+
+void Spieler::wiederbelebung( Spiel *zSpiel )
+{
+    amLeben = 1;
+    leben = (float)maxLeben;
+    Ereignis *e = new Ereignis( SPIELER_WIEDERBELEBT );
+    e->addParameter( "Betroffener Spieler", getThis() );
+    zSpiel->throwEvent( e );
+}
+
+void Spieler::tick( double zeit, Spiel *zSpiel )
+{
+    if( istAmLeben() )
+    {
+        for( int i = 0; i < effekte.getEintragAnzahl(); i++ )
+        {
+            if( effekte.z( i )->tick( zeit, zSpiel ) && istAmLeben() )
+            {
+                effekte.remove( i );
+                i--;
+            }
+            if( !istAmLeben() )
+                break;
+        }
+        if( tastenStand[ ' ' ] )
+            useItem( zSpiel );
+    }
+    else
+    {
+        effekte.leeren();
+        wiederbelebungsZeit -= (float)zeit;
+        if( wiederbelebungsZeit <= 0 )
+        {
+            wiederbelebung( zSpiel );
+        }
+    }
+}
+
+void Spieler::useItem( Spiel *zSpiel )
+{
+    if( istAmLeben() && inv.selectedItem() != KEIN_GEGENSTAND && istGegenstandErlaubt( inv.selectedItem() ) )
+    {
+        itemsVerwendet++;
+        GegenstandTyp typ = inv.useItem();
+        Ereignis *e = new Ereignis( SPIELER_BENUTZT_GEGENSTAND );
+        e->addParameter( "Betroffener Spieler", getThis() );
+        e->addParameter( "Betroffener Gegenstand", new GegenstandTypVar( typ ) );
+        zSpiel->throwEvent( e );
+        switch( typ )
+        {
+        case PFEIL:
+            geschosseGeschossen++;
+            zSpiel->addGeschoss( new Geschoss( zSpiel->getNextId(), geschossTempo, GESCHOSS_PFEIL, getAusrichtung(), (int)x, (int)y, (Spieler *)getThis() ) );
+            break;
+        case LEBEN:
+            addEffekt( new LebenEffect( this ) );
+            break;
+        case SCHILD:
+            addEffekt( new SchildEffect( this ) );
+            break;
+        case SCHUH:
+            addEffekt( new SchuhEffect( this ) );
+            break;
+        case GEIST:
+            addEffekt( new GeistEffect( this ) );
+            break;
+        case KUGEL:
+            geschosseGeschossen++;
+            zSpiel->addGeschoss( new Geschoss( zSpiel->getNextId(), geschossTempo, GESCHOSS_KUGEL, getAusrichtung(), (int)x, (int)y, (Spieler *)getThis() ) );
+            break;
+        case ROLLE:
+            addEffekt( new RolleEffect( this, getAusrichtung() ) );
+            break;
+        case STURM:
+            addEffekt( new SturmEffect( this, getAusrichtung() ) );
+            break;
+        case DRACHENAUGE:
+            geschosseGeschossen++;
+            zSpiel->addGeschoss( new Geschoss( zSpiel->getNextId(), geschossTempo, GESCHOSS_DRACHENAUGE, getAusrichtung(), (int)x, (int)y, (Spieler *)getThis() ) );
+            break;
+        case FEUERBALL:
+            geschosseGeschossen++;
+            zSpiel->addGeschoss( new Geschoss( zSpiel->getNextId(), geschossTempo, GESCHOSS_FEUERBALL, getAusrichtung(), (int)x, (int)y, (Spieler *)getThis() ) );
+            break;
+        case ENTERHAKEN:
+            addEffekt( new EnterhakenEffect( this, getAusrichtung() ) );
+            break;
+        case MINE:
+            geschosseGeschossen++;
+            zSpiel->addGeschoss( new Geschoss( zSpiel->getNextId(), 0, GESCHOSS_MINE, MITTE, (int)x, (int)y, (Spieler *)getThis() ) );
+            break;
+        default:
+            break;
+        }
+    }
+}
+
+bool Spieler::addItem( GegenstandTyp typ, int anz, Spiel *zSpiel )
+{
+    if( storable( typ ) )
+    {
+        if( inv.canAddItem( typ ) )
+        {
+            itemsAufgehoben += anz;
+            inv.addItem( typ, anz );
+            Ereignis *e = new Ereignis( SPIELER_BEKOMMT_GEGENSTAND );
+            e->addParameter( "Betroffener Spieler", getThis() );
+            e->addParameter( "Betroffener Gegenstand", new GegenstandTypVar( typ ) );
+            e->addParameter( "Anzahl", new Integer( anz ) );
+            zSpiel->throwEvent( e );
+            return 1;
+        }
+    }
+    else
+    {
+        itemsAufgehoben += anz;
+        Ereignis *e = new Ereignis( SPIELER_BEKOMMT_GEGENSTAND );
+        e->addParameter( "Betroffener Spieler", getThis() );
+        e->addParameter( "Betroffener Gegenstand", new GegenstandTypVar( typ ) );
+        e->addParameter( "Anzahl", new Integer( anz ) );
+        zSpiel->throwEvent( e );
+        for( int i = 0; i < anz; i++ )
+        {
+            Ereignis *e = new Ereignis( SPIELER_BENUTZT_GEGENSTAND );
+            e->addParameter( "Betroffener Spieler", getThis() );
+            e->addParameter( "Betroffener Gegenstand", new GegenstandTypVar( typ ) );
+            zSpiel->throwEvent( e );
+            itemsVerwendet++;
+            switch( typ )
+            {
+            case RWEISHEIT:
+                addEffekt( new WeisheitRuneEffect( this ) );
+                break;
+            case RSTRENGTH:
+                addEffekt( new StrengthRuneEffect( this ) );
+                break;
+            case RBOSHEIT:
+                addEffekt( new BosheitRuneEffect( this ) );
+                break;
+            case RLEBEN:
+                addEffekt( new LebenRuneEffect( this ) );
+                break;
+            case RTEMPO:
+                addEffekt( new TempoRuneEffect( this ) );
+                break;
+            default:
+                break;
+            }
+        }
+    }
+    return 0;
+}
+
+// heilt auch um den lebensraub prozentsatz
+void Spieler::addGemachterSchaden( float schaden, Spiel *zSpiel )
+{
+    schadenGemacht += schaden;
+    Ereignis *e = new Ereignis( SPIELER_MACHT_SCHADEN );
+    e->addParameter( "Betroffener Spieler", getThis() );
+    e->addParameter( "Wert", new Float( schaden ) );
+    zSpiel->throwEvent( e );
+    heilung( schaden / 100 * lebensraub, zSpiel );
+}
+
+// zieht die rüstung ab
+void Spieler::nimmSchaden( float schaden, Spieler *zVerursacher, Richtung r, Spiel *zSpiel )
+{
+    if( !isVerwundbar( r ) || !amLeben )
+        return;
+    if( zVerursacher )
+        schaden += schaden / 100 * zVerursacher->getSchadenBonus();
+    schaden -= schaden / 100 * armor;
+    schaden = leben < schaden ? leben : schaden;
+    schadenGenommen += schaden;
+    leben -= schaden;
+    Ereignis *e = new Ereignis( SPIELER_NIMMT_SCHADEN );
+    e->addParameter( "Betroffener Spieler", getThis() );
+    e->addParameter( "Wert", new Float( schaden ) );
+    zSpiel->throwEvent( e );
+    if( zVerursacher )
+        zVerursacher->addGemachterSchaden( schaden, zSpiel );
+    if( leben == 0 )
+    {
+        wiederbelebungsZeit = (float)( maxWiederbelebungsZeit + team->getMaxWiederbelebungsZeit() );
+        wiederbelebungsZeit -= wiederbelebungsZeit / 100 * abklingZeitVerringerung;
+        team->addTod();
+        amLeben = 0;
+        tode++;
+        Ereignis *e = new Ereignis( SPIELER_STIRBT );
+        e->addParameter( "Betroffener Spieler", getThis() );
+        zSpiel->throwEvent( e );
+        if( zVerursacher )
+            zVerursacher->addKill();
+    }
+}
+
+void Spieler::heilung( float heal, Spiel *zSpiel )
+{
+    if( amLeben )
+    {
+        lebenGeheilt += heal;
+        leben += heal;
+        Ereignis *e = new Ereignis( SPIELER_WIRD_GEHEILT );
+        e->addParameter( "Betroffener Spieler", getThis() );
+        e->addParameter( "Wert", new Float( heal ) );
+        zSpiel->throwEvent( e );
+    }
+}
+
+float Spieler::getSchadenBonus() const
+{
+    return schadensBonus;
+}
+
+Klient *Spieler::zKlient() const
+{
+    return klient;
+}
+
+int Spieler::getSpielerNummer() const
+{
+    return spielerNummer;
+}
+
+Team *Spieler::zTeam() const
+{
+    return team;
+}
+
+int Spieler::getFarbe() const
+{
+    return color;
+}
+
+int Spieler::getAccountId() const
+{
+    return accountId;
+}
+
+int Spieler::getPunkte() const
+{
+    return kills - tode + ( treffer - getroffen ) / 2;
+}
+
+bool Spieler::istAmLeben() const
+{
+    return amLeben;
+}
+
+float Spieler::getLaufTempo() const
+{
+    return laufTempo;
+}
+
+bool Spieler::isVerwundbar( Richtung r ) const
+{
+    bool verwundbar = 1;
+    for( auto e = effekte.getIterator(); e; e++ )
+    {
+        verwundbar &= e->istSpielerVerwundbar( r );
+        if( !verwundbar )
+            return 0;
+    }
+    return 1;
+}
+
+bool Spieler::istBeweglich( Richtung r ) const
+{
+    bool beweglich = 1;
+    for( auto e = effekte.getIterator(); e; e++ )
+    {
+        beweglich &= e->istSpielerBeweglich( r );
+        if( !beweglich )
+            return 0;
+    }
+    return 1;
+}
+
+bool Spieler::istSichtbar( Team *zTeam ) const
+{
+    bool sichtbar = 1;
+    for( auto e = effekte.getIterator(); e; e++ )
+    {
+        sichtbar &= e->istSpielerSichtbar( zTeam );
+        if( !sichtbar )
+            return 0;
+    }
+    return 1;
+}
+
+bool Spieler::istGegenstandErlaubt( GegenstandTyp typ ) const
+{
+    bool erlaubt = !brauchtRichtung( typ ) || ausrichtung != MITTE;
+    for( auto e = effekte.getIterator(); e; e++ )
+    {
+        erlaubt &= e->istGegenstandErlaubt( typ );
+        if( !erlaubt )
+            return 0;
+    }
+    return 1;
+}
+
+Richtung Spieler::getAusrichtung() const
+{
+    return ausrichtung;
+}

+ 54 - 56
StickmanWorldOnline/Spieler.h

@@ -3,108 +3,100 @@
 #include "Team.h"
 #include "Gegenstand.h"
 #include "SSKlient.h"
+#include "Effect.h"
 
-class Effekt
-{
-private:
-    Spieler *zSpieler;
-    double timeLeft;
-    int ref;
+class Spiel;
 
-public:
-    Effekt( Spieler *zSpieler, int maxTime );
-    virtual bool tick( double time );
-    Effekt *getThis();
-    Effekt *release();
-};
+#define INVENTORY_SLOTS 8
 
-class DrachenAugeEffekt : public Effekt
+class Inventar
 {
 private:
-    Spieler *zVerursacher;
+    GegenstandTyp slots[ INVENTORY_SLOTS ];
+    int anzahl[ INVENTORY_SLOTS ];
+    float abklingzeit[ INVENTORY_SLOTS ];
+    int selected;
 
 public:
-    DrachenAugeEffekt( Spieler *zVerursacher, Spieler *zOpfer, int maxTime );
-    bool tick( double time ) override;
+    Inventar();
+    void addItem( GegenstandTyp typ, int anzahl );
+    void setSelected( int slot );
+    GegenstandTyp useItem();
+    void tick( double zeit );
+    bool canAddItem( GegenstandTyp typ ) const;
+    GegenstandTyp selectedItem() const;
 };
 
 class Spieler : public GameObject
 {
-public:
-    class Style
-    {
-        const static int MOVES_RIGHT = 1;
-        const static int MOVES_LEFT = 2;
-        const static int MOVES_BOTTOM = 4;
-        const static int MOVES_TOP = 8;
-        const static int AM_LEBEN = 0x10;
-        const static int UNSICHTBAR = 0x20;
-        const static int ENTERHAKEN_AKTIV = 0x40;
-        const static int ENTERHAKEN_UNVERWUNDBAR = 0x40;
-    };
 private:
-    RCArray< Effekt > effekte;
+    RCArray< Effect > effekte;
     Klient *klient;
     int accountId;
     int spielerNummer;
     Team *team;
-    int style;
+    bool amLeben;
     int maxWiederbelebungsZeit;
     float wiederbelebungsZeit;
     GegenstandTyp zuletztAufgehoben;
     GegenstandTyp zuletztAktiviert;
-    int leben;
+    float leben;
     int maxLeben;
     int level;
-    int erfahrung;
+    float erfahrung;
     int maxErfahrung;
     int spawnX;
     int spawnY;
-    int laufTempo;
-    int geschossTempo;
-    int armor;
-    int schadensBonus;
-    int lebensraub;
-    int lebensRegeneration;
-    int abklingZeitVerringerung;
+    float laufTempo;
+    float geschossTempo;
+    float armor;
+    float schadensBonus;
+    float lebensraub;
+    float lebensRegeneration;
+    float abklingZeitVerringerung;
     int color;
-    float gegenstandAbklingzeit[ ITEMANZAHL ];
     int kills;
     int tode;
     int treffer;
     int getroffen;
-    int schadenGenommen;
-    int schadenGemacht;
-    int lebenGeheilt;
-    int erhalteneErfahrung;
+    float schadenGenommen;
+    float schadenGemacht;
+    float lebenGeheilt;
+    float erhalteneErfahrung;
     int itemsAufgehoben;
     int itemsVerwendet;
     int tunnelBenutzt;
     int schalterAktiviert;
     int geschosseGeschossen;
-    char *tastenStand;
+    bool tastenStand[ 256 ];
+    Richtung ausrichtung;
+    Inventar inv;
 
 public:
-    Spieler( int id, Team *team, int spawnX, int spawnY, int breite, int height, 
-             int farbe, int leben, int erfahrung, int laufTempo, int geschossTempo,
-             int armor, int schadenBonus, int lebensraub, int lebensReg,
-             int abkVerringerung, int level );
+    Spieler( int id, Team *team, int spawnX, int spawnY, int farbe );
     ~Spieler();
-    bool setTastenStand( char taste, bool pressed );
+    bool setTastenStand( unsigned char taste, bool pressed );
     void setTeam( Team *team );
     void setAccount( int id );
     void setKlient( Klient *klient );
-    void addEffekt( Effekt *e );
+    void addEffekt( Effect *e );
+    void setLaufTempo( float pps );
+    void addErfahrung( float anz, Spiel *zSpiel );
     // aktualisiert auch die team statistik
     void addKill();
-    void addTreffer();
+    void addTreffer( Spiel *zSpiel );
     void addGetroffen();
-    void tick( double zeit );
+    void move( double zeit );
+    void wiederbelebung( Spiel *zSpiel );
+    void tick( double zeit, Spiel *zSpiel );
+    void useItem(Spiel *zSpiel);
+    bool addItem( GegenstandTyp typ, int anz, Spiel *zSpiel );
     // heilt auch um den lebensraub prozentsatz
-    void addGemachterSchaden( double schaden );
+    void addGemachterSchaden( float schaden, Spiel *zSpiel );
     // zieht die rüstung ab
-    void nimmSchaden( double &schaden );
-    int getSchadenBonus() const;
+    void nimmSchaden( float schaden, Spieler *zVerursacher, Richtung r, Spiel *zSpiel );
+    void heilung( float heal, Spiel *zSpiel );
+    float getSchadenBonus() const;
     Klient *zKlient() const;
     int getSpielerNummer() const;
     Team *zTeam() const;
@@ -112,4 +104,10 @@ public:
     int getAccountId() const;
     int getPunkte() const;
     bool istAmLeben() const;
+    float getLaufTempo() const;
+    bool isVerwundbar( Richtung r ) const;
+    bool istBeweglich( Richtung r ) const;
+    bool istSichtbar( Team *zTeam ) const;
+    bool istGegenstandErlaubt( GegenstandTyp typ ) const;
+    Richtung getAusrichtung() const;
 };

+ 20 - 0
StickmanWorldOnline/StickmanWorldOnline.vcxproj

@@ -79,14 +79,19 @@
   <ItemGroup>
     <ClCompile Include="Bariere.cpp" />
     <ClCompile Include="Base.cpp" />
+    <ClCompile Include="Brand.cpp" />
     <ClCompile Include="DllStart.cpp" />
+    <ClCompile Include="DrachenAuge.cpp" />
     <ClCompile Include="Drop.cpp" />
+    <ClCompile Include="Effect.cpp" />
     <ClCompile Include="GameObject.cpp" />
     <ClCompile Include="Gegenstand.cpp" />
     <ClCompile Include="Geschoss.cpp" />
     <ClCompile Include="Reader.cpp" />
     <ClCompile Include="Schalter.cpp" />
+    <ClCompile Include="Schiene.cpp" />
     <ClCompile Include="Spiel.cpp" />
+    <ClCompile Include="Spieler.cpp" />
     <ClCompile Include="Team.cpp" />
     <ClCompile Include="Timer.cpp" />
     <ClCompile Include="Tunnel.cpp" />
@@ -94,13 +99,27 @@
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="Aktionen.h" />
+    <ClInclude Include="BosheitRune.h" />
+    <ClInclude Include="Brand.h" />
+    <ClInclude Include="DrachenAuge.h" />
+    <ClInclude Include="Effect.h" />
+    <ClInclude Include="Enterhaken.h" />
+    <ClInclude Include="Geist.h" />
     <ClInclude Include="Geschoss.h" />
+    <ClInclude Include="Leben.h" />
+    <ClInclude Include="LebenRune.h" />
     <ClInclude Include="Reader.h" />
+    <ClInclude Include="Rolle.h" />
+    <ClInclude Include="Schild.h" />
+    <ClInclude Include="Schuh.h" />
     <ClInclude Include="Spieler.h" />
     <ClInclude Include="SpielerStatistik.h" />
     <ClInclude Include="SSKlient.h" />
     <ClInclude Include="Statistik.h" />
+    <ClInclude Include="StrengthRune.h" />
+    <ClInclude Include="Sturm.h" />
     <ClInclude Include="TeamStatistik.h" />
+    <ClInclude Include="TempoRune.h" />
     <ClInclude Include="Trigger.h" />
     <ClInclude Include="Bariere.h" />
     <ClInclude Include="Base.h" />
@@ -122,6 +141,7 @@
     <ClInclude Include="Tunnel.h" />
     <ClInclude Include="Umlenkung.h" />
     <ClInclude Include="Variablen.h" />
+    <ClInclude Include="WeisheitRune.h" />
   </ItemGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <Link>

+ 63 - 0
StickmanWorldOnline/StickmanWorldOnline.vcxproj.filters

@@ -28,6 +28,9 @@
     <Filter Include="Spiel\Objekte">
       <UniqueIdentifier>{214ae990-4b8e-4fad-a428-7f6f31c33648}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Spiel\Effekte">
+      <UniqueIdentifier>{d99cde07-5280-4dc6-8c0e-006968ee345e}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="DllStart.cpp">
@@ -72,6 +75,21 @@
     <ClCompile Include="Schalter.cpp">
       <Filter>Spiel\Objekte</Filter>
     </ClCompile>
+    <ClCompile Include="Schiene.cpp">
+      <Filter>Spiel\Objekte</Filter>
+    </ClCompile>
+    <ClCompile Include="Spieler.cpp">
+      <Filter>Spiel\Objekte</Filter>
+    </ClCompile>
+    <ClCompile Include="Effect.cpp">
+      <Filter>Spiel\Effekte</Filter>
+    </ClCompile>
+    <ClCompile Include="DrachenAuge.cpp">
+      <Filter>Spiel\Effekte</Filter>
+    </ClCompile>
+    <ClCompile Include="Brand.cpp">
+      <Filter>Spiel\Effekte</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="SpielKlasse.h">
@@ -161,5 +179,50 @@
     <ClInclude Include="SSKlient.h">
       <Filter>Netzwerk</Filter>
     </ClInclude>
+    <ClInclude Include="Effect.h">
+      <Filter>Spiel\Effekte</Filter>
+    </ClInclude>
+    <ClInclude Include="Brand.h">
+      <Filter>Spiel\Effekte</Filter>
+    </ClInclude>
+    <ClInclude Include="Leben.h">
+      <Filter>Spiel\Effekte</Filter>
+    </ClInclude>
+    <ClInclude Include="Schild.h">
+      <Filter>Spiel\Effekte</Filter>
+    </ClInclude>
+    <ClInclude Include="Schuh.h">
+      <Filter>Spiel\Effekte</Filter>
+    </ClInclude>
+    <ClInclude Include="Geist.h">
+      <Filter>Spiel\Effekte</Filter>
+    </ClInclude>
+    <ClInclude Include="Rolle.h">
+      <Filter>Spiel\Effekte</Filter>
+    </ClInclude>
+    <ClInclude Include="Sturm.h">
+      <Filter>Spiel\Effekte</Filter>
+    </ClInclude>
+    <ClInclude Include="Enterhaken.h">
+      <Filter>Spiel\Effekte</Filter>
+    </ClInclude>
+    <ClInclude Include="WeisheitRune.h">
+      <Filter>Spiel\Effekte</Filter>
+    </ClInclude>
+    <ClInclude Include="StrengthRune.h">
+      <Filter>Spiel\Effekte</Filter>
+    </ClInclude>
+    <ClInclude Include="BosheitRune.h">
+      <Filter>Spiel\Effekte</Filter>
+    </ClInclude>
+    <ClInclude Include="LebenRune.h">
+      <Filter>Spiel\Effekte</Filter>
+    </ClInclude>
+    <ClInclude Include="TempoRune.h">
+      <Filter>Spiel\Effekte</Filter>
+    </ClInclude>
+    <ClInclude Include="DrachenAuge.h">
+      <Filter>Spiel\Effekte</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>

+ 12 - 0
StickmanWorldOnline/StrengthRune.h

@@ -0,0 +1,12 @@
+#pragma once
+
+#include "Effect.h"
+
+class StrengthRuneEffect : public Effect
+{
+private:
+
+public:
+    StrengthRuneEffect( Spieler *zSpieler );
+    ~StrengthRuneEffect();
+};

+ 15 - 0
StickmanWorldOnline/Sturm.h

@@ -0,0 +1,15 @@
+#pragma once
+
+#include "Effect.h"
+
+class SturmEffect : public Effect
+{
+private:
+
+public:
+    SturmEffect( Spieler *zSpieler, Richtung r );
+    ~SturmEffect();
+    bool istSpielerBeweglich( Richtung r ) override;
+    bool istSpielerVerwundbar( Richtung r ) override;
+    void move( double time ) override;
+};

+ 3 - 0
StickmanWorldOnline/Team.cpp

@@ -32,11 +32,14 @@ void Team::removeSpieler()
 
 void Team::addTod()
 {
+    punkte -= 4;
+    maxWiederbelebungsZeit++;
     tode++;
 }
 
 void Team::addKill()
 {
+    punkte += 2;
     kills++;
 }
 

+ 12 - 0
StickmanWorldOnline/TempoRune.h

@@ -0,0 +1,12 @@
+#pragma once
+
+#include "Effect.h"
+
+class TempoRuneEffect : public Effect
+{
+private:
+
+public:
+    TempoRuneEffect( Spieler *zSpieler );
+    ~TempoRuneEffect();
+};

+ 1 - 1
StickmanWorldOnline/Timer.cpp

@@ -2,7 +2,7 @@
 #include "Spiel.h"
 
 Timer::Timer( int id, const char *name, int maxZeit, int x, int y, bool visible, bool autoWiederhohlung, bool runns, int farbe )
-    : GameObject( x, y, 0, 0 )
+    : GameObject( TIMER, x, y, 0, 0 )
 {
     this->id = id;
     this->name = name;

+ 1 - 1
StickmanWorldOnline/Tunnel.cpp

@@ -2,7 +2,7 @@
 
 
 Tunnel::Tunnel( int id, int x, int y, int width, int height, int zielX, int zielY, bool aktiv )
-    : GameObject( x, y, width, height )
+    : GameObject( TUNNEL, x, y, width, height )
 {
     this->id = id;
     this->aktiv = aktiv;

+ 4 - 1
StickmanWorldOnline/Umlenkung.cpp

@@ -2,7 +2,7 @@
 
 
 Umlenkung::Umlenkung( int id, int x, int y, int breite, int height, Richtung richtung, int maxAbklingzeit, bool drehend, bool aktiv )
-    : GameObject( x, y, breite, height )
+    : GameObject( UMLENKUNG, x, y, breite, height )
 {
     this->id = id;
     this->richtung = richtung;
@@ -51,6 +51,9 @@ void Umlenkung::addBenutzt()
             break;
         case LINKS:
             richtung = OBEN;
+            break;
+        case MITTE:
+            break;
         }
     }
     abklingzeitVerbleibend = (float)maxAbklingzeit;

+ 2 - 1
StickmanWorldOnline/Variablen.h

@@ -26,7 +26,8 @@ enum VariableTyp
     SCHIENE,
     TUNNEL,
     UMLENKUNG,
-    TRIGGER
+    TRIGGER,
+    FEUERBALL_TREFFER
 };
 
 class Variable

+ 12 - 0
StickmanWorldOnline/WeisheitRune.h

@@ -0,0 +1,12 @@
+#pragma once
+
+#include "Effect.h"
+
+class WeisheitRuneEffect : public Effect
+{
+private:
+
+public:
+    WeisheitRuneEffect( Spieler *zSpieler );
+    ~WeisheitRuneEffect();
+};