58
58
using Widelands::Building;
59
59
using Widelands::Map;
63
// Returns the brightness value in [0, 1.] for 'fcoords' at 'gametime' for
64
// 'pf'. See 'field_brightness' in fields_to_draw.cc for scale of values.
65
float adjusted_field_brightness(const Widelands::FCoords& fcoords,
66
const uint32_t gametime,
67
const Widelands::Player::Field& pf) {
72
uint32_t brightness = 144 + fcoords.field->get_brightness();
73
brightness = std::min<uint32_t>(255, (brightness * 255) / 160);
76
static const uint32_t kDecayTimeInMs = 20000;
77
const Widelands::Duration time_ago = gametime - pf.time_node_last_unseen;
78
if (time_ago < kDecayTimeInMs) {
79
brightness = (brightness * (2 * kDecayTimeInMs - time_ago)) / (2 * kDecayTimeInMs);
81
brightness = brightness / 2;
84
return brightness / 255.;
87
void draw_immovables_for_visible_field(const Widelands::EditorGameBase& egbase,
88
const FieldsToDraw::Field& field,
90
const TextToDraw text_to_draw,
91
const Widelands::Player& player,
93
Widelands::BaseImmovable* const imm = field.fcoords.field->get_immovable();
94
if (imm != nullptr && imm->get_positions(egbase).front() == field.fcoords) {
95
TextToDraw draw_text_for_this_immovable = text_to_draw;
96
const Widelands::Player* owner = imm->get_owner();
97
if (owner != nullptr && !player.see_all() && player.is_hostile(*owner)) {
98
draw_text_for_this_immovable =
99
static_cast<TextToDraw>(draw_text_for_this_immovable & ~TextToDraw::kStatistics);
102
egbase.get_gametime(), draw_text_for_this_immovable, field.rendertarget_pixel, scale, dst);
106
void draw_bobs_for_visible_field(const Widelands::EditorGameBase& egbase,
107
const FieldsToDraw::Field& field,
109
const TextToDraw text_to_draw,
110
const Widelands::Player& player,
112
for (Widelands::Bob* bob = field.fcoords.field->get_first_bob(); bob;
113
bob = bob->get_next_bob()) {
114
TextToDraw draw_text_for_this_bob = text_to_draw;
115
const Widelands::Player* owner = bob->get_owner();
116
if (owner != nullptr && !player.see_all() && player.is_hostile(*owner)) {
117
draw_text_for_this_bob =
118
static_cast<TextToDraw>(draw_text_for_this_bob & ~TextToDraw::kStatistics);
120
bob->draw(egbase, draw_text_for_this_bob, field.rendertarget_pixel, scale, dst);
124
void draw_immovables_for_formerly_visible_field(const FieldsToDraw::Field& field,
125
const Widelands::Player::Field& player_field,
128
if (const Widelands::MapObjectDescr* const map_object_descr =
129
player_field.map_object_descr[Widelands::TCoords<>::None]) {
130
if (player_field.constructionsite.becomes) {
131
assert(field.owner != nullptr);
132
const Widelands::ConstructionsiteInformation& csinf = player_field.constructionsite;
133
// draw the partly finished constructionsite
136
anim_idx = csinf.becomes->get_animation("build");
137
} catch (Widelands::MapObjectDescr::AnimationNonexistent&) {
139
anim_idx = csinf.becomes->get_animation("unoccupied");
140
} catch (Widelands::MapObjectDescr::AnimationNonexistent) {
141
anim_idx = csinf.becomes->get_animation("idle");
144
const Animation& anim = g_gr->animations().get_animation(anim_idx);
145
const size_t nr_frames = anim.nr_frames();
147
csinf.totaltime ? csinf.completedtime * nr_frames / csinf.totaltime : 0;
148
uint32_t tanim = cur_frame * FRAME_LENGTH;
150
uint32_t percent = 100 * csinf.completedtime * nr_frames;
151
if (csinf.totaltime) {
152
percent /= csinf.totaltime;
154
percent -= 100 * cur_frame;
156
if (cur_frame) { // not the first frame
157
// Draw the prev frame
158
dst->blit_animation(field.rendertarget_pixel, scale, anim_idx, tanim - FRAME_LENGTH,
159
field.owner->get_playercolor());
160
} else if (csinf.was) {
161
// Is the first frame, but there was another building here before,
162
// get its last build picture and draw it instead.
165
a = csinf.was->get_animation("unoccupied");
166
} catch (Widelands::MapObjectDescr::AnimationNonexistent&) {
167
a = csinf.was->get_animation("idle");
169
dst->blit_animation(field.rendertarget_pixel, scale, a, tanim - FRAME_LENGTH,
170
field.owner->get_playercolor());
172
dst->blit_animation(field.rendertarget_pixel, scale, anim_idx, tanim,
173
field.owner->get_playercolor(), percent);
174
} else if (upcast(const Widelands::BuildingDescr, building, map_object_descr)) {
175
assert(field.owner != nullptr);
176
// this is a building therefore we either draw unoccupied or idle animation
179
pic = building->get_animation("unoccupied");
180
} catch (Widelands::MapObjectDescr::AnimationNonexistent&) {
181
pic = building->get_animation("idle");
184
field.rendertarget_pixel, scale, pic, 0, field.owner->get_playercolor());
185
} else if (map_object_descr->type() == Widelands::MapObjectType::FLAG) {
186
assert(field.owner != nullptr);
187
dst->blit_animation(field.rendertarget_pixel, scale, field.owner->tribe().flag_animation(),
188
0, field.owner->get_playercolor());
189
} else if (const uint32_t pic = map_object_descr->main_animation()) {
190
if (field.owner != nullptr) {
192
field.rendertarget_pixel, scale, pic, 0, field.owner->get_playercolor());
194
dst->blit_animation(field.rendertarget_pixel, scale, pic, 0);
61
202
InteractivePlayer::InteractivePlayer(Widelands::Game& g,
62
203
Section& global_s,
63
204
Widelands::PlayerNumber const plyn,
315
void InteractivePlayer::draw(RenderTarget& dst) {
316
// Bail out if the game isn't actually loaded.
317
// This fixes a crash with displaying an error dialog during loading.
318
if (!game().is_loaded())
321
draw_map_view(map_view(), &dst);
324
void InteractivePlayer::draw_map_view(MapView* given_map_view, RenderTarget* dst) {
325
const Widelands::Player& plr = player();
326
const auto& gbase = egbase();
327
const Widelands::Map& map = gbase.map();
328
const uint32_t gametime = gbase.get_gametime();
330
auto* fields_to_draw = given_map_view->draw_terrain(gbase, dst);
331
const auto& roads_preview = road_building_preview();
333
for (size_t idx = 0; idx < fields_to_draw->size(); ++idx) {
334
auto* f = fields_to_draw->mutable_field(idx);
336
const Widelands::Player::Field& player_field =
337
plr.fields()[map.get_index(f->fcoords, map.get_width())];
339
// Adjust this field for visibility for this player.
340
if (!plr.see_all()) {
341
f->brightness = adjusted_field_brightness(f->fcoords, gametime, player_field);
342
f->roads = player_field.roads;
343
f->vision = player_field.vision;
344
if (player_field.vision == 0) {
345
// If the player cannot see the field, no need to do any more work.
347
} else if (player_field.vision == 1) {
348
f->owner = player_field.owner != 0 ? &gbase.player(player_field.owner) : nullptr;
349
f->is_border = player_field.border;
353
// Add road building overlays if applicable.
354
const auto it = roads_preview.find(f->fcoords);
355
if (it != roads_preview.end()) {
356
f->roads |= it->second;
359
const float scale = 1.f / given_map_view->view().zoom;
360
draw_border_markers(*f, scale, *fields_to_draw, dst);
362
// Render stuff that belongs to the node.
364
const auto text_to_draw = get_text_to_draw();
365
draw_immovables_for_visible_field(gbase, *f, scale, text_to_draw, plr, dst);
366
draw_bobs_for_visible_field(gbase, *f, scale, text_to_draw, plr, dst);
367
} else if (f->vision == 1) {
368
// We never show census or statistics for objects in the fog.
369
draw_immovables_for_formerly_visible_field(*f, player_field, scale, dst);
372
// TODO(sirver): Do not use the field_overlay_manager, instead draw the
373
// overlays we are interested in here directly.
374
field_overlay_manager().foreach_overlay(
375
f->fcoords, [dst, f, scale](const Image* pic, const Vector2i& hotspot) {
376
dst->blitrect_scale(Rectf(f->rendertarget_pixel - hotspot.cast<float>() * scale,
377
pic->width() * scale, pic->height() * scale),
378
pic, Recti(0, 0, pic->width(), pic->height()), 1.f,
379
BlendMode::UseAlpha);
172
384
void InteractivePlayer::popup_message(Widelands::MessageId const id,
173
385
const Widelands::Message& message) {
174
386
message_menu_.create();