Exemplo n.º 1
0
/*
 * 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;
}
Exemplo n.º 2
0
/**
 * 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;
}
Exemplo n.º 3
0
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();
	}
}
Exemplo n.º 4
0
/**
 * 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;
}
Exemplo n.º 5
0
/**
 * 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;
}
Exemplo n.º 6
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;
}
Exemplo n.º 7
0
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;
}
Exemplo n.º 8
0
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;
}
Exemplo n.º 9
0
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"));
		}
	}
}
Exemplo n.º 10
0
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();
	}
}