/**
   * Returns TRUE if given element is colliding something at given location.
   *
   * @param tx
   * @param ty
   * @param quelElement (can be NULL)
   * @param rayon
   * @return boolean
   */
  public Perso checkCollision(int x, int y, Element quelElement, int rayon) {

    int gridX = x >> 4;
    int gridY = y >> 4;
    int fromId = quelElement != null ? quelElement.getId() : -1;
    boolean foreGround = quelElement != null && quelElement.isForeground();

    // Try on given grid case
    Perso perso = locatePerso(gridX, gridY, foreGround, fromId);
    if (perso != null && checkCollisionOnPerso(x, y, quelElement, perso, rayon)) {
      return perso;
    }
    int nbPersoAround = CollBuffer.howManyAround(gridX, gridY);
    if (nbPersoAround <= 1) {
      return null;
    }
    nbPersoAround--;
    if (nbPersoAround != 0) {
      for (Angle a : Angle.values()) {
        Point offset = a.coords;
        int gx = gridX + offset.x;
        int gy = gridY + offset.y;
        perso = locatePerso(gx, gy, foreGround, fromId);
        if (perso != null && checkCollisionOnPerso(x, y, quelElement, perso, rayon)) {
          return perso;
        }
      }
    }
    return null;
  }
  // /////////////////////////////////////////////////////////////////////////////////////
  // clearSpritesWithoutZildo
  // /////////////////////////////////////////////////////////////////////////////////////
  // -Delete every sprites in the entities list
  // -Clean the sort array
  // -Reinitializes local camera
  // /////////////////////////////////////////////////////////////////////////////////////
  public void clearSprites(boolean includingZildo) {
    // Get Zildo to avoid to remove it
    Perso zildo = EngineZildo.persoManagement.getZildo();

    // Destroy entities
    List<SpriteEntity> listToRemove = new ArrayList<SpriteEntity>();

    for (SpriteEntity entity : spriteEntities) {
      if (entity != null) {
        boolean canDelete = true;
        if (entity == zildo) {
          // This IS Zildo ! So we keep him
          canDelete = includingZildo;
        } else if (entity.getEntityType().isElement()) {
          Element element = (Element) entity;
          if (zildo != null && element.getLinkedPerso() == zildo) {
            // This is an element related to zildo, so we can't
            // remove it now
            canDelete = includingZildo;
          }
        } else if (entity.getEntityType().isPerso()) {
          canDelete = false;
        }
        if (canDelete) {
          listToRemove.add(entity);
        }
      }
    }

    for (SpriteEntity entity : listToRemove) {
      deleteSprite(entity);
    }

    walkableEntities.clear();
  }
 /**
  * Check if 'quelPerso' is colliding with the given element.
  *
  * @param x
  * @param y
  * @param quelElement
  * @param quelPerso
  * @param rayon
  * @return Perso
  */
 private boolean checkCollisionOnPerso(
     int x, int y, Element quelElement, Perso quelPerso, int rayon) {
   if (quelPerso.isZildo()
       && quelElement != null
       && quelElement.getDesc() instanceof ElementDescription) {
     ElementDescription d = (ElementDescription) quelElement.getDesc();
     if (d.isPushable() && quelElement.vx + quelElement.vy != 0f) {
       return false;
     }
   }
   int tx = (int) quelPerso.getX();
   int ty = (int) quelPerso.getY();
   PersoDescription descToCompare = quelPerso.getDesc();
   int rayonPersoToCompare = rayon;
   if (descToCompare != null) {
     rayonPersoToCompare = descToCompare.getRadius();
   }
   // Do we have a Perso in parameters ?
   Perso perso = null;
   if (quelElement != null && quelElement.getEntityType().isPerso()) {
     perso = (Perso) quelElement;
   }
   if (EngineZildo.collideManagement.checkCollisionCircles(
       x, y, tx, ty, rayon, rayonPersoToCompare)) {
     if (perso != null && perso.isZildo() && perso.linkedSpritesContains(quelPerso)) {
       // Collision entre Zildo et l'objet qu'il porte dans les mains => on laisse
     } else if (quelElement == null || quelElement.getLinkedPerso() != quelPerso) {
       return true;
     }
   }
   // No collision
   return false;
 }
  public void animate() {

    switch (shieldType) {
      case REDBALL:
        float beta = 0.0f;
        float coeff = 1.0f;
        for (CompositeElement composite : composites) {
          composite.animate();
          Element elem = composite.getRefElement();
          elem.x = (int) (affected.x + 5 * Math.sin((alpha * alpha + beta) * coeff));
          elem.y = (int) (affected.y + 10 + 2 * Math.cos((alpha + beta) * coeff));
          elem.z = 20; // - beta * 10;

          elem.y -= elem.getSprModel().getTaille_y() / 2;

          elem.setAjustedX((int) elem.x);
          elem.setAjustedY((int) elem.y);

          beta += 0.8f; // gamma; //0.9;//Math.PI / 4;
          coeff *= -1f;
        }
        alpha += 0.1;
        gamma += 0.2;
        break;
    }
  }
 /**
  * Translate every entities with the given offset.
  *
  * @param p_offset
  * @param p_translateZildo TRUE=Translate Zildo too / FALSE=Don't touch him
  */
 public void translateEntities(Point p_offset, boolean p_translateZildo) {
   for (SpriteEntity entity : spriteEntities) {
     if (!entity.clientSpecific && (!entity.isZildo() || p_translateZildo)) {
       if (entity.getEntityType().isElement()) {
         Element e = (Element) entity;
         if (e.getLinkedPerso() != null && e.getLinkedPerso().isZildo()) {
           continue;
         }
       }
       entity.x += p_offset.x;
       entity.y += p_offset.y;
       entity.setAjustedX(entity.getAjustedX() + p_offset.x);
       entity.setAjustedY(entity.getAjustedY() + p_offset.y);
     }
   }
 }
  /**
   * Find an element near a given one.<br>
   * WARNING: it's an unoptimized method, contrary to {@link #collideSprite(int, int, Element)}, but
   * it's used only once when player press action key. So it's acceptable now.
   *
   * @param x
   * @param y
   * @param quelElement
   * @param radius
   * @return Element
   */
  public Element collideElement(
      int x, int y, Element quelElement, int radius, SpriteDescription... expectedDesc) {
    Perso perso = null;
    if (quelElement != null && quelElement.getEntityType().isPerso()) {
      perso = (Perso) quelElement;
    }

    for (SpriteEntity entity : spriteEntities) {
      if (entity.getEntityType().isElement()) {
        if (entity != quelElement) {
          int tx = (int) entity.x;
          int ty = (int) entity.y;
          if (EngineZildo.collideManagement.checkCollisionCircles(x, y, tx, ty, radius, radius)) {
            if (perso != null && perso.isZildo() && perso.linkedSpritesContains(entity)) {
              // Collision between hero and object he's carrying => let it go
            } else if (quelElement == null || quelElement.getLinkedPerso() != entity) {
              // Check that found element is one of expected ones
              if (expectedDesc != null && expectedDesc.length > 0) {
                for (SpriteDescription sDesc : expectedDesc) {
                  if (sDesc == entity.getDesc()) {
                    return (Element) entity;
                  }
                }
                continue; // Check next one
              }
              Element elem = (Element) entity;
              // Found an element, but is it really the most pertinent ? (ex:shadow)
              if (elem.getLinkedPerso() != null) {
                return elem.getLinkedPerso();
              }
              return elem;
            }
          }
        }
      }
    }
    return null;
  }
  // /////////////////////////////////////////////////////////////////////////////////////
  // spawnElement
  // /////////////////////////////////////////////////////////////////////////////////////
  // IN:nBank, nSpr, x, y
  // /////////////////////////////////////////////////////////////////////////////////////
  // Spawn an element with minimal requirements
  // -build an element with given parameters
  // -add it to the sprite engine
  public Element spawnElement(
      int nBank, int nSpr, int x, int y, int z, Reverse reverse, Rotation rotation) {

    // SpriteEntity informations
    Element element;
    if (nBank == SpriteBank.BANK_GEAR) {
      element = new ElementGear(x, y);
      element.setAjustedX(x);
      element.setAjustedY(y);
    } else {
      element = new Element();
    }
    element.setX(x);
    element.setY(y);
    element.setZ(z);
    element.setNSpr(nSpr);
    element.setNBank(nBank);
    element.reverse = reverse;
    element.rotation = rotation;

    spawnSprite(element);

    return element;
  }
 public ShieldEffect(Element p_linked, ShieldType p_shieldType) {
   affected = p_linked;
   shieldType = p_shieldType;
   switch (shieldType) {
     case REDBALL:
       for (int i = 0; i < 4; i++) {
         Element ball = new Element();
         ball.setNSpr(ElementDescription.REDBALL3.ordinal());
         ball.setNBank(SpriteBank.BANK_ELEMENTS);
         ball.setSpecialEffect(EngineFX.SHINY);
         EngineZildo.spriteManagement.spawnSprite(ball);
         CompositeElement composite = new CompositeElement(ball);
         composite.followShape();
         composites.add(composite);
         ball.x = affected.x;
         ball.y = affected.y;
         ball.z = affected.z;
       }
       break;
   }
 }
  /**
   * @param p_action
   * @return boolean
   */
  public boolean render(ActionElement p_action) {
    boolean achieved = false;
    if (p_action.waiting) {
      waitForEndAction(p_action);
      achieved = p_action.done;
    } else {
      Perso perso = EngineZildo.persoManagement.getNamedPerso(p_action.who);
      if (perso != null) {
        scriptExec.involved.add(perso); // Note that this perso is concerned
      }
      Point location = p_action.location;
      if (p_action.delta && location != null) {
        Point currentPos = null;
        if (perso != null) {
          // Given position is a delta with current one (work ONLY with perso, not with camera)
          currentPos = new Point(perso.x, perso.y);
        } else if ("camera".equals(p_action.what)) {
          currentPos = ClientEngineZildo.mapDisplay.getCamera();
        } else {
          Element elem = EngineZildo.spriteManagement.getNamedElement(p_action.what);
          currentPos = new Point(elem.x, elem.y);
        }
        if (currentPos == null) {
          throw new RuntimeException("We need valid 'who' or 'what' attribute");
        }
        location = location.translate(currentPos.x, currentPos.y);
      }
      String text = p_action.text;
      switch (p_action.kind) {
        case pos:
          if (perso != null) {
            perso.x = location.x;
            perso.y = location.y;
          } else if ("camera".equals(p_action.what)) {
            ClientEngineZildo.mapDisplay.setCamera(location);
            ClientEngineZildo.mapDisplay.setFocusedEntity(null);
          } else {
            Element elem = EngineZildo.spriteManagement.getNamedElement(p_action.what);
            elem.x = location.x;
            elem.y = location.y;
            // TODO:the 'pushable' attribute shouldn't be set by this default way
            elem.setPushable(false);
          }
          achieved = true;
          break;
        case moveTo:
          if (perso != null) {
            perso.setGhost(true);
            perso.setTarget(location);
            perso.setForward(p_action.backward);
            perso.setSpeed(p_action.speed);
            perso.setOpen(p_action.open);
            perso.setUnstoppable(p_action.unstoppable);
          } else if ("camera".equals(p_action.what)) {
            ClientEngineZildo.mapDisplay.setTargetCamera(location);
            ClientEngineZildo.mapDisplay.setFocusedEntity(null);
          }
          break;
        case speak:
          String sentence = UIText.getGameText(text);
          EngineZildo.dialogManagement.launchDialog(
              SinglePlayer.getClientState(), null, new ScriptAction(sentence));
          scriptExec.userEndedAction = false;
          break;
        case script:
          MouvementPerso script = MouvementPerso.fromInt(p_action.val);
          perso.setQuel_deplacement(script, true);
          String param = p_action.fx;
          if (param != null) {
            switch (script) {
              case ZONE:
                perso.setZone_deplacement(
                    EngineZildo.mapManagement.range(
                        perso.getX() - 16 * 5,
                        perso.getY() - 16 * 5,
                        perso.getX() + 16 * 5,
                        perso.getY() + 16 * 5));
                break;
              case OBSERVE:
                Perso persoToObserve = EngineZildo.persoManagement.getNamedPerso(param);
                perso.setFollowing(persoToObserve);
                break;
            }
          }
          achieved = true;
          break;
        case angle:
          if (perso.getTarget() != null) {
            return false;
          }
          perso.setAngle(Angle.fromInt(p_action.val));
          achieved = true;
          break;
        case wait:
          count = p_action.val;
          break;
        case fadeIn:
          EngineZildo.askEvent(
              new ClientEvent(ClientEventNature.FADE_IN, FilterEffect.fromInt(p_action.val)));
          break;
        case fadeOut:
          EngineZildo.askEvent(
              new ClientEvent(ClientEventNature.FADE_OUT, FilterEffect.fromInt(p_action.val)));
          break;
        case clear:
          EngineZildo.askEvent(new ClientEvent(ClientEventNature.CLEAR));
          achieved = true;
          break;
        case map: // Change current map
          EngineZildo.mapManagement.loadMap(p_action.text, false);
          ClientEngineZildo.mapDisplay.setCurrentMap(EngineZildo.mapManagement.getCurrentMap());
          achieved = true;
          break;
        case focus: // Camera focus on given character
          Element toFocus = perso;
          if (p_action.what != null) {
            toFocus = EngineZildo.spriteManagement.getNamedElement(p_action.what);
          }
          if (toFocus == null) {
            ClientEngineZildo.mapDisplay.setFocusedEntity(null);
          }
          if (p_action.delta) {
            Point cameraLoc =
                new Point(toFocus.x - MapDisplay.CENTER_X, toFocus.y - MapDisplay.CENTER_Y);
            ClientEngineZildo.mapDisplay.setTargetCamera(cameraLoc);
          }
          ClientEngineZildo.mapDisplay.setFocusedEntity(toFocus);
          // If delta, we go smoothly to the target, except if it's explicitly asked to be
          // unblocking
          achieved = !p_action.delta || p_action.unblock;
          break;
        case spawn: // Spawn a new character
          if (p_action.who != null) {
            PersoDescription desc = PersoDescription.valueOf(p_action.text);
            Perso newOne =
                EngineZildo.persoManagement.createPerso(
                    desc, location.x, location.y, 0, p_action.who, p_action.val);
            newOne.setSpeed(p_action.speed);
            newOne.setEffect(p_action.fx);
            newOne.initPersoFX();
            EngineZildo.spriteManagement.spawnPerso(newOne);
          } else { // Spawn a new element
            if (EngineZildo.spriteManagement.getNamedElement(p_action.what) == null) {
              // Spawn only if doesn't exist yet
              SpriteDescription desc = SpriteDescription.Locator.findNamedSpr(p_action.text);
              Reverse rev = Reverse.fromInt(p_action.reverse);
              Rotation rot = Rotation.fromInt(p_action.rotation);
              Element elem =
                  EngineZildo.spriteManagement.spawnElement(
                      desc, location.x, location.y, 0, rev, rot);
              elem.setName(p_action.what);
            }
          }
          achieved = true;
          break;
        case impact:
          ImpactKind impactKind = ImpactKind.valueOf(p_action.text);
          EngineZildo.spriteManagement.spawnSprite(
              new ElementImpact(location.x, location.y, impactKind, null));
          achieved = true;
          break;
        case animation:
          SpriteAnimation anim = SpriteAnimation.valueOf(p_action.text);
          Element animElem =
              EngineZildo.spriteManagement.spawnSpriteGeneric(
                  anim, location.x, location.y, 0, null, null);
          if (p_action.what != null) {
            animElem.setName(p_action.what);
          }
          achieved = true;
          break;
        case take: // Someone takes an item
          if (p_action.who == null || "zildo".equalsIgnoreCase(p_action.who)) {
            // This is Zildo
            PersoZildo zildo = EngineZildo.persoManagement.getZildo();
            if (p_action.val != 0) {
              zildo.pickGoodies(null, p_action.val);
            } else {
              zildo.pickItem(ItemKind.fromString(text), null);
            }
          } else if (perso != null) {
            // This is somebody else
            Element elem = EngineZildo.spriteManagement.getNamedElement(p_action.what);
            perso.addPersoSprites(elem);
          }
          achieved = true;
          break;
        case putDown: // Zildo loses an item
          PersoZildo zildo = EngineZildo.persoManagement.getZildo();
          zildo.removeItem(ItemKind.fromString(text));
          achieved = true;
          break;
        case mapReplace:
          EngineZildo.scriptManagement.addReplacedMapName(p_action.what, text);
          achieved = true;
          break;
        case exec:
          // Note : we can sequence scripts in an action tag.
          EngineZildo.scriptManagement.execute(text);
          break;
        case music:
          if (text == null) { // Stop music ?
            EngineZildo.soundManagement.broadcastSound((BankMusic) null, (Point) null);
          } else {
            BankMusic musicSnd = BankMusic.valueOf(text);
            EngineZildo.soundManagement.broadcastSound(musicSnd, (Point) null);
          }
          EngineZildo.soundManagement.setForceMusic(true);
          achieved = true;
          break;
        case sound:
          BankSound snd = BankSound.valueOf(text);
          EngineZildo.soundManagement.playSound(snd, null);
          achieved = true;
          break;
        case remove:
          Element toRemove;
          if (p_action.what != null) {
            toRemove = EngineZildo.spriteManagement.getNamedElement(p_action.what);
          } else {
            toRemove = perso;
            EngineZildo.persoManagement.removePerso((Perso) toRemove);
          }
          EngineZildo.spriteManagement.deleteSprite(toRemove);
          achieved = true;
          break;
        case markQuest:
          if (p_action.val == 1) {
            EngineZildo.scriptManagement.accomplishQuest(p_action.text, true);
          } else {
            EngineZildo.scriptManagement.resetQuest(p_action.text);
          }
          achieved = true;
          break;
        case attack:
          if (p_action.text != null) {
            Item weapon = new Item(ItemKind.fromString(text));
            perso.setWeapon(weapon);
            perso.attack();
            achieved = true;
          }
          break;
        case activate:
          Element toActivate = EngineZildo.spriteManagement.getNamedElement(p_action.what);
          ElementGear gearToActivate = (ElementGear) toActivate;
          gearToActivate.activate(p_action.activate);
          break;
        case tile:
          // Change tile on map
          Area area = EngineZildo.mapManagement.getCurrentMap();
          Case c = area.get_mapcase(location.x, location.y + 4);
          if (p_action.back != -1) {
            c.setBackTile(new Tile(p_action.back, c));
          }
          if (p_action.back2 != -1) {
            c.setBackTile2(new Tile(p_action.back2, c));
          }
          if (p_action.fore != -1) {
            c.setForeTile(new Tile(p_action.fore, c));
          }
          EngineZildo.mapManagement.getCurrentMap().set_mapcase(location.x, location.y + 4, c);
          achieved = true;
          break;
        case filter:
          switch (p_action.val) {
            case 0: // REGULAR
              ClientEngineZildo.ortho.setFilteredColor(new Vector3f(1, 1, 1));
              break;
            case 1: // NIGHT
              ClientEngineZildo.ortho.setFilteredColor(Ortho.NIGHT_FILTER);
              break;
            case 2: // SEMI_NIGHT
              ClientEngineZildo.ortho.setFilteredColor(Ortho.SEMI_NIGHT_FILTER);
              break;
          }
          achieved = true;
          break;
        case end:
          new GameOverAction().launchAction(null);
      }

      p_action.done = achieved;
      p_action.waiting = !achieved;
    }
    return achieved;
  }
 /**
  * Update SpriteModel, which used to display the correct texture part, according to nBank, nSpr
  * and addSpr *
  */
 private void updateSprModel(Element element) {
   SpriteModel spr =
       getSpriteBank(element.getNBank()).get_sprite(element.getNSpr() + element.getAddSpr());
   element.setSprModel(spr);
 }
  /**
   * Do sprite's stuff
   *
   * <ul>
   *   <li>animate sprites & persos
   *   <li>
   *   <li>delete if need (the only place to do this)
   * </ul>
   *
   * @param p_blockMoves TRUE=don't animate perso except Zildo
   */
  public void updateSprites(boolean p_blockMoves) {
    spriteUpdating = true;
    spriteEntitiesToAdd.clear();

    // Backup current entities, if backup buffer is empty
    if (EngineZildo.game.multiPlayer && backupEntities.size() == 0) {
      for (SpriteEntity entity : spriteEntities) {
        SpriteEntity cloned = entity.clone();
        backupEntities.put(cloned.getId(), cloned);
      }
    }

    sprColli.initFrame(spriteEntities);
    persoColli.initFrame(EngineZildo.persoManagement.tab_perso);

    boolean blockNPC = p_blockMoves || temporaryBlocked;

    // Do perso animations
    // Mandatory to do that first, because one perso can be connected to
    // other sprites
    int compt = EngineZildo.compteur_animation; // % (3 * 20);
    for (SpriteEntity entity : spriteEntities) {
      if (entity.getEntityType().isPerso()) {
        Perso perso = (Perso) entity;
        boolean allowedToMoveAndCollide =
            !blockNPC || /*perso.getInfo() == PersoInfo.ZILDO ||*/ perso.getFollowing() != null;
        if (allowedToMoveAndCollide) {
          // Animate persos
          perso.animate(compt);
        }
        perso.finaliseComportement(compt);
        updateSprModel(perso);
        SpriteModel spr = perso.getSprModel();
        if (allowedToMoveAndCollide) {
          perso.manageCollision();
        }

        if (!perso.isZildo()) {
          // Non-zildo sprite haven't same way to display correctly (bad...)
          perso.setAjustedX(perso.getAjustedX() - (spr.getTaille_x() / 2));
          perso.setAjustedY(perso.getAjustedY() - (spr.getTaille_y() - 3));
        }
      }
    }

    List<SpriteEntity> toDelete = new ArrayList<SpriteEntity>();
    for (Iterator<SpriteEntity> it = spriteEntities.iterator(); it.hasNext(); ) {
      SpriteEntity entity = it.next();
      if (toDelete.contains(entity)) {
        continue; // It's a dead one
      }
      Element element = null;
      // Calcul physique du sprite
      if (entity.dying) {
        toDelete.add(entity);
      } else if (entity.getEntityType().isEntity()) {
        entity.animate();
      } else if (entity.getEntityType().isElement()) {
        // X, vX, aX, ...
        element = (Element) entity;
        if (!blockNPC || element.isLinkedToZildo()) {
          element.animate();
          if (element.dying) {
            SpriteEntity linkedOne = element.getLinkedPerso();
            // L'élément est arrivé au terme de son existence : on le supprime de la liste
            if (linkedOne != null && EntityType.ELEMENT == linkedOne.getEntityType()) {
              toDelete.add(linkedOne);
            }
            toDelete.add(element);
          } else {
            if (element.isVisible()) {
              updateSprModel(element);
            }
          }
        }
      }
    }

    // Remove what need to
    for (SpriteEntity entity : toDelete) {
      deleteSprite(entity);
      if (entity.getEntityType().isPerso()) {
        persoColli.notifyDeletion((Perso) entity);
      } else {
        sprColli.notifyDeletion(entity);
      }
    }

    spriteUpdating = false;
    spriteEntities.addAll(spriteEntitiesToAdd);
  }
  /**
   * Spawns a generic sprite animation (see note for particular case)
   *
   * @param typeSprite
   * @param x
   * @param y
   * @param floor floor to spark the animation
   * @param misc money value (just for GOLDCOIN)
   * @param miscPerso perso dying (just for DEATH)
   * @param desc
   * @return Spawned {@link Element} Note: Can return NULL (example: ask for a blue drop, but hero
   *     hasn't necklace ==> nothing spawned)
   */
  public Element spawnSpriteGeneric(
      SpriteAnimation typeSprite,
      int x,
      int y,
      int floor,
      int misc,
      Perso miscPerso,
      ElementDescription desc) {
    Element element = null;
    Element element2 = null;
    ElementDescription elemDesc = null;
    int j;

    switch (typeSprite) {
      case CHIMNEY_SMOKE:
        elemDesc = ElementDescription.SMOKE_SMALL;
        element = new ElementSmoke(x, y);
        element.setZ(6.0f);
        element.setVx(0.2f + 0.1f * (float) Math.random());
        element.setVy(0.0f);
        element.setVz(0.0f);
        element.setAx(-0.01f);
        element.setAy(0.0f);
        element.setAz(0.01f); // + rnd()*0.005f);

        element.setSprModel(elemDesc);

        element.setScrX((int) element.x);
        element.setScrY((int) element.y);

        element.setForeground(true);
        break;

      case BUSHES:
        for (j = 0; j < 8; j++) {
          Element e = new Element();
          e.setX((float) (x + Math.random() * 10 - 5));
          e.setY((float) (y + Math.random() * 6 - 2));
          e.setZ((float) (7 + Math.random() * 10));
          e.setVx(0.2f * (j - 1));
          e.setVz((float) (-0.5f + Math.random() * 3 * 0.1f));
          e.setAx(-0.05f * e.getVx());
          if (misc == 1) {
            e.setNSpr(ElementDescription.NETTLE_LEAF.ordinal());
          } else {
            e.setNSpr(ElementDescription.LEAF_GREEN.ordinal());
          }
          if ((j % 2) == 0) {
            e.reverse = Reverse.HORIZONTAL;
          }
          spawnSprite(e);
          // Peut-être qu'un diamant va apparaitre !
        }
        break;

      case GOLDCOIN:
      case ARROW:
      case FROMGROUND:
        // Diamond, arrows, everything coming from ground
        // First of all : check if this is a right place (no collision, and no lava)
        if (EngineZildo.mapManagement.collide(x, y, miscPerso)) {
          break;
        }
        element = new ElementGoodies();
        element.setX(x);
        element.setY(y);
        element.setZ(4.0f);
        element.setVz(1.5f);
        element.setAz(-0.1f);
        ElementDescription shadow = ElementDescription.SHADOW_MINUS;
        if (typeSprite == SpriteAnimation.GOLDCOIN) {
          switch (misc) {
            case 0:
              element.setDesc(ElementDescription.GOLDCOIN1);
              break;
            case 1:
              element.setDesc(ElementDescription.THREEGOLDCOINS1);
              shadow = ElementDescription.SHADOW;
              break;
            default:
              element.setDesc(ElementDescription.GOLDPURSE1);
              break;
          }
        } else if (typeSprite == SpriteAnimation.FROMGROUND) {
          element.setSprModel(desc);
        } else {
          element.setSprModel(ElementDescription.ARROW_UP);
          element.setY(y - 3);
        }
        // Ombre
        element2 = new Element();
        element2.setX(x);
        element2.setY(y - 2);
        element2.setSprModel(shadow);
        element2.floor = floor;
        spawnSprite(element2);
        element.setLinkedPerso(element2);
        break;

      case BLUE_DROP:
        if (EngineZildo.scriptManagement.isBlueDropDisplayable()) {
          element = new ElementGoodies();
          element.setX(x - 1);
          element.setY(y);
          if (misc == 1) { // Heart should be on the ground
            element.setX(x - 3);
            element.setY(y);
            element.setZ(0);
            element.setSprModel(ElementDescription.DROP_FLOOR);
          } else {
            element.setZ(11.0f);
            // element.setVx(0.15f);
            element.setVz(-0.02f);
            element.setAz(-0.01f);
            // element.setAx(-0.01f);
            element.setSprModel(ElementDescription.DROP_SMALL);
          }
        }
        break;

      case DEATH:
        element = new ElementAnimMort(miscPerso);
        element.setX(x);
        element.setY(y);
        element.setZ(8.0f);
        break;

      case BREAKING_ROCK:
        Angle temp = Angle.NORDOUEST;
        for (j = 0; j < 4; j++) {
          Element e = new Element();
          Point move = temp.coords;
          e.setX(x);
          e.setY(y);
          e.setZ(4);
          e.setVx(0.5f * move.x + (float) Math.random() * 0.2f);
          e.setVy(0.5f * move.y + (float) Math.random() * 0.2f);
          e.setVz(1f);
          e.setAz(-0.08f);
          e.setFx(0.04f);
          e.setFy(0.04f);
          e.setNSpr(ElementDescription.TINY_ROCK.ordinal());
          if (j % 2 == 1) {
            e.rotation = Rotation.UPSIDEDOWN;
          }
          e.alphaV = -10;
          spawnSprite(e);

          temp = Angle.rotate(temp, 1);
        }
        break;

      case FROM_CHEST:
        element = new ElementGoodies(miscPerso);
        element.x = x;
        element.y = y;
        element.z = 16;
        element.vx = 0;
        element.vy = 0.0f;
        element.vz = 0.18f;
        element.ax = 0;
        element.fy = 0.005f;
        element.fz = 0.03f;
        element.setDesc(desc);
        break;
      case STAR_CIRCLE:
        element = new ElementStars(StarKind.CIRCLE, x, y);
        break;
      case STAR_SHINE:
        element = new ElementImpact(x, y, ImpactKind.STAR_YELLOW, null);
        element.setForeground(true);
        break;
      case STAR_TRAIL:
        element = new ElementStars(StarKind.TRAIL, x, y);
        break;
      case CLOUD_FOG:
        element = new ElementClouds(x, y);
        EngineZildo.soundManagement.broadcastSound(BankSound.CannonBall, element);
        break;
      case HEARTS:
        element = new ElementHearts(x, y);
        break;
      case ROCKBALL:
        element =
            new ElementThrown(Angle.EST, x, y, 15, 2.9f, null) {
              @Override
              public void animate() {
                super.animate();
              }
            };
        element.vy = Hasard.intervalle(0.2f);
        element.vz = 1.2f;
        element.az = -0.1f;
        // element.fx = 0.01f;
        element.setDesc(ElementDescription.ROCK_BALL);
        element.setForeground(true);
        break;
      case STAFF_POUM:
        element = new ElementStaffs(x, y);
        break;
      case BIG_FIREBALL:
        element = new ElementFireballs(x, y, Angle.fromInt(misc));
        break;
      case LAVA_DROP:
        element = new ElementImpact(x, y, ImpactKind.LAVA_DROP, null);
        break;
      case DUST:
        element = new ElementImpact(x, y, ImpactKind.DUST, null);
        break;
      case POISONCLOUD:
        element = new ElementPoison(x, y, miscPerso);
        break;
      case WATER_SPLASH:
        element = new ElementImpact(x, y, ImpactKind.WATER_SPLASH, null);
        break;
      case SEWER_SMOKE:
        element = new ElementSewerSmoke(x, y, Angle.fromInt(misc));
        break;
    }
    if (element != null) {
      element.floor = floor;
      spawnSprite(element);
    }

    return element;
  }