1 #include "class.hpp" 2 3 #include <stdexcept> 4 5 #include <components/esm/defs.hpp> 6 7 #include "../mwbase/environment.hpp" 8 #include "../mwbase/windowmanager.hpp" 9 #include "../mwbase/world.hpp" 10 #include "../mwworld/esmstore.hpp" 11 12 #include "ptr.hpp" 13 #include "refdata.hpp" 14 #include "nullaction.hpp" 15 #include "failedaction.hpp" 16 #include "actiontake.hpp" 17 #include "containerstore.hpp" 18 19 #include "../mwgui/tooltips.hpp" 20 21 #include "../mwmechanics/creaturestats.hpp" 22 #include "../mwmechanics/npcstats.hpp" 23 24 namespace MWWorld 25 { 26 std::map<std::string, std::shared_ptr<Class> > Class::sClasses; 27 Class()28 Class::Class() {} 29 ~Class()30 Class::~Class() {} 31 insertObjectRendering(const Ptr & ptr,const std::string & mesh,MWRender::RenderingInterface & renderingInterface) const32 void Class::insertObjectRendering (const Ptr& ptr, const std::string& mesh, MWRender::RenderingInterface& renderingInterface) const 33 { 34 35 } 36 insertObject(const Ptr & ptr,const std::string & mesh,MWPhysics::PhysicsSystem & physics) const37 void Class::insertObject(const Ptr& ptr, const std::string& mesh, MWPhysics::PhysicsSystem& physics) const 38 { 39 40 } 41 apply(const MWWorld::Ptr & ptr,const std::string & id,const MWWorld::Ptr & actor) const42 bool Class::apply (const MWWorld::Ptr& ptr, const std::string& id, const MWWorld::Ptr& actor) const 43 { 44 return false; 45 } 46 skillUsageSucceeded(const MWWorld::Ptr & ptr,int skill,int usageType,float extraFactor) const47 void Class::skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType, float extraFactor) const 48 { 49 throw std::runtime_error ("class does not represent an actor"); 50 } 51 canSell(const MWWorld::ConstPtr & item,int npcServices) const52 bool Class::canSell (const MWWorld::ConstPtr& item, int npcServices) const 53 { 54 return false; 55 } 56 getServices(const ConstPtr & actor) const57 int Class::getServices(const ConstPtr &actor) const 58 { 59 throw std::runtime_error ("class does not have services"); 60 } 61 getCreatureStats(const Ptr & ptr) const62 MWMechanics::CreatureStats& Class::getCreatureStats (const Ptr& ptr) const 63 { 64 throw std::runtime_error ("class does not have creature stats"); 65 } 66 getNpcStats(const Ptr & ptr) const67 MWMechanics::NpcStats& Class::getNpcStats (const Ptr& ptr) const 68 { 69 throw std::runtime_error ("class does not have NPC stats"); 70 } 71 hasItemHealth(const ConstPtr & ptr) const72 bool Class::hasItemHealth (const ConstPtr& ptr) const 73 { 74 return false; 75 } 76 getItemHealth(const ConstPtr & ptr) const77 int Class::getItemHealth(const ConstPtr &ptr) const 78 { 79 if (ptr.getCellRef().getCharge() == -1) 80 return getItemMaxHealth(ptr); 81 else 82 return ptr.getCellRef().getCharge(); 83 } 84 getItemNormalizedHealth(const ConstPtr & ptr) const85 float Class::getItemNormalizedHealth (const ConstPtr& ptr) const 86 { 87 if (getItemMaxHealth(ptr) == 0) 88 { 89 return 0.f; 90 } 91 else 92 { 93 return getItemHealth(ptr) / static_cast<float>(getItemMaxHealth(ptr)); 94 } 95 } 96 getItemMaxHealth(const ConstPtr & ptr) const97 int Class::getItemMaxHealth (const ConstPtr& ptr) const 98 { 99 throw std::runtime_error ("class does not have item health"); 100 } 101 hit(const Ptr & ptr,float attackStrength,int type) const102 void Class::hit(const Ptr& ptr, float attackStrength, int type) const 103 { 104 throw std::runtime_error("class cannot hit"); 105 } 106 block(const Ptr & ptr) const107 void Class::block(const Ptr &ptr) const 108 { 109 throw std::runtime_error("class cannot block"); 110 } 111 onHit(const Ptr & ptr,float damage,bool ishealth,const Ptr & object,const Ptr & attacker,const osg::Vec3f & hitPosition,bool successful) const112 void Class::onHit(const Ptr& ptr, float damage, bool ishealth, const Ptr& object, const Ptr& attacker, const osg::Vec3f& hitPosition, bool successful) const 113 { 114 throw std::runtime_error("class cannot be hit"); 115 } 116 activate(const Ptr & ptr,const Ptr & actor) const117 std::shared_ptr<Action> Class::activate (const Ptr& ptr, const Ptr& actor) const 118 { 119 return std::shared_ptr<Action> (new NullAction); 120 } 121 use(const Ptr & ptr,bool force) const122 std::shared_ptr<Action> Class::use (const Ptr& ptr, bool force) const 123 { 124 return std::shared_ptr<Action> (new NullAction); 125 } 126 getContainerStore(const Ptr & ptr) const127 ContainerStore& Class::getContainerStore (const Ptr& ptr) const 128 { 129 throw std::runtime_error ("class does not have a container store"); 130 } 131 getInventoryStore(const Ptr & ptr) const132 InventoryStore& Class::getInventoryStore (const Ptr& ptr) const 133 { 134 throw std::runtime_error ("class does not have an inventory store"); 135 } 136 hasInventoryStore(const Ptr & ptr) const137 bool Class::hasInventoryStore(const Ptr &ptr) const 138 { 139 return false; 140 } 141 canLock(const ConstPtr & ptr) const142 bool Class::canLock(const ConstPtr &ptr) const 143 { 144 return false; 145 } 146 setRemainingUsageTime(const Ptr & ptr,float duration) const147 void Class::setRemainingUsageTime (const Ptr& ptr, float duration) const 148 { 149 throw std::runtime_error ("class does not support time-based uses"); 150 } 151 getRemainingUsageTime(const ConstPtr & ptr) const152 float Class::getRemainingUsageTime (const ConstPtr& ptr) const 153 { 154 return -1; 155 } 156 getScript(const ConstPtr & ptr) const157 std::string Class::getScript (const ConstPtr& ptr) const 158 { 159 return ""; 160 } 161 getMaxSpeed(const Ptr & ptr) const162 float Class::getMaxSpeed (const Ptr& ptr) const 163 { 164 return 0; 165 } 166 getCurrentSpeed(const Ptr & ptr) const167 float Class::getCurrentSpeed (const Ptr& ptr) const 168 { 169 return 0; 170 } 171 getJump(const Ptr & ptr) const172 float Class::getJump (const Ptr& ptr) const 173 { 174 return 0; 175 } 176 getEnchantmentPoints(const MWWorld::ConstPtr & ptr) const177 int Class::getEnchantmentPoints (const MWWorld::ConstPtr& ptr) const 178 { 179 throw std::runtime_error ("class does not support enchanting"); 180 } 181 getMovementSettings(const Ptr & ptr) const182 MWMechanics::Movement& Class::getMovementSettings (const Ptr& ptr) const 183 { 184 throw std::runtime_error ("movement settings not supported by class"); 185 } 186 getRotationVector(const Ptr & ptr) const187 osg::Vec3f Class::getRotationVector (const Ptr& ptr) const 188 { 189 return osg::Vec3f (0, 0, 0); 190 } 191 getEquipmentSlots(const ConstPtr & ptr) const192 std::pair<std::vector<int>, bool> Class::getEquipmentSlots (const ConstPtr& ptr) const 193 { 194 return std::make_pair (std::vector<int>(), false); 195 } 196 getEquipmentSkill(const ConstPtr & ptr) const197 int Class::getEquipmentSkill (const ConstPtr& ptr) const 198 { 199 return -1; 200 } 201 getValue(const ConstPtr & ptr) const202 int Class::getValue (const ConstPtr& ptr) const 203 { 204 throw std::logic_error ("value not supported by this class"); 205 } 206 getCapacity(const MWWorld::Ptr & ptr) const207 float Class::getCapacity (const MWWorld::Ptr& ptr) const 208 { 209 throw std::runtime_error ("capacity not supported by this class"); 210 } 211 getWeight(const ConstPtr & ptr) const212 float Class::getWeight(const ConstPtr &ptr) const 213 { 214 throw std::runtime_error ("weight not supported by this class"); 215 } 216 getEncumbrance(const MWWorld::Ptr & ptr) const217 float Class::getEncumbrance (const MWWorld::Ptr& ptr) const 218 { 219 throw std::runtime_error ("encumbrance not supported by class"); 220 } 221 isEssential(const MWWorld::ConstPtr & ptr) const222 bool Class::isEssential (const MWWorld::ConstPtr& ptr) const 223 { 224 return false; 225 } 226 getArmorRating(const MWWorld::Ptr & ptr) const227 float Class::getArmorRating (const MWWorld::Ptr& ptr) const 228 { 229 throw std::runtime_error("Class does not support armor rating"); 230 } 231 get(const std::string & key)232 const Class& Class::get (const std::string& key) 233 { 234 if (key.empty()) 235 throw std::logic_error ("Class::get(): attempting to get an empty key"); 236 237 std::map<std::string, std::shared_ptr<Class> >::const_iterator iter = sClasses.find (key); 238 239 if (iter==sClasses.end()) 240 throw std::logic_error ("Class::get(): unknown class key: " + key); 241 242 return *iter->second; 243 } 244 isPersistent(const ConstPtr & ptr) const245 bool Class::isPersistent(const ConstPtr &ptr) const 246 { 247 throw std::runtime_error ("class does not support persistence"); 248 } 249 registerClass(const std::string & key,std::shared_ptr<Class> instance)250 void Class::registerClass(const std::string& key, std::shared_ptr<Class> instance) 251 { 252 instance->mTypeName = key; 253 sClasses.insert(std::make_pair(key, instance)); 254 } 255 getUpSoundId(const ConstPtr & ptr) const256 std::string Class::getUpSoundId (const ConstPtr& ptr) const 257 { 258 throw std::runtime_error ("class does not have an up sound"); 259 } 260 getDownSoundId(const ConstPtr & ptr) const261 std::string Class::getDownSoundId (const ConstPtr& ptr) const 262 { 263 throw std::runtime_error ("class does not have an down sound"); 264 } 265 getSoundIdFromSndGen(const Ptr & ptr,const std::string & type) const266 std::string Class::getSoundIdFromSndGen(const Ptr &ptr, const std::string &type) const 267 { 268 throw std::runtime_error("class does not support soundgen look up"); 269 } 270 getInventoryIcon(const MWWorld::ConstPtr & ptr) const271 std::string Class::getInventoryIcon (const MWWorld::ConstPtr& ptr) const 272 { 273 throw std::runtime_error ("class does not have any inventory icon"); 274 } 275 getToolTipInfo(const ConstPtr & ptr,int count) const276 MWGui::ToolTipInfo Class::getToolTipInfo (const ConstPtr& ptr, int count) const 277 { 278 throw std::runtime_error ("class does not have a tool tip"); 279 } 280 showsInInventory(const ConstPtr & ptr) const281 bool Class::showsInInventory (const ConstPtr& ptr) const 282 { 283 // NOTE: Don't show WerewolfRobe objects in the inventory, or allow them to be taken. 284 // Vanilla likely uses a hack like this since there's no other way to prevent it from 285 // being shown or taken. 286 return (ptr.getCellRef().getRefId() != "werewolfrobe"); 287 } 288 hasToolTip(const ConstPtr & ptr) const289 bool Class::hasToolTip (const ConstPtr& ptr) const 290 { 291 return true; 292 } 293 getEnchantment(const ConstPtr & ptr) const294 std::string Class::getEnchantment (const ConstPtr& ptr) const 295 { 296 return ""; 297 } 298 adjustScale(const MWWorld::ConstPtr & ptr,osg::Vec3f & scale,bool rendering) const299 void Class::adjustScale(const MWWorld::ConstPtr& ptr, osg::Vec3f& scale, bool rendering) const 300 { 301 } 302 getModel(const MWWorld::ConstPtr & ptr) const303 std::string Class::getModel(const MWWorld::ConstPtr &ptr) const 304 { 305 return ""; 306 } 307 useAnim() const308 bool Class::useAnim() const 309 { 310 return false; 311 } 312 getModelsToPreload(const Ptr & ptr,std::vector<std::string> & models) const313 void Class::getModelsToPreload(const Ptr &ptr, std::vector<std::string> &models) const 314 { 315 std::string model = getModel(ptr); 316 if (!model.empty()) 317 models.push_back(model); 318 } 319 applyEnchantment(const MWWorld::ConstPtr & ptr,const std::string & enchId,int enchCharge,const std::string & newName) const320 std::string Class::applyEnchantment(const MWWorld::ConstPtr &ptr, const std::string& enchId, int enchCharge, const std::string& newName) const 321 { 322 throw std::runtime_error ("class can't be enchanted"); 323 } 324 canBeEquipped(const MWWorld::ConstPtr & ptr,const MWWorld::Ptr & npc) const325 std::pair<int, std::string> Class::canBeEquipped(const MWWorld::ConstPtr &ptr, const MWWorld::Ptr &npc) const 326 { 327 return std::make_pair (1, ""); 328 } 329 adjustPosition(const MWWorld::Ptr & ptr,bool force) const330 void Class::adjustPosition(const MWWorld::Ptr& ptr, bool force) const 331 { 332 } 333 defaultItemActivate(const Ptr & ptr,const Ptr & actor) const334 std::shared_ptr<Action> Class::defaultItemActivate(const Ptr &ptr, const Ptr &actor) const 335 { 336 if(!MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory)) 337 return std::shared_ptr<Action>(new NullAction()); 338 339 if(actor.getClass().isNpc() && actor.getClass().getNpcStats(actor).isWerewolf()) 340 { 341 const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore(); 342 const ESM::Sound *sound = store.get<ESM::Sound>().searchRandom("WolfItem"); 343 344 std::shared_ptr<MWWorld::Action> action(new MWWorld::FailedAction("#{sWerewolfRefusal}")); 345 if(sound) action->setSound(sound->mId); 346 347 return action; 348 } 349 350 std::shared_ptr<MWWorld::Action> action(new ActionTake(ptr)); 351 action->setSound(getUpSoundId(ptr)); 352 353 return action; 354 } 355 356 MWWorld::Ptr copyToCellImpl(const ConstPtr & ptr,CellStore & cell) const357 Class::copyToCellImpl(const ConstPtr &ptr, CellStore &cell) const 358 { 359 throw std::runtime_error("unable to copy class to cell"); 360 } 361 362 MWWorld::Ptr copyToCell(const ConstPtr & ptr,CellStore & cell,int count) const363 Class::copyToCell(const ConstPtr &ptr, CellStore &cell, int count) const 364 { 365 Ptr newPtr = copyToCellImpl(ptr, cell); 366 newPtr.getCellRef().unsetRefNum(); // This RefNum is only valid within the original cell of the reference 367 newPtr.getRefData().setCount(count); 368 return newPtr; 369 } 370 371 MWWorld::Ptr copyToCell(const ConstPtr & ptr,CellStore & cell,const ESM::Position & pos,int count) const372 Class::copyToCell(const ConstPtr &ptr, CellStore &cell, const ESM::Position &pos, int count) const 373 { 374 Ptr newPtr = copyToCell(ptr, cell, count); 375 newPtr.getRefData().setPosition(pos); 376 377 return newPtr; 378 } 379 isBipedal(const ConstPtr & ptr) const380 bool Class::isBipedal(const ConstPtr &ptr) const 381 { 382 return false; 383 } 384 canFly(const ConstPtr & ptr) const385 bool Class::canFly(const ConstPtr &ptr) const 386 { 387 return false; 388 } 389 canSwim(const ConstPtr & ptr) const390 bool Class::canSwim(const ConstPtr &ptr) const 391 { 392 return false; 393 } 394 canWalk(const ConstPtr & ptr) const395 bool Class::canWalk(const ConstPtr &ptr) const 396 { 397 return false; 398 } 399 isPureWaterCreature(const ConstPtr & ptr) const400 bool Class::isPureWaterCreature(const ConstPtr& ptr) const 401 { 402 return canSwim(ptr) 403 && !isBipedal(ptr) 404 && !canFly(ptr) 405 && !canWalk(ptr); 406 } 407 isPureFlyingCreature(const ConstPtr & ptr) const408 bool Class::isPureFlyingCreature(const ConstPtr& ptr) const 409 { 410 return canFly(ptr) 411 && !isBipedal(ptr) 412 && !canSwim(ptr) 413 && !canWalk(ptr); 414 } 415 isPureLandCreature(const Ptr & ptr) const416 bool Class::isPureLandCreature(const Ptr& ptr) const 417 { 418 return canWalk(ptr) 419 && !isBipedal(ptr) 420 && !canFly(ptr) 421 && !canSwim(ptr); 422 } 423 isMobile(const MWWorld::Ptr & ptr) const424 bool Class::isMobile(const MWWorld::Ptr& ptr) const 425 { 426 return canSwim(ptr) || canWalk(ptr) || canFly(ptr); 427 } 428 getSkill(const MWWorld::Ptr & ptr,int skill) const429 float Class::getSkill(const MWWorld::Ptr& ptr, int skill) const 430 { 431 throw std::runtime_error("class does not support skills"); 432 } 433 getBloodTexture(const MWWorld::ConstPtr & ptr) const434 int Class::getBloodTexture (const MWWorld::ConstPtr& ptr) const 435 { 436 throw std::runtime_error("class does not support gore"); 437 } 438 readAdditionalState(const MWWorld::Ptr & ptr,const ESM::ObjectState & state) const439 void Class::readAdditionalState (const MWWorld::Ptr& ptr, const ESM::ObjectState& state) const {} 440 writeAdditionalState(const MWWorld::ConstPtr & ptr,ESM::ObjectState & state) const441 void Class::writeAdditionalState (const MWWorld::ConstPtr& ptr, ESM::ObjectState& state) const {} 442 getBaseGold(const MWWorld::ConstPtr & ptr) const443 int Class::getBaseGold(const MWWorld::ConstPtr& ptr) const 444 { 445 throw std::runtime_error("class does not support base gold"); 446 } 447 isClass(const MWWorld::ConstPtr & ptr,const std::string & className) const448 bool Class::isClass(const MWWorld::ConstPtr& ptr, const std::string &className) const 449 { 450 return false; 451 } 452 getDoorState(const MWWorld::ConstPtr & ptr) const453 MWWorld::DoorState Class::getDoorState (const MWWorld::ConstPtr &ptr) const 454 { 455 throw std::runtime_error("this is not a door"); 456 } 457 setDoorState(const MWWorld::Ptr & ptr,MWWorld::DoorState state) const458 void Class::setDoorState (const MWWorld::Ptr &ptr, MWWorld::DoorState state) const 459 { 460 throw std::runtime_error("this is not a door"); 461 } 462 getNormalizedEncumbrance(const Ptr & ptr) const463 float Class::getNormalizedEncumbrance(const Ptr &ptr) const 464 { 465 float capacity = getCapacity(ptr); 466 float encumbrance = getEncumbrance(ptr); 467 468 if (encumbrance == 0) 469 return 0.f; 470 471 if (capacity == 0) 472 return 1.f; 473 474 return encumbrance / capacity; 475 } 476 getSound(const MWWorld::ConstPtr &) const477 std::string Class::getSound(const MWWorld::ConstPtr&) const 478 { 479 return std::string(); 480 } 481 getBaseFightRating(const ConstPtr & ptr) const482 int Class::getBaseFightRating(const ConstPtr &ptr) const 483 { 484 throw std::runtime_error("class does not support fight rating"); 485 } 486 getPrimaryFaction(const MWWorld::ConstPtr & ptr) const487 std::string Class::getPrimaryFaction (const MWWorld::ConstPtr& ptr) const 488 { 489 return std::string(); 490 } getPrimaryFactionRank(const MWWorld::ConstPtr & ptr) const491 int Class::getPrimaryFactionRank (const MWWorld::ConstPtr& ptr) const 492 { 493 return -1; 494 } 495 getEffectiveArmorRating(const ConstPtr & armor,const Ptr & actor) const496 float Class::getEffectiveArmorRating(const ConstPtr &armor, const Ptr &actor) const 497 { 498 throw std::runtime_error("class does not support armor ratings"); 499 } 500 getEnchantmentColor(const MWWorld::ConstPtr & item) const501 osg::Vec4f Class::getEnchantmentColor(const MWWorld::ConstPtr& item) const 502 { 503 osg::Vec4f result(1,1,1,1); 504 std::string enchantmentName = item.getClass().getEnchantment(item); 505 if (enchantmentName.empty()) 506 return result; 507 508 const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(enchantmentName); 509 if (!enchantment) 510 return result; 511 512 assert (enchantment->mEffects.mList.size()); 513 514 const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().search( 515 enchantment->mEffects.mList.front().mEffectID); 516 if (!magicEffect) 517 return result; 518 519 result.x() = magicEffect->mData.mRed / 255.f; 520 result.y() = magicEffect->mData.mGreen / 255.f; 521 result.z() = magicEffect->mData.mBlue / 255.f; 522 return result; 523 } 524 setBaseAISetting(const std::string & id,MWMechanics::CreatureStats::AiSetting setting,int value) const525 void Class::setBaseAISetting(const std::string& id, MWMechanics::CreatureStats::AiSetting setting, int value) const 526 { 527 throw std::runtime_error ("class does not have creature stats"); 528 } 529 modifyBaseInventory(const std::string & actorId,const std::string & itemId,int amount) const530 void Class::modifyBaseInventory(const std::string& actorId, const std::string& itemId, int amount) const 531 { 532 throw std::runtime_error ("class does not have an inventory store"); 533 } 534 getWalkSpeed(const Ptr &) const535 float Class::getWalkSpeed(const Ptr& /*ptr*/) const 536 { 537 return 0; 538 } 539 getRunSpeed(const Ptr &) const540 float Class::getRunSpeed(const Ptr& /*ptr*/) const 541 { 542 return 0; 543 } 544 getSwimSpeed(const Ptr &) const545 float Class::getSwimSpeed(const Ptr& /*ptr*/) const 546 { 547 return 0; 548 } 549 } 550