/** * Updates item info. * @param action Pointer to an action. */ void InventoryState::invClick(Action *action) { BattleItem *item = _inv->getSelectedItem(); _txtItem->setText(L""); _txtAmmo->setText(L""); _selAmmo->clear(); if (item != 0) { if (item->getUnit() && item->getUnit()->getStatus() == STATUS_UNCONSCIOUS) { _txtItem->setText(item->getUnit()->getName(_game->getLanguage())); } else { if (_game->getSavedGame()->isResearched(item->getRules()->getRequirements())) { _txtItem->setText(_game->getLanguage()->getString(item->getRules()->getName())); } else { _txtItem->setText(_game->getLanguage()->getString("STR_ALIEN_ARTIFACT")); } } std::wstringstream ss; if (item->getAmmoItem() != 0 && item->needsAmmo()) { ss << _game->getLanguage()->getString("STR_AMMO_ROUNDS_LEFT") << L'\x01' << item->getAmmoItem()->getAmmoQuantity(); SDL_Rect r; r.x = 0; r.y = 0; r.w = RuleInventory::HAND_W * RuleInventory::SLOT_W; r.h = RuleInventory::HAND_H * RuleInventory::SLOT_H; _selAmmo->drawRect(&r, Palette::blockOffset(0)+8); r.x++; r.y++; r.w -= 2; r.h -= 2; _selAmmo->drawRect(&r, 0); item->getAmmoItem()->getRules()->drawHandSprite(_game->getResourcePack()->getSurfaceSet("BIGOBS.PCK"), _selAmmo); } else if (item->getAmmoQuantity() != 0 && item->needsAmmo()) { ss << _game->getLanguage()->getString("STR_AMMO_ROUNDS_LEFT") << L'\x01' << item->getAmmoQuantity(); } _txtAmmo->setText(ss.str()); } if (_tu) { std::wstringstream ss; ss << _game->getLanguage()->getString("STR_TUS") << L'\x01' << _battleGame->getSelectedUnit()->getTimeUnits(); _txtTus->setText(ss.str()); } }
/** * Updates item info. * @param action Pointer to an action. */ void InventoryState::invClick(Action *) { BattleItem *item = _inv->getSelectedItem(); _txtItem->setText(L""); _txtAmmo->setText(L""); _selAmmo->clear(); if (item != 0) { if (item->getUnit() && item->getUnit()->getStatus() == STATUS_UNCONSCIOUS) { _txtItem->setText(item->getUnit()->getName(_game->getLanguage())); } else { if (_game->getSavedGame()->isResearched(item->getRules()->getRequirements())) { _txtItem->setText(tr(item->getRules()->getName())); } else { _txtItem->setText(tr("STR_ALIEN_ARTIFACT")); } } std::wstring s; if (item->getAmmoItem() != 0 && item->needsAmmo()) { s = tr("STR_AMMO_ROUNDS_LEFT").arg(item->getAmmoItem()->getAmmoQuantity()); SDL_Rect r; r.x = 0; r.y = 0; r.w = RuleInventory::HAND_W * RuleInventory::SLOT_W; r.h = RuleInventory::HAND_H * RuleInventory::SLOT_H; _selAmmo->drawRect(&r, Palette::blockOffset(0)+8); r.x++; r.y++; r.w -= 2; r.h -= 2; _selAmmo->drawRect(&r, 0); item->getAmmoItem()->getRules()->drawHandSprite(_game->getResourcePack()->getSurfaceSet("BIGOBS.PCK"), _selAmmo); } else if (item->getAmmoQuantity() != 0 && item->needsAmmo()) { s = tr("STR_AMMO_ROUNDS_LEFT").arg(item->getAmmoQuantity()); } else if (item->getRules()->getBattleType() == BT_MEDIKIT) { s = tr("STR_MEDI_KIT_QUANTITIES_LEFT").arg(item->getPainKillerQuantity()).arg(item->getStimulantQuantity()).arg(item->getHealQuantity()); } _txtAmmo->setText(s); } updateStats(); }
/** * Get the "main hand weapon" from the unit. * @return Pointer to item. */ BattleItem *BattleUnit::getMainHandWeapon() const { BattleItem *weaponRightHand = getItem("STR_RIGHT_HAND"); BattleItem *weaponLeftHand = getItem("STR_LEFT_HAND"); // if there is only one weapon, or only one weapon loaded (rules out grenades) it's easy: if (!weaponRightHand || !weaponRightHand->getAmmoItem() || !weaponRightHand->getAmmoItem()->getAmmoQuantity()) return weaponLeftHand; if (!weaponLeftHand || !weaponLeftHand->getAmmoItem() || !weaponLeftHand->getAmmoItem()->getAmmoQuantity()) return weaponRightHand; // otherwise pick the one with the least snapshot TUs int tuRightHand = weaponRightHand->getRules()->getTUSnap(); int tuLeftHand = weaponRightHand->getRules()->getTUSnap(); if (tuLeftHand >= tuRightHand) { return weaponRightHand; } else { return weaponLeftHand; } }
/** * init sequence: * - check if shot is valid * - calculate base accuracy */ void ProjectileFlyBState::init() { if (_initialized) return; _initialized = true; BattleItem *weapon = _action.weapon; _projectileItem = 0; _autoshotCounter = 0; if (!weapon) // can't shoot without weapon return; if (!_parent->getSave()->getTile(_action.target)) // invalid target position return; if (_action.actor->getTimeUnits() < _action.TU && !_parent->dontSpendTUs()) { _action.result = "STR_NOT_ENOUGH_TIME_UNITS"; _parent->popState(); return; } _unit = _action.actor; _ammo = weapon->getAmmoItem(); if (_unit->isOut()) { // something went wrong - we can't shoot when dead or unconscious _parent->popState(); return; } // autoshot will default back to snapshot if it's not possible if (weapon->getRules()->getAccuracyAuto() == 0 && _action.type == BA_AUTOSHOT) _action.type = BA_SNAPSHOT; // snapshot defaults to "hit" if it's a melee weapon // (in case of reaction "shots" with a melee weapon) if (weapon->getRules()->getBattleType() == BT_MELEE && _action.type == BA_SNAPSHOT) _action.type = BA_HIT; switch (_action.type) { case BA_SNAPSHOT: case BA_AIMEDSHOT: case BA_AUTOSHOT: case BA_LAUNCH: if (_ammo == 0) { _action.result = "STR_NO_AMMUNITION_LOADED"; _parent->popState(); return; } if (_ammo->getAmmoQuantity() == 0) { _action.result = "STR_NO_ROUNDS_LEFT"; _parent->popState(); return; } break; case BA_THROW: if (!validThrowRange(&_action)) { // out of range _action.result = "STR_OUT_OF_RANGE"; _parent->popState(); return; } _projectileItem = weapon; break; case BA_HIT: if (!validMeleeRange(&_action)) { _action.result = "STR_THERE_IS_NO_ONE_THERE"; _parent->popState(); return; } break; case BA_PANIC: case BA_MINDCONTROL: _parent->statePushFront(new ExplosionBState(_parent, Position((_action.target.x*16)+8,(_action.target.y*16)+8,(_action.target.z*24)+10), weapon, _action.actor)); return; default: _parent->popState(); return; } if (createNewProjectile() == true) { BattleAction action; BattleUnit *potentialVictim = _parent->getSave()->getTile(_action.target)->getUnit(); if (potentialVictim && potentialVictim->getFaction() != _unit->getFaction()) { if (_parent->getSave()->getTileEngine()->checkReactionFire(_unit, &action, potentialVictim, false)) { _parent->statePushBack(new ProjectileFlyBState(_parent, action)); } } } }
/** * init sequence: * - check if shot is valid * - calculate base accuracy */ void ProjectileFlyBState::init() { if (_initialized) return; _initialized = true; BattleItem *weapon = _action.weapon; _projectileItem = 0; if (!weapon) // can't shoot without weapon { _parent->popState(); return; } if (!_parent->getSave()->getTile(_action.target)) // invalid target position { _parent->popState(); return; } if (_parent->getPanicHandled() && _action.actor->getTimeUnits() < _action.TU) { _action.result = "STR_NOT_ENOUGH_TIME_UNITS"; _parent->popState(); return; } _unit = _action.actor; _ammo = weapon->getAmmoItem(); if (_unit->isOut()) { // something went wrong - we can't shoot when dead or unconscious _parent->popState(); return; } // reaction fire if (_unit->getFaction() != _parent->getSave()->getSide()) { // no ammo or target is dead: give the time units back and cancel the shot. if (_ammo == 0 || !_parent->getSave()->getTile(_action.target)->getUnit() || _parent->getSave()->getTile(_action.target)->getUnit()->isOut()) { _unit->setTimeUnits(_unit->getTimeUnits() + _unit->getActionTUs(_action.type, _action.weapon)); _parent->popState(); return; } } // autoshot will default back to snapshot if it's not possible if (weapon->getRules()->getAccuracyAuto() == 0 && _action.type == BA_AUTOSHOT) _action.type = BA_SNAPSHOT; // snapshot defaults to "hit" if it's a melee weapon // (in case of reaction "shots" with a melee weapon) if (weapon->getRules()->getBattleType() == BT_MELEE && _action.type == BA_SNAPSHOT) _action.type = BA_HIT; switch (_action.type) { case BA_SNAPSHOT: case BA_AIMEDSHOT: case BA_AUTOSHOT: case BA_LAUNCH: if (_ammo == 0) { _action.result = "STR_NO_AMMUNITION_LOADED"; _parent->popState(); return; } if (_ammo->getAmmoQuantity() == 0) { _action.result = "STR_NO_ROUNDS_LEFT"; _parent->popState(); return; } break; case BA_THROW: if (!validThrowRange(&_action)) { // out of range _action.result = "STR_OUT_OF_RANGE"; _parent->popState(); return; } _projectileItem = weapon; break; case BA_HIT: if (!_parent->getTileEngine()->validMeleeRange(_action.actor->getPosition(), _action.actor->getDirection(), _action.actor->getArmor()->getSize(), 0)) { _action.result = "STR_THERE_IS_NO_ONE_THERE"; _parent->popState(); return; } break; case BA_PANIC: case BA_MINDCONTROL: _parent->statePushFront(new ExplosionBState(_parent, Position((_action.target.x*16)+8,(_action.target.y*16)+8,(_action.target.z*24)+10), weapon, _action.actor)); return; default: _parent->popState(); return; } createNewProjectile(); }
/** * Shows item info. * @param action Pointer to an action. */ void InventoryState::invMouseOver(Action *) { if (_inv->getSelectedItem() != 0) { return; } BattleItem *item = _inv->getMouseOverItem(); if (item != 0) { if (item->getUnit() && item->getUnit()->getStatus() == STATUS_UNCONSCIOUS) { _txtItem->setText(item->getUnit()->getName(_game->getLanguage())); } else { if (_game->getSavedGame()->isResearched(item->getRules()->getRequirements())) { _txtItem->setText(tr(item->getRules()->getName())); } else { _txtItem->setText(tr("STR_ALIEN_ARTIFACT")); } } std::wstring s; if (item->getAmmoItem() != 0 && item->needsAmmo()) { s = tr("STR_AMMO_ROUNDS_LEFT").arg(item->getAmmoItem()->getAmmoQuantity()); SDL_Rect r; r.x = 0; r.y = 0; r.w = RuleInventory::HAND_W * RuleInventory::SLOT_W; r.h = RuleInventory::HAND_H * RuleInventory::SLOT_H; _selAmmo->drawRect(&r, _game->getMod()->getInterface("inventory")->getElement("grid")->color); r.x++; r.y++; r.w -= 2; r.h -= 2; _selAmmo->drawRect(&r, Palette::blockOffset(0)+15); item->getAmmoItem()->getRules()->drawHandSprite(_game->getMod()->getSurfaceSet("BIGOBS.PCK"), _selAmmo); _updateTemplateButtons(false); } else { _selAmmo->clear(); _updateTemplateButtons(!_tu); } if (item->getAmmoQuantity() != 0 && item->needsAmmo()) { s = tr("STR_AMMO_ROUNDS_LEFT").arg(item->getAmmoQuantity()); } else if (item->getRules()->getBattleType() == BT_MEDIKIT) { s = tr("STR_MEDI_KIT_QUANTITIES_LEFT").arg(item->getPainKillerQuantity()).arg(item->getStimulantQuantity()).arg(item->getHealQuantity()); } _txtAmmo->setText(s); } else { if (_currentTooltip.empty()) { _txtItem->setText(L""); } _txtAmmo->setText(L""); _selAmmo->clear(); _updateTemplateButtons(!_tu); } }
void InventoryState::btnApplyTemplateClick(Action *) { // don't accept clicks when moving items // it's ok if the template is empty -- it will just result in clearing the // unit's inventory if (_inv->getSelectedItem() != 0) { return; } BattleUnit *unit = _battleGame->getSelectedUnit(); std::vector<BattleItem*> *unitInv = unit->getInventory(); Tile *groundTile = unit->getTile(); std::vector<BattleItem*> *groundInv = groundTile->getInventory(); RuleInventory *groundRuleInv = _game->getMod()->getInventory("STR_GROUND"); _clearInventory(_game, unitInv, groundTile); // attempt to replicate inventory template by grabbing corresponding items // from the ground. if any item is not found on the ground, display warning // message, but continue attempting to fulfill the template as best we can bool itemMissing = false; std::vector<EquipmentLayoutItem*>::iterator templateIt; for (templateIt = _curInventoryTemplate.begin(); templateIt != _curInventoryTemplate.end(); ++templateIt) { // search for template item in ground inventory std::vector<BattleItem*>::iterator groundItem; const bool needsAmmo = !_game->getMod()->getItem((*templateIt)->getItemType())->getCompatibleAmmo()->empty(); bool found = false; bool rescan = true; while (rescan) { rescan = false; const std::string targetAmmo = (*templateIt)->getAmmoItem(); BattleItem *matchedWeapon = NULL; BattleItem *matchedAmmo = NULL; for (groundItem = groundInv->begin(); groundItem != groundInv->end(); ++groundItem) { // if we find the appropriate ammo, remember it for later for if we find // the right weapon but with the wrong ammo const std::string groundItemName = (*groundItem)->getRules()->getType(); if (needsAmmo && targetAmmo == groundItemName) { matchedAmmo = *groundItem; } if ((*templateIt)->getItemType() == groundItemName) { // if the loaded ammo doesn't match the template item's, // remember the weapon for later and continue scanning BattleItem *loadedAmmo = (*groundItem)->getAmmoItem(); if ((needsAmmo && loadedAmmo && targetAmmo != loadedAmmo->getRules()->getType()) || (needsAmmo && !loadedAmmo)) { // remember the last matched weapon for simplicity (but prefer empty weapons if any are found) if (!matchedWeapon || matchedWeapon->getAmmoItem()) { matchedWeapon = *groundItem; } continue; } // move matched item from ground to the appropriate inv slot (*groundItem)->setOwner(unit); (*groundItem)->setSlot(_game->getMod()->getInventory((*templateIt)->getSlot())); (*groundItem)->setSlotX((*templateIt)->getSlotX()); (*groundItem)->setSlotY((*templateIt)->getSlotY()); (*groundItem)->setFuseTimer((*templateIt)->getFuseTimer()); unitInv->push_back(*groundItem); groundInv->erase(groundItem); found = true; break; } } // if we failed to find an exact match, but found unloaded ammo and // the right weapon, unload the target weapon, load the right ammo, and use it if (!found && matchedWeapon && (!needsAmmo || matchedAmmo)) { // unload the existing ammo (if any) from the weapon BattleItem *loadedAmmo = matchedWeapon->getAmmoItem(); if (loadedAmmo) { groundTile->addItem(loadedAmmo, groundRuleInv); matchedWeapon->setAmmoItem(NULL); } // load the correct ammo into the weapon if (matchedAmmo) { matchedWeapon->setAmmoItem(matchedAmmo); groundTile->removeItem(matchedAmmo); } // rescan and pick up the newly-loaded/unloaded weapon rescan = true; } } if (!found) { itemMissing = true; } } if (itemMissing) { _inv->showWarning(tr("STR_NOT_ENOUGH_ITEMS_FOR_TEMPLATE")); } // refresh ui _inv->arrangeGround(false); updateStats(); _refreshMouse(); // give audio feedback _game->getMod()->getSoundByDepth(_battleGame->getDepth(), Mod::ITEM_DROP)->play(); }
/** * init sequence: * - check if shot is valid * - calculate base accuracy */ void ProjectileFlyBState::init() { if (_initialized) return; _initialized = true; BattleItem *weapon = _action.weapon; _projectileItem = 0; _autoshotCounter = 0; if (!weapon) // can't shoot without weapon return; if (_action.actor->getTimeUnits() < _action.TU && !_parent->dontSpendTUs()) { _result = "STR_NOT_ENOUGH_TIME_UNITS"; _parent->popState(); return; } _unit = _action.actor; _ammo = weapon->getAmmoItem(); if (_unit->isOut()) { // something went wrong _parent->popState(); return; } if (_action.type != BA_THROW) { if (_ammo == 0) { _result = "STR_NO_AMMUNITION_LOADED"; _parent->popState(); return; } if (_ammo->getAmmoQuantity() == 0) { _result = "STR_NO_ROUNDS_LEFT"; _parent->popState(); return; } } // action specific initialisation switch (_action.type) { case BA_AUTOSHOT: _baseAcc = weapon->getRules()->getAccuracyAuto(); break; case BA_SNAPSHOT: _baseAcc = weapon->getRules()->getAccuracySnap(); break; case BA_AIMEDSHOT: _baseAcc = weapon->getRules()->getAccuracyAimed(); break; case BA_THROW: if (!validThrowRange()) { // out of range _result = "STR_OUT_OF_RANGE"; _parent->popState(); return; } _baseAcc = (int)(_unit->getThrowingAccuracy()*100.0); _projectileItem = weapon; break; default: _baseAcc = 0; } createNewProjectile(); BattleAction action; BattleUnit *potentialVictim = _parent->getGame()->getSavedGame()->getBattleGame()->getTile(_action.target)->getUnit(); if (potentialVictim && potentialVictim->getFaction() != _unit->getFaction()) { if (_parent->getGame()->getSavedGame()->getBattleGame()->getTileEngine()->checkReactionFire(_unit, &action, potentialVictim, false)) { _parent->statePushBack(new ProjectileFlyBState(_parent, action)); } } }