/* * Locks a shared-memory FIFO. * * Preconditions: * The shared-memory FIFO is unlocked. * Arguments: * shm Pointer to the shared-memory FIFO data-structure. * Returns: * 0 Success * ECANCELED Operating-system failure. Error-message logged. * EINVAL "shm" is uninitialized. Error-message logged. * EINVAL Semaphore is uninitialized. Error-message logged. * EINVAL FIFO is already locked by this process. Error-message * logged. */ static int shmfifo_lock( const struct shmhandle* const shm) { int status = checkUnlocked(shm); if (0 == status) { struct sembuf op[1]; /* printf("called shmfifo_lock semid: %d in process %d\n",shm->semid, * getpid()); * printf("<%d>locking %d\n",getpid(),shm->semid); */ op[0].sem_num = SI_LOCK; op[0].sem_op = -1; op[0].sem_flg = 0; /* dvbs_multicast(1) used to hang here */ if (semop (shm->semid, op, 1) == -1) { log_syserr("semop(2) failure"); status = ECANCELED; } else { status = 0; /* success */ } /* printf("<%d> locked\n",getpid()); */ } return status; }
/** * Show mouseover descriptions of disciplines and powers */ TooltipData MenuPowers::checkTooltip(const Point& mouse) { TooltipData tip; for (size_t i=0; i<power_cell.size(); i++) { if (tab_control && (tab_control->getActiveTab() != power_cell[i].tab)) continue; int cell_index = getCellByPowerIndex(power_cell[i].id, power_cell_all); if (!checkCellVisible(cell_index)) continue; if (slots[i] && isWithinRect(slots[i]->pos, mouse)) { bool base_unlocked = checkUnlocked(cell_index) || std::find(stats->powers_list.begin(), stats->powers_list.end(), power_cell[i].id) != stats->powers_list.end(); createTooltip(&tip, static_cast<int>(i), power_cell, !base_unlocked); if (!power_cell[i].upgrades.empty()) { int next_level = getNextLevelCell(static_cast<int>(i)); if (next_level != -1) { tip.addText("\n" + msg->get("Next Level:")); createTooltip(&tip, next_level, power_cell_upgrade, base_unlocked); } } return tip; } } return tip; }
void MenuPowers::setUnlockedPowers() { std::vector<int> power_ids; bool unlocked_cleared = false; // only clear/repopulate power_cell_unlocked if the size of the hero's powers_list has changed if (prev_powers_list_size != stats->powers_list.size() || power_cell_unlocked.empty()) { prev_powers_list_size = stats->powers_list.size(); power_cell_unlocked.clear(); unlocked_cleared = true; } for (size_t i=0; i<power_cell.size(); ++i) { if (std::find(stats->powers_list.begin(), stats->powers_list.end(), power_cell[i].id) != stats->powers_list.end()) { if (!unlocked_cleared) continue; // base power if (std::find(power_ids.begin(), power_ids.end(), power_cell[i].id) == power_ids.end()) { power_ids.push_back(power_cell_base[i].id); power_cell_unlocked.push_back(power_cell_base[i]); } if (power_cell[i].id == power_cell_base[i].id) continue; //upgrades for (size_t j=0; j<power_cell[i].upgrades.size(); ++j) { if (std::find(power_ids.begin(), power_ids.end(), power_cell[i].upgrades[j]) == power_ids.end()) { int id = getCellByPowerIndex(power_cell[i].upgrades[j], power_cell_upgrade); if (id != -1) { power_ids.push_back(power_cell[i].upgrades[j]); power_cell_unlocked.push_back(power_cell_upgrade[id]); if (power_cell[i].id == power_cell[i].upgrades[j]) break; } else { break; } } } } else { // power is unlocked, but not in the player's powers_list int pci = getCellByPowerIndex(power_cell[i].id, power_cell_all); if (checkUnlocked(pci)) { stats->powers_list.push_back(power_cell[i].id); } } } // the hero's powers_list may have grown, so we need to re-check unlocked powers if (prev_powers_list_size != stats->powers_list.size()) { setUnlockedPowers(); } }
/** * Check if we can unlock power. */ bool MenuPowers::checkUnlock(int pci) { // If we didn't find power in power_menu, than it has no requirements if (pci == -1) return true; if (!checkCellVisible(pci)) return false; // If we already have a power, don't try to unlock it if (checkUnlocked(pci)) return false; // Check base requirements if (checkRequirements(pci)) return true; return false; }
/** * Click-to-drag a power (to the action bar) */ int MenuPowers::click(const Point& mouse) { int active_tab = (tab_control) ? tab_control->getActiveTab() : 0; for (size_t i=0; i<power_cell.size(); i++) { if (slots[i] && isWithinRect(slots[i]->pos, mouse) && (power_cell[i].tab == active_tab)) { if (TOUCHSCREEN) { if (!slots[i]->in_focus) { slots[i]->in_focus = true; if (!tabs.empty()) { tablist_pow[active_tab].setCurrent(slots[i]); } else { tablist.setCurrent(slots[i]); } return 0; } } int cell_index = getCellByPowerIndex(power_cell[i].id, power_cell_all); if (checkUnlock(cell_index) && points_left > 0 && power_cell[i].requires_point) { // unlock power stats->powers_list.push_back(power_cell[i].id); stats->check_title = true; setUnlockedPowers(); action_bar->addPower(power_cell[i].id, 0); return 0; } else if (checkUnlocked(cell_index) && !powers->powers[power_cell[i].id].passive) { // pick up and drag power slots[i]->defocus(); if (!tabs.empty()) { tablist_pow[active_tab].setCurrent(NULL); } else { tablist.setCurrent(NULL); } return power_cell[i].id; } else return 0; } } // nothing selected, defocus everything defocusTabLists(); return 0; }
bool MenuPowers::checkUpgrade(int pci) { int id = getCellByPowerIndex(power_cell[pci].id, power_cell_all); if (!checkUnlocked(id)) return false; int next_index = getNextLevelCell(pci); if (next_index == -1) return false; if (power_cell_upgrade[next_index].requires_point && points_left < 1) return false; int id_upgrade = getCellByPowerIndex(power_cell_upgrade[next_index].id, power_cell_all); if (!checkUnlock(id_upgrade)) return false; return true; }
bool MenuPowers::checkRequirements(int pci) { if (pci == -1) return false; for (size_t i = 0; i < power_cell_all[pci].requires_power_cell.size(); ++i) if (!checkUnlocked(power_cell_all[pci].requires_power_cell[i])) return false; if (stats->level < power_cell_all[pci].requires_level) return false; for (size_t i = 0; i < PRIMARY_STATS.size(); ++i) { if (stats->get_primary(i) < power_cell_all[pci].requires_primary[i]) return false; } return true; }
bool MenuPowers::checkRequirements(int pci) { if (pci == -1) return false; for (size_t i = 0; i < power_cell_all[pci].requires_power_cell.size(); ++i) if (!checkUnlocked(power_cell_all[pci].requires_power_cell[i])) return false; if ((stats->physoff() >= power_cell_all[pci].requires_physoff) && (stats->physdef() >= power_cell_all[pci].requires_physdef) && (stats->mentoff() >= power_cell_all[pci].requires_mentoff) && (stats->mentdef() >= power_cell_all[pci].requires_mentdef) && (stats->get_defense() >= power_cell_all[pci].requires_defense) && (stats->get_offense() >= power_cell_all[pci].requires_offense) && (stats->get_physical() >= power_cell_all[pci].requires_physical) && (stats->get_mental() >= power_cell_all[pci].requires_mental) && (stats->level >= power_cell_all[pci].requires_level)) return true; return false; }
void MenuPowers::createTooltip(TooltipData* tip, int slot_num, const std::vector<Power_Menu_Cell>& power_cells, bool show_unlock_prompt) { if (power_cells[slot_num].upgrade_level > 0) tip->addText(powers->powers[power_cells[slot_num].id].name + " (" + msg->get("Level %d", power_cells[slot_num].upgrade_level) + ")"); else tip->addText(powers->powers[power_cells[slot_num].id].name); if (powers->powers[power_cells[slot_num].id].passive) tip->addText(msg->get("Passive")); tip->addColoredText(substituteVarsInString(powers->powers[power_cells[slot_num].id].description, pc), color_flavor); // add mana cost if (powers->powers[power_cells[slot_num].id].requires_mp > 0) { tip->addText(msg->get("Costs %d MP", powers->powers[power_cells[slot_num].id].requires_mp)); } // add health cost if (powers->powers[power_cells[slot_num].id].requires_hp > 0) { tip->addText(msg->get("Costs %d HP", powers->powers[power_cells[slot_num].id].requires_hp)); } // add cooldown time if (powers->powers[power_cells[slot_num].id].cooldown > 0) { std::stringstream ss; ss << msg->get("Cooldown:") << " " << getDurationString(powers->powers[power_cells[slot_num].id].cooldown); tip->addText(ss.str()); } const Power &pwr = powers->powers[power_cells[slot_num].id]; for (size_t i=0; i<pwr.post_effects.size(); ++i) { std::stringstream ss; EffectDef* effect_ptr = powers->getEffectDef(pwr.post_effects[i].id); // base stats if (effect_ptr == NULL) { if (pwr.post_effects[i].magnitude > 0) { ss << "+"; } ss << pwr.post_effects[i].magnitude; bool found_key = false; for (size_t j=0; j<STAT_COUNT; ++j) { if (pwr.post_effects[i].id == STAT_KEY[j]) { if (STAT_PERCENT[j]) ss << "%"; ss << " " << STAT_NAME[j]; found_key = true; break; } } if (!found_key) { for (size_t j=0; j<ELEMENTS.size(); ++j) { if (pwr.post_effects[i].id == ELEMENTS[j].id + "_resist") { ss << "% " << msg->get("%s Resistance", ELEMENTS[j].name.c_str()); found_key = true; break; } } } if (!found_key) { for (size_t j=0; j<PRIMARY_STATS.size(); ++j) { if (pwr.post_effects[i].id == PRIMARY_STATS[j].id) { ss << " " << PRIMARY_STATS[j].name; found_key = true; break; } } } if (!found_key) { for (size_t j=0; j<DAMAGE_TYPES.size(); ++j) { if (pwr.post_effects[i].id == DAMAGE_TYPES[j].min) { ss << " " << DAMAGE_TYPES[j].name_min; found_key = true; break; } else if (pwr.post_effects[i].id == DAMAGE_TYPES[j].max) { ss << " " << DAMAGE_TYPES[j].name_max; found_key = true; break; } } } } else { if (effect_ptr->type == "damage") { ss << pwr.post_effects[i].magnitude << " " << msg->get("Damage per second"); } else if (effect_ptr->type == "damage_percent") { ss << pwr.post_effects[i].magnitude << "% " << msg->get("Damage per second"); } else if (effect_ptr->type == "hpot") { ss << pwr.post_effects[i].magnitude << " " << msg->get("HP per second"); } else if (effect_ptr->type == "hpot_percent") { ss << pwr.post_effects[i].magnitude << "% " << msg->get("HP per second"); } else if (effect_ptr->type == "mpot") { ss << pwr.post_effects[i].magnitude << " " << msg->get("MP per second"); } else if (effect_ptr->type == "mpot_percent") { ss << pwr.post_effects[i].magnitude << "% " << msg->get("MP per second"); } else if (effect_ptr->type == "speed") { if (pwr.post_effects[i].magnitude == 0) ss << msg->get("Immobilize"); else ss << msg->get("%d%% Speed", pwr.post_effects[i].magnitude); } else if (effect_ptr->type == "attack_speed") { ss << msg->get("%d%% Attack Speed", pwr.post_effects[i].magnitude); } else if (effect_ptr->type == "immunity") { ss << msg->get("Immunity"); } else if (effect_ptr->type == "immunity_damage") { ss << msg->get("Immunity to damage over time"); } else if (effect_ptr->type == "immunity_slow") { ss << msg->get("Immunity to slow"); } else if (effect_ptr->type == "immunity_stun") { ss << msg->get("Immunity to stun"); } else if (effect_ptr->type == "immunity_hp_steal") { ss << msg->get("Immunity to HP steal"); } else if (effect_ptr->type == "immunity_mp_steal") { ss << msg->get("Immunity to MP steal"); } else if (effect_ptr->type == "immunity_knockback") { ss << msg->get("Immunity to knockback"); } else if (effect_ptr->type == "immunity_damage_reflect") { ss << msg->get("Immunity to damage reflection"); } else if (effect_ptr->type == "stun") { ss << msg->get("Stun"); } else if (effect_ptr->type == "revive") { ss << msg->get("Automatic revive on death"); } else if (effect_ptr->type == "convert") { ss << msg->get("Convert"); } else if (effect_ptr->type == "fear") { ss << msg->get("Fear"); } else if (effect_ptr->type == "death_sentence") { ss << msg->get("Lifespan"); } else if (effect_ptr->type == "shield") { if (pwr.base_damage == DAMAGE_TYPES.size()) continue; if (pwr.mod_damage_mode == STAT_MODIFIER_MODE_MULTIPLY) { int magnitude = stats->getDamageMax(pwr.base_damage) * pwr.mod_damage_value_min / 100; ss << magnitude; } else if (pwr.mod_damage_mode == STAT_MODIFIER_MODE_ADD) { int magnitude = stats->getDamageMax(pwr.base_damage) + pwr.mod_damage_value_min; ss << magnitude; } else if (pwr.mod_damage_mode == STAT_MODIFIER_MODE_ABSOLUTE) { if (pwr.mod_damage_value_max == 0 || pwr.mod_damage_value_min == pwr.mod_damage_value_max) ss << pwr.mod_damage_value_min; else ss << pwr.mod_damage_value_min << "-" << pwr.mod_damage_value_max; } else { ss << stats->getDamageMax(pwr.base_damage); } ss << " " << msg->get("Magical Shield"); } else if (effect_ptr->type == "heal") { if (pwr.base_damage == DAMAGE_TYPES.size()) continue; int mag_min = stats->getDamageMin(pwr.base_damage); int mag_max = stats->getDamageMax(pwr.base_damage); if (pwr.mod_damage_mode == STAT_MODIFIER_MODE_MULTIPLY) { mag_min = mag_min * pwr.mod_damage_value_min / 100; mag_max = mag_max * pwr.mod_damage_value_min / 100; ss << mag_min << "-" << mag_max; } else if (pwr.mod_damage_mode == STAT_MODIFIER_MODE_ADD) { mag_min = mag_min + pwr.mod_damage_value_min; mag_max = mag_max + pwr.mod_damage_value_min; ss << mag_min << "-" << mag_max; } else if (pwr.mod_damage_mode == STAT_MODIFIER_MODE_ABSOLUTE) { if (pwr.mod_damage_value_max == 0 || pwr.mod_damage_value_min == pwr.mod_damage_value_max) ss << pwr.mod_damage_value_min; else ss << pwr.mod_damage_value_min << "-" << pwr.mod_damage_value_max; } else { ss << mag_min << "-" << mag_max; } ss << " " << msg->get("Healing"); } else if (effect_ptr->type == "knockback") { ss << pwr.post_effects[i].magnitude << " " << msg->get("Knockback"); } else if (pwr.post_effects[i].magnitude == 0) { // nothing } } if (!ss.str().empty()) { if (pwr.post_effects[i].duration > 0) { if (effect_ptr && effect_ptr->type == "death_sentence") { ss << ": " << getDurationString(pwr.post_effects[i].duration); } else { ss << " (" << getDurationString(pwr.post_effects[i].duration) << ")"; } if (pwr.post_effects[i].chance != 100) ss << " "; } if (pwr.post_effects[i].chance != 100) { ss << "(" << msg->get("%d%% chance", pwr.post_effects[i].chance) << ")"; } tip->addColoredText(ss.str(), color_bonus); } } if (pwr.use_hazard || pwr.type == POWTYPE_REPEATER) { std::stringstream ss; // modifier_damage if (pwr.mod_damage_mode > -1) { if (pwr.mod_damage_mode == STAT_MODIFIER_MODE_ADD && pwr.mod_damage_value_min > 0) ss << "+"; if (pwr.mod_damage_value_max == 0 || pwr.mod_damage_value_min == pwr.mod_damage_value_max) { ss << pwr.mod_damage_value_min; } else { ss << pwr.mod_damage_value_min << "-" << pwr.mod_damage_value_max; } if (pwr.mod_damage_mode == STAT_MODIFIER_MODE_MULTIPLY) { ss << "%"; } ss << " "; if (pwr.base_damage != DAMAGE_TYPES.size()) { ss << DAMAGE_TYPES[pwr.base_damage].name; } if (pwr.count > 1 && pwr.type != POWTYPE_REPEATER) ss << " (x" << pwr.count << ")"; if (!ss.str().empty()) tip->addColoredText(ss.str(), color_bonus); } // modifier_accuracy if (pwr.mod_accuracy_mode > -1) { ss.str(""); if (pwr.mod_accuracy_mode == STAT_MODIFIER_MODE_ADD && pwr.mod_accuracy_value > 0) ss << "+"; ss << pwr.mod_accuracy_value; if (pwr.mod_accuracy_mode == STAT_MODIFIER_MODE_MULTIPLY) { ss << "%"; } ss << " "; ss << msg->get("Base Accuracy"); if (!ss.str().empty()) tip->addColoredText(ss.str(), color_bonus); } // modifier_critical if (pwr.mod_crit_mode > -1) { ss.str(""); if (pwr.mod_crit_mode == STAT_MODIFIER_MODE_ADD && pwr.mod_crit_value > 0) ss << "+"; ss << pwr.mod_crit_value; if (pwr.mod_crit_mode == STAT_MODIFIER_MODE_MULTIPLY) { ss << "%"; } ss << " "; ss << msg->get("Base Critical Chance"); if (!ss.str().empty()) tip->addColoredText(ss.str(), color_bonus); } if (pwr.trait_armor_penetration) { ss.str(""); ss << msg->get("Ignores Absorbtion"); tip->addColoredText(ss.str(), color_bonus); } if (pwr.trait_avoidance_ignore) { ss.str(""); ss << msg->get("Ignores Avoidance"); tip->addColoredText(ss.str(), color_bonus); } if (pwr.trait_crits_impaired > 0) { ss.str(""); ss << msg->get("%d%% Chance to crit slowed targets", pwr.trait_crits_impaired); tip->addColoredText(ss.str(), color_bonus); } if (pwr.trait_elemental > -1) { ss.str(""); ss << msg->get("%s Elemental Damage", ELEMENTS[pwr.trait_elemental].name.c_str()); tip->addColoredText(ss.str(), color_bonus); } } std::set<std::string>::iterator it; for (it = powers->powers[power_cells[slot_num].id].requires_flags.begin(); it != powers->powers[power_cells[slot_num].id].requires_flags.end(); ++it) { for (size_t i=0; i<EQUIP_FLAGS.size(); ++i) { if ((*it) == EQUIP_FLAGS[i].id) { tip->addText(msg->get("Requires a %s", msg->get(EQUIP_FLAGS[i].name))); } } } // add requirement for (size_t i = 0; i < PRIMARY_STATS.size(); ++i) { if (power_cells[slot_num].requires_primary[i] > 0) { if (stats->get_primary(i) < power_cells[slot_num].requires_primary[i]) tip->addColoredText(msg->get("Requires %s %d", power_cells[slot_num].requires_primary[i], PRIMARY_STATS[i].name.c_str()), color_penalty); else tip->addText(msg->get("Requires %s %d", power_cells[slot_num].requires_primary[i], PRIMARY_STATS[i].name.c_str())); } } // Draw required Level Tooltip if ((power_cells[slot_num].requires_level > 0) && stats->level < power_cells[slot_num].requires_level) { tip->addColoredText(msg->get("Requires Level %d", power_cells[slot_num].requires_level), color_penalty); } else if ((power_cells[slot_num].requires_level > 0) && stats->level >= power_cells[slot_num].requires_level) { tip->addText(msg->get("Requires Level %d", power_cells[slot_num].requires_level)); } for (size_t j=0; j < power_cells[slot_num].requires_power.size(); ++j) { if (power_cells[slot_num].requires_power[j] == 0) continue; int req_index = getCellByPowerIndex(power_cells[slot_num].requires_power[j], power_cell_all); if (req_index == -1) continue; std::string req_power_name; if (power_cell_all[req_index].upgrade_level > 0) req_power_name = powers->powers[power_cell_all[req_index].id].name + " (" + msg->get("Level %d", power_cell_all[req_index].upgrade_level) + ")"; else req_power_name = powers->powers[power_cell_all[req_index].id].name; // Required Power Tooltip int req_cell_index = getCellByPowerIndex(power_cells[slot_num].requires_power[j], power_cell_all); if (!checkUnlocked(req_cell_index)) { tip->addColoredText(msg->get("Requires Power: %s", req_power_name), color_penalty); } else { tip->addText(msg->get("Requires Power: %s", req_power_name)); } } // Draw unlock power Tooltip if (power_cells[slot_num].requires_point && !(std::find(stats->powers_list.begin(), stats->powers_list.end(), power_cells[slot_num].id) != stats->powers_list.end())) { int unlock_id = getCellByPowerIndex(power_cells[slot_num].id, power_cell_all); if (show_unlock_prompt && points_left > 0 && checkUnlock(unlock_id)) { tip->addColoredText(msg->get("Click to Unlock (uses 1 Skill Point)"), color_bonus); } else { if (power_cells[slot_num].requires_point && points_left < 1) tip->addColoredText(msg->get("Requires 1 Skill Point"), color_penalty); else tip->addText(msg->get("Requires 1 Skill Point")); } } }
void MenuPowers::renderPowers(int tab_num) { Rect disabled_src; disabled_src.x = disabled_src.y = 0; disabled_src.w = disabled_src.h = ICON_SIZE; for (size_t i=0; i<power_cell.size(); i++) { bool power_in_vector = false; // Continue if slot is not filled with data if (power_cell[i].tab != tab_num) continue; int cell_index = getCellByPowerIndex(power_cell[i].id, power_cell_all); if (!checkCellVisible(cell_index)) continue; if (std::find(stats->powers_list.begin(), stats->powers_list.end(), power_cell[i].id) != stats->powers_list.end()) power_in_vector = true; if (slots[i]) slots[i]->render(); // highlighting if (power_in_vector || checkUnlocked(cell_index)) { Rect src_unlock; src_unlock.x = 0; src_unlock.y = 0; src_unlock.w = ICON_SIZE; src_unlock.h = ICON_SIZE; int selected_slot = -1; if (isTabListSelected()) { selected_slot = getSelectedCellIndex(); } for (size_t j=0; j<power_cell.size(); j++) { if (selected_slot == static_cast<int>(j)) continue; if (power_cell[j].id == power_cell[i].id && powers_unlock && slots[j]) { powers_unlock->setClip(src_unlock); powers_unlock->setDest(slots[j]->pos); render_device->render(powers_unlock); } } } else { if (overlay_disabled && slots[i]) { overlay_disabled->setClip(disabled_src); overlay_disabled->setDest(slots[i]->pos); render_device->render(overlay_disabled); } } if (slots[i]) slots[i]->renderSelection(); // upgrade buttons if (upgradeButtons[i]) upgradeButtons[i]->render(); } }