void LootManager::addLoot(ItemStack stack, FPoint pos, bool dropped_by_hero) { if (static_cast<size_t>(stack.item) >= items->items.size()) { logError("LootManager: Loot item with id %d is not valid.", stack.item); return; } Loot ld; ld.stack = stack; ld.pos.x = pos.x; ld.pos.y = pos.y; alignFPoint(&ld.pos); ld.dropped_by_hero = dropped_by_hero; if (!items->items[stack.item].loot_animation.empty()) { size_t index = items->items[stack.item].loot_animation.size()-1; for (unsigned int i=0; i<items->items[stack.item].loot_animation.size(); i++) { int low = items->items[stack.item].loot_animation[i].low; int high = items->items[stack.item].loot_animation[i].high; if (stack.quantity >= low && (stack.quantity <= high || high == 0)) { index = i; break; } } ld.loadAnimation(items->items[stack.item].loot_animation[index].name); } else { // immediately place the loot on the ground if there's no animation ld.on_ground = true; } loot.push_back(ld); snd->play(sfx_loot, GLOBAL_VIRTUAL_CHANNEL, pos, false); }
/** * Perform miscellaneous state-based actions. * 1) Set animations and sound effects * 2) Return to the default state (Stance) when actions are complete */ void BehaviorStandard::updateState() { // stunned enemies can't act if (e->stats.effects.stun) return; int power_id; int power_state; // continue current animations e->activeAnimation->advanceFrame(); switch (e->stats.cur_state) { case ENEMY_STANCE: e->setAnimation("stance"); break; case ENEMY_MOVE: e->setAnimation("run"); break; case ENEMY_POWER: power_id = e->stats.power_index[e->stats.activated_powerslot]; power_state = powers->powers[power_id].new_state; // animation based on power type if (power_state == POWSTATE_INSTANT) e->instant_power = true; else if (power_state == POWSTATE_ATTACK) e->setAnimation(powers->powers[power_id].attack_anim); // sound effect based on power type if (e->activeAnimation->isFirstFrame()) { if (powers->powers[power_id].attack_anim == "swing" || powers->powers[power_id].attack_anim == "shoot") e->play_sfx_phys = true; else if (powers->powers[power_id].attack_anim == "cast") e->play_sfx_ment = true; } if (e->activeAnimation->isLastFrame() || (power_state == POWSTATE_ATTACK && e->activeAnimation->getName() != powers->powers[power_id].attack_anim)) e->newState(ENEMY_STANCE); break; case ENEMY_SPAWN: e->setAnimation("spawn"); //the second check is needed in case the entity does not have a spawn animation if (e->activeAnimation->isLastFrame() || e->activeAnimation->getName() != "spawn") { e->newState(ENEMY_STANCE); } break; case ENEMY_BLOCK: e->setAnimation("block"); break; case ENEMY_HIT: e->setAnimation("hit"); if (e->activeAnimation->isFirstFrame()) { e->stats.effects.triggered_hit = true; } if (e->activeAnimation->isLastFrame() || e->activeAnimation->getName() != "hit") e->newState(ENEMY_STANCE); break; case ENEMY_DEAD: if (e->stats.effects.triggered_death) break; e->setAnimation("die"); if (e->activeAnimation->isFirstFrame()) { e->play_sfx_die = true; e->stats.corpse_ticks = CORPSE_TIMEOUT; e->stats.effects.clearEffects(); } if (e->activeAnimation->isSecondLastFrame()) { if (percentChance(e->stats.power_chance[ON_DEATH])) powers->activate(e->stats.power_index[ON_DEATH], &e->stats, e->stats.pos); } if (e->activeAnimation->isLastFrame() || e->activeAnimation->getName() != "die") { // puts renderable under object layer e->stats.corpse = true; //allow free movement over the corpse mapr->collider.unblock(e->stats.pos.x, e->stats.pos.y); // remove corpses that land on blocked tiles, such as water or pits if (!mapr->collider.is_valid_position(e->stats.pos.x, e->stats.pos.y, MOVEMENT_NORMAL, false)) { e->stats.corpse_ticks = 0; } // prevent "jumping" when rendering alignFPoint(&e->stats.pos); } break; case ENEMY_CRITDEAD: e->setAnimation("critdie"); if (e->activeAnimation->isFirstFrame()) { e->play_sfx_critdie = true; e->stats.corpse_ticks = CORPSE_TIMEOUT; e->stats.effects.clearEffects(); } if (e->activeAnimation->isSecondLastFrame()) { if (percentChance(e->stats.power_chance[ON_DEATH])) powers->activate(e->stats.power_index[ON_DEATH], &e->stats, e->stats.pos); } if (e->activeAnimation->isLastFrame() || e->activeAnimation->getName() != "critdie") { // puts renderable under object layer e->stats.corpse = true; //allow free movement over the corpse mapr->collider.unblock(e->stats.pos.x, e->stats.pos.y); // prevent "jumping" when rendering alignFPoint(&e->stats.pos); } break; default: break; } }