void CmpProjectileWeaponUsable::use() { if(m_timeTillCanFire == 0) { // Determine the character which is firing the projectile (the owner of the weapon). ICmpOwnable_CPtr cmpOwnable = m_objectManager->get_component(m_objectID, cmpOwnable); ObjectID firer = cmpOwnable->owner(); if(!firer.valid()) throw Exception("Can't use a projectile weapon when it's not owned"); // Check that there's enough ammo. ICmpInventory_Ptr cmpFirerInventory = m_objectManager->get_component(firer, cmpFirerInventory); if(!cmpFirerInventory) throw Exception("The firer must have an inventory component"); if(cmpFirerInventory->consumables_count(m_ammoType) > 0) { // Fire a bullet from each hotspot of the weapon (note that this in principle makes it easy to implement things like double-barrelled shotguns). const std::vector<std::string>& spots = hotspots(); for(size_t i=0, size=spots.size(); i<size; ++i) { boost::optional<Vector3d> pos = hotspot_position(spots[i]); boost::optional<Vector3d> ori = hotspot_orientation(spots[i]); if(pos && ori) { ObjectSpecification specification = m_objectManager->get_archetype(m_ammoType); specification.set_component_property("Projectile", "Firer", firer); specification.set_component_property("Simulation", "Position", *pos); specification.set_component_property("Simulation", "Velocity", m_muzzleSpeed * *ori); m_objectManager->queue_for_construction(specification); } } cmpFirerInventory->destroy_consumables(m_ammoType, 1); m_timeTillCanFire = m_firingInterval; } } }
//#################### PUBLIC METHODS #################### void CmdUseActiveItem::execute(const ObjectManager_Ptr& objectManager, const std::vector<CollisionPolygon_Ptr>& polygons, const OnionTree_CPtr& tree, const NavManager_CPtr& navManager, int milliseconds) { ICmpInventory_Ptr cmpInventory = objectManager->get_component(m_objectID, cmpInventory); if(!cmpInventory) return; ObjectID activeItem = cmpInventory->active_item(); if(!activeItem.valid()) return; ICmpUsable_Ptr cmpItemUsable = objectManager->get_component(activeItem, cmpItemUsable); if(!cmpItemUsable) return; cmpItemUsable->use(); }
//#################### CONSTRUCTORS #################### CmpInventory::CmpInventory(const ObjectID& activeItem, const std::map<std::string,int>& consumables, const std::set<ObjectID>& items) : m_initialised(false), m_activeItem(activeItem), m_consumables(consumables), m_items(items) { // Note: We can't update the usable groups at this stage, because the items we're holding generally haven't been created yet. // Instead, they are initialised "on demand" later on. // Check that the active item (if any) is actually one of the items in the inventory. if(activeItem.valid() && items.find(activeItem) == items.end()) { throw Exception("The active item must be in the inventory"); } }
void CmpCharacterModelRender::render_first_person() const { ICmpInventory_Ptr cmpInventory = m_objectManager->get_component(m_objectID, cmpInventory); assert(cmpInventory); ObjectID activeItem = cmpInventory->active_item(); if(!activeItem.valid()) return; ICmpBasicModelRender_Ptr cmpItemRender = m_objectManager->get_component(activeItem, cmpItemRender); if(!cmpItemRender) return; cmpItemRender->render_first_person(); render_crosshair(); }
void CmpCharacterModelRender::render() const { ICmpOrientation_CPtr cmpOrientation = m_objectManager->get_component(m_objectID, cmpOrientation); ICmpPosition_CPtr cmpPosition = m_objectManager->get_component(m_objectID, cmpPosition); const Vector3d& p = cmpPosition->position(); const Vector3d& n = cmpOrientation->nuv_axes()->n(); const Vector3d& u = cmpOrientation->nuv_axes()->u(); const Vector3d& v = cmpOrientation->nuv_axes()->v(); if(m_modelPose != NULL) { RBTMatrix_CPtr mat = construct_model_matrix(p, n, u, v); glPushMatrix(); glMultMatrixd(&mat->rep()[0]); // Render the model. model()->render(m_modelPose); // Render the active item (if any). ICmpInventory_Ptr cmpInventory = m_objectManager->get_component(m_objectID, cmpInventory); assert(cmpInventory); ObjectID activeItem = cmpInventory->active_item(); if(activeItem.valid()) { ICmpBasicModelRender_Ptr cmpItemRender = m_objectManager->get_component(activeItem, cmpItemRender); if(cmpItemRender) { cmpItemRender->render_child(); } } glPopMatrix(); } if(m_highlights) { // If the object should be highlighted, render the object's bounds. render_bounds(p); } // Render the object's NUV axes. render_nuv_axes(p, n, u, v); }
void CmpCharacterModelRender::update_animation(int milliseconds) { // Decide which animation should be playing, and update it. ICmpAnimChooser_Ptr cmpAnimChooser = m_objectManager->get_component(m_objectID, cmpAnimChooser); assert(cmpAnimChooser); m_animController->request_animation(cmpAnimChooser->choose_animation()); m_animController->update(milliseconds); // Clear any existing pose modifiers. m_animController->clear_pose_modifiers(); // Determine the animation extension of any carried item in order to determine which bones need to be inclined. std::string animExtension = ""; // the explicit initialisation is to make it clear that "" is the default ICmpInventory_Ptr cmpInventory = m_objectManager->get_component(m_objectID, cmpInventory); assert(cmpInventory); ObjectID activeItem = cmpInventory->active_item(); if(activeItem.valid()) { ICmpOwnable_Ptr cmpItemOwnable = m_objectManager->get_component(activeItem, cmpItemOwnable); assert(cmpItemOwnable); animExtension = cmpItemOwnable->anim_extension(); } // Calculate the inclination of the object's coordinate system and apply pose modifiers to the relevant bones. BoneModifierMap::const_iterator it = m_inclineBones.find(animExtension); if(it != m_inclineBones.end()) { ICmpOrientation_Ptr cmpOrientation = m_objectManager->get_component(m_objectID, cmpOrientation); const Vector3d& n = cmpOrientation->nuv_axes()->n(); double sinInclination = n.z / n.length(); if(sinInclination < -1) sinInclination = -1; if(sinInclination > 1) sinInclination = 1; double inclination = asin(sinInclination); for(std::map<std::string,Vector3d>::const_iterator jt=it->second.begin(), jend=it->second.end(); jt!=jend; ++jt) { m_animController->set_pose_modifier(jt->first, PoseModifier(jt->second, -inclination)); } } // Configure the pose. m_modelPose = model()->configure_pose(m_animController); // Update the animation for the active item (if any), e.g. the weapon being carried. if(activeItem.valid()) { ICmpOrientation_CPtr cmpOrientation = m_objectManager->get_component(m_objectID, cmpOrientation); ICmpPosition_CPtr cmpPosition = m_objectManager->get_component(m_objectID, cmpPosition); const Vector3d& p = cmpPosition->position(); const Vector3d& n = cmpOrientation->nuv_axes()->n(); const Vector3d& u = cmpOrientation->nuv_axes()->u(); const Vector3d& v = cmpOrientation->nuv_axes()->v(); RBTMatrix_CPtr modelMatrix = construct_model_matrix(p, n, u, v); ICmpOwnable_Ptr cmpItemOwnable = m_objectManager->get_component(activeItem, cmpItemOwnable); assert(cmpItemOwnable); ICmpBasicModelRender_Ptr cmpItemRender = m_objectManager->get_component(activeItem, cmpItemRender); if(cmpItemRender) { cmpItemRender->update_child_animation(milliseconds, skeleton()->bone_hierarchy(), cmpItemOwnable->attach_point(), modelMatrix); } } }