/************************************************************************** Returns state of the tech for current pplayer. This can be: TECH_KNOWN, TECH_UNKNOWN, or TECH_PREREQS_KNOWN Should be called with existing techs or A_FUTURE If pplayer is NULL this checks whether any player knows the tech (used by the client). **************************************************************************/ enum tech_state player_invention_state(const struct player *pplayer, Tech_type_id tech) { fc_assert_ret_val(tech == A_FUTURE || (tech >= 0 && tech < game.control.num_tech_types), -1); if (!pplayer) { if (tech != A_FUTURE && game.info.global_advances[tech]) { return TECH_KNOWN; } else { return TECH_UNKNOWN; } } else { struct player_research *research = player_research_get(pplayer); /* Research can be null in client when looking for tech_leakage * from player not yet received. */ if (research) { return research->inventions[tech].state; } else { return TECH_UNKNOWN; } } }
/************************************************************************** Marks all techs which are requirements for goal in pplayer->research->inventions[goal].required_techs. Works recursive. **************************************************************************/ static void build_required_techs_helper(struct player *pplayer, Tech_type_id tech, Tech_type_id goal) { /* The is_tech_a_req_for_goal condition is true if the tech is * already marked */ if (!player_invention_reachable(pplayer, tech, FALSE) || player_invention_state(pplayer, tech) == TECH_KNOWN || is_tech_a_req_for_goal(pplayer, tech, goal)) { return; } /* Mark the tech as required for the goal */ BV_SET(player_research_get(pplayer)->inventions[goal].required_techs, tech); if (advance_required(tech, AR_ONE) == goal || advance_required(tech, AR_TWO) == goal) { log_fatal("tech \"%s\": requires itself", advance_name_by_player(pplayer, goal)); exit(EXIT_FAILURE); } build_required_techs_helper(pplayer, advance_required(tech, AR_ONE), goal); build_required_techs_helper(pplayer, advance_required(tech, AR_TWO), goal); }
/**************************************************************************** Player has researched a new technology ****************************************************************************/ static void tech_researched(struct player *plr) { struct player_research *research = player_research_get(plr); /* plr will be notified when new tech is chosen */ if (!is_future_tech(research->researching)) { notify_embassies(plr, NULL, NULL, E_TECH_GAIN, ftc_server, _("The %s have researched %s."), nation_plural_for_player(plr), advance_name_researching(plr)); } else { notify_embassies(plr, NULL, NULL, E_TECH_GAIN, ftc_server, _("The %s have researched Future Tech. %d."), nation_plural_for_player(plr), research->future_tech); } /* Deduct tech cost */ research->bulbs_researched = MAX(research->bulbs_researched - total_bulbs_required(plr), 0); /* cache researched technology for event signal, because found_new_tech() changes the research goal */ Tech_type_id researched_tech = research->researching; /* do all the updates needed after finding new tech */ found_new_tech(plr, research->researching, TRUE, TRUE); script_server_signal_emit("tech_researched", 3, API_TYPE_TECH_TYPE, advance_by_number(researched_tech), API_TYPE_PLAYER, plr, API_TYPE_STRING, "researched"); }
/************************************************************************** Reduce conquer cost bulbs from player. **************************************************************************/ void do_conquer_cost(struct player *pplayer, Tech_type_id tech) { struct player_research * research = player_research_get(pplayer); research->bulbs_researched -= (base_total_bulbs_required(pplayer, tech) * game.server.conquercost) / 100; research->researching_saved = A_UNKNOWN; }
/************************************************************************** Returns if the given tech has to be researched to reach the goal. The goal itself isn't a requirement of itself. pplayer may be NULL; however the function will always return FALSE in that case. **************************************************************************/ bool is_tech_a_req_for_goal(const struct player *pplayer, Tech_type_id tech, Tech_type_id goal) { if (tech == goal) { return FALSE; } else if (!pplayer) { /* FIXME: We need a proper implementation here! */ return FALSE; } else { return BV_ISSET(player_research_get(pplayer)->inventions[goal].required_techs, tech); } }
/************************************************************************** Mark as TECH_PREREQS_KNOWN each tech which is available, not known and which has all requirements fullfiled. If there is no such a tech mark A_FUTURE as researchable. Recalculate research->num_known_tech_with_flag Should always be called after player_invention_set() **************************************************************************/ void player_research_update(struct player *pplayer) { enum tech_flag_id flag; int researchable = 0; struct player_research *research = player_research_get(pplayer); /* This is set when the game starts, but not everybody finds out * right away. */ player_invention_set(pplayer, A_NONE, TECH_KNOWN); advance_index_iterate(A_FIRST, i) { if (!player_invention_reachable(pplayer, i, FALSE)) { player_invention_set(pplayer, i, TECH_UNKNOWN); } else { if (player_invention_state(pplayer, i) == TECH_PREREQS_KNOWN) { player_invention_set(pplayer, i, TECH_UNKNOWN); } if (player_invention_state(pplayer, i) == TECH_UNKNOWN && player_invention_state(pplayer, advance_required(i, AR_ONE)) == TECH_KNOWN && player_invention_state(pplayer, advance_required(i, AR_TWO)) == TECH_KNOWN) { player_invention_set(pplayer, i, TECH_PREREQS_KNOWN); researchable++; } } build_required_techs(pplayer, i); } advance_index_iterate_end; #ifdef DEBUG_TECH advance_index_iterate(A_FIRST, i) { char buf[advance_count() + 1]; advance_index_iterate(A_NONE, j) { if (BV_ISSET(research->inventions[i].required_techs, j)) { buf[j] = '1'; } else { buf[j] = '0'; } } advance_index_iterate_end; buf[advance_count()] = '\0'; log_debug("%s: [%3d] %-25s => %s", player_name(pplayer), i, advance_rule_name(advance_by_number(i)), tech_state_name(player_invention_state(pplayer, i))); log_debug("%s: [%3d] %s", player_name(pplayer), i, buf); } advance_index_iterate_end;
/************************************************************************** Set player knowledge about tech to given state. **************************************************************************/ enum tech_state player_invention_set(struct player *pplayer, Tech_type_id tech, enum tech_state value) { struct player_research *research = player_research_get(pplayer); enum tech_state old = research->inventions[tech].state; if (old == value) { return old; } research->inventions[tech].state = value; if (value == TECH_KNOWN) { game.info.global_advances[tech] = TRUE; } return old; }
/************************************************************************** Updates required_techs, num_required_techs and bulbs_required in pplayer->research->inventions[goal]. **************************************************************************/ static void build_required_techs(struct player *pplayer, Tech_type_id goal) { int counter; struct player_research *research = player_research_get(pplayer); BV_CLR_ALL(research->inventions[goal].required_techs); if (player_invention_state(pplayer, goal) == TECH_KNOWN) { research->inventions[goal].num_required_techs = 0; research->inventions[goal].bulbs_required = 0; return; } build_required_techs_helper(pplayer, goal, goal); /* Include the goal tech */ research->inventions[goal].bulbs_required = base_total_bulbs_required(pplayer, goal); research->inventions[goal].num_required_techs = 1; counter = 0; advance_index_iterate(A_FIRST, i) { if (!is_tech_a_req_for_goal(pplayer, i, goal)) { continue; } /* * This is needed to get a correct result for the * base_total_bulbs_required call. */ research->techs_researched++; counter++; research->inventions[goal].num_required_techs++; research->inventions[goal].bulbs_required += base_total_bulbs_required(pplayer, i); } advance_index_iterate_end; /* Undo the changes made above */ research->techs_researched -= counter; }
/************************************************************************** Slot for selecting player/nation **************************************************************************/ void plr_widget::nation_selected(const QItemSelection &sl, const QItemSelection &ds) { QModelIndex index; QVariant qvar; QModelIndexList indexes = sl.indexes(); struct city *pcity; const struct player_diplstate *state; struct player_research *research; char tbuf[256]; QString res; QString sp = " "; QString nl = "<br>"; struct player *pplayer; int a , b; bool added; bool entry_exist = false; struct player *me; Tech_type_id tech_id; other_player = NULL; intel_str.clear(); tech_str.clear(); ally_str.clear(); if (indexes.isEmpty()) { plr->update_report(); return; } index = indexes.at(0); qvar = index.data(Qt::UserRole); pplayer = reinterpret_cast<player *>(qvar.value<void *>()); other_player = pplayer; if (pplayer->is_alive == false) { plr->update_report(); return; } pcity = player_capital(pplayer); research = player_research_get(pplayer); switch (research->researching) { case A_UNKNOWN: res = _("(Unknown)"); break; case A_UNSET: res = _("(none)"); break; default: res = QString(advance_name_researching(pplayer)) + sp + "(" + QString::number(research->bulbs_researched) + "/" + QString::number(total_bulbs_required(pplayer)) + ")"; break; } /** Formatting rich text */ intel_str = QString("<table><tr><td><b>") + _("Nation") + QString("</b></td><td>") + QString(nation_adjective_for_player(pplayer)) + QString("</td><tr><td><b>") + N_("Ruler:") + QString("</b></td><td>") + QString(ruler_title_for_player(pplayer, tbuf, sizeof(tbuf))) + QString("</td></tr><tr><td><b>") + N_("Government:") + QString("</b></td><td>") + QString(government_name_for_player(pplayer)) + QString("</td></tr><tr><td><b>") + N_("Capital:") + QString("</b></td><td>") + QString(((!pcity) ? _("(unknown)") : city_name(pcity))) + QString("</td></tr><tr><td><b>") + N_("Gold:") + QString("</b></td><td>") + QString::number(pplayer->economic.gold) + QString("</td></tr><tr><td><b>") + N_("Tax:") + QString("</b></td><td>") + QString::number(pplayer->economic.tax) + QString("%</td></tr><tr><td><b>") + N_("Science:") + QString("</b></td><td>") + QString::number(pplayer->economic.science) + QString("%</td></tr><tr><td><b>") + N_("Luxury:") + QString("</b></td><td>") + QString::number(pplayer->economic.luxury) + QString("%</td></tr><tr><td><b>") + N_("Researching:") + QString("</b></td><td>") + res + QString("</td></table>"); for (int i = 0; i < static_cast<int>(DS_LAST); i++) { added = false; if (entry_exist) { ally_str += "<br>"; } entry_exist = false; players_iterate_alive(other) { if (other == pplayer) { continue; } state = player_diplstate_get(pplayer, other); if (static_cast<int>(state->type) == i) { if (added == false) { ally_str = ally_str + QString("<b>") + QString(diplstate_type_translated_name( static_cast<diplstate_type>(i))) + ": " + QString("</b>") + nl; added = true; } ally_str = ally_str + nation_plural_for_player(other) + ", "; entry_exist = true; } } players_iterate_alive_end; if (entry_exist) { ally_str.replace(ally_str.lastIndexOf(","), 1, "."); } } me = client_player(); if ((player_has_embassy(me, pplayer) || client_is_global_observer()) && me != pplayer) { a = 0; b = 0; techs_known = QString("<b>") + _("Techs unknown by") + sp + QString(nation_adjective_for_player(pplayer)) + sp + QString(_("nation")) + QString("</b> :"); techs_unknown = QString("<b>") + _("Techs unkown by you") + sp + QString("</b> :"); advance_iterate(A_FIRST, padvance) { tech_id = advance_number(padvance); if (player_invention_state(me, tech_id) == TECH_KNOWN && (player_invention_state(pplayer, tech_id) == TECH_UNKNOWN)) { a++; techs_known = techs_known + QString("<i>") + advance_name_for_player(pplayer, tech_id) + "," + QString("</i>") + sp; } if (player_invention_state(me, tech_id) == TECH_UNKNOWN && (player_invention_state(pplayer, tech_id) == TECH_KNOWN)) { b++; techs_unknown = techs_unknown + QString("<i>") + advance_name_for_player(pplayer, tech_id) + "," + QString("</i>") + sp; } } advance_iterate_end;