void MapRenderer::renderOrthoLayer(const unsigned short layerdata[256][256]) { const Point upperleft = floor(screen_to_map(0, 0, shakycam.x, shakycam.y)); short int startj = std::max(0, upperleft.y); short int starti = std::max(0, upperleft.x); const short max_tiles_width = std::min(w, static_cast<short int>(starti + (VIEW_W / TILE_W) + 2 * tset.max_size_x)); const short max_tiles_height = std::min(h, static_cast<short int>(startj + (VIEW_H / TILE_H) + 2 * tset.max_size_y)); short int i; short int j; for (j = startj; j < max_tiles_height; j++) { Point p = map_to_screen(starti, j, shakycam.x, shakycam.y); p = center_tile(p); for (i = starti; i < max_tiles_width; i++) { if (const unsigned short current_tile = layerdata[i][j]) { Rect dest; dest.x = p.x - tset.tiles[current_tile].offset.x; dest.y = p.y - tset.tiles[current_tile].offset.y; tset.tiles[current_tile].tile->setDest(dest); render_device->render(tset.tiles[current_tile].tile); } p.x += TILE_W; } } }
/** * On mouseover, display NPC's name */ void NPCManager::renderTooltips(Point cam, Point mouse) { Point p; SDL_Rect r; TooltipData td; for(int i=0; i<npc_count; i++) { p = map_to_screen(npcs[i]->pos.x, npcs[i]->pos.y, cam.x, cam.y); r.w = npcs[i]->render_size.x; r.h = npcs[i]->render_size.y; r.x = p.x - npcs[i]->render_offset.x; r.y = p.y - npcs[i]->render_offset.y; if (isWithin(r, mouse)) { // adjust dest.y so that the tooltip floats above the item p.y -= tooltip_margin; td.num_lines = 1; td.colors[0] = FONT_WHITE; td.lines[0] = npcs[i]->name; tip->render(td, p, STYLE_TOPLABEL); } } }
void MapRenderer::drawRenderable(std::vector<Renderable>::iterator r_cursor) { if (r_cursor->image != NULL) { Rect dest; Point p = map_to_screen(r_cursor->map_pos.x, r_cursor->map_pos.y, shakycam.x, shakycam.y); dest.x = p.x - r_cursor->offset.x; dest.y = p.y - r_cursor->offset.y; render_device->render(*r_cursor, dest); } }
void MapIso::checkTooltip() { Point p; SDL_Rect r; Point tip_pos; bool skip; for (int i=0; i<event_count; i++) { skip = false; if(!isActive(i)) skip = true; if (skip) continue; p = map_to_screen(events[i].location.x * UNITS_PER_TILE + UNITS_PER_TILE/2, events[i].location.y * UNITS_PER_TILE + UNITS_PER_TILE/2, cam.x, cam.y); r.x = p.x + events[i].hotspot.x; r.y = p.y + events[i].hotspot.y; r.h = events[i].hotspot.h; r.w = events[i].hotspot.w; // DEBUG TOOL: outline hotspot /* SDL_Rect screen_size; screen_size.x = screen_size.y = 0; screen_size.w = VIEW_W; screen_size.h = VIEW_H; Point pixpos; pixpos.x = r.x; pixpos.y = r.y; if (isWithin(screen_size, pixpos)) drawPixel(screen, r.x, r.y, 255); pixpos.x = r.x+r.w; pixpos.y = r.y; if (isWithin(screen_size, pixpos)) drawPixel(screen, r.x+r.w, r.y, 255); pixpos.x = r.x; pixpos.y = r.y+r.h; if (isWithin(screen_size, pixpos)) drawPixel(screen, r.x, r.y+r.h, 255); pixpos.x = r.x+r.w; pixpos.y = r.y+r.h; if (isWithin(screen_size, pixpos)) drawPixel(screen, r.x+r.w, r.y+r.h, 255); */ if (isWithin(r,inp->mouse) && events[i].tooltip != "") { TooltipData td; td.num_lines = 1; td.colors[0] = FONT_WHITE; td.lines[0] = events[i].tooltip; tip_pos.x = r.x + r.w/2; tip_pos.y = r.y; tip->render(td, tip_pos, STYLE_TOPLABEL); } } }
/** * Click on the map to pick up loot. We need the camera position to translate * screen coordinates to map locations. */ ItemStack LootManager::checkPickup(Point mouse, FPoint cam, FPoint hero_pos, MenuInventory *inv) { Rect r; ItemStack loot_stack; // check left mouse click if (!NO_MOUSE) { // I'm starting at the end of the loot list so that more recently-dropped // loot is picked up first. If a player drops several loot in the same // location, picking it back up will work like a stack. std::vector<Loot>::iterator it; for (it = loot.end(); it != loot.begin(); ) { --it; // loot close enough to pickup? if (fabs(hero_pos.x - it->pos.x) < INTERACT_RANGE && fabs(hero_pos.y - it->pos.y) < INTERACT_RANGE && !it->isFlying()) { Point p = map_to_screen(it->pos.x, it->pos.y, cam.x, cam.y); r.x = p.x - TILE_W_HALF; r.y = p.y - TILE_H_HALF; r.w = TILE_W; r.h = TILE_H; // clicked in pickup hotspot? if (isWithin(r, mouse)) { curs->setCursor(CURSOR_INTERACT); if (inpt->pressing[MAIN1] && !inpt->lock[MAIN1]) { inpt->lock[MAIN1] = true; if (!it->stack.empty()) { if (!(inv->full(it->stack.item))) { loot_stack = it->stack; it = loot.erase(it); return loot_stack; } else { full_msg = true; } } } } } } } // check pressing Enter/Return if (inpt->pressing[ACCEPT] && !inpt->lock[ACCEPT]) { loot_stack = checkNearestPickup(hero_pos, inv); if (!loot_stack.empty()) { inpt->lock[ACCEPT] = true; } } return loot_stack; }
void CombatText::addMessage(std::string message, Point location, int displaytype) { if (COMBAT_TEXT) { Point p = map_to_screen(location.x - UNITS_PER_TILE, location.y - UNITS_PER_TILE, cam.x, cam.y); Combat_Text_Item *c = new Combat_Text_Item(); WidgetLabel *label = new WidgetLabel(); c->pos = p; c->label = label; c->text = message; c->lifespan = duration; c->displaytype = displaytype; combat_text.push_back(*c); delete c; } }
void MapRenderer::checkNearestEvent() { if (NO_MOUSE) show_tooltip = false; std::vector<Event>::iterator it; std::vector<Event>::iterator nearest = events.end(); float best_distance = std::numeric_limits<float>::max(); // loop in reverse because we may erase elements for (it = events.end(); it != events.begin(); ) { --it; // skip inactive events if (!EventManager::isActive(*it)) continue; // skip events without hotspots if ((*it).hotspot.h == 0) continue; // skip events on cooldown if ((*it).cooldown_ticks != 0) continue; float distance = calcDist(cam, (*it).center); if ((((*it).reachable_from.w == 0 && (*it).reachable_from.h == 0) || isWithin((*it).reachable_from, floor(cam))) && distance < INTERACT_RANGE && distance < best_distance) { best_distance = distance; nearest = it; } } if (nearest != events.end()) { if (NO_MOUSE || TOUCHSCREEN) { // new tooltip? createTooltip((*nearest).getComponent("tooltip")); tip_pos = map_to_screen((*nearest).center.x, (*nearest).center.y, shakycam.x, shakycam.y); if ((*nearest).getComponent("npc_hotspot")) { tip_pos.y -= npc_tooltip_margin; } else { tip_pos.y -= TILE_H; } } if (inpt->pressing[ACCEPT] && !inpt->lock[ACCEPT]) { if (inpt->pressing[ACCEPT]) inpt->lock[ACCEPT] = true; if(EventManager::executeEvent(*nearest)) events.erase(nearest); } } }
void MapIso::checkEventClick() { Point p; SDL_Rect r; for(int i=0; i<event_count; i++) { p = map_to_screen(events[i].location.x * UNITS_PER_TILE + UNITS_PER_TILE/2, events[i].location.y * UNITS_PER_TILE + UNITS_PER_TILE/2, cam.x, cam.y); r.x = p.x + events[i].hotspot.x; r.y = p.y + events[i].hotspot.y; r.h = events[i].hotspot.h; r.w = events[i].hotspot.w; // execute if: EVENT IS ACTIVE && MOUSE IN HOTSPOT && HOTSPOT EXISTS && CLICKING && HERO WITHIN RANGE if (isActive(i) && isWithin(r, inp->mouse) && (events[i].hotspot.h != 0) && inp->pressing[MAIN1] && !inp->lock[MAIN1] && (abs(cam.x - events[i].location.x * UNITS_PER_TILE) < CLICK_RANGE && abs(cam.y - events[i].location.y * UNITS_PER_TILE) < CLICK_RANGE)) { inp->lock[MAIN1] = true; executeEvent(i); } } }
void MapRenderer::renderOrthoFrontObjects(std::vector<Renderable> &r) { short int i; short int j; Rect dest; std::vector<Renderable>::iterator r_cursor = r.begin(); std::vector<Renderable>::iterator r_end = r.end(); const Point upperleft = floor(screen_to_map(0, 0, shakycam.x, shakycam.y)); short int startj = std::max(0, upperleft.y); short int starti = std::max(0, upperleft.x); const short max_tiles_width = std::min(w, static_cast<short int>(starti + (VIEW_W / TILE_W) + 2 * tset.max_size_x)); const short max_tiles_height = std::min(h, static_cast<short int>(startj + (VIEW_H / TILE_H) + 2 * tset.max_size_y)); while (r_cursor != r_end && (int)(r_cursor->map_pos.y) < startj) ++r_cursor; if (index_objectlayer >= layers.size()) return; maprow *objectlayer = layers[index_objectlayer]; for (j = startj; j < max_tiles_height; j++) { Point p = map_to_screen(starti, j, shakycam.x, shakycam.y); p = center_tile(p); for (i = starti; i<max_tiles_width; i++) { if (const unsigned short current_tile = objectlayer[i][j]) { dest.x = p.x - tset.tiles[current_tile].offset.x; dest.y = p.y - tset.tiles[current_tile].offset.y; tset.tiles[current_tile].tile->setDest(dest); render_device->render(tset.tiles[current_tile].tile); } p.x += TILE_W; while (r_cursor != r_end && (int)(r_cursor->map_pos.y) == j && (int)(r_cursor->map_pos.x) < i) // implicit floor ++r_cursor; // some renderable entities go in this layer while (r_cursor != r_end && (int)(r_cursor->map_pos.y) == j && (int)(r_cursor->map_pos.x) == i) // implicit floor drawRenderable(r_cursor++); } while (r_cursor != r_end && (int)(r_cursor->map_pos.y) <= j) // implicit floor ++r_cursor; } }
/** * Click on the map to pick up loot. We need the camera position to translate * screen coordinates to map locations. We need the hero position because * the hero has to be within range to pick up an item. */ ItemStack LootManager::checkPickup(Point mouse, Point cam, Point hero_pos, int &gold, bool inv_full) { Point p; SDL_Rect r; ItemStack loot_stack; gold = 0; loot_stack.item = 0; loot_stack.quantity = 0; // I'm starting at the end of the loot list so that more recently-dropped // loot is picked up first. If a player drops several loot in the same // location, picking it back up will work like a stack. for (int i=loot_count-1; i>=0; i--) { // loot close enough to pickup? if (abs(hero_pos.x - loot[i].pos.x) < LOOT_RANGE && abs(hero_pos.y - loot[i].pos.y) < LOOT_RANGE && !isFlying(i)) { p = map_to_screen(loot[i].pos.x, loot[i].pos.y, cam.x, cam.y); r.w = 32; r.h = 48; r.x = p.x - 16; r.y = p.y - 32; // clicked in pickup hotspot? if (mouse.x > r.x && mouse.x < r.x+r.w && mouse.y > r.y && mouse.y < r.y+r.h) { if (loot[i].stack.item > 0 && !inv_full) { loot_stack = loot[i].stack; removeLoot(i); return loot_stack; } else if (loot[i].stack.item > 0) { full_msg = true; } else if (loot[i].gold > 0) { gold = loot[i].gold; removeLoot(i); return loot_stack; } } } } return loot_stack; }
int NPCManager::checkNPCClick(Point mouse, Point cam) { Point p; SDL_Rect r; for(int i=0; i<npc_count; i++) { p = map_to_screen(npcs[i]->pos.x, npcs[i]->pos.y, cam.x, cam.y); r.w = npcs[i]->render_size.x; r.h = npcs[i]->render_size.y; r.x = p.x - npcs[i]->render_offset.x; r.y = p.y - npcs[i]->render_offset.y; if (isWithin(r, mouse)) { return i; } } return -1; }
void CombatText::addMessage(int num, Point location, int displaytype, bool from_hero) { if (COMBAT_TEXT) { Combat_Text_Item *c = new Combat_Text_Item(); WidgetLabel *label = new WidgetLabel(); c->pos = map_to_screen(location.x - UNITS_PER_TILE, location.y - UNITS_PER_TILE, cam.x, cam.y); c->src_pos = location; c->label = label; c->from_hero = from_hero; std::stringstream ss; ss << num; c->text = ss.str(); c->lifespan = duration; c->displaytype = displaytype; combat_text.push_back(*c); delete c; } }
Enemy* EnemyManager::enemyFocus(Point mouse, Point cam, bool alive_only) { Point p; SDL_Rect r; for(int i = 0; i < enemy_count; i++) { if(alive_only && (enemies[i]->stats.cur_state == ENEMY_DEAD || enemies[i]->stats.cur_state == ENEMY_CRITDEAD)) { continue; } p = map_to_screen(enemies[i]->stats.pos.x, enemies[i]->stats.pos.y, cam.x, cam.y); r.w = enemies[i]->getRender().src.w; r.h = enemies[i]->getRender().src.h; r.x = p.x - enemies[i]->getRender().offset.x; r.y = p.y - enemies[i]->getRender().offset.y; if (isWithin(r, mouse)) { Enemy *enemy = enemies[i]; return enemy; } } return NULL; }
void CombatText::logic(const FPoint& _cam) { cam = _cam; for(std::vector<Combat_Text_Item>::iterator it = combat_text.begin(); it != combat_text.end(); ++it) { it->lifespan--; it->floating_offset += speed; Point scr_pos; scr_pos = map_to_screen(it->pos.x, it->pos.y, cam.x, cam.y); scr_pos.y -= static_cast<int>(it->floating_offset); it->label->setX(scr_pos.x); it->label->setY(scr_pos.y); } // delete expired messages while (combat_text.size() && combat_text.begin()->lifespan <= 0) { delete combat_text.begin()->label; combat_text.erase(combat_text.begin()); } }
/** * Show all tooltips for loot on the floor */ void LootManager::renderTooltips(FPoint cam) { Point dest; std::vector<Loot>::iterator it; for (it = loot.end(); it != loot.begin(); ) { --it; if (it->on_ground) { Point p = map_to_screen(it->pos.x, it->pos.y, cam.x, cam.y); dest.x = p.x; dest.y = p.y + TILE_H_HALF; // adjust dest.y so that the tooltip floats above the item dest.y -= tooltip_margin; // set hitbox for mouse hover Rect hover; hover.x = p.x - TILE_W_HALF; hover.y = p.y - TILE_H_HALF; hover.w = TILE_W; hover.h = TILE_H; if (LOOT_TOOLTIPS || inpt->pressing[ALT] || isWithin(hover, inpt->mouse)) { // create tooltip data if needed if (it->tip.isEmpty()) { if (!it->stack.empty()) { it->tip = items->getShortTooltip(it->stack); } } tip->render(it->tip, dest, STYLE_TOPLABEL); // only display one tooltip if we got it from hovering if (!LOOT_TOOLTIPS && !inpt->pressing[ALT]) break; } } } }
void CombatText::render() { for(std::vector<Combat_Text_Item>::iterator it = combat_text.begin(); it != combat_text.end(); ++it) { it->lifespan--; it->floating_offset += speed; Point scr_pos; scr_pos = map_to_screen(it->pos.x, it->pos.y, cam.x, cam.y); scr_pos.y -= it->floating_offset; it->label->set(scr_pos.x, scr_pos.y, JUSTIFY_CENTER, VALIGN_BOTTOM, it->text, msg_color[it->displaytype]); if (it->lifespan > 0) it->label->render(); } // delete expired messages while (combat_text.size() && combat_text.begin()->lifespan <= 0) { delete combat_text.begin()->label; combat_text.erase(combat_text.begin()); } }
void CombatText::render() { for(std::vector<Combat_Text_Item>::iterator it = combat_text.begin(); it != combat_text.end(); it++) { it->lifespan--; // check if we need to position the text relative to the map if (!it->from_hero) { it->ydelta += speed; it->pos = map_to_screen(it->src_pos.x - UNITS_PER_TILE, it->src_pos.y - UNITS_PER_TILE, cam.x, cam.y); it->pos.y -= it->ydelta; } else { it->pos.y -= speed; } it->label->set(it->pos.x, it->pos.y, JUSTIFY_CENTER, VALIGN_BOTTOM, it->text, msg_color[it->displaytype]); if (it->lifespan > 0) it->label->render(); } // delete expired messages while (combat_text.size() > 0 && combat_text.begin()->lifespan <= 0) { combat_text.erase(combat_text.begin()); } }
void ListWeatherCloud::renderSnow(){ if (!spr_flake) return; int nr = 0; int i = 0; int j = 0; int r3 = 1; // changes type int r4 = 2;// changes offset int density = 3; Point p; FPoint fp; // needed to check if is_valid_position if (is_strong_rainfall){ density = 2; } // initialize the flake_state Array, if it isn't yet if (!flakes_arr_initialized){ flakes_arr_initialized = true; while (nr < MAX_NUMBER_OF_FLAKES){ r3 = randBetween(0,6); r4 = randBetween(-2,2); flake_state[nr][0] = r3; // type, stays the same flake_state[nr][1] = r4; // offset x flake_state[nr][2] = 0; // dx flake_state[nr][3] = 0; // dy flake_state[nr][4] = randBetween(-2,2); // offset y flake_state[nr][5] = randBetween(0,6); // change offset, stays nr+=1; } } i = -RADIUS; j = -RADIUS; while(j < RADIUS){ if (nr>=MAX_NUMBER_OF_FLAKES) nr=0; // update of position info should be rather slow... // otherwise the snowflakes appear to move with the hero if ((cycle_i % (RENDER_CHANGE_AFTER * 10) == 0) || mapr->map_change) { p_flakes = floor(mapr->cam); } spr_flake->setClipW(8); spr_flake->setClipH(10); spr_flake->setClipX(flake_state[nr][0]*9); // TODO: take into account wind direction (variable 'direction') p = map_to_screen(p_flakes.x + i, p_flakes.y + j, mapr->cam.x, mapr->cam.y); if ((cycle_i + flake_state[nr][5]) % RENDER_CHANGE_AFTER == 0) { flake_state[nr][1] = flake_state[nr][1] + randBetween(-2,2); // offset x flake_state[nr][2] = flake_state[nr][2] + randBetween(-1,1); // dx flake_state[nr][3] = flake_state[nr][3] + randBetween(-1,2); // dy flake_state[nr][4] = flake_state[nr][4] + randBetween(-2,2); // Offset y } spr_flake->setOffset(flake_state[nr][1],flake_state[nr][4]); spr_flake->setDestX(p.x + flake_state[nr][2]); spr_flake->setDestY(p.y + (flake_state[nr][3] % 160) - 160); if (mapr->collider.is_valid_position(p_flakes.x + i, p_flakes.y + j, MOVEMENT_FLYING, false)){ // fade off effect for snowflakes near the ground if (flake_state[nr][3] % 160 > 60){ spr_flake->setClipY(10); } else spr_flake->setClipY(0); render_device->render(spr_flake); } i+=density; if (i>RADIUS){ i= -RADIUS; j+=density; } nr+=1; } }
void ListWeatherCloud::renderClouds(){ //if (cycle_i > time_of_rain) renderRainfall(); renderRainfall(); // TODO: remove this line, uncomment previous if ( (clouds_arr_initialized) && (!cloud_list.empty()) ){ std::list<WeatherCloud*>::iterator it=cloud_list.begin(); WeatherCloud *cloud; Sprite *spr_cloud; Point p; FPoint fp; Point dest_p; int i, j, nr=0; i=-RADIUS; j=0; // -> with j=-RADIUS: segmentation faults quite common while (j < RADIUS){ // use a cloud from the list several times if needed if ((it == cloud_list.end())) it=cloud_list.begin(); cloud = *it; if (cloud==NULL){ it++; continue; // break; } spr_cloud = cloud->getSprite(); if (spr_cloud==NULL) break; fp.x = cloud_state[nr][4] + i; fp.y = cloud_state[nr][5] + j; if (!isWithin(mapr->cam,RADIUS + 4,fp)){ // move cloud to the opposite direction direction = calcDirection(mapr->cam.x, mapr->cam.y, fp.x, fp.y); if (direction < 4) direction +=4; else direction -=4; FPoint fpn = calcVector(fp, direction, RADIUS+24); cloud_state[nr][4] = floor(fpn.x) - i; cloud_state[nr][5] = floor(fpn.y) - j; } p = map_to_screen(cloud_state[nr][4] + i, cloud_state[nr][5] + j, mapr->cam.x, mapr->cam.y); if (cycle_i % RENDER_CHANGE_AFTER/2 == 0) { // TODO: should depend on wind direction and perhaps speed; cloud_state[nr][2] = cloud_state[nr][2] + randBetween(1,2); cloud_state[nr][3] = cloud_state[nr][3] + randBetween(1,2); direction = calcDirection(0.0,0.0, cloud_state[nr][2], cloud_state[nr][3]); } // overflow of cloud_state[nr][2] possible, but with little consequences dest_p.x = p.x + (cloud_state[nr][2] % 800) - 400; dest_p.y = p.y + (cloud_state[nr][3] % 600) - 300; spr_cloud->setOffset(cloud_state[nr][1],cloud_state[nr][1]); spr_cloud->setDest(dest_p); render_device->render(spr_cloud); i+=cloud_distance; if (i>RADIUS){ i=-RADIUS; j+=cloud_distance; } it++; nr++; } } }
/** * Show all tooltips for loot on the floor */ void LootManager::renderTooltips(const FPoint& cam) { if (!SHOW_HUD) return; Point dest; bool tooltip_below = true; std::vector<Loot>::iterator it; for (it = loot.begin(); it != loot.end(); ) { it->tip_visible = false; if (it->on_ground) { Point p = map_to_screen(it->pos.x, it->pos.y, cam.x, cam.y); dest.x = p.x; dest.y = p.y + TILE_H_HALF; // adjust dest.y so that the tooltip floats above the item dest.y -= tooltip_margin; // set hitbox for mouse hover Rect hover; hover.x = p.x - TILE_W_HALF; hover.y = p.y - TILE_H_HALF; hover.w = TILE_W; hover.h = TILE_H; if ((LOOT_TOOLTIPS && !inpt->pressing[ALT]) || (!LOOT_TOOLTIPS && inpt->pressing[ALT]) || isWithinRect(hover, inpt->mouse)) { it->tip_visible = true; // create tooltip data if needed if (it->tip.isEmpty()) { if (!it->stack.empty()) { it->tip = items->getShortTooltip(it->stack); } } // try to prevent tooltips from overlapping tip->prerender(it->tip, dest, STYLE_TOPLABEL); std::vector<Loot>::iterator test_it; for (test_it = loot.begin(); test_it != it; ) { if (rectsOverlap(test_it->tip_bounds, tip->bounds)) { if (tooltip_below) dest.y = test_it->tip_bounds.y + test_it->tip_bounds.h + TOOLTIP_OFFSET; else dest.y = test_it->tip_bounds.y - test_it->tip_bounds.h + TOOLTIP_OFFSET; tip->bounds.y = dest.y; } ++test_it; } tip->render(it->tip, dest, STYLE_TOPLABEL); it->tip_bounds = tip->bounds; // only display one tooltip if we got it from hovering if (!LOOT_TOOLTIPS && !inpt->pressing[ALT]) break; } } tooltip_below = !tooltip_below; ++it; } }
/** * Some events have a hotspot (rectangle screen area) where the user can click * to trigger the event. * * The hero must be within range (INTERACT_RANGE) to activate an event. * * This function checks valid mouse clicks against all clickable events, and * executes */ void MapRenderer::checkHotspots() { if (NO_MOUSE) return; show_tooltip = false; std::vector<Event>::iterator it; // work backwards through events because events can be erased in the loop. // this prevents the iterator from becoming invalid. for (it = events.end(); it != events.begin(); ) { --it; for (int x=it->hotspot.x; x < it->hotspot.x + it->hotspot.w; ++x) { for (int y=it->hotspot.y; y < it->hotspot.y + it->hotspot.h; ++y) { bool matched = false; bool is_npc = false; Event_Component* npc = (*it).getComponent("npc_hotspot"); if (npc) { is_npc = true; Point p = map_to_screen(float(npc->x), float(npc->y), shakycam.x, shakycam.y); p = center_tile(p); Rect dest; dest.x = p.x - npc->z; dest.y = p.y - npc->a; dest.w = npc->b; dest.h = npc->c; if (isWithin(dest, inpt->mouse)) { matched = true; tip_pos.x = dest.x + dest.w/2; tip_pos.y = p.y - npc_tooltip_margin; } } else { for (unsigned index = 0; index <= index_objectlayer; ++index) { maprow *current_layer = layers[index]; Point p = map_to_screen(float(x), float(y), shakycam.x, shakycam.y); p = center_tile(p); if (const short current_tile = current_layer[x][y]) { // first check if mouse pointer is in rectangle of that tile: Rect dest; dest.x = p.x - tset.tiles[current_tile].offset.x; dest.y = p.y - tset.tiles[current_tile].offset.y; dest.w = tset.tiles[current_tile].tile->getClip().w; dest.h = tset.tiles[current_tile].tile->getClip().h; if (isWithin(dest, inpt->mouse)) { matched = true; tip_pos = map_to_screen(it->center.x, it->center.y, shakycam.x, shakycam.y); tip_pos.y -= TILE_H; } } } } if (matched) { // skip inactive events if (!EventManager::isActive(*it)) continue; // skip events without hotspots if ((*it).hotspot.h == 0) continue; // skip events on cooldown if ((*it).cooldown_ticks != 0) continue; // new tooltip? createTooltip((*it).getComponent("tooltip")); if ((((*it).reachable_from.w == 0 && (*it).reachable_from.h == 0) || isWithin((*it).reachable_from, floor(cam))) && calcDist(cam, (*it).center) < INTERACT_RANGE) { // only check events if the player is clicking // and allowed to click if (is_npc) { curs->setCursor(CURSOR_TALK); } else { curs->setCursor(CURSOR_INTERACT); } if (!inpt->pressing[MAIN1]) return; else if (inpt->lock[MAIN1]) return; inpt->lock[MAIN1] = true; if (EventManager::executeEvent(*it)) it = events.erase(it); } return; } else show_tooltip = false; } } } }
void MapRenderer::renderIsoLayer(const unsigned short layerdata[256][256]) { int_fast16_t i; // first index of the map array int_fast16_t j; // second index of the map array Rect dest; const Point upperleft = floor(screen_to_map(0, 0, shakycam.x, shakycam.y)); const int_fast16_t max_tiles_width = (VIEW_W / TILE_W) + 2*tset.max_size_x; const int_fast16_t max_tiles_height = (2 * VIEW_H / TILE_H) + 2*tset.max_size_y; j = upperleft.y - tset.max_size_y/2 + tset.max_size_x; i = upperleft.x - tset.max_size_y/2 - tset.max_size_x; for (uint_fast16_t y = max_tiles_height ; y; --y) { int_fast16_t tiles_width = 0; // make sure the isometric corners are not rendered: // corner north west, upper left (i < 0) if (i < -1) { j += i + 1; tiles_width -= i + 1; i = -1; } // corner north east, upper right (j > mapheight) const int_fast16_t d = j - h; if (d >= 0) { j -= d; tiles_width += d; i += d; } // lower right (south east) corner is covered by (j+i-w+1) // lower left (south west) corner is caught by having 0 in there, so j>0 const int_fast16_t j_end = std::max(static_cast<int_fast16_t>(j+i-w+1), std::max(static_cast<int_fast16_t>(j - max_tiles_width), static_cast<int_fast16_t>(0))); Point p = map_to_screen(float(i), float(j), shakycam.x, shakycam.y); p = center_tile(p); // draw one horizontal line while (j > j_end) { --j; ++i; ++tiles_width; p.x += TILE_W; if (const uint_fast16_t current_tile = layerdata[i][j]) { dest.x = p.x - tset.tiles[current_tile].offset.x; dest.y = p.y - tset.tiles[current_tile].offset.y; // no need to set w and h in dest, as it is ignored // by SDL_BlitSurface tset.tiles[current_tile].tile->setDest(dest); render_device->render(tset.tiles[current_tile].tile); } } j += tiles_width; i -= tiles_width; // Go one line deeper, the starting position goes zig-zag if (y % 2) i++; else j++; } }
void MapRenderer::renderIsoFrontObjects(std::vector<Renderable> &r) { Rect dest; const Point upperleft = floor(screen_to_map(0, 0, shakycam.x, shakycam.y)); const int_fast16_t max_tiles_width = (VIEW_W / TILE_W) + 2 * tset.max_size_x; const int_fast16_t max_tiles_height = ((VIEW_H / TILE_H) + 2 * tset.max_size_y)*2; std::vector<Renderable>::iterator r_cursor = r.begin(); std::vector<Renderable>::iterator r_end = r.end(); // object layer int_fast16_t j = upperleft.y - tset.max_size_y + tset.max_size_x; int_fast16_t i = upperleft.x - tset.max_size_y - tset.max_size_x; while (r_cursor != r_end && ((int)(r_cursor->map_pos.x) + (int)(r_cursor->map_pos.y) < i + j || (int)(r_cursor->map_pos.x) < i)) // implicit floor ++r_cursor; if (index_objectlayer >= layers.size()) return; maprow *objectlayer = layers[index_objectlayer]; for (uint_fast16_t y = max_tiles_height ; y; --y) { int_fast16_t tiles_width = 0; // make sure the isometric corners are not rendered: if (i < -1) { j += i + 1; tiles_width -= i + 1; i = -1; } const int_fast16_t d = j - h; if (d >= 0) { j -= d; tiles_width += d; i += d; } const int_fast16_t j_end = std::max(static_cast<int_fast16_t>(j+i-w+1), std::max(static_cast<int_fast16_t>(j - max_tiles_width), static_cast<int_fast16_t>(0))); // draw one horizontal line Point p = map_to_screen(float(i), float(j), shakycam.x, shakycam.y); p = center_tile(p); while (j > j_end) { --j; ++i; ++tiles_width; p.x += TILE_W; if (const uint_fast16_t current_tile = objectlayer[i][j]) { dest.x = p.x - tset.tiles[current_tile].offset.x; dest.y = p.y - tset.tiles[current_tile].offset.y; tset.tiles[current_tile].tile->setDest(dest); render_device->render(tset.tiles[current_tile].tile); } // some renderable entities go in this layer while (r_cursor != r_end && ((int)r_cursor->map_pos.x == i && (int)r_cursor->map_pos.y == j)) { // implicit floor by int cast drawRenderable(r_cursor); ++r_cursor; } } j += tiles_width; i -= tiles_width; if (y % 2) i++; else j++; while (r_cursor != r_end && ((int)r_cursor->map_pos.x + (int)r_cursor->map_pos.y < i + j || (int)r_cursor->map_pos.x <= i)) // implicit floor by int cast ++r_cursor; } }