//======== (C) Copyright 2002 Charles G. Cleveland All rights reserved. ========= // // The copyright to the contents herein is the property of Charles G. Cleveland. // The contents may be used and/or copied only with the written permission of // Charles G. Cleveland, or in accordance with the terms and conditions stipulated in // the agreement/contract under which the contents have been supplied. // // Purpose: // // $Workfile: AvHTechNodes.cpp $ // $Date: 2002/09/23 22:36:08 $ // //------------------------------------------------------------------------------- // $Log: AvHTechNodes.cpp,v $ // Revision 1.9 2002/09/23 22:36:08 Flayra // - Slight refactoring // // Revision 1.8 2002/07/08 17:20:32 Flayra // - Added hooks to support disallowing actions when a building is "busy" // //=============================================================================== #include "util/nowarnings.h" #include "mod/AvHTechNodes.h" #ifdef AVH_SERVER #include "extdll.h" #include "util.h" #endif #ifdef AVH_CLIENT #include "cl_dll/parsemsg.h" #endif // Prototype here instead of include to prevent vec3_t nightmare bool AvHSHUGetIsResearchTech(AvHMessageID inMessageID); AvHTechNode::AvHTechNode() { this->mMessageID = MESSAGE_NULL; this->mTechID = this->mPrereqID1 = this->mPrereqID2 = TECH_NULL; this->mCost = -1; this->mBuildTime = 1; this->mResearchable = true; this->mResearched = false; this->mAllowMultiples = false; } AvHTechNode::AvHTechNode(AvHMessageID inMessageID, AvHTechID inID, AvHTechID inPrereq1, AvHTechID inPrereq2, int inCost, int inBuildTime, bool inResearched) { this->mMessageID = inMessageID; this->mTechID = inID; this->mPrereqID1 = inPrereq1; this->mPrereqID2 = inPrereq2; this->mCost = inCost; this->mBuildTime = inBuildTime; this->mResearchable = true; this->mResearched = inResearched; this->mAllowMultiples = false; } bool AvHTechNode::GetAllowMultiples() const { return this->mAllowMultiples; } AvHMessageID AvHTechNode::GetMessageID() const { return this->mMessageID; } AvHTechID AvHTechNode::GetTechID() const { return this->mTechID; } AvHTechID AvHTechNode::GetPrereqTechID1() const { return this->mPrereqID1; } AvHTechID AvHTechNode::GetPrereqTechID2() const { return this->mPrereqID2; } int AvHTechNode::GetBuildTime() const { return this->mBuildTime; } int AvHTechNode::GetCost() const { return this->mCost; } bool AvHTechNode::GetIsResearchable() const { return this->mResearchable; } bool AvHTechNode::GetIsResearched() const { return this->mResearched; } void AvHTechNode::SetAllowMultiples() { this->mAllowMultiples = true; } void AvHTechNode::SetBuildTime(int inBuildTime) { this->mBuildTime = inBuildTime; } void AvHTechNode::SetCost(int inCost) { this->mCost = inCost; } void AvHTechNode::SetResearchable(bool inState) { this->mResearchable = inState; } void AvHTechNode::SetResearchState(bool inState) { this->mResearched = inState; if(!this->GetAllowMultiples()) { this->mResearchable = !this->mResearched; } } #ifdef AVH_SERVER void AvHTechNode::SendToNetworkStream() const { // Send tech node WRITE_BYTE(this->mMessageID); WRITE_BYTE(this->mTechID); // Send prereqs WRITE_BYTE(this->mPrereqID1); WRITE_BYTE(this->mPrereqID2); // Send cost WRITE_SHORT(this->mCost); // Send build time WRITE_SHORT(this->mBuildTime); // Send researchable, researched, multiples WRITE_BYTE(this->mResearchable); WRITE_BYTE(this->mResearched); WRITE_BYTE(this->mAllowMultiples); } #endif #ifdef AVH_CLIENT string AvHTechNode::GetLabel() const { return this->mLabel; } void AvHTechNode::SetLabel(const string& inLabel) { this->mLabel = inLabel; } string AvHTechNode::GetHelpText() const { return this->mHelpText; } void AvHTechNode::SetHelpText(const string& inHelpText) { this->mHelpText = inHelpText; } int AvHTechNode::ReceiveFromNetworkStream() { int theBytesRead = 0; this->mMessageID = (AvHMessageID)READ_BYTE(); theBytesRead++; this->mTechID = (AvHTechID)READ_BYTE(); theBytesRead++; this->mPrereqID1 = (AvHTechID)READ_BYTE(); theBytesRead++; this->mPrereqID2 = (AvHTechID)READ_BYTE(); theBytesRead++; this->mCost = READ_SHORT(); theBytesRead += 2; this->mBuildTime = READ_SHORT(); theBytesRead += 2; this->mResearchable = READ_BYTE(); theBytesRead++; this->mResearched = READ_BYTE(); theBytesRead++; this->mAllowMultiples = READ_BYTE(); theBytesRead++; return theBytesRead; } #endif bool AvHTechNode::operator==(const AvHTechNode& inTechNode) const { bool theIsEqual = false; if(this->mMessageID == inTechNode.mMessageID) { if(this->mTechID == inTechNode.mTechID) { if(this->mPrereqID1 == inTechNode.mPrereqID1) { if(this->mPrereqID2 == inTechNode.mPrereqID2) { if(this->mCost == inTechNode.mCost) { if(this->mBuildTime == inTechNode.mBuildTime) { if(this->mResearchable == inTechNode.mResearchable) { if(this->mResearched == inTechNode.mResearched) { if(this->mAllowMultiples == inTechNode.mAllowMultiples) { #ifdef AVH_CLIENT if(this->mHelpText == inTechNode.mHelpText) { if(this->mLabel == inTechNode.mLabel) { #endif theIsEqual = true; #ifdef AVH_CLIENT } } #endif } } } } } } } } } return theIsEqual; } bool AvHTechNode::operator!=(const AvHTechNode& inTechNode) const { return !this->operator==(inTechNode); } void AvHTechNode::operator=(const AvHTechNode& inTechNode) { this->mMessageID = inTechNode.mMessageID; this->mTechID = inTechNode.mTechID; this->mCost = inTechNode.mCost; this->mPrereqID1 = inTechNode.mPrereqID1; this->mPrereqID2 = inTechNode.mPrereqID2; this->mBuildTime = inTechNode.mBuildTime; this->mResearchable = inTechNode.mResearchable; this->mResearched = inTechNode.mResearched; this->mAllowMultiples = inTechNode.mAllowMultiples; #ifdef AVH_CLIENT this->mHelpText = inTechNode.mHelpText; this->mLabel = inTechNode.mLabel; #endif } void AvHTechNodes::AddTechNode(const AvHTechNode& inTechNode) { this->mTechNodes.push_back(inTechNode); } #ifdef AVH_PLAYTEST_BUILD #ifdef AVH_SERVER #include "mod/AvHGamerules.h" void AvHTechNodes::BalanceChanged() { // Run through our tech nodes and update cost and build time for(TechNodeListType::iterator theIter = this->mTechNodes.begin(); theIter != this->mTechNodes.end(); theIter++) { AvHMessageID theMessageID = theIter->GetMessageID(); int theBuildTime = GetGameRules()->GetBuildTimeForMessageID(theMessageID); if(theBuildTime != theIter->GetBuildTime()) { theIter->SetBuildTime(theBuildTime); } int theCost = GetGameRules()->GetCostForMessageID(theMessageID); if(theCost != theIter->GetCost()) { theIter->SetCost(theCost); } } } #endif #endif void AvHTechNodes::Clear() { this->mTechNodes.clear(); } bool AvHTechNodes::GetAllowMultiples(AvHMessageID& inMessageID) const { bool theAllowMultiples = false; for(TechNodeListType::const_iterator theIter = this->mTechNodes.begin(); theIter != this->mTechNodes.end(); theIter++) { if(theIter->GetMessageID() == inMessageID) { theAllowMultiples = theIter->GetAllowMultiples(); break; } } return theAllowMultiples; } bool AvHTechNodes::GetIsMessageInTechTree(AvHMessageID& inMessageID) const { bool theMessageIsInTechTree = false; // Message must be in the tech tree for(TechNodeListType::const_iterator theIter = this->mTechNodes.begin(); theIter != this->mTechNodes.end(); theIter++) { if(theIter->GetMessageID() == inMessageID) { theMessageIsInTechTree = true; break; } } if(!theMessageIsInTechTree) { int a = 0; } return theMessageIsInTechTree; } bool AvHTechNodes::GetIsMessageAvailable(AvHMessageID& inMessageID) const { bool theMessageIsAvailable = false; // Get prereqs for message AvHTechID thePrereqOne = TECH_NULL; AvHTechID thePrereqTwo = TECH_NULL; // Are they both available? if(this->GetPrequisiteForMessage(inMessageID, thePrereqOne, thePrereqTwo)) { if((thePrereqOne == TECH_NULL) || (this->GetIsTechResearched(thePrereqOne))) { if((thePrereqTwo == TECH_NULL) || (this->GetIsTechResearched(thePrereqTwo))) { theMessageIsAvailable = true; } } } else { theMessageIsAvailable = true; } // Non-multiple research not available if researched for(TechNodeListType::const_iterator theIter = this->mTechNodes.begin(); theIter != this->mTechNodes.end(); theIter++) { if(theIter->GetMessageID() == inMessageID) { if(!theIter->GetAllowMultiples() && theIter->GetIsResearched()) { theMessageIsAvailable = false; break; } } } return theMessageIsAvailable; } bool AvHTechNodes::GetIsMessageAvailableForSelection(AvHMessageID& inMessageID, EntityListType& inSelection) const { bool theMessageIsAvailable = this->GetIsMessageAvailable(inMessageID); return theMessageIsAvailable; } bool AvHTechNodes::GetIsTechResearched(AvHTechID inTech) const { bool theTechIsResearched = false; for(TechNodeListType::const_iterator theIter = this->mTechNodes.begin(); theIter != this->mTechNodes.end(); theIter++) { if(theIter->GetTechID() == inTech) { theTechIsResearched = theIter->GetIsResearched(); break; } } return theTechIsResearched; } bool AvHTechNodes::SetFirstNodeWithTechResearchState(AvHTechID inTech, bool inState) { bool theSuccess = false; for(TechNodeListType::iterator theIter = this->mTechNodes.begin(); theIter != this->mTechNodes.end(); theIter++) { if(theIter->GetTechID() == inTech) { theIter->SetResearchState(inState); theSuccess = true; break; } } return theSuccess; } bool AvHTechNodes::GetMessageForTech(const AvHTechID inTechID, AvHMessageID& outMessageID) const { bool theSuccess = false; for(TechNodeListType::const_iterator theIter = this->mTechNodes.begin(); theIter != this->mTechNodes.end(); theIter++) { if(theIter->GetTechID() == inTechID) { outMessageID = theIter->GetMessageID(); theSuccess = true; break; } } return theSuccess; } AvHMessageID AvHTechNodes::GetNextMessageNeededFor(AvHMessageID inMessageID) const { AvHMessageID theNextMessage = inMessageID; // while theNextMessage isn't available for research bool theIsDone = false; do { int theBottleNeckCost = 0; float theBottleNeckTime = 0; bool theIsAvailable = false; this->GetResearchInfo(theNextMessage, theIsAvailable, theBottleNeckCost, theBottleNeckTime); AvHTechID theTechID = TECH_NULL; if(this->GetTechForMessage(theNextMessage, theTechID)) { // Looking for first tech that isn't researched, but has prereqs researched or NULL if(!this->GetIsTechResearched(theTechID)) { do { AvHTechID thePrereqID1; AvHTechID thePrereqID2; if(this->GetPrequisiteForMessage(theNextMessage, thePrereqID1, thePrereqID2)) { // If both prereqs are researched or NULL, then theNextMessage is right for(int i = 0; i < 2; i++) { AvHTechID theCurrentPrereq = ((i == 0) ? thePrereqID1 : thePrereqID2); if((theCurrentPrereq == TECH_NULL) || this->GetIsTechResearched(theCurrentPrereq)) { theIsDone = true; } // else dig deeper else { if(this->GetMessageForTech(theCurrentPrereq, theNextMessage)) { i = 2; } } } } else { theIsDone = true; } } while (!theIsDone); } else { theIsDone = true; } } else { theIsDone = true; } } while(!theIsDone); return theNextMessage; } void AvHTechNodes::GetResearchNodesDependentOn(AvHTechID inTechID, TechNodeListType& outTechNodes) const { if(inTechID != TECH_NULL) { // Add all techs that directly depend on this one for(TechNodeListType::const_iterator theIter = this->mTechNodes.begin(); theIter != this->mTechNodes.end(); theIter++) { AvHMessageID theMessageID = theIter->GetMessageID(); if(AvHSHUGetIsResearchTech(theMessageID) && ((theIter->GetPrereqTechID1() == inTechID) || (theIter->GetPrereqTechID2() == inTechID))) { AvHTechID theDependentID = theIter->GetTechID(); if(theDependentID != TECH_NULL) { if(std::find(outTechNodes.begin(), outTechNodes.end(), *theIter) == outTechNodes.end()) { // Add node outTechNodes.push_back(*theIter); // Add research nodes that are recursively dependent on this one this->GetResearchNodesDependentOn(theDependentID, outTechNodes); } } } } } } int AvHTechNodes::GetNumNodes() const { return this->mTechNodes.size(); } bool AvHTechNodes::GetTechForMessage(const AvHMessageID inMessageID, AvHTechID& outTechID) const { bool theSuccess = false; for(TechNodeListType::const_iterator theIter = this->mTechNodes.begin(); theIter != this->mTechNodes.end(); theIter++) { if(theIter->GetMessageID() == inMessageID) { outTechID = theIter->GetTechID(); theSuccess = true; break; } } return theSuccess; } const TechNodeListType& AvHTechNodes::GetTechNodes() const { return this->mTechNodes; } bool AvHTechNodes::GetPrequisiteForMessage(const AvHMessageID inMessageID, AvHTechID& outTech1, AvHTechID& outTech2) const { bool theTechHasPrereq = false; for(TechNodeListType::const_iterator theIter = this->mTechNodes.begin(); theIter != this->mTechNodes.end(); theIter++) { if(theIter->GetMessageID() == inMessageID) { AvHTechID thePrereqTechID1 = theIter->GetPrereqTechID1(); AvHTechID thePrereqTechID2 = theIter->GetPrereqTechID2(); if((thePrereqTechID1 != TECH_NULL) || (thePrereqTechID2 != TECH_NULL)) { outTech1 = thePrereqTechID1; outTech2 = thePrereqTechID2; theTechHasPrereq = true; } break; } } return theTechHasPrereq; } int AvHTechNodes::GetNumTechNodes() const { return this->mTechNodes.size(); } bool AvHTechNodes::GetResearchInfo(AvHMessageID inTech, bool& outIsResearchable, int& outCost, float& outTime) const { bool theFoundIt = false; outIsResearchable = false; outCost = -1; outTime = -1; // Run through list, remembering previous node for(TechNodeListType::const_iterator theIter = this->mTechNodes.begin(); theIter != this->mTechNodes.end(); theIter++) { // If node found, make sure previous node is empty or researched //if(theIter->GetTechID() == inTech) if(theIter->GetMessageID() == inTech) { // Fill in info theFoundIt = true; outCost = theIter->GetCost(); outTime = (float)theIter->GetBuildTime(); outIsResearchable = theIter->GetIsResearchable(); // AvHTechID thePrereq = theIter->GetPrereqTechID(); // if((thePrereq == TECH_NULL) || (this->GetIsTechResearched(thePrereq))) // { // outIsResearchable = true; // } break; } } return theFoundIt; } bool AvHTechNodes::GetTechNode(int inOffset, AvHTechNode& outTechNode) const { bool theFoundTechNode = false; if(inOffset < (signed)this->mTechNodes.size()) { outTechNode = this->mTechNodes[inOffset]; theFoundTechNode = true; } return theFoundTechNode; } bool AvHTechNodes::GetTechNode(AvHMessageID inMessageID, AvHTechNode& outTechNode) const { bool theSuccess = false; for(TechNodeListType::const_iterator theIter = this->mTechNodes.begin(); theIter != this->mTechNodes.end(); theIter++) { if(theIter->GetMessageID() == inMessageID) { outTechNode = *theIter; theSuccess = true; break; } } return theSuccess; } bool AvHTechNodes::SetIsResearchable(AvHMessageID inMessageID, bool inState) { bool theSuccess = false; for(TechNodeListType::iterator theIter = this->mTechNodes.begin(); theIter != this->mTechNodes.end(); theIter++) { if(theIter->GetMessageID() == inMessageID) { theIter->SetResearchable(inState); theSuccess = true; break; } } return theSuccess; } bool AvHTechNodes::SetResearchDone(AvHMessageID inMessageID, bool inState) { bool theSuccess = false; for(TechNodeListType::iterator theIter = this->mTechNodes.begin(); theIter != this->mTechNodes.end(); theIter++) { if(theIter->GetMessageID() == inMessageID) { theIter->SetResearchState(inState); theSuccess = true; break; } } return theSuccess; } bool AvHTechNodes::SetTechNode(int inOffset, const AvHTechNode& inTechNode) { bool theSuccess = false; if(inOffset < (signed)this->mTechNodes.size()) { this->mTechNodes[inOffset] = inTechNode; theSuccess = true; } else if(inOffset == (signed)this->mTechNodes.size()) { this->mTechNodes.push_back(inTechNode); theSuccess = true; } else { ASSERT(false); } return theSuccess; } void AvHTechNodes::TriggerAddTech(AvHTechID inTechID) { for(TechNodeListType::iterator theIter = this->mTechNodes.begin(); theIter != this->mTechNodes.end(); theIter++) { if(theIter->GetTechID() == inTechID) { theIter->SetResearchState(true); } } } void AvHTechNodes::TriggerRemoveTech(AvHTechID inTechID) { for(TechNodeListType::iterator theIter = this->mTechNodes.begin(); theIter != this->mTechNodes.end(); theIter++) { if(theIter->GetTechID() == inTechID) { theIter->SetResearchState(false); } } } bool AvHTechNodes::operator!=(const AvHTechNodes& inTechNodes) const { return !this->operator==(inTechNodes); } bool AvHTechNodes::operator==(const AvHTechNodes& inTechNodes) const { bool theAreEqual = false; if(this->mTechNodes == inTechNodes.mTechNodes) { theAreEqual = true; } return theAreEqual; } void AvHTechNodes::operator=(const AvHTechNodes& inTechNodes) { this->mTechNodes = inTechNodes.mTechNodes; } //#ifdef AVH_SERVER //void AvHTechNodes::SendToNetworkStream() const //{ // // send num nodes // int theNumNodes = this->mTechNodes.size(); // WRITE_SHORT(theNumNodes); // // // for each one // for(TechNodeListType::const_iterator theIterator = this->mTechNodes.begin(); theIterator != this->mTechNodes.end(); theIterator++) // { // theIterator->SendToNetworkStream(); // } //} //#endif // //#ifdef AVH_CLIENT //int AvHTechNodes::ReceiveFromNetworkStream() //{ // int theBytesRead = 0; // // this->Clear(); // // int theNumNodes = READ_SHORT(); // theBytesRead += 2; // // for(int i = 0; i < theNumNodes; i++) // { // AvHTechNode theTechNode; // theBytesRead += theTechNode.ReceiveFromNetworkStream(); // this->mTechNodes.push_back(theTechNode); // } // // return theBytesRead; //} //#endif