00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00031
00032
00033
00034
00035
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038 #include <string.h>
00039 #include <stdarg.h>
00040 #include <math.h>
00041 #include <sstream>
00042
00043 #include "stratagus.h"
00044 #include "video.h"
00045 #include "font.h"
00046 #include "sound.h"
00047 #include "unitsound.h"
00048 #include "unittype.h"
00049 #include "player.h"
00050 #include "unit.h"
00051 #include "upgrade.h"
00052 #include "icons.h"
00053 #include "interface.h"
00054 #include "ui.h"
00055 #include "map.h"
00056 #include "trigger.h"
00057 #include "network.h"
00058 #include "menus.h"
00059 #include "spells.h"
00060
00061
00062
00063
00064
00068 void DrawMenuButtonArea(void)
00069 {
00070 if (!IsNetworkGame()) {
00071 if (UI.MenuButton.X != -1) {
00072 DrawMenuButton(UI.MenuButton.Style,
00073 (ButtonAreaUnderCursor == ButtonAreaMenu &&
00074 ButtonUnderCursor == ButtonUnderMenu ? MI_FLAGS_ACTIVE : 0) |
00075 (GameMenuButtonClicked ? MI_FLAGS_CLICKED : 0),
00076 UI.MenuButton.X, UI.MenuButton.Y,
00077 UI.MenuButton.Text);
00078 }
00079 } else {
00080 if (UI.NetworkMenuButton.X != -1) {
00081 DrawMenuButton(UI.NetworkMenuButton.Style,
00082 (ButtonAreaUnderCursor == ButtonAreaMenu &&
00083 ButtonUnderCursor == ButtonUnderNetworkMenu ? MI_FLAGS_ACTIVE : 0) |
00084 (GameMenuButtonClicked ? MI_FLAGS_CLICKED : 0),
00085 UI.NetworkMenuButton.X, UI.NetworkMenuButton.Y,
00086 UI.NetworkMenuButton.Text);
00087 }
00088 if (UI.NetworkDiplomacyButton.X != -1) {
00089 DrawMenuButton(UI.NetworkDiplomacyButton.Style,
00090 (ButtonAreaUnderCursor == ButtonAreaMenu &&
00091 ButtonUnderCursor == ButtonUnderNetworkDiplomacy ? MI_FLAGS_ACTIVE : 0) |
00092 (GameDiplomacyButtonClicked ? MI_FLAGS_CLICKED : 0),
00093 UI.NetworkDiplomacyButton.X, UI.NetworkDiplomacyButton.Y,
00094 UI.NetworkDiplomacyButton.Text);
00095 }
00096 }
00097 }
00098
00099
00100
00101
00102
00111 static void UiDrawLifeBar(const CUnit *unit, int x, int y)
00112 {
00113
00114 y += unit->Type->Icon.Icon->G->Height;
00115 Video.FillRectangleClip(ColorBlack, x, y,
00116 unit->Type->Icon.Icon->G->Width, 7);
00117
00118 if (unit->Variable[HP_INDEX].Value) {
00119 Uint32 color;
00120 int f = (100 * unit->Variable[HP_INDEX].Value) / unit->Variable[HP_INDEX].Max;
00121
00122 if (f > 75) {
00123 color = ColorDarkGreen;
00124 } else if (f > 50) {
00125 color = ColorYellow;
00126 } else if (f > 25) {
00127 color = ColorOrange;
00128 } else {
00129 color = ColorRed;
00130 }
00131
00132 f = (f * (unit->Type->Icon.Icon->G->Width)) / 100;
00133 Video.FillRectangleClip(color, x + 1, y + 1, f, 5);
00134 }
00135 }
00136
00145 static void UiDrawManaBar(const CUnit *unit, int x, int y)
00146 {
00147
00148 y += unit->Type->Icon.Icon->G->Height;
00149 Video.FillRectangleClip(ColorBlack, x, y + 3,
00150 unit->Type->Icon.Icon->G->Width, 4);
00151
00152 if (unit->Stats->Variables[MANA_INDEX].Max) {
00153 int f = (100 * unit->Variable[MANA_INDEX].Value) / unit->Variable[MANA_INDEX].Max;
00154 f = (f * (unit->Type->Icon.Icon->G->Width)) / 100;
00155 Video.FillRectangleClip(ColorBlue, x + 1, y + 3 + 1, f, 2);
00156 }
00157 }
00158
00162 static void DrawUnitStats(const CUnit *unit)
00163 {
00164 int x = UI.InfoPanel.X;
00165 int y = UI.InfoPanel.Y;
00166 CUnitType *type = unit->Type;
00167
00168
00169 std::ostringstream armor;
00170 armor << _("Armor: ") << type->Variable[ARMOR_INDEX].Value;
00171 VideoDrawText(x + 16, y + 83, GameFont, armor.str());
00172
00173 if (type->Variable[RADAR_INDEX].Value) {
00174
00175 std::ostringstream radarRange;
00176 radarRange << _("Radar Range: ") << type->Variable[RADAR_INDEX].Value;
00177 VideoDrawText(x + 16, y + 97, GameFont, radarRange.str());
00178 } else {
00179
00180 std::ostringstream sightRange;
00181 sightRange << _("Sight Range: ") << type->Variable[SIGHTRANGE_INDEX].Value;
00182 VideoDrawText(x + 16, y + 97, GameFont, sightRange.str());
00183 }
00184
00185 if (type->CanAttack) {
00186
00187 std::ostringstream kills;
00188 kills << _("Kills: ") << "~<" << unit->Variable[KILL_INDEX].Value << "~>";
00189 VideoDrawTextCentered(x + 114, y + 52, GameFont, kills.str());
00190
00191
00192 std::ostringstream attackRange;
00193 attackRange << _("Attack Range: ") << type->Variable[ATTACKRANGE_INDEX].Value;
00194 VideoDrawText(x + 16, y + 111, GameFont, attackRange.str());
00195
00196
00197 int min_damage = std::max(1, type->Variable[PIERCINGDAMAGE_INDEX].Value / 2);
00198 int max_damage = type->Variable[PIERCINGDAMAGE_INDEX].Value + type->Variable[BASICDAMAGE_INDEX].Value;
00199 std::ostringstream damage;
00200 damage << _("Damage: ") << min_damage << "-" << max_damage;
00201 VideoDrawText(x + 16, y + 125, GameFont, damage.str());
00202 } else if (unit->Variable[MANA_INDEX].Max != 0) {
00203
00204 std::ostringstream mana;
00205 mana << _("Mana: ") << unit->Variable[MANA_INDEX].Value;
00206 VideoDrawText(x + 16, y + 111, GameFont, mana.str());
00207 }
00208 }
00209
00213 static void DrawTrainingUnits(const CUnit *unit)
00214 {
00215 if (unit->OrderCount == 1 || unit->Orders[1]->Action != UnitActionTrain) {
00216 if (!UI.SingleTrainingText.empty()) {
00217 VideoDrawText(UI.SingleTrainingTextX, UI.SingleTrainingTextY,
00218 UI.SingleTrainingFont, UI.SingleTrainingText);
00219 }
00220 if (UI.SingleTrainingButton) {
00221 CUIButton *button = UI.SingleTrainingButton;
00222 bool mouseOver = (ButtonAreaUnderCursor == ButtonAreaTraining && ButtonUnderCursor == 0);
00223
00224 unit->Orders[0]->Type->Icon.Icon->DrawUnitIcon(unit->Player, button->Style,
00225 mouseOver ? (IconActive | (MouseButtons & LeftButton)) : 0,
00226 button->X, button->Y, "");
00227 }
00228 } else {
00229 if (!UI.TrainingText.empty()) {
00230 VideoDrawTextCentered(UI.TrainingTextX, UI.TrainingTextY,
00231 UI.TrainingFont, UI.TrainingText);
00232 }
00233 if (!UI.TrainingButtons.empty()) {
00234 size_t currentButton = 0;
00235
00236 for (int i = 0; i < unit->OrderCount; ++i) {
00237 if (unit->Orders[i]->Action == UnitActionTrain && currentButton < UI.TrainingButtons.size()) {
00238 CUIButton *button = &UI.TrainingButtons[i];
00239 bool mouseOver = (ButtonAreaUnderCursor == ButtonAreaTraining && ButtonUnderCursor == i);
00240
00241 unit->Orders[i]->Type->Icon.Icon->DrawUnitIcon(unit->Player, button->Style,
00242 mouseOver ? (IconActive | (MouseButtons & LeftButton)) : 0,
00243 button->X, button->Y, "");
00244
00245 currentButton++;
00246 }
00247 }
00248 }
00249 }
00250 }
00251
00255 static void DrawTransportingUnits(const CUnit *unit)
00256 {
00257 const CUnit *insideUnit = unit->UnitInside;
00258 int currentButton = 0;
00259
00260 for (int i = 0; i < unit->InsideCount; ++i, insideUnit = insideUnit->NextContained) {
00261 if (insideUnit->Boarded && currentButton < (int)UI.TransportingButtons.size()) {
00262 CUIButton *button = &UI.TransportingButtons[currentButton];
00263 bool mouseOver = (ButtonAreaUnderCursor == ButtonAreaTransporting && ButtonUnderCursor == currentButton);
00264
00265 insideUnit->Type->Icon.Icon->DrawUnitIcon(unit->Player, button->Style,
00266 mouseOver ? (IconActive | (MouseButtons & LeftButton)) : 0,
00267 button->X, button->Y, "");
00268
00269 UiDrawLifeBar(insideUnit, button->X, button->Y);
00270
00271 if (insideUnit->Type->CanCastSpell && insideUnit->Variable[MANA_INDEX].Max) {
00272 UiDrawManaBar(insideUnit, button->X, button->Y);
00273 }
00274
00275 if (mouseOver) {
00276 UI.StatusLine.Set(insideUnit->Type->Name);
00277 }
00278
00279 ++currentButton;
00280 }
00281 }
00282 }
00283
00290 static void DrawUnitInfo(CUnit *unit)
00291 {
00292 int x = UI.InfoPanel.X;
00293 int y = UI.InfoPanel.Y;
00294 bool isEnemy = unit->IsEnemy(ThisPlayer);
00295 bool isNeutral = (unit->Player->Type == PlayerNeutral);
00296
00297 UpdateUnitVariables(unit);
00298
00299
00300 if (UI.SingleSelectedButton) {
00301 CUIButton *button = UI.SingleSelectedButton;
00302 bool mouseOver = (ButtonAreaUnderCursor == ButtonAreaSelected && ButtonUnderCursor == 0);
00303
00304 unit->Type->Icon.Icon->DrawUnitIcon(unit->Player, button->Style,
00305 mouseOver ? (IconActive | (MouseButtons & LeftButton)) : 0,
00306 button->X, button->Y, "");
00307 if (!isNeutral) {
00308 UiDrawLifeBar(unit, button->X, button->Y);
00309 }
00310 }
00311
00312
00313 VideoDrawTextCentered(x + 114, y + 25, GameFont, unit->Type->Name);
00314
00315
00316 if (!isEnemy && !isNeutral) {
00317 std::ostringstream os;
00318 os << unit->Variable[HP_INDEX].Value << "/" << unit->Variable[HP_INDEX].Max;
00319 VideoDrawTextCentered(x + 38, y + 62, SmallFont, os.str());
00320 }
00321
00322
00323 if (unit->Type->CanHarvestFrom && isNeutral) {
00324 std::string resourceName;
00325 int amount = 0;
00326
00327 for (int i = 0; i < MaxCosts; ++i) {
00328 if (unit->ResourcesHeld[i] != 0) {
00329 resourceName = DefaultResourceNames[i];
00330 amount = unit->ResourcesHeld[i] / CYCLES_PER_SECOND;
00331 break;
00332 }
00333 }
00334
00335 std::ostringstream os;
00336 os << resourceName << ": " << amount;
00337 VideoDrawTextCentered(x + 76, y + 86, GameFont, os.str());
00338 }
00339
00340
00341
00342
00343 if (NumSelected == 1 && Selected[0] == unit) {
00344
00345 if (!isEnemy && unit->Orders[0]->Action == UnitActionTrain) {
00346 DrawTrainingUnits(unit);
00347 return;
00348 }
00349
00350
00351 if (!isEnemy && unit->Type->CanTransport && unit->BoardCount) {
00352 DrawTransportingUnits(unit);
00353 return;
00354 }
00355
00356
00357 if (!isEnemy && !isNeutral &&
00358 unit->Orders[0]->Action != UnitActionBuilt) {
00359 DrawUnitStats(unit);
00360 }
00361 }
00362 }
00363
00364
00365
00366
00367
00373 void DrawResources(void)
00374 {
00375 const char *names[] = {_("Energy"), _("Magma")};
00376 char tmp[128];
00377 int totalproduction = 0;
00378 int totalrequested = 0;
00379 int i;
00380 int p = 0;
00381
00382 for (i = 0; i < MaxCosts; ++i) {
00383 sprintf_s(tmp, sizeof(tmp), "%s:+%d-%d %d/%d",
00384 names[i],
00385 ThisPlayer->ProductionRate[i],
00386 ThisPlayer->RequestedUtilizationRate[i],
00387 ThisPlayer->StoredResources[i] / CYCLES_PER_SECOND / 100,
00388 ThisPlayer->StorageCapacity[i] / CYCLES_PER_SECOND / 100);
00389 VideoDrawText(40 + 176 * i, 1, GameFont, tmp);
00390 totalproduction += ThisPlayer->ProductionRate[i];
00391 totalrequested += ThisPlayer->RequestedUtilizationRate[i];
00392 }
00393
00394 if (totalproduction + totalrequested) {
00395 p = 100 - abs(totalproduction - totalrequested) * 100 / (totalproduction + totalrequested);
00396 }
00397 sprintf_s(tmp, sizeof(tmp), "%d%%", p);
00398 VideoDrawText(400, 1, GameFont, tmp);
00399 }
00400
00401
00402
00403
00404
00405 #define MESSAGES_MAX 10
00406
00407 static char MessagesEvent[MESSAGES_MAX][64];
00408 static int MessagesEventX[MESSAGES_MAX];
00409 static int MessagesEventY[MESSAGES_MAX];
00410 static int MessagesEventCount;
00411 static int MessagesEventIndex;
00412
00413 class MessagesDisplay
00414 {
00415 public:
00416 MessagesDisplay()
00417 {
00418 CleanMessages();
00419 }
00420
00421 void UpdateMessages();
00422 void AddUniqueMessage(const char *s);
00423 void DrawMessages();
00424 void CleanMessages();
00425
00426 protected:
00427 void ShiftMessages();
00428 void AddMessage(const char *msg);
00429 bool CheckRepeatMessage(const char *msg);
00430
00431 private:
00432 char Messages[MESSAGES_MAX][128];
00433 int MessagesCount;
00434 int MessagesSameCount;
00435 int MessagesScrollY;
00436 unsigned long MessagesFrameTimeout;
00437 };
00438
00442 void MessagesDisplay::ShiftMessages()
00443 {
00444 if (MessagesCount) {
00445 --MessagesCount;
00446 for (int z = 0; z < MessagesCount; ++z) {
00447 strcpy_s(Messages[z], sizeof(Messages[z]), Messages[z + 1]);
00448 }
00449 }
00450 }
00451
00455 void MessagesDisplay::UpdateMessages()
00456 {
00457 if (!MessagesCount) {
00458 return;
00459 }
00460
00461
00462 unsigned long ticks = GetTicks();
00463 if (MessagesFrameTimeout < ticks) {
00464 ++MessagesScrollY;
00465 if (MessagesScrollY == UI.MessageFont->Height() + 1) {
00466 MessagesFrameTimeout = ticks + UI.MessageScrollSpeed * 1000;
00467 MessagesScrollY = 0;
00468 ShiftMessages();
00469 }
00470 }
00471 }
00472
00476 void MessagesDisplay::DrawMessages()
00477 {
00478
00479 if (MessagesCount) {
00480 Uint32 color = Video.MapRGB(TheScreen->format, 38, 38, 78);
00481 Video.FillTransRectangleClip(color, UI.MapArea.X + 8, UI.MapArea.Y + 8,
00482 UI.MapArea.EndX - UI.MapArea.X - 16, MessagesCount * (UI.MessageFont->Height() + 1) - MessagesScrollY, 0x80);
00483 }
00484
00485
00486 for (int z = 0; z < MessagesCount; ++z) {
00487 if (z == 0) {
00488 PushClipping();
00489 SetClipping(UI.MapArea.X + 8, UI.MapArea.Y + 8, Video.Width - 1,
00490 Video.Height - 1);
00491 }
00492 VideoDrawTextClip(UI.MapArea.X + 8,
00493 UI.MapArea.Y + 8 + z * (UI.MessageFont->Height() + 1) - MessagesScrollY,
00494 UI.MessageFont, Messages[z]);
00495 if (z == 0) {
00496 PopClipping();
00497 }
00498 }
00499 if (MessagesCount < 1) {
00500 MessagesSameCount = 0;
00501 }
00502 }
00503
00509 void MessagesDisplay::AddMessage(const char *msg)
00510 {
00511 char *ptr;
00512 char *message;
00513 char *next;
00514 unsigned long ticks = GetTicks();
00515
00516 if (!MessagesCount) {
00517 MessagesFrameTimeout = ticks + UI.MessageScrollSpeed * 1000;
00518 }
00519
00520 if (MessagesCount == MESSAGES_MAX) {
00521
00522 ShiftMessages();
00523 MessagesFrameTimeout = ticks + UI.MessageScrollSpeed * 1000;
00524 MessagesScrollY = 0;
00525 }
00526
00527 message = Messages[MessagesCount];
00528
00529 if (strlen(msg) >= sizeof(Messages[0])) {
00530 strncpy(message, msg, sizeof(Messages[0]) - 1);
00531 ptr = message + sizeof(Messages[0]) - 1;
00532 *ptr-- = '\0';
00533 next = ptr + 1;
00534 while (ptr >= message) {
00535 if (*ptr == ' ') {
00536 *ptr = '\0';
00537 next = ptr + 1;
00538 break;
00539 }
00540 --ptr;
00541 }
00542 if (ptr < message) {
00543 ptr = next - 1;
00544 }
00545 } else {
00546 strcpy_s(message, sizeof(Messages[MessagesCount]), msg);
00547 next = ptr = message + strlen(message);
00548 }
00549
00550 while (UI.MessageFont->Width(message) + 8 >= UI.MapArea.EndX - UI.MapArea.X) {
00551 while (1) {
00552 --ptr;
00553 if (*ptr == ' ') {
00554 *ptr = '\0';
00555 next = ptr + 1;
00556 break;
00557 } else if (ptr == message) {
00558 break;
00559 }
00560 }
00561
00562 if (ptr == message) {
00563 ptr = next - 1;
00564 while (UI.MessageFont->Width(message) + 8 >= UI.MapArea.EndX - UI.MapArea.X) {
00565 *--ptr = '\0';
00566 }
00567 next = ptr + 1;
00568 break;
00569 }
00570 }
00571
00572 ++MessagesCount;
00573
00574 if (strlen(msg) != (size_t)(ptr - message)) {
00575 AddMessage(msg + (next - message));
00576 }
00577 }
00578
00586 bool MessagesDisplay::CheckRepeatMessage(const char *msg)
00587 {
00588 if (MessagesCount < 1) {
00589 return false;
00590 }
00591 if (!strcmp(msg, Messages[MessagesCount - 1])) {
00592 ++MessagesSameCount;
00593 return true;
00594 }
00595 if (MessagesSameCount > 0) {
00596 char temp[128];
00597 int n;
00598
00599 n = MessagesSameCount;
00600 MessagesSameCount = 0;
00601 sprintf_s(temp, sizeof(temp), _("Last message repeated ~<%d~> times"), n + 1);
00602 AddMessage(temp);
00603 }
00604 return false;
00605 }
00606
00610 void MessagesDisplay::AddUniqueMessage(const char *s)
00611 {
00612 if (!CheckRepeatMessage(s)) {
00613 AddMessage(s);
00614 }
00615 }
00616
00620 void MessagesDisplay::CleanMessages()
00621 {
00622 MessagesCount = 0;
00623 MessagesSameCount = 0;
00624 MessagesScrollY = 0;
00625 MessagesFrameTimeout = 0;
00626
00627 MessagesEventCount = 0;
00628 MessagesEventIndex = 0;
00629 }
00630
00631 static MessagesDisplay allmessages;
00632
00636 void UpdateMessages() {
00637 allmessages.UpdateMessages();
00638 }
00639
00643 void CleanMessages()
00644 {
00645 allmessages.CleanMessages();
00646 }
00647
00651 void DrawMessages()
00652 {
00653 allmessages.DrawMessages();
00654 }
00655
00661 void SetMessage(const char *fmt, ...)
00662 {
00663 char temp[512];
00664 va_list va;
00665
00666 va_start(va, fmt);
00667 vsnprintf(temp, sizeof(temp) - 1, fmt, va);
00668 temp[sizeof(temp) - 1] = '\0';
00669 va_end(va);
00670 allmessages.AddUniqueMessage(temp);
00671 }
00672
00676 void ShiftMessagesEvent(void)
00677 {
00678 if (MessagesEventCount) {
00679 --MessagesEventCount;
00680 for (int z = 0; z < MessagesEventCount; ++z) {
00681 MessagesEventX[z] = MessagesEventX[z + 1];
00682 MessagesEventY[z] = MessagesEventY[z + 1];
00683 strcpy_s(MessagesEvent[z], sizeof(MessagesEvent[z]), MessagesEvent[z + 1]);
00684 }
00685 }
00686 }
00687
00695 void SetMessageEvent(int x, int y, const char *fmt, ...)
00696 {
00697 char temp[128];
00698 va_list va;
00699
00700 va_start(va, fmt);
00701 vsnprintf(temp, sizeof(temp) - 1, fmt, va);
00702 temp[sizeof(temp) - 1] = '\0';
00703 va_end(va);
00704 allmessages.AddUniqueMessage(temp);
00705
00706 if (MessagesEventCount == MESSAGES_MAX) {
00707 ShiftMessagesEvent();
00708 }
00709
00710 if (x != -1) {
00711 strcpy_s(MessagesEvent[MessagesEventCount], sizeof(MessagesEvent[MessagesEventCount]), temp);
00712 MessagesEventX[MessagesEventCount] = x;
00713 MessagesEventY[MessagesEventCount] = y;
00714 MessagesEventIndex = MessagesEventCount;
00715 ++MessagesEventCount;
00716 }
00717 }
00718
00722 void CenterOnMessage(void)
00723 {
00724 if (MessagesEventIndex >= MessagesEventCount) {
00725 MessagesEventIndex = 0;
00726 }
00727 if (MessagesEventCount == 0) {
00728 return;
00729 }
00730 UI.SelectedViewport->Center(
00731 MessagesEventX[MessagesEventIndex], MessagesEventY[MessagesEventIndex],
00732 TileSizeX / 2, TileSizeY / 2);
00733 SetMessage(_("~<Event: %s~>"), MessagesEvent[MessagesEventIndex]);
00734 ++MessagesEventIndex;
00735 }
00736
00737
00738
00739
00740
00741
00745 void CStatusLine::Draw(void)
00746 {
00747 if (!this->StatusLine.empty()) {
00748 PushClipping();
00749 SetClipping(this->TextX, this->TextY,
00750 this->TextX + this->Width - 1, Video.Height - 1);
00751 VideoDrawTextClip(this->TextX, this->TextY, this->Font,
00752 this->StatusLine);
00753 PopClipping();
00754 }
00755 }
00756
00762 void CStatusLine::Set(const std::string &status)
00763 {
00764 if (KeyState != KeyStateInput) {
00765 this->StatusLine = status;
00766 }
00767 }
00768
00772 void CStatusLine::Clear(void)
00773 {
00774 if (KeyState != KeyStateInput) {
00775 this->StatusLine.clear();
00776 }
00777 }
00778
00779
00780
00781
00782
00783 static int CostsMana;
00784 static int Costs[MaxCosts];
00785
00791 void DrawCosts(void)
00792 {
00793 int x = UI.StatusLine.TextX + 268;
00794 if (CostsMana) {
00795
00796 UI.Resources[EnergyCost].G->DrawFrameClip(3, x, UI.StatusLine.TextY);
00797
00798 VideoDrawNumber(x + 15, UI.StatusLine.TextY, GameFont, CostsMana);
00799 x += 60;
00800 }
00801
00802 for (int i = 0; i < MaxCosts; ++i) {
00803 if (Costs[i]) {
00804 if (UI.Resources[i].G) {
00805 UI.Resources[i].G->DrawFrameClip(UI.Resources[i].IconFrame,
00806 x, UI.StatusLine.TextY);
00807 }
00808 VideoDrawNumber(x + 15, UI.StatusLine.TextY, GameFont, Costs[i] / CYCLES_PER_SECOND);
00809 x += 60;
00810 if (x > Video.Width - 60) {
00811 break;
00812 }
00813 }
00814 }
00815 }
00816
00823 void SetCosts(int mana, const int *costs)
00824 {
00825 CostsMana = mana;
00826 if (costs) {
00827 memcpy(Costs, costs, MaxCosts * sizeof(*costs));
00828 } else {
00829 memset(Costs, 0, sizeof(Costs));
00830 }
00831 }
00832
00836 void ClearCosts(void)
00837 {
00838 SetCosts(0, NULL);
00839 }
00840
00841
00842
00843
00844
00848 static void DrawInfoPanelMultipleSelected()
00849 {
00850
00851 for (int i = 0; i < std::min(NumSelected, (int)UI.SelectedButtons.size()); ++i) {
00852 CUIButton *button = &UI.SelectedButtons[i];
00853 bool mouseOver = (ButtonAreaUnderCursor == ButtonAreaSelected && ButtonUnderCursor == i);
00854
00855 Selected[i]->Type->Icon.Icon->DrawUnitIcon(ThisPlayer, button->Style,
00856 mouseOver ? (IconActive | (MouseButtons & LeftButton)) : 0,
00857 button->X, button->Y, "");
00858 UiDrawLifeBar(Selected[i], button->X, button->Y);
00859
00860 if (mouseOver) {
00861 UI.StatusLine.Set(Selected[i]->Type->Name);
00862 }
00863 }
00864
00865
00866 if (NumSelected > (int)UI.SelectedButtons.size()) {
00867 std::ostringstream os;
00868 os << "+" << (unsigned)(NumSelected - UI.SelectedButtons.size());
00869
00870 VideoDrawText(UI.MaxSelectedTextX, UI.MaxSelectedTextY,
00871 UI.MaxSelectedFont, os.str());
00872 }
00873 }
00874
00878 static void DrawInfoPanelSingleSelected()
00879 {
00880 DrawUnitInfo(Selected[0]);
00881 if (ButtonAreaUnderCursor == ButtonAreaSelected && ButtonUnderCursor == 0) {
00882 UI.StatusLine.Set(Selected[0]->Type->Name);
00883 }
00884 }
00885
00889 static void DrawInfoPanelNoneSelected()
00890 {
00891
00892 if (UnitUnderCursor && UnitUnderCursor->IsVisible(ThisPlayer)) {
00893 DrawUnitInfo(UnitUnderCursor);
00894 return;
00895 }
00896
00897 std::string nc;
00898 std::string rc;
00899 int x = UI.InfoPanel.X + 16;
00900 int y = UI.InfoPanel.Y + 8;
00901
00902 VideoDrawText(x, y, GameFont, "Bos Wars");
00903 y += 16;
00904 VideoDrawText(x, y, GameFont, "Cycle:");
00905 VideoDrawNumber(x + 48, y, GameFont, GameCycle);
00906 VideoDrawNumber(x + 110, y, GameFont,
00907 CYCLES_PER_SECOND * VideoSyncSpeed / 100);
00908 y += 20;
00909
00910 GetDefaultTextColors(nc, rc);
00911 for (int i = 0; i < PlayerMax - 1; ++i) {
00912 if (Players[i].Type != PlayerNobody) {
00913 if (ThisPlayer->Allied & (1 << Players[i].Index)) {
00914 SetDefaultTextColors(FontGreen, rc);
00915 } else if (ThisPlayer->Enemy & (1 << Players[i].Index)) {
00916 SetDefaultTextColors(FontRed, rc);
00917 } else {
00918 SetDefaultTextColors(nc, rc);
00919 }
00920
00921 VideoDrawNumber(x + 15, y, GameFont, i);
00922
00923 Video.DrawRectangle(ColorWhite,x, y, 12, 12);
00924 Video.FillRectangle(Players[i].Color, x + 1, y + 1, 10, 10);
00925
00926 VideoDrawText(x + 27, y, GameFont,Players[i].Name);
00927 VideoDrawNumber(x + 117, y, GameFont,Players[i].Score);
00928 y += 14;
00929 }
00930 }
00931 SetDefaultTextColors(nc, rc);
00932 }
00933
00937 void CInfoPanel::Draw(void)
00938 {
00939 if (NumSelected > 1) {
00940 DrawInfoPanelMultipleSelected();
00941 } else if (NumSelected == 1) {
00942 DrawInfoPanelSingleSelected();
00943 } else {
00944 DrawInfoPanelNoneSelected();
00945 }
00946 }
00947
00948
00949
00950
00951
00955 void DrawTimer(void)
00956 {
00957 if (!GameTimer.Init) {
00958 return;
00959 }
00960
00961 int sec = GameTimer.Cycles / CYCLES_PER_SECOND % 60;
00962 int min = (GameTimer.Cycles / CYCLES_PER_SECOND / 60) % 60;
00963 int hour = (GameTimer.Cycles / CYCLES_PER_SECOND / 3600);
00964 char buf[30];
00965
00966 if (hour) {
00967 sprintf_s(buf, sizeof(buf), "%d:%02d:%02d", hour, min, sec);
00968 } else {
00969 sprintf_s(buf, sizeof(buf), "%d:%02d", min, sec);
00970 }
00971
00972 VideoDrawText(UI.Timer.X, UI.Timer.Y, UI.Timer.Font, buf);
00973 }
00974
00978 void UpdateTimer(void)
00979 {
00980 if (GameTimer.Running) {
00981 if (GameTimer.Increasing) {
00982 GameTimer.Cycles += GameCycle - GameTimer.LastUpdate;
00983 } else {
00984 GameTimer.Cycles -= GameCycle - GameTimer.LastUpdate;
00985 if (GameTimer.Cycles < 0) {
00986 GameTimer.Cycles = 0;
00987 }
00988 }
00989 GameTimer.LastUpdate = GameCycle;
00990 }
00991 }
00992