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
00030
00031
00032
00033
00034
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <string.h>
00038
00039 #include "stratagus.h"
00040
00041 #include <vector>
00042
00043 #include "video.h"
00044 #include "editor.h"
00045 #include "unittype.h"
00046 #include "player.h"
00047 #include "unit.h"
00048 #include "unit_cache.h"
00049 #include "map.h"
00050 #include "construct.h"
00051 #include "cursor.h"
00052 #include "interface.h"
00053 #include "font.h"
00054 #include "ui.h"
00055 #include "script.h"
00056
00057
00058
00059
00060
00064 class Decoration {
00065 public:
00066 Decoration() : HotX(0), HotY(0), Width(0), Height(0), Sprite(NULL) {}
00067
00068 std::string File;
00069 int HotX;
00070 int HotY;
00071 int Width;
00072 int Height;
00073
00074
00075 CGraphic *Sprite;
00076 };
00077
00078
00082 class DecoSpriteType {
00083 public:
00084 std::vector<std::string> Name;
00085 std::vector<Decoration> SpriteArray;
00086 };
00087
00088 static DecoSpriteType DecoSprite;
00089
00090 unsigned long ShowOrdersCount;
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 const CViewport *CurrentViewport;
00105
00106
00107
00113 void DrawUnitSelection(const CUnit *unit)
00114 {
00115 Uint32 color;
00116
00117
00118
00119 if (Editor.Running && unit == UnitUnderCursor &&
00120 Editor.State == EditorSelecting) {
00121 color = ColorWhite;
00122 } else if (unit->Selected || unit->TeamSelected || (unit->Blink & 1)) {
00123 if (unit->Player->Index == PlayerNumNeutral) {
00124 color = ColorYellow;
00125 } else if ((unit->Selected || (unit->Blink & 1)) &&
00126 (unit->Player == ThisPlayer ||
00127 ThisPlayer->IsTeamed(unit))) {
00128 color = ColorGreen;
00129 } else if (ThisPlayer->IsEnemy(unit)) {
00130 color = ColorRed;
00131 } else {
00132 int i;
00133
00134 for (i = 0; i < PlayerMax; ++i) {
00135 if (unit->TeamSelected & (1 << i)) {
00136 break;
00137 }
00138 }
00139 if (i == PlayerMax) {
00140 color = unit->Player->Color;
00141 } else {
00142 color = Players[i].Color;
00143 }
00144 }
00145 } else if (CursorBuilding && unit->Type->Building &&
00146 unit->Orders[0]->Action != UnitActionDie &&
00147 (unit->Player == ThisPlayer || ThisPlayer->IsTeamed(unit))) {
00148
00149 color = ColorGray;
00150 } else {
00151 return;
00152 }
00153
00154 const CUnitType *type = unit->Type;
00155 int x = CurrentViewport->Map2ViewportX(unit->X) + unit->IX +
00156 type->TileWidth * TileSizeX / 2 - type->BoxWidth / 2 -
00157 (type->Width - type->Sprite->Width) / 2;
00158 int y = CurrentViewport->Map2ViewportY(unit->Y) + unit->IY +
00159 type->TileHeight * TileSizeY / 2 - type->BoxHeight / 2 -
00160 (type->Height - type->Sprite->Height) / 2;
00161
00162 DrawSelection(color, x, y, x + type->BoxWidth, y + type->BoxHeight);
00163 }
00164
00172 void DrawSelection(Uint32 color, int x1, int y1, int x2, int y2)
00173 {
00174 const int cornerPixels = 6;
00175
00176 Video.DrawVLineClip(color, x1, y1, cornerPixels);
00177 Video.DrawHLineClip(color, x1 + 1, y1, cornerPixels - 1);
00178
00179 Video.DrawVLineClip(color, x2, y1, cornerPixels);
00180 Video.DrawHLineClip(color, x2 - cornerPixels + 1, y1, cornerPixels - 1);
00181
00182 Video.DrawVLineClip(color, x1, y2 - cornerPixels + 1, cornerPixels);
00183 Video.DrawHLineClip(color, x1, y2, cornerPixels - 1);
00184
00185 Video.DrawVLineClip(color, x2, y2 - cornerPixels + 1, cornerPixels);
00186 Video.DrawHLineClip(color, x2 - cornerPixels + 1, y2, cornerPixels - 1);
00187 }
00188
00189
00197 int GetSpriteIndex(const std::string &spriteName)
00198 {
00199 int index = -1;
00200
00201 for (int i = 0; i < (int)DecoSprite.Name.size(); ++i) {
00202 if (spriteName == DecoSprite.Name[i]) {
00203 index = i;
00204 break;
00205 }
00206 }
00207 return index;
00208 }
00209
00215 static int CclDefineSprites(lua_State *l)
00216 {
00217 int args;
00218
00219 args = lua_gettop(l);
00220 for (int i = 0; i < args; ++i) {
00221 Decoration deco;
00222 const char *name = NULL;
00223
00224 lua_pushnil(l);
00225 while (lua_next(l, i + 1)) {
00226 const char *key = LuaToString(l, -2);
00227 if (!strcmp(key, "Name")) {
00228 name = LuaToString(l, -1);
00229 } else if (!strcmp(key, "File")) {
00230 deco.File = LuaToString(l, -1);
00231 } else if (!strcmp(key, "Offset")) {
00232 if (!lua_istable(l, -1) || lua_objlen(l, -1) != 2) {
00233 LuaError(l, "incorrect argument");
00234 }
00235 lua_rawgeti(l, -1, 1);
00236 lua_rawgeti(l, -2, 2);
00237 deco.HotX = LuaToNumber(l, -2);
00238 deco.HotY = LuaToNumber(l, -1);
00239 lua_pop(l, 2);
00240 } else if (!strcmp(key, "Size")) {
00241 if (!lua_istable(l, -1) || lua_objlen(l, -1) != 2) {
00242 LuaError(l, "incorrect argument");
00243 }
00244 lua_rawgeti(l, -1, 1);
00245 lua_rawgeti(l, -2, 2);
00246 deco.Width = LuaToNumber(l, -2);
00247 deco.Height = LuaToNumber(l, -1);
00248 lua_pop(l, 2);
00249 } else {
00250 LuaError(l, "incorrect field '%s' for the DefineSprite." _C_ key);
00251 }
00252 lua_pop(l, 1);
00253 }
00254 if (name == NULL) {
00255 LuaError(l, "CclDefineSprites requires the Name flag for sprite.");
00256 }
00257
00258 int index = GetSpriteIndex(name);
00259 if (index == -1) {
00260 index = DecoSprite.SpriteArray.size();
00261 DecoSprite.Name.push_back(name);
00262 DecoSprite.SpriteArray.push_back(deco);
00263 } else {
00264 DecoSprite.SpriteArray[index] = deco;
00265 }
00266
00267
00268 if (DecoSprite.SpriteArray[index].File.empty()) {
00269 LuaError(l, "CclDefineSprites requires the File flag for sprite.");
00270 }
00271
00272 }
00273 return 0;
00274 }
00275
00279 void DecorationCclRegister(void)
00280 {
00281 lua_register(Lua, "DefineSprites", CclDefineSprites);
00282 }
00283
00287 void LoadDecorations(void)
00288 {
00289 std::vector<Decoration>::iterator i;
00290 for (i = DecoSprite.SpriteArray.begin(); i != DecoSprite.SpriteArray.end(); ++i) {
00291 ShowLoadProgress("Decorations `%s'", (*i).File.c_str());
00292 (*i).Sprite = CGraphic::New((*i).File, (*i).Width, (*i).Height);
00293 (*i).Sprite->Load();
00294 }
00295 }
00296
00300 void CleanDecorations(void)
00301 {
00302 for (size_t i = 0; i < DecoSprite.SpriteArray.size(); ++i) {
00303 CGraphic::Free(DecoSprite.SpriteArray[i].Sprite);
00304 }
00305
00306 DecoSprite.Name.clear();
00307 DecoSprite.SpriteArray.clear();
00308 }
00309
00318 void CDecoVarSpriteBar::Draw(int x, int y, const CUnit *unit) const
00319 {
00320 int n;
00321 CGraphic *sprite;
00322 Decoration *decosprite;
00323
00324 Assert(unit->Variable[this->Index].Max);
00325 Assert(this->SpriteIndex != -1);
00326
00327 decosprite = &DecoSprite.SpriteArray[(int)this->SpriteIndex];
00328 sprite = decosprite->Sprite;
00329 x += decosprite->HotX;
00330 y += decosprite->HotY;
00331
00332 n = sprite->NumFrames - 1;
00333 n -= (n * unit->Variable[this->Index].Value) / unit->Variable[this->Index].Max;
00334
00335 if (this->IsCenteredInX) {
00336 x -= sprite->Width / 2;
00337 }
00338 if (this->IsCenteredInY) {
00339 y -= sprite->Height / 2;
00340 }
00341 sprite->DrawFrameClip(n, x, y);
00342 }
00343
00344 extern void UpdateUnitVariables(const CUnit *unit);
00345
00354 static void DrawDecoration(const CUnit *unit, const CUnitType *type, int x, int y)
00355 {
00356 UpdateUnitVariables(unit);
00357
00358 for (std::vector<CDecoVar *>::const_iterator i = UnitTypeVar.DecoVar.begin();
00359 i < UnitTypeVar.DecoVar.end(); ++i) {
00360 int value;
00361 int max;
00362
00363 value = unit->Variable[(*i)->Index].Value;
00364 max = unit->Variable[(*i)->Index].Max;
00365 Assert(value <= max);
00366
00367 if (!((value == max && !(*i)->ShowWhenMax) ||
00368 (!(*i)->ShowIfNotEnable && !unit->Variable[(*i)->Index].Enable) ||
00369 ((*i)->ShowOnlySelected && !unit->Selected) ||
00370 (unit->Player->Type == PlayerNeutral && (*i)->HideNeutral) ||
00371 (ThisPlayer->IsEnemy(unit) && !(*i)->ShowOpponent) ||
00372 (ThisPlayer->IsAllied(unit) && (unit->Player != ThisPlayer) && (*i)->HideAllied) ||
00373 max == 0)) {
00374 (*i)->Draw(
00375 x + (*i)->OffsetX + (*i)->OffsetXPercent * unit->Type->TileWidth * TileSizeX / 100,
00376 y + (*i)->OffsetY + (*i)->OffsetYPercent * unit->Type->TileHeight * TileSizeY / 100,
00377 unit);
00378 }
00379 }
00380
00381
00382
00383
00384 if (unit->Selected && unit->GroupId != 0) {
00385 int num;
00386 int width;
00387
00388 for (num = 0; !(unit->GroupId & (1 << num)); ++num) {
00389 ;
00390 }
00391 width = GameFont->Width(std::string(1, '0' + num));
00392 x += (type->TileWidth * TileSizeX + type->BoxWidth) / 2 - width;
00393 width = GameFont->Height();
00394 y += (type->TileHeight * TileSizeY + type->BoxHeight) / 2 - width;
00395 VideoDrawNumberClip(x, y, GameFont, num);
00396 }
00397 }
00398
00410 void DrawShadow(const CUnit *unit, const CUnitType *type, int frame,
00411 int x, int y)
00412 {
00413 if (!type) {
00414 Assert(unit);
00415 type = unit->Type;
00416 }
00417 Assert(type);
00418 Assert(!unit || unit->Type == type);
00419
00420
00421 if (unit && unit->Orders[0]->Action == UnitActionDie) {
00422 return;
00423 }
00424
00425
00426 if (type->ShadowSprite) {
00427 x -= (type->ShadowWidth - type->TileWidth * TileSizeX) / 2;
00428 y -= (type->ShadowHeight - type->TileHeight * TileSizeY) / 2;
00429 x += type->OffsetX + type->ShadowOffsetX;
00430 y += type->OffsetY + type->ShadowOffsetY;
00431
00432 if (type->Flip) {
00433 if (frame < 0) {
00434 type->ShadowSprite->DrawFrameClipX(-frame - 1, x, y);
00435 } else {
00436 type->ShadowSprite->DrawFrameClip(frame, x, y);
00437 }
00438 } else {
00439 int row = type->NumDirections / 2 + 1;
00440 if (frame < 0) {
00441 frame = ((-frame - 1) / row) * type->NumDirections + type->NumDirections - (-frame - 1) % row;
00442 } else {
00443 frame = (frame / row) * type->NumDirections + frame % row;
00444 }
00445 type->ShadowSprite->DrawFrameClip(frame, x, y);
00446 }
00447 }
00448 }
00449
00458 static void GetOrderPosition(const CUnit *unit, const COrder *order, int *x, int *y)
00459 {
00460 CUnit *goal;
00461
00462
00463 if ((goal = order->Goal) && (!goal->Removed)) {
00464
00465 *x = CurrentViewport->Map2ViewportX(goal->X) + goal->IX +
00466 goal->Type->TileWidth * TileSizeX / 2;
00467 *y = CurrentViewport->Map2ViewportY(goal->Y) + goal->IY +
00468 goal->Type->TileHeight * TileSizeY / 2;
00469 } else {
00470 if (order->X >= 0 && order->Y >= 0) {
00471
00472 *x = CurrentViewport->Map2ViewportX(order->X) + TileSizeX / 2;
00473 *y = CurrentViewport->Map2ViewportY(order->Y) + TileSizeY / 2;
00474 } else {
00475
00476
00477 *x = CurrentViewport->Map2ViewportX(unit->X) + unit->IX +
00478 unit->Type->TileWidth * TileSizeX / 2;
00479 *y = CurrentViewport->Map2ViewportY(unit->Y) + unit->IY +
00480 unit->Type->TileHeight * TileSizeY / 2;
00481 }
00482 if (order->Action == UnitActionBuild) {
00483 *x += (order->Type->TileWidth - 1) * TileSizeX / 2;
00484 *y += (order->Type->TileHeight - 1) * TileSizeY / 2;
00485 }
00486 }
00487 }
00488
00497 static void ShowSingleOrder(const CUnit *unit, int x1, int y1, const COrder *order)
00498 {
00499 int x2;
00500 int y2;
00501 Uint32 color;
00502 Uint32 e_color;
00503 bool dest;
00504
00505 GetOrderPosition(unit, order, &x2, &y2);
00506
00507 dest = false;
00508 switch (order->Action) {
00509 case UnitActionNone:
00510 e_color = color = ColorGray;
00511 break;
00512
00513 case UnitActionStill:
00514 e_color = color = ColorGray;
00515 break;
00516
00517 case UnitActionStandGround:
00518 e_color = color = ColorGreen;
00519 break;
00520
00521 case UnitActionFollow:
00522 case UnitActionMove:
00523 e_color = color = ColorGreen;
00524 dest = true;
00525 break;
00526
00527 case UnitActionPatrol:
00528 Video.DrawLineClip(ColorGreen, x1, y1, x2, y2);
00529 e_color = color = ColorBlue;
00530 x1 = CurrentViewport->Map2ViewportX(order->Arg1.Patrol.X) + TileSizeX / 2;
00531 y1 = CurrentViewport->Map2ViewportY(order->Arg1.Patrol.Y) + TileSizeY / 2;
00532 dest = true;
00533 break;
00534
00535 case UnitActionRepair:
00536 e_color = color = ColorGreen;
00537 dest = true;
00538 break;
00539
00540 case UnitActionAttackGround:
00541 x2 = CurrentViewport->Map2ViewportX(order->X) + TileSizeX / 2;
00542 y2 = CurrentViewport->Map2ViewportY(order->Y) + TileSizeY / 2;
00543
00544 case UnitActionAttack:
00545 if (unit->SubAction & 2) {
00546 e_color = ColorBlue;
00547 } else {
00548 e_color = ColorRed;
00549 }
00550 color = ColorRed;
00551 dest = true;
00552 break;
00553
00554 case UnitActionBoard:
00555 e_color = color = ColorGreen;
00556 dest = true;
00557 break;
00558
00559 case UnitActionUnload:
00560 e_color = color = ColorGreen;
00561 dest = true;
00562 break;
00563
00564 case UnitActionDie:
00565 e_color = color = ColorGray;
00566 break;
00567
00568 case UnitActionSpellCast:
00569 e_color = color = ColorBlue;
00570 dest = true;
00571 break;
00572
00573 case UnitActionTrain:
00574 e_color = color = ColorGray;
00575 break;
00576
00577 case UnitActionBuild:
00578 DrawSelection(ColorGray, x2 - order->Type->BoxWidth / 2,
00579 y2 - order->Type->BoxHeight / 2,
00580 x2 + order->Type->BoxWidth / 2,
00581 y2 + order->Type->BoxHeight / 2);
00582 e_color = color = ColorGreen;
00583 dest = true;
00584 break;
00585
00586 case UnitActionBuilt:
00587 e_color = color = ColorGray;
00588 break;
00589
00590 case UnitActionResource:
00591 e_color = color = ColorYellow;
00592 dest = true;
00593 break;
00594
00595 default:
00596 e_color = color = ColorGray;
00597 DebugPrint("Unknown action %d\n" _C_ order->Action);
00598 break;
00599 }
00600
00601 Video.FillCircleClip(color, x1, y1, 2);
00602 if (dest) {
00603 Video.DrawLineClip(color, x1, y1, x2, y2);
00604 Video.FillCircleClip(e_color, x2, y2, 3);
00605 }
00606 }
00607
00613 void ShowOrder(const CUnit *unit)
00614 {
00615 int x1;
00616 int y1;
00617 COrder *order;
00618
00619 if (unit->Destroyed) {
00620 return;
00621 }
00622
00623
00624 x1 = CurrentViewport->Map2ViewportX(
00625 unit->X) + unit->IX + unit->Type->TileWidth * TileSizeX / 2;
00626 y1 = CurrentViewport->Map2ViewportY(
00627 unit->Y) + unit->IY + unit->Type->TileHeight * TileSizeY / 2;
00628
00629
00630 if (unit->OrderCount > 1 && unit->OrderFlush) {
00631 order = unit->Orders[1];
00632 } else {
00633 order = unit->Orders[0];
00634 }
00635 ShowSingleOrder(unit, x1, y1, order);
00636
00637
00638 for (int i = 1 + (unit->OrderFlush ? 1 : 0); i < unit->OrderCount; ++i) {
00639 GetOrderPosition(unit, unit->Orders[i - 1], &x1, &y1);
00640 ShowSingleOrder(unit, x1, y1, unit->Orders[i]);
00641 }
00642
00643
00644 if (!CanMove(unit)) {
00645 ShowSingleOrder(unit, x1, y1, &unit->NewOrder);
00646 }
00647 }
00648
00659 static void DrawInformations(const CUnit *unit, const CUnitType *type, int x, int y)
00660 {
00661 const CUnitStats *stats;
00662 int r;
00663
00664 #if 0 && DEBUG // This is for showing vis counts and refs.
00665 char buf[10];
00666 sprintf_s(buf, sizeof(buf), "%d%c%c%d", unit->VisCount[ThisPlayer->Index],
00667 unit->Seen.ByPlayer & (1 << ThisPlayer->Index) ? 'Y' : 'N',
00668 unit->Seen.Destroyed & (1 << ThisPlayer->Index) ? 'Y' : 'N',
00669 unit->Refs);
00670 VideoDrawTextClip(x + 10, y + 10, 1, buf);
00671 #endif
00672
00673 stats = unit->Stats;
00674
00675
00676
00677
00678 if (NumSelected == 1 && unit->Selected) {
00679 if (Preference.ShowSightRange) {
00680
00681 Video.DrawCircleClip(ColorGreen,
00682 x + type->TileWidth * TileSizeX / 2,
00683 y + type->TileHeight * TileSizeY / 2,
00684 ((stats->Variables[SIGHTRANGE_INDEX].Max + (type->TileWidth - 1)) * TileSizeX) - 1);
00685 }
00686 if (type->CanAttack) {
00687 if (Preference.ShowReactionRange) {
00688 r = (unit->Player->Type == PlayerPerson) ?
00689 type->ReactRangePerson : type->ReactRangeComputer;
00690 if (r) {
00691 Video.DrawCircleClip(ColorBlue,
00692 x + type->TileWidth * TileSizeX / 2,
00693 y + type->TileHeight * TileSizeY / 2,
00694 (r + (type->TileWidth - 1)) * TileSizeX);
00695 }
00696 }
00697 if (Preference.ShowAttackRange && stats->Variables[ATTACKRANGE_INDEX].Max) {
00698
00699 Video.DrawCircleClip(ColorRed,
00700 x + type->TileWidth * TileSizeX / 2,
00701 y + type->TileHeight * TileSizeY / 2,
00702 (stats->Variables[ATTACKRANGE_INDEX].Max + (type->TileWidth - 1)) * TileSizeX + 1);
00703 }
00704 }
00705 }
00706
00707
00708 if (unit->Orders[0]->Action != UnitActionDie && unit->IsVisible(ThisPlayer)) {
00709 DrawDecoration(unit, type, x, y);
00710 }
00711 }
00712
00722 static void DrawConstructionShadow(const CUnit *unit, const CConstructionFrame *cframe,
00723 int frame, int x, int y)
00724 {
00725 if (cframe->File == ConstructionFileConstruction) {
00726 if (unit->Type->Construction->ShadowSprite) {
00727 x -= (unit->Type->Construction->Width - unit->Type->TileWidth * TileSizeX) / 2;
00728 x += unit->Type->OffsetX;
00729 y -= (unit->Type->Construction->Height - unit->Type->TileHeight * TileSizeY )/ 2;
00730 y += unit->Type->OffsetY;
00731 if (frame < 0) {
00732 unit->Type->Construction->ShadowSprite->DrawFrameClipX(
00733 -frame - 1, x, y);
00734 } else {
00735 unit->Type->Construction->ShadowSprite->DrawFrameClip(
00736 frame, x, y);
00737 }
00738 }
00739 } else {
00740 if (unit->Type->ShadowSprite) {
00741 x -= (unit->Type->ShadowWidth - unit->Type->TileWidth * TileSizeX) / 2;
00742 x += unit->Type->ShadowOffsetX + unit->Type->OffsetX;
00743 y -= (unit->Type->ShadowHeight - unit->Type->TileHeight * TileSizeY) / 2;
00744 y += unit->Type->ShadowOffsetY + unit->Type->OffsetY;
00745 if (frame < 0) {
00746 unit->Type->ShadowSprite->DrawFrameClipX(-frame - 1, x, y);
00747 } else {
00748 unit->Type->ShadowSprite->DrawFrameClip(frame, x, y);
00749 }
00750 }
00751 }
00752 }
00753
00764 static void DrawConstruction(const CUnit *unit, const CConstructionFrame *cframe,
00765 const CUnitType *type, int frame, int x, int y)
00766 {
00767 int player;
00768
00769 player = unit->RescuedFrom ? unit->RescuedFrom->Index : unit->Player->Index;
00770 if (cframe->File == ConstructionFileConstruction) {
00771 const CConstruction *construction;
00772
00773 construction = type->Construction;
00774 x -= construction->Width / 2;
00775 y -= construction->Height / 2;
00776 if (frame < 0) {
00777 construction->Sprite->DrawPlayerColorFrameClipX(player, -frame - 1, x, y);
00778 } else {
00779 construction->Sprite->DrawPlayerColorFrameClip(player, frame, x, y);
00780 }
00781 } else {
00782 x += type->OffsetX - type->Width / 2;
00783 y += type->OffsetY - type->Height / 2;
00784 if (frame < 0) {
00785 frame = -frame - 1;
00786 }
00787 type->Sprite->DrawPlayerColorFrameClip(player, frame, x, y);
00788 }
00789 }
00790
00794 void CUnit::Draw() const
00795 {
00796 int x;
00797 int y;
00798 int frame;
00799 int state;
00800 int constructed;
00801 CConstructionFrame *cframe;
00802 CUnitType *type;
00803
00804 if (this->Type->Revealer) {
00805 return;
00806 }
00807
00808
00809 Assert(ReplayRevealMap || this->Type->VisibleUnderFog || this->IsVisible(ThisPlayer));
00810
00811 if (ReplayRevealMap || this->IsVisible(ThisPlayer)) {
00812 type = this->Type;
00813 frame = this->Frame;
00814 y = this->IY;
00815 x = this->IX;
00816 x += CurrentViewport->Map2ViewportX(this->X);
00817 y += CurrentViewport->Map2ViewportY(this->Y);
00818 state = (this->Orders[0]->Action == UnitActionBuilt);
00819 constructed = this->Constructed;
00820
00821 if (state == 2) {
00822 type = this->Orders[0]->Type;
00823 }
00824
00825 cframe = this->Data.Built.Frame;
00826 } else {
00827 y = this->Seen.IY;
00828 x = this->Seen.IX;
00829 x += CurrentViewport->Map2ViewportX(this->Seen.X);
00830 y += CurrentViewport->Map2ViewportY(this->Seen.Y);
00831 frame = this->Seen.Frame;
00832 type = this->Seen.Type;
00833 constructed = this->Seen.Constructed;
00834 state = this->Seen.State;
00835 cframe = this->Seen.CFrame;
00836 }
00837
00838 if (!this->IsVisible(ThisPlayer) && frame == UnitNotSeen) {
00839 DebugPrint("FIXME: Something is wrong, unit %d not seen but drawn time %lu?.\n" _C_
00840 this->Slot _C_ GameCycle);
00841 return;
00842 }
00843
00844
00845 if (state == 1 && constructed) {
00846 DrawConstructionShadow(this, cframe, frame, x, y);
00847 } else {
00848 DrawShadow(this, NULL, frame, x, y);
00849 }
00850
00851
00852
00853
00854 DrawUnitSelection(this);
00855
00856
00857
00858
00859
00860 if (state == 1) {
00861 if (constructed) {
00862 DrawConstruction(this, cframe, type, frame,
00863 x + (type->TileWidth * TileSizeX) / 2,
00864 y + (type->TileHeight * TileSizeY) / 2);
00865 }
00866
00867
00868
00869 } else if (state == 2) {
00870
00871 DrawUnitType(type, type->Sprite,
00872 this->RescuedFrom ? this->RescuedFrom->Index : this->Player->Index,
00873 frame < 0 ? -1 - 1 : 1, x, y);
00874 } else {
00875 DrawUnitType(type, type->Sprite,
00876 this->RescuedFrom ? this->RescuedFrom->Index : this->Player->Index,
00877 frame, x, y);
00878 }
00879
00880
00881 DrawInformations(this, type, x, y);
00882 }
00883
00892 static int DrawLevelCompare(const void *v1, const void *v2) {
00893
00894 const CUnit *c1, *c2;
00895 int drawlevel1, drawlevel2;
00896 int diffpos;
00897
00898 c1 = *(CUnit **)v1;
00899 c2 = *(CUnit **)v2;
00900
00901 if (c1->Orders[0]->Action == UnitActionDie && c1->Type->CorpseType) {
00902 drawlevel1 = c1->Type->CorpseType->DrawLevel;
00903 } else {
00904 drawlevel1 = c1->Type->DrawLevel;
00905 }
00906 if (c2->Orders[0]->Action == UnitActionDie && c2->Type->CorpseType) {
00907 drawlevel2 = c2->Type->CorpseType->DrawLevel;
00908 } else {
00909 drawlevel2 = c2->Type->DrawLevel;
00910 }
00911
00912 if (drawlevel1 == drawlevel2) {
00913
00914
00915
00916 diffpos = c1->Y * TileSizeY + c1->IY + c1->Type->Height -
00917 (c2->Y * TileSizeY + c2->IY + c2->Type->Height);
00918 return diffpos ? diffpos : c1->X - c2->X ? c1->X - c2->X : c1->Slot - c2->Slot;
00919 } else {
00920 return drawlevel1 <= drawlevel2 ? -1 : 1;
00921 }
00922 }
00930 int FindAndSortUnits(const CViewport *vp, CUnit **table, int tablesize)
00931 {
00932
00933
00934
00935 int n = UnitCache.Select(vp->MapX - 1, vp->MapY - 1, vp->MapX + vp->MapWidth + 1,
00936 vp->MapY + vp->MapHeight + 1, table, tablesize);
00937
00938 for (int i = 0; i < n; ++i) {
00939 if (!table[i]->IsVisibleInViewport(vp)) {
00940 table[i--] = table[--n];
00941 }
00942 }
00943
00944 if (n) {
00945 qsort((void *)table, n, sizeof(CUnit *), DrawLevelCompare);
00946 }
00947
00948 return n;
00949 }
00950