/** * Set a target depending on how a power was triggered */ FPoint MenuActionBar::setTarget(bool have_aim, bool aim_assist) { if (have_aim && MOUSE_AIM) { if (aim_assist) return screen_to_map(inpt->mouse.x, inpt->mouse.y + AIM_ASSIST, pc->stats.pos.x, pc->stats.pos.y); else return screen_to_map(inpt->mouse.x, inpt->mouse.y, pc->stats.pos.x, pc->stats.pos.y); } else { return calcVector(pc->stats.pos, pc->stats.direction, pc->stats.melee_range); } }
void MenuDevHUD::align() { std::stringstream ss; int line_width = 0; int line_height = font->getLineHeight(); ss.str(""); ss << msg->get("Player (x,y): ") << pc->stats.pos.x << ", " << pc->stats.pos.y; player_pos.set(window_area.x, window_area.y, JUSTIFY_LEFT, VALIGN_TOP, ss.str(), font->getColor("menu_normal")); line_width = std::max(line_width, player_pos.bounds.w); FPoint target = screen_to_map(inpt->mouse.x, inpt->mouse.y, pc->stats.pos.x, pc->stats.pos.y); ss.str(""); ss << msg->get("Target (x,y): ") << target.x << ", " << target.y; target_pos.set(window_area.x, window_area.y+line_height, JUSTIFY_LEFT, VALIGN_TOP, ss.str(), font->getColor("menu_normal")); line_width = std::max(line_width, target_pos.bounds.w); ss.str(""); ss << msg->get("Mouse (x,y): ") << inpt->mouse.x << ", " << inpt->mouse.y; mouse_pos.set(window_area.x, window_area.y+line_height*2, JUSTIFY_LEFT, VALIGN_TOP, ss.str(), font->getColor("menu_normal")); line_width = std::max(line_width, mouse_pos.bounds.w); window_area = original_area; window_area.w = line_width; window_area.h = line_height*3; Menu::align(); }
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; } } }
static carmen_inline void screen_to_world(carmen_point_t *p, carmen_world_point_t *wp, GtkMapViewer *map_view) { carmen_map_point_t mp; screen_to_map(p, &mp, map_view); carmen_map_to_world(&mp, wp); }
void Avatar::set_direction() { // handle direction changes if(MOUSE_MOVE) { Point target = screen_to_map(inp->mouse.x, inp->mouse.y, stats.pos.x, stats.pos.y); stats.direction = face(target.x, target.y); } else { if(inp->pressing[UP] && inp->pressing[LEFT]) stats.direction = 1; else if(inp->pressing[UP] && inp->pressing[RIGHT]) stats.direction = 3; else if(inp->pressing[DOWN] && inp->pressing[RIGHT]) stats.direction = 5; else if(inp->pressing[DOWN] && inp->pressing[LEFT]) stats.direction = 7; else if(inp->pressing[LEFT]) stats.direction = 0; else if(inp->pressing[UP]) stats.direction = 2; else if(inp->pressing[RIGHT]) stats.direction = 4; else if(inp->pressing[DOWN]) stats.direction = 6; } }
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; } }
void Avatar::set_direction() { // handle direction changes if (MOUSE_MOVE) { FPoint target = screen_to_map(inpt->mouse.x, inpt->mouse.y, stats.pos.x, stats.pos.y); stats.direction = calcDirection(stats.pos, target); } else { if (inpt->pressing[UP] && !inpt->lock[UP] && inpt->pressing[LEFT] && !inpt->lock[LEFT]) stats.direction = 1; else if (inpt->pressing[UP] && !inpt->lock[UP] && inpt->pressing[RIGHT] && !inpt->lock[RIGHT]) stats.direction = 3; else if (inpt->pressing[DOWN] && !inpt->lock[DOWN] && inpt->pressing[RIGHT] && !inpt->lock[RIGHT]) stats.direction = 5; else if (inpt->pressing[DOWN] && !inpt->lock[DOWN] && inpt->pressing[LEFT] && !inpt->lock[LEFT]) stats.direction = 7; else if (inpt->pressing[LEFT] && !inpt->lock[LEFT]) stats.direction = 0; else if (inpt->pressing[UP] && !inpt->lock[UP]) stats.direction = 2; else if (inpt->pressing[RIGHT] && !inpt->lock[RIGHT]) stats.direction = 4; else if (inpt->pressing[DOWN] && !inpt->lock[DOWN]) stats.direction = 6; // Adjust for ORTHO tilesets if (TILESET_ORIENTATION == TILESET_ORTHOGONAL && ((inpt->pressing[UP] && !inpt->lock[UP]) || (inpt->pressing[DOWN] && !inpt->lock[UP]) || (inpt->pressing[LEFT] && !inpt->lock[LEFT]) || (inpt->pressing[RIGHT] && !inpt->lock[RIGHT]))) stats.direction = static_cast<unsigned char>((stats.direction == 7) ? 0 : stats.direction + 1); } }
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; } }
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++; } }
/** * logic() * Handle a single frame. This includes: * - move the avatar based on buttons pressed * - calculate the next frame of animation * - calculate camera position based on avatar position * * @param power_index The actionbar power activated. -1 means no power. */ void Avatar::logic(int actionbar_power, bool restrictPowerUse) { Point target; int stepfx; stats.logic(); if (stats.stun_duration > 0) return; bool allowed_to_move; bool allowed_to_use_power; // check level up if (stats.level < 17 && stats.xp >= stats.xp_table[stats.level]) { stats.level++; stringstream ss; ss << "Congratulations, you have reached level " << stats.level << "! You may increase one attribute through the Character Menu."; log_msg = ss.str(); stats.recalc(); Mix_PlayChannel(-1, level_up, 0); } // check for bleeding spurt if (stats.bleed_duration % 30 == 1) { powers->activate(POWER_SPARK_BLOOD, &stats, stats.pos); } // check for bleeding to death if (stats.hp == 0 && !(stats.cur_state == AVATAR_DEAD)) { stats.cur_state = AVATAR_DEAD; } // assist mouse movement if (!inp->pressing[MAIN1]) drag_walking = false; // handle animation activeAnimation->advanceFrame(); switch(stats.cur_state) { case AVATAR_STANCE: setAnimation("stance"); // allowed to move or use powers? if (MOUSE_MOVE) { allowed_to_move = restrictPowerUse && (!inp->lock[MAIN1] || drag_walking); allowed_to_use_power = !allowed_to_move; } else { allowed_to_move = true; allowed_to_use_power = true; } // handle transitions to RUN if (allowed_to_move) set_direction(); if (pressing_move() && allowed_to_move) { if (MOUSE_MOVE && inp->pressing[MAIN1]) { inp->lock[MAIN1] = true; drag_walking = true; } if (move()) { // no collision stats.cur_state = AVATAR_RUN; } } // handle power usage if (allowed_to_use_power && actionbar_power != -1 && stats.cooldown_ticks == 0) { target = screen_to_map(inp->mouse.x, inp->mouse.y + powers->powers[actionbar_power].aim_assist, stats.pos.x, stats.pos.y); // check requirements if (powers->powers[actionbar_power].requires_mp > stats.mp) break; if (powers->powers[actionbar_power].requires_physical_weapon && !stats.wielding_physical) break; if (powers->powers[actionbar_power].requires_mental_weapon && !stats.wielding_mental) break; if (powers->powers[actionbar_power].requires_offense_weapon && !stats.wielding_offense) break; if (powers->powers[actionbar_power].requires_los && !map->collider.line_of_sight(stats.pos.x, stats.pos.y, target.x, target.y)) break; if (powers->powers[actionbar_power].requires_empty_target && !map->collider.is_empty(target.x, target.y)) break; current_power = actionbar_power; act_target.x = target.x; act_target.y = target.y; // is this a power that requires changing direction? if (powers->powers[current_power].face) { stats.direction = face(target.x, target.y); } // handle melee powers if (powers->powers[current_power].new_state == POWSTATE_SWING) { stats.cur_state = AVATAR_MELEE; break; } // handle ranged powers if (powers->powers[current_power].new_state == POWSTATE_SHOOT) { stats.cur_state = AVATAR_SHOOT; break; } // handle ment powers if (powers->powers[current_power].new_state == POWSTATE_CAST) { stats.cur_state = AVATAR_CAST; break; } if (powers->powers[current_power].new_state == POWSTATE_BLOCK) { stats.cur_state = AVATAR_BLOCK; stats.blocking = true; break; } } break; case AVATAR_RUN: setAnimation("run"); stepfx = rand() % 4; if (activeAnimation->getCurFrame() == 1 || activeAnimation->getCurFrame() == activeAnimation->getMaxFrame()/2) { Mix_PlayChannel(-1, sound_steps[stepfx], 0); } // allowed to move or use powers? if (MOUSE_MOVE) { allowed_to_use_power = !(restrictPowerUse && !inp->lock[MAIN1]); } else { allowed_to_use_power = true; } // handle direction changes set_direction(); // handle transition to STANCE if (!pressing_move()) { stats.cur_state = AVATAR_STANCE; break; } else if (!move()) { // collide with wall stats.cur_state = AVATAR_STANCE; break; } // handle power usage if (allowed_to_use_power && actionbar_power != -1 && stats.cooldown_ticks == 0) { target = screen_to_map(inp->mouse.x, inp->mouse.y + powers->powers[actionbar_power].aim_assist, stats.pos.x, stats.pos.y); // check requirements if (powers->powers[actionbar_power].requires_mp > stats.mp) break; if (powers->powers[actionbar_power].requires_physical_weapon && !stats.wielding_physical) break; if (powers->powers[actionbar_power].requires_mental_weapon && !stats.wielding_mental) break; if (powers->powers[actionbar_power].requires_offense_weapon && !stats.wielding_offense) break; if (powers->powers[actionbar_power].requires_los && !map->collider.line_of_sight(stats.pos.x, stats.pos.y, target.x, target.y)) break; if (powers->powers[actionbar_power].requires_empty_target && !map->collider.is_empty(target.x, target.y)) break; current_power = actionbar_power; act_target.x = target.x; act_target.y = target.y; // is this a power that requires changing direction? if (powers->powers[current_power].face) { stats.direction = face(target.x, target.y); } // handle melee powers if (powers->powers[current_power].new_state == POWSTATE_SWING) { stats.cur_state = AVATAR_MELEE; break; } // handle ranged powers if (powers->powers[current_power].new_state == POWSTATE_SHOOT) { stats.cur_state = AVATAR_SHOOT; break; } // handle ment powers if (powers->powers[current_power].new_state == POWSTATE_CAST) { stats.cur_state = AVATAR_CAST; break; } if (powers->powers[current_power].new_state == POWSTATE_BLOCK) { stats.cur_state = AVATAR_BLOCK; stats.blocking = true; break; } } break; case AVATAR_MELEE: setAnimation("melee"); if (activeAnimation->getCurFrame() == 1) { Mix_PlayChannel(-1, sound_melee, 0); } // do power if (activeAnimation->getCurFrame() == activeAnimation->getMaxFrame()/2) { powers->activate(current_power, &stats, act_target); } if (activeAnimation->getTimesPlayed() >= 1) { stats.cur_state = AVATAR_STANCE; if (stats.haste_duration == 0) stats.cooldown_ticks += stats.cooldown; } break; case AVATAR_CAST: setAnimation("ment"); // do power if (activeAnimation->getCurFrame() == activeAnimation->getMaxFrame()/2) { powers->activate(current_power, &stats, act_target); } if (activeAnimation->getTimesPlayed() >= 1) { stats.cur_state = AVATAR_STANCE; if (stats.haste_duration == 0) stats.cooldown_ticks += stats.cooldown; } break; case AVATAR_SHOOT: setAnimation("ranged"); // do power if (activeAnimation->getCurFrame() == activeAnimation->getMaxFrame()/2) { powers->activate(current_power, &stats, act_target); } if (activeAnimation->getTimesPlayed() >= 1) { stats.cur_state = AVATAR_STANCE; if (stats.haste_duration == 0) stats.cooldown_ticks += stats.cooldown; } break; case AVATAR_BLOCK: setAnimation("block"); if (powers->powers[actionbar_power].new_state != POWSTATE_BLOCK) { stats.cur_state = AVATAR_STANCE; stats.blocking = false; } break; case AVATAR_HIT: setAnimation("hit"); if (activeAnimation->getTimesPlayed() >= 1) { stats.cur_state = AVATAR_STANCE; } break; case AVATAR_DEAD: setAnimation("die"); if (activeAnimation->getCurFrame() == 1 && activeAnimation->getTimesPlayed() < 1) { Mix_PlayChannel(-1, sound_die, 0); log_msg = "You are defeated. You lose half your gold. Press Enter to continue."; } if (activeAnimation->getTimesPlayed() >= 1) { stats.corpse = true; } // allow respawn with Accept if (inp->pressing[ACCEPT]) { stats.hp = stats.maxhp; stats.mp = stats.maxmp; stats.alive = true; stats.corpse = false; stats.cur_state = AVATAR_STANCE; // remove temporary effects stats.clearEffects(); // set teleportation variables. GameEngine acts on these. map->teleportation = true; map->teleport_mapname = map->respawn_map; map->teleport_destination.x = map->respawn_point.x; map->teleport_destination.y = map->respawn_point.y; } break; default: break; } // calc new cam position from player position // cam is focused at player position map->cam.x = stats.pos.x; map->cam.y = stats.pos.y; map->hero_tile.x = stats.pos.x / 32; map->hero_tile.y = stats.pos.y / 32; // check for map events map->checkEvents(stats.pos); }