예제 #1
0
    /// Fills \a buffer with the ends points for the lines that connect
    /// technologies in \a techs
    void FillArcBuffer(GG::GL2DVertexBuffer& buffer, const std::set<std::string>& techs) {
        for (std::set<std::string>::const_iterator it = techs.begin(); it != techs.end(); ++it) {

            const std::vector<TechTreeLayout::Edge*> edges = m_layout.GetOutEdges(*it);
            //prerequisite edge
            for (std::vector<TechTreeLayout::Edge*>::const_iterator edge = edges.begin();
                 edge != edges.end(); edge++)
            {
                std::vector<std::pair<double, double> > points;
                const std::string& from = (*edge)->GetTechFrom();
                const std::string& to   = (*edge)->GetTechTo();
                // Do not show lines leading to techs
                // we are not showing
                if (techs.find(to) == techs.end()) {
                    continue;
                }
                // Remember what edges we are showing so
                // we can eventually highlight them
                m_edges_to_show[from].insert(to);
                if (!GetTech(from) || !GetTech(to)) {
                    ErrorLogger() << "TechTreeArcs::FillArcBuffer missing arc endpoint tech " << from << "->" << to;
                    continue;
                }
                (*edge)->ReadPoints(points);
                // To be able to draw all the lines in one call,
                // we will draw the with GL_LINES, which means all
                // vertices except the first and the last must occur twice
                for (unsigned i = 0; i < points.size() - 1; ++i){
                    buffer.store(points[i].first, points[i].second);
                    buffer.store(points[i+1].first, points[i+1].second);
                }
            }
        }
        buffer.createServerBuffer();
    }
예제 #2
0
void TechTreeLayout::AddNode(const std::string& tech, GG::X width, GG::Y height) {
    assert(width > 0 && height > 0 && GetTech(tech));
    TechTreeLayout::Node* node = new TechTreeLayout::Node(tech, width, height);
    //DebugLogger() << "Adding Node: " << node << " for tech " << tech;
    m_nodes.push_back(node);
    m_node_map[tech] = node;
}
예제 #3
0
    int IssueDequeueTechOrder(const std::string& tech_name) {
        const Tech* tech = GetTech(tech_name);
        if (!tech) {
            Logger().errorStream() << "AIInterface::IssueDequeueTechOrder : passed tech_name that is not the name of a tech.";
            return 0;
        }

        int empire_id = AIClientApp::GetApp()->EmpireID();

        AIClientApp::GetApp()->Orders().IssueOrder(OrderPtr(new ResearchQueueOrder(empire_id, tech_name)));

        return 1;
    }
예제 #4
0
    int IssueEnqueueTechOrder(const std::string& tech_name, int position) {
        const Tech* tech = GetTech(tech_name);
        if (!tech) {
            ErrorLogger() << "IssueEnqueueTechOrder : passed tech_name that is not the name of a tech.";
            return 0;
        }

        int empire_id = AIClientApp::GetApp()->EmpireID();

        AIClientApp::GetApp()->Orders().IssueOrder(OrderPtr(
            new ResearchQueueOrder(empire_id, tech_name, position)));

        return 1;
    }
예제 #5
0
static void LoadShader()
{
	GLuint techID = MakeShader("content/shader.vsh", "content/shader.fsh");
	Shader = malloc(sizeof(ColorShader));
	GLuint error = glGetError();
	if (error>0) 
	{
		__android_log_print(ANDROID_LOG_INFO, "NATIVE", "MAKESHADER ERROR %i", error);
		assert(error==0);
	}
	GetTech(techID, Shader);
	error = glGetError();
	if (error>0) 
	{
		__android_log_print(ANDROID_LOG_INFO, "NATIVE", "GET TECH ERROR %i", error);
		assert(error==0);
	}
}
예제 #6
0
/**
 * creates and initialises all nodes
 * @param column_width width of each column
 * @param row_height height of each row
 * @param x_margin horizontal part of arrow before changing direction to child node
 */
void TechTreeLayout::DoLayout(double column_width, double row_height, double x_margin) {
    assert(column_width > 0 && row_height > 0);
    double internal_height = row_height / NODE_CELL_HEIGHT; // node has NODE_CELL_HEIGHT rows internally
    //1. set all node depths from root parents
    for (std::vector<Node*>::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
        if ((*it)->IsStartNode())
            (*it)->SetDepthRecursive(0);    // also sets all children's depths

    // find max node depth
    int max_node_depth = 0;
    for (std::vector<Node*>::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it)
        max_node_depth = std::max(max_node_depth, (*it)->GetDepth());

    //2. create placeholder nodes
    DebugLogger() << "TechTreeLayout::DoLayout creaing place holder nodes...";
    std::vector<Node*> raw_nodes = m_nodes; // just iterator over initial nodes, not also over the placeholders
    for (std::vector<Node*>::iterator it = raw_nodes.begin(); it != raw_nodes.end(); ++it)
        (*it)->CreatePlaceHolder(m_nodes);

    //3. put nodes into containers for each depth column
    std::vector<std::vector<Node*> > nodes_at_each_depth(max_node_depth + 1);
    for (std::vector<Node*>::iterator it = m_nodes.begin(); it != m_nodes.end(); ++it) {
        Node* node = *it;
        assert(node->GetDepth() >= 0 && node->GetDepth() < nodes_at_each_depth.size());
        nodes_at_each_depth[node->GetDepth()].push_back(node);
    }
    // sort within each depth column
    for (std::vector<std::vector<Node*> >::iterator it = nodes_at_each_depth.begin();
         it != nodes_at_each_depth.end(); ++it)
    { std::sort(it->begin(), it->end(), NodePointerCmp()); }


    //4. do layout
    std::vector<Column> row_index = std::vector<Column>(nodes_at_each_depth.size());

    // in what order do columns receive nodes?
    std::vector<int> column_order;
    column_order.reserve(nodes_at_each_depth.size());
    // start with column with most nodes, progess outwards from it
    int first_column = 0;
    unsigned int max_column_nodes = 0;
    for (unsigned int i = 0; i < nodes_at_each_depth.size(); ++i) {
        if (nodes_at_each_depth[i].size() > max_column_nodes) {
            max_column_nodes = nodes_at_each_depth[i].size();
            first_column = i;
        }
    }
    // progress outwards from initial column
    column_order.push_back(first_column);
    int next_column = column_order[0] + 1;
    int prev_column = column_order[0] - 1;
    while (column_order.size() < nodes_at_each_depth.size()) {
        if (prev_column >= 0) {
            column_order.push_back(prev_column);
            prev_column--;
        }
        if (next_column < static_cast<int>(nodes_at_each_depth.size())) {
            column_order.push_back(next_column);
            next_column++;
        }
    }
    // distribute tech nodes over the table, one column at a time
    for (std::vector<int>::iterator it = column_order.begin(); it != column_order.end(); ++it) {
        int column = *it;
        std::vector<Node*>& column_nodes = nodes_at_each_depth[column];
        std::string current_category;
        for (std::vector<Node*>::iterator it = column_nodes.begin(); it != column_nodes.end(); ++it) {
            Node* node = *it;
            const Tech* node_tech = GetTech(node->GetTech());
            const std::string& node_category = node_tech ? node_tech->Category() : "";
            bool new_category = node_category != current_category;
            node->DoLayout(row_index, new_category);
            current_category = node_category;
        }
    }
    // optimize layout, every node gets a rating if moving would shorten the distance to it's family
    // if the movement is possible either if the place if free or the neighbour has the opposite wish
    bool movement = true;
    while (movement) {
        movement = false;
        for (unsigned int i = m_nodes.size(); i --> 0;) {
            if (m_nodes[i]->Wobble(row_index[m_nodes[i]->m_depth])) {
                movement = true;
                break;
            }
        }
    }
    //4.d. count used rows and columns
    unsigned int column_count = row_index.size();
    unsigned int row_count = 0;
    for (int i = row_index.size(); i-->0;)
        row_count = std::max(row_count, row_index[i].Size());
    //4.e. set size
    for (int i = m_nodes.size(); i --> 0 ; )
         m_nodes[i]->CalculateCoordinate(column_width, internal_height);

    m_width = column_count * column_width;
    m_height = row_count * internal_height;

    //5. create edges
    for (int i = m_nodes.size(); i --> 0 ; )
        m_nodes[i]->CreateEdges(x_margin, column_width, internal_height);
}
예제 #7
0
////////////////
// class Edge //
////////////////
TechTreeLayout::Edge::Edge(const std::string& from, const std::string& to) :
    m_points(std::vector<std::pair<double,double> >()),
    m_from(from),
    m_to(to)
{ assert(GetTech(from) && GetTech(to)); }
예제 #8
0
void ResearchQueue::Update(float RPs, const std::map<std::string, float>& research_progress) {
    // status of all techs for this empire
    const Empire* empire = GetEmpire(m_empire_id);
    if (!empire)
        return;

    std::map<std::string, TechStatus> sim_tech_status_map;
    for (const auto& tech : GetTechManager()) {
        const std::string& tech_name = tech->Name();
        sim_tech_status_map[tech_name] = empire->GetTechStatus(tech_name);
    }

    SetTechQueueElementSpending(RPs, research_progress, sim_tech_status_map, m_queue,
                                m_total_RPs_spent, m_projects_in_progress, m_empire_id);

    if (m_queue.empty()) {
        ResearchQueueChangedSignal();
        return;    // nothing more to do...
    }

    const int TOO_MANY_TURNS = 500; // stop counting turns to completion after this long, to prevent seemingly endless loops

    // initialize status of everything to never getting done
    for (Element& element : m_queue)
        element.turns_left = -1;

    if (RPs <= EPSILON) {
        ResearchQueueChangedSignal();
        return;    // nothing more to do if not enough RP...
    }

    boost::posix_time::ptime dp_time_start;
    boost::posix_time::ptime dp_time_end;

    // "Dynamic Programming" version of research queue simulator -- copy the queue simulator containers
    // perform dynamic programming calculation of completion times, then after regular simulation is done compare results (if both enabled)

    //record original order & progress
    // will take advantage of fact that sets (& map keys) are by default kept in sorted order lowest to highest
    std::map<std::string, float> dp_prog = research_progress;
    std::map< std::string, int > orig_queue_order;
    std::map<int, float> dpsim_research_progress;
    for (unsigned int i = 0; i < m_queue.size(); ++i) {
        std::string tname = m_queue[i].name;
        orig_queue_order[tname] = i;
        dpsim_research_progress[i] = dp_prog[tname];
    }

    std::map<std::string, TechStatus> dpsim_tech_status_map = std::move(sim_tech_status_map);

    // initialize simulation_results with -1 for all techs, so that any techs that aren't
    // finished in simulation by turn TOO_MANY_TURNS will be left marked as never to be finished
    std::vector<int>  dpsimulation_results(m_queue.size(), -1);

    const int DP_TURNS = TOO_MANY_TURNS; // track up to this many turns

    std::map<std::string, std::set<std::string>> waiting_for_prereqs;
    std::set<int> dp_researchable_techs;

    for (unsigned int i = 0; i < m_queue.size(); ++i) {
        std::string techname = m_queue[i].name;
        if (m_queue[i].paused)
            continue;
        const Tech* tech = GetTech(techname);
        if (!tech)
            continue;
        if (dpsim_tech_status_map[techname] == TS_RESEARCHABLE) {
            dp_researchable_techs.insert(i);
        } else if (dpsim_tech_status_map[techname] == TS_UNRESEARCHABLE ||
                   dpsim_tech_status_map[techname] == TS_HAS_RESEARCHED_PREREQ)
        {
            std::set<std::string> these_prereqs = tech->Prerequisites();
            for (auto ptech_it = these_prereqs.begin(); ptech_it != these_prereqs.end();) {
                if (dpsim_tech_status_map[*ptech_it] != TS_COMPLETE) {
                    ++ptech_it;
                } else {
                    auto erase_it = ptech_it;
                    ++ptech_it;
                    these_prereqs.erase(erase_it);
                }
            }
            waiting_for_prereqs[techname] = these_prereqs;
        }
    }

    int dp_turns = 0;
    //pp_still_available[turn-1] gives the RP still available in this resource pool at turn "turn"
    std::vector<float> rp_still_available(DP_TURNS, RPs);  // initialize to the  full RP allocation for every turn

    while ((dp_turns < DP_TURNS) && !(dp_researchable_techs.empty())) {// if we haven't used up our turns and still have techs to process
        ++dp_turns;
        std::map<int, bool> already_processed;
        for (int tech_id : dp_researchable_techs) {
            already_processed[tech_id] = false;
        }
        auto cur_tech_it = dp_researchable_techs.begin();
        while ((rp_still_available[dp_turns-1] > EPSILON)) { // try to use up this turns RPs
            if (cur_tech_it == dp_researchable_techs.end()) {
                break; //will be wasting some RP this turn
            }
            int cur_tech = *cur_tech_it;
            if (already_processed[cur_tech]) {
                ++cur_tech_it;
                continue;
            }
            already_processed[cur_tech] = true;
            const std::string& tech_name = m_queue[cur_tech].name;
            const Tech* tech = GetTech(tech_name);
            float progress = dpsim_research_progress[cur_tech];
            float tech_cost = tech ? tech->ResearchCost(m_empire_id) : 0.0f;
            float RPs_needed = tech ? tech_cost * (1.0f - std::min(progress, 1.0f)) : 0.0f;
            float RPs_per_turn_limit = tech ? tech->PerTurnCost(m_empire_id) : 1.0f;
            float RPs_to_spend = std::min(std::min(RPs_needed, RPs_per_turn_limit), rp_still_available[dp_turns-1]);
            progress += RPs_to_spend / std::max(EPSILON, tech_cost);
            dpsim_research_progress[cur_tech] = progress;
            rp_still_available[dp_turns-1] -= RPs_to_spend;
            auto next_res_tech_it = cur_tech_it;
            int next_res_tech_idx;
            if (++next_res_tech_it == dp_researchable_techs.end()) {
                next_res_tech_idx = m_queue.size()+1;
            } else {
                next_res_tech_idx = *(next_res_tech_it);
            }

            if (tech_cost - EPSILON <= progress * tech_cost) {
                dpsim_tech_status_map[tech_name] = TS_COMPLETE;
                dpsimulation_results[cur_tech] = dp_turns;
#ifndef ORIG_RES_SIMULATOR
                m_queue[cur_tech].turns_left = dp_turns;
#endif
                dp_researchable_techs.erase(cur_tech_it);
                std::set<std::string> unlocked_techs;
                if (tech)
                    unlocked_techs = tech->UnlockedTechs();
                for (std::string u_tech_name : unlocked_techs) {
                    auto prereq_tech_it = waiting_for_prereqs.find(u_tech_name);
                    if (prereq_tech_it != waiting_for_prereqs.end() ){
                        std::set<std::string>& these_prereqs = prereq_tech_it->second;
                        auto just_finished_it = these_prereqs.find(tech_name);
                        if (just_finished_it != these_prereqs.end() ) {  //should always find it
                            these_prereqs.erase(just_finished_it);
                            if (these_prereqs.empty()) { // tech now fully unlocked
                                int this_tech_idx = orig_queue_order[u_tech_name];
                                dp_researchable_techs.insert(this_tech_idx);
                                waiting_for_prereqs.erase(prereq_tech_it);
                                already_processed[this_tech_idx] = true;    //doesn't get any allocation on current turn
                                if (this_tech_idx < next_res_tech_idx ) {
                                    next_res_tech_idx = this_tech_idx;
                                }
                            }
                        } else { //couldnt find tech_name in prereqs list
                            DebugLogger() << "ResearchQueue::Update tech unlocking problem:"<< tech_name << "thought it was a prereq for " << u_tech_name << "but the latter disagreed";
                        }
                    } //else { //tech_name thinks itself a prereq for ytechName, but u_tech_name not in prereqs -- not a problem so long as u_tech_name not in our queue at all
                      //  DebugLogger() << "ResearchQueue::Update tech unlocking problem:"<< tech_name << "thought it was a prereq for " << u_tech_name << "but the latter disagreed";
                      //}
                }
            }// if (tech->ResearchCost() - EPSILON <= progress * tech_cost)
            cur_tech_it = dp_researchable_techs.find(next_res_tech_idx);
        }//while ((rp_still_available[dp_turns-1]> EPSILON))
        //dp_time = dpsim_queue_timer.elapsed() * 1000;
        // DebugLogger() << "ProductionQueue::Update queue dynamic programming sim time: " << dpsim_queue_timer.elapsed() * 1000.0;
    } // while ((dp_turns < DP_TURNS ) && !(dp_researchable_techs.empty() ) )

    ResearchQueueChangedSignal();
}