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 #define ICON_SIZE_X (UI.ButtonPanel.Buttons[0].Style->Width)
00032 #define ICON_SIZE_Y (UI.ButtonPanel.Buttons[0].Style->Height)
00033
00034
00035
00036
00037
00038 #include <stdio.h>
00039 #include <stdlib.h>
00040 #include <ctype.h>
00041
00042 #include "stratagus.h"
00043 #include "video.h"
00044 #include "map.h"
00045 #include "sound.h"
00046 #include "unitsound.h"
00047 #include "unittype.h"
00048 #include "player.h"
00049 #include "unit.h"
00050 #include "missile.h"
00051 #include "commands.h"
00052 #include "minimap.h"
00053 #include "font.h"
00054 #include "cursor.h"
00055 #include "interface.h"
00056 #include "menus.h"
00057 #include "sound.h"
00058 #include "ui.h"
00059 #include "network.h"
00060 #include "spells.h"
00061 #include "widgets.h"
00062
00063
00064
00065
00066
00067 int MouseButtons;
00068
00069 int KeyModifiers;
00070
00071 CUnit *UnitUnderCursor;
00072 int ButtonAreaUnderCursor = -1;
00073 int ButtonUnderCursor = -1;
00074 bool GameMenuButtonClicked;
00075 bool GameDiplomacyButtonClicked;
00076 bool LeaveStops;
00077
00078 enum _cursor_on_ CursorOn = CursorOnUnknown;
00079
00080
00081
00082
00083 static void HandlePieMenuMouseSelection(void);
00084
00088 void CancelBuildingMode(void)
00089 {
00090 CursorBuilding = NULL;
00091 UI.StatusLine.Clear();
00092 ClearCosts();
00093 CurrentButtonLevel = 0;
00094 UI.ButtonPanel.Update();
00095 }
00096
00103 void DoRightButton(int sx, int sy)
00104 {
00105 int i;
00106 int x;
00107 int y;
00108 CUnit *dest;
00109 CUnit *unit;
00110 CUnitType *type;
00111 int action;
00112 int acknowledged;
00113 int flush;
00114 unsigned int spellnum;
00115
00116
00117 if (!NumSelected) {
00118 return;
00119 }
00120
00121 x = sx / TileSizeX;
00122 y = sy / TileSizeY;
00123
00124
00125
00126
00127 flush = !(KeyModifiers & ModifierShift);
00128
00129 if (UnitUnderCursor && !UnitUnderCursor->Type->Decoration) {
00130 dest = UnitUnderCursor;
00131 } else {
00132 dest = NULL;
00133 }
00134
00135
00136
00137
00138
00139
00140 if (!CanSelectMultipleUnits(Selected[0]->Player)) {
00141 unit = Selected[0];
00142 if (unit->Player->Index != PlayerNumNeutral || dest == NULL ||
00143 !(dest->Player == ThisPlayer || dest->IsTeamed(ThisPlayer))) {
00144 return;
00145 }
00146
00147 if (dest->Type->Harvester && unit->Type->CanHarvestFrom) {
00148 unit->Blink = 4;
00149 SendCommandResource(dest, unit, flush);
00150 return;
00151 }
00152 return;
00153 }
00154
00155 if (dest && dest->Type->CanTransport) {
00156 for (i = 0; i < NumSelected; i++) {
00157 if (CanTransport(dest, Selected[i])) {
00158
00159
00160
00161
00162
00163
00164
00165 SendCommandStopUnit(dest);
00166 break;
00167 }
00168 }
00169 }
00170
00171 acknowledged = 0;
00172 for (i = 0; i < NumSelected; ++i) {
00173 unit = Selected[i];
00174
00175 if (unit == dest) {
00176 continue;
00177 }
00178 Assert(unit);
00179 if (!acknowledged) {
00180 PlayUnitSound(unit, VoiceAcknowledging);
00181 acknowledged = 1;
00182 }
00183 type = unit->Type;
00184 action = type->MouseAction;
00185
00186
00187
00188
00189 if ((KeyModifiers & ModifierControl) && dest) {
00190 dest->Blink = 4;
00191 SendCommandFollow(unit, dest, flush);
00192 continue;
00193 }
00194
00195
00196
00197
00198 if (dest) {
00199
00200 if (dest->Type->CanTransport) {
00201
00202 if (CanMove(dest) && CanTransport(dest, unit)) {
00203 DebugPrint("Send command follow\n");
00204
00205 SendCommandFollow(dest, unit, 0);
00206 }
00207
00208 if (!CanMove(unit) || CanTransport(dest, unit)) {
00209 dest->Blink = 4;
00210 DebugPrint("Board transporter\n");
00211 SendCommandBoard(unit, -1, -1, dest, flush);
00212 continue;
00213 }
00214 }
00215
00216
00217 if (CanTransport(unit, dest)) {
00218
00219 if (CanMove(unit)) {
00220 DebugPrint("Send command follow\n");
00221
00222 SendCommandFollow(unit, dest, 0);
00223 } else if (!CanMove(dest)) {
00224 DebugPrint("Want to transport but no unit can move\n");
00225 continue;
00226 }
00227 dest->Blink = 4;
00228 DebugPrint("Board transporter\n");
00229 SendCommandBoard(dest, -1, -1, unit, flush);
00230 continue;
00231 }
00232 }
00233
00234
00235
00236
00237 if (action == MouseActionHarvest) {
00238
00239 if (type->RepairRange && dest &&
00240 dest->Type->RepairHP &&
00241 dest->Variable[HP_INDEX].Value < dest->Variable[HP_INDEX].Max &&
00242 (dest->Player == unit->Player || unit->IsAllied(dest))) {
00243 dest->Blink = 4;
00244 SendCommandRepair(unit, x, y, dest, flush);
00245 continue;
00246 }
00247
00248 if (type->Harvester) {
00249 if (dest) {
00250
00251 if (dest->Type->CanHarvestFrom && type->Harvester &&
00252 dest->Player->Index == PlayerNumNeutral) {
00253 dest->Blink = 4;
00254 SendCommandResource(unit, dest, flush);
00255 continue;
00256 }
00257 }
00258 }
00259
00260 if (UnitUnderCursor && dest && dest != unit &&
00261 (dest->Player == unit->Player || unit->IsAllied(dest))) {
00262 dest->Blink = 4;
00263 SendCommandFollow(unit, dest, flush);
00264 continue;
00265 }
00266
00267 SendCommandMove(unit, x, y, flush);
00268 continue;
00269 }
00270
00271
00272
00273
00274 if (action == MouseActionSpellCast || action == MouseActionAttack) {
00275 if (dest && unit->Orders[0]->Action != UnitActionBuilt) {
00276 if (unit->IsEnemy(dest)) {
00277 dest->Blink = 4;
00278 if (action == MouseActionSpellCast) {
00279
00280 Assert(unit->Type->CanCastSpell);
00281 for (spellnum = 0; !type->CanCastSpell[spellnum] &&
00282 spellnum < SpellTypeTable.size() ; spellnum++) ;
00283 SendCommandSpellCast(unit, x, y, dest, spellnum, flush);
00284 } else {
00285 if (CanTarget(type, dest->Type)) {
00286 SendCommandAttack(unit, x, y, dest, flush);
00287 } else {
00288
00289 SendCommandAttack(unit, x, y, NoUnitP, flush);
00290 }
00291 }
00292 continue;
00293 }
00294
00295 if ((dest->Player == unit->Player || unit->IsAllied(dest)) &&
00296 dest != unit) {
00297 dest->Blink = 4;
00298 SendCommandFollow(unit, dest, flush);
00299 continue;
00300 }
00301
00302 }
00303
00304
00305 if ((KeyModifiers & ModifierControl)) {
00306 if (RightButtonAttacks) {
00307 SendCommandMove(unit, x, y, flush);
00308 } else {
00309 SendCommandAttack(unit, x, y, NoUnitP, flush);
00310 }
00311 } else {
00312 if (RightButtonAttacks) {
00313 SendCommandAttack(unit, x, y, NoUnitP, flush);
00314 } else {
00315
00316 SendCommandMove(unit, x, y, flush);
00317 }
00318 }
00319
00320 continue;
00321 }
00322
00323
00324 if ((action == MouseActionMove || action == MouseActionSail) &&
00325 (dest && dest != unit) &&
00326 (dest->Player == unit->Player || unit->IsAllied(dest))) {
00327 dest->Blink = 4;
00328 SendCommandFollow(unit, dest, flush);
00329 continue;
00330 }
00331
00332
00333 if (dest && dest->Type->Harvester) {
00334
00335 if (type->CanHarvestFrom && dest->Type->Harvester &&
00336 dest->Player == unit->Player) {
00337 unit->Blink = 4;
00338 SendCommandResource(dest, unit, flush);
00339 continue;
00340 }
00341 }
00342
00343
00344 if (!CanMove(unit)) {
00345
00346 if (dest && dest->Type->CanHarvestFrom &&
00347 (dest->Player == unit->Player || dest->Player->Index == PlayerNumNeutral)) {
00348 dest->Blink = 4;
00349 SendCommandResource(unit, dest, flush);
00350 continue;
00351 }
00352 }
00353
00354 SendCommandMove(unit, x, y, flush);
00355 }
00356 ShowOrdersCount = GameCycle + Preference.ShowOrders * CYCLES_PER_SECOND;
00357 }
00358
00368 static inline bool OnButton(int x, int y, CUIButton *button)
00369 {
00370 return x >= button->X && x < button->X + button->Style->Width &&
00371 y >= button->Y && y < button->Y + button->Style->Height;
00372 }
00373
00385 static inline bool OnGraphic(int x, int y, CGraphic *g, int gx, int gy)
00386 {
00387 x -= gx;
00388 y -= gy;
00389 if (x >= 0 && x < g->Width && y >= 0 && y < g->Height) {
00390 return !g->TransparentPixel(x, y);
00391 }
00392 return false;
00393 }
00394
00401 static void HandleMouseOn(int x, int y)
00402 {
00403 int i;
00404 bool on_ui;
00405
00406 MouseScrollState = ScrollNone;
00407 ButtonAreaUnderCursor = -1;
00408 ButtonUnderCursor = -1;
00409
00410
00411 if (BigMapMode) {
00412 CursorOn = CursorOnMap;
00413
00414
00415
00416 HandleMouseScrollArea(x, y);
00417 return;
00418 }
00419
00420
00421
00422 if (!IsNetworkGame()) {
00423 if (UI.MenuButton.X != -1) {
00424 if (OnButton(x, y, &UI.MenuButton)) {
00425 ButtonAreaUnderCursor = ButtonAreaMenu;
00426 ButtonUnderCursor = ButtonUnderMenu;
00427 CursorOn = CursorOnButton;
00428 return;
00429 }
00430 }
00431 } else {
00432 if (UI.NetworkMenuButton.X != -1) {
00433 if (OnButton(x, y, &UI.NetworkMenuButton)) {
00434 ButtonAreaUnderCursor = ButtonAreaMenu;
00435 ButtonUnderCursor = ButtonUnderNetworkMenu;
00436 CursorOn = CursorOnButton;
00437 return;
00438 }
00439 }
00440 if (UI.NetworkDiplomacyButton.X != -1) {
00441 if (OnButton(x, y, &UI.NetworkDiplomacyButton)) {
00442 ButtonAreaUnderCursor = ButtonAreaMenu;
00443 ButtonUnderCursor = ButtonUnderNetworkDiplomacy;
00444 CursorOn = CursorOnButton;
00445 return;
00446 }
00447 }
00448 }
00449 for (i = 0; i < (int)UI.ButtonPanel.Buttons.size(); ++i) {
00450 if (OnButton(x, y, &UI.ButtonPanel.Buttons[i])) {
00451 ButtonAreaUnderCursor = ButtonAreaButton;
00452 if (CurrentButtons && CurrentButtons[i].Pos != -1) {
00453 ButtonUnderCursor = i;
00454 CursorOn = CursorOnButton;
00455 return;
00456 }
00457 }
00458 }
00459 if (NumSelected == 1 && Selected[0]->Type->CanTransport &&
00460 Selected[0]->BoardCount) {
00461 i = Selected[0]->BoardCount < (int)UI.TransportingButtons.size() ?
00462 Selected[0]->BoardCount - 1 : (int)UI.TransportingButtons.size() - 1;
00463 for (; i >= 0; --i) {
00464 if (OnButton(x, y, &UI.TransportingButtons[i])) {
00465 ButtonAreaUnderCursor = ButtonAreaTransporting;
00466 ButtonUnderCursor = i;
00467 CursorOn = CursorOnButton;
00468 return;
00469 }
00470 }
00471 }
00472 if (NumSelected == 1) {
00473 if (Selected[0]->Orders[0]->Action == UnitActionTrain) {
00474 if (Selected[0]->OrderCount == 1) {
00475 if (OnButton(x, y, UI.SingleTrainingButton)) {
00476 ButtonAreaUnderCursor = ButtonAreaTraining;
00477 ButtonUnderCursor = 0;
00478 CursorOn = CursorOnButton;
00479 return;
00480 }
00481 } else {
00482 i = Selected[0]->OrderCount < (int)UI.TrainingButtons.size() ?
00483 Selected[0]->OrderCount - 1 : UI.TrainingButtons.size() - 1;
00484 for (; i >= 0; --i) {
00485 if (Selected[0]->Orders[i]->Action == UnitActionTrain &&
00486 OnButton(x, y, &UI.TrainingButtons[i])) {
00487 ButtonAreaUnderCursor = ButtonAreaTraining;
00488 ButtonUnderCursor = i;
00489 CursorOn = CursorOnButton;
00490 return;
00491 }
00492 }
00493 }
00494 }
00495 }
00496 if (NumSelected == 1) {
00497 if (UI.SingleSelectedButton && OnButton(x, y, UI.SingleSelectedButton)) {
00498 ButtonAreaUnderCursor = ButtonAreaSelected;
00499 ButtonUnderCursor = 0;
00500 CursorOn = CursorOnButton;
00501 return;
00502 }
00503 } else {
00504 i = NumSelected > (int)UI.SelectedButtons.size() ?
00505 UI.SelectedButtons.size() - 1 : NumSelected - 1;
00506 for (; i >= 0; --i) {
00507 if (OnButton(x, y, &UI.SelectedButtons[i])) {
00508 ButtonAreaUnderCursor = ButtonAreaSelected;
00509 ButtonUnderCursor = i;
00510 CursorOn = CursorOnButton;
00511 return;
00512 }
00513 }
00514 }
00515
00516
00517
00518
00519 if (x >= UI.Minimap.X && x < UI.Minimap.X + UI.Minimap.W &&
00520 y >= UI.Minimap.Y && y < UI.Minimap.Y + UI.Minimap.H) {
00521 CursorOn = CursorOnMinimap;
00522 return;
00523 }
00524
00525
00526
00527
00528 on_ui = false;
00529 for (i = 0; i < (int)UI.Fillers.size(); ++i) {
00530 if (OnGraphic(x, y, UI.Fillers[i].G, UI.Fillers[i].X, UI.Fillers[i].Y)) {
00531 on_ui = true;
00532 break;
00533 }
00534 }
00535
00536
00537
00538
00539 if (!on_ui && x >= UI.MapArea.X && x <= UI.MapArea.EndX &&
00540 y >= UI.MapArea.Y && y <= UI.MapArea.EndY) {
00541 CViewport *vp;
00542
00543 vp = GetViewport(x, y);
00544 Assert(vp);
00545
00546 if (UI.MouseViewport != vp) {
00547 UI.MouseViewport = vp;
00548 DebugPrint("current viewport changed to %ld.\n" _C_
00549 static_cast<long int>(vp - UI.Viewports));
00550 }
00551
00552
00553 CursorOn = CursorOnMap;
00554 } else {
00555 CursorOn = CursorOnUnknown;
00556 }
00557
00558
00559
00560
00561 HandleMouseScrollArea(x, y);
00562 }
00563
00570 void HandleMouseExit(void)
00571 {
00572
00573 if (!LeaveStops) {
00574 return;
00575 }
00576
00577 CursorOn = CursorOnUnknown;
00578
00579
00580 KeyScrollState = MouseScrollState = ScrollNone;
00581
00582
00583
00584 CursorX = Video.Width / 2;
00585 CursorY = Video.Height / 2;
00586 GameCursor = UI.Point.Cursor;
00587 }
00588
00592 void RestrictCursorToViewport(void)
00593 {
00594 if (CursorX < UI.SelectedViewport->X) {
00595 CursorStartX = UI.SelectedViewport->X;
00596 } else if (CursorX >= UI.SelectedViewport->EndX) {
00597 CursorStartX = UI.SelectedViewport->EndX - 1;
00598 } else {
00599 CursorStartX = CursorX;
00600 }
00601
00602 if (CursorY < UI.SelectedViewport->Y) {
00603 CursorStartY = UI.SelectedViewport->Y;
00604 } else if (CursorY >= UI.SelectedViewport->EndY) {
00605 CursorStartY = UI.SelectedViewport->EndY - 1;
00606 } else {
00607 CursorStartY = CursorY;
00608 }
00609
00610 UI.MouseWarpX = CursorX = CursorStartX;
00611 UI.MouseWarpY = CursorY = CursorStartY;
00612 CursorOn = CursorOnMap;
00613 }
00614
00618 void RestrictCursorToMinimap(void)
00619 {
00620 if (CursorX < UI.Minimap.X) {
00621 CursorStartX = UI.Minimap.X;
00622 } else if (CursorX >= UI.Minimap.X + UI.Minimap.W) {
00623 CursorStartX = UI.Minimap.X + UI.Minimap.W - 1;
00624 } else {
00625 CursorStartX = CursorX;
00626 }
00627
00628 if (CursorY < UI.Minimap.Y) {
00629 CursorStartY = UI.Minimap.Y;
00630 } else if (CursorY >= UI.Minimap.Y + UI.Minimap.H) {
00631 CursorStartY = UI.Minimap.Y + UI.Minimap.H - 1;
00632 } else {
00633 CursorStartY = CursorY;
00634 }
00635
00636 CursorX = UI.MouseWarpX = CursorStartX;
00637 CursorY = UI.MouseWarpY = CursorStartY;
00638 CursorOn = CursorOnMinimap;
00639 }
00640
00647 void MouseScrollMap(int x, int y)
00648 {
00649 int speed;
00650
00651 if (KeyModifiers & ModifierControl) {
00652 speed = UI.MouseScrollSpeedControl;
00653 } else {
00654 speed = UI.MouseScrollSpeedDefault;
00655 }
00656
00657 UI.MouseViewport->Set(UI.MouseViewport->MapX, UI.MouseViewport->MapY,
00658 UI.MouseViewport->OffsetX + speed * (x - CursorStartX),
00659 UI.MouseViewport->OffsetY + speed * (y - CursorStartY));
00660 UI.MouseWarpX = CursorStartX;
00661 UI.MouseWarpY = CursorStartY;
00662 }
00663
00670 void UIHandleMouseMove(int x, int y)
00671 {
00672 int mx;
00673 int my;
00674 enum _cursor_on_ OldCursorOn;
00675
00676 OldCursorOn = CursorOn;
00677
00678
00679
00680 if (CursorState == CursorStateRectangle) {
00681
00682 if (CursorX < UI.SelectedViewport->X) {
00683 CursorX = UI.SelectedViewport->X;
00684 } else if (CursorX >= UI.SelectedViewport->EndX) {
00685 CursorX = UI.SelectedViewport->EndX - 1;
00686 }
00687 if (CursorY < UI.SelectedViewport->Y) {
00688 CursorY = UI.SelectedViewport->Y;
00689 } else if (CursorY >= UI.SelectedViewport->EndY) {
00690 CursorY = UI.SelectedViewport->EndY - 1;
00691 }
00692 UI.MouseWarpX = CursorX;
00693 UI.MouseWarpY = CursorY;
00694 return;
00695 }
00696
00697
00698
00699
00700 if (GameCursor == UI.Scroll.Cursor) {
00701 MouseScrollMap(x, y);
00702 return;
00703 }
00704
00705 UnitUnderCursor = NULL;
00706 GameCursor = UI.Point.Cursor;
00707 HandleMouseOn(x, y);
00708
00709
00710
00711
00712 if (CursorState == CursorStatePieMenu && CursorOn == CursorOnMap) {
00713 if (CursorX - CursorStartX > UI.PieMenu.X[2]) {
00714 CursorStartX = CursorX - UI.PieMenu.X[2];
00715 }
00716 if (CursorStartX - CursorX > UI.PieMenu.X[2]) {
00717 CursorStartX = CursorX + UI.PieMenu.X[2];
00718 }
00719 if (CursorStartY - CursorY > UI.PieMenu.Y[4]) {
00720 CursorStartY = CursorY + UI.PieMenu.Y[4];
00721 }
00722 if (CursorY - CursorStartY > UI.PieMenu.Y[4]) {
00723 CursorStartY = CursorY - UI.PieMenu.Y[4];
00724 }
00725 return;
00726 }
00727
00728
00729 if (OldCursorOn == CursorOnMinimap && CursorOn != CursorOnMinimap &&
00730 (MouseButtons & LeftButton)) {
00731 RestrictCursorToMinimap();
00732 UI.SelectedViewport->Center(
00733 UI.Minimap.Screen2MapX(CursorX), UI.Minimap.Screen2MapY(CursorY),
00734 TileSizeX / 2, TileSizeY / 2);
00735 return;
00736 }
00737
00738
00739
00740
00741 if (GameMenuButtonClicked || GameDiplomacyButtonClicked) {
00742 return;
00743 }
00744
00745
00746
00747 if (CursorOn == CursorOnMap && UI.MouseViewport->IsInsideMapArea(CursorX, CursorY)) {
00748 const CViewport *vp = UI.MouseViewport;
00749 if (Map.IsFieldExplored(ThisPlayer, vp->Viewport2MapX(x), vp->Viewport2MapY(y)) ||
00750 ReplayRevealMap) {
00751 UnitUnderCursor = UnitOnScreen(x - vp->X + vp->MapX * TileSizeX + vp->OffsetX,
00752 y - vp->Y + vp->MapY * TileSizeY + vp->OffsetY);
00753 }
00754 } else if (CursorOn == CursorOnMinimap) {
00755 mx = UI.Minimap.Screen2MapX(x);
00756 my = UI.Minimap.Screen2MapY(y);
00757 if (Map.IsFieldExplored(ThisPlayer, mx, my) || ReplayRevealMap) {
00758 UnitUnderCursor = UnitOnMapTile(mx, my);
00759 }
00760 }
00761
00762
00763 if (UnitUnderCursor && !UnitUnderCursor->IsVisibleAsGoal(ThisPlayer) &&
00764 !ReplayRevealMap) {
00765 UnitUnderCursor = NULL;
00766 }
00767
00768
00769
00770
00771 if (CursorState == CursorStateSelect) {
00772 if (CursorOn == CursorOnMap || CursorOn == CursorOnMinimap) {
00773 GameCursor = UI.YellowHair.Cursor;
00774 if (UnitUnderCursor && !UnitUnderCursor->Type->Decoration) {
00775 if (UnitUnderCursor->Player == ThisPlayer ||
00776 ThisPlayer->IsAllied(UnitUnderCursor)) {
00777 GameCursor = UI.GreenHair.Cursor;
00778 } else if (UnitUnderCursor->Player->Index != PlayerNumNeutral) {
00779 GameCursor = UI.RedHair.Cursor;
00780 }
00781 }
00782 if (CursorOn == CursorOnMinimap && (MouseButtons & RightButton)) {
00783
00784
00785
00786 UI.SelectedViewport->Center(
00787 UI.Minimap.Screen2MapX(CursorX),
00788 UI.Minimap.Screen2MapY(CursorY), TileSizeX / 2, TileSizeY / 2);
00789 }
00790 }
00791
00792 return;
00793 }
00794
00795
00796
00797
00798 if (CursorOn == CursorOnMap) {
00799
00800
00801
00802 if (UnitUnderCursor && !UnitUnderCursor->Type->Decoration &&
00803 (UnitUnderCursor->IsVisible(ThisPlayer) || ReplayRevealMap)) {
00804 GameCursor = UI.Glass.Cursor;
00805 }
00806
00807 return;
00808 }
00809
00810 if (CursorOn == CursorOnMinimap && (MouseButtons & LeftButton)) {
00811
00812
00813
00814 UI.SelectedViewport->Center(
00815 UI.Minimap.Screen2MapX(CursorX), UI.Minimap.Screen2MapY(CursorY),
00816 TileSizeX / 2, TileSizeY / 2);
00817 CursorStartX = CursorX;
00818 CursorStartY = CursorY;
00819 return;
00820 }
00821 }
00822
00823
00824
00831 static int SendRepair(int sx, int sy)
00832 {
00833 CUnit *dest;
00834 int ret = 0;
00835
00836
00837 if ((dest = UnitUnderCursor) && dest->Variable[HP_INDEX].Value < dest->Variable[HP_INDEX].Max &&
00838 dest->Type->RepairHP &&
00839 (dest->Player == ThisPlayer || ThisPlayer->IsAllied(dest))) {
00840 for (int i = 0; i < NumSelected; ++i) {
00841 CUnit *unit = Selected[i];
00842 if (unit->Type->RepairRange) {
00843 SendCommandRepair(unit, sx / TileSizeX, sy / TileSizeY, dest,
00844 !(KeyModifiers & ModifierShift));
00845 ret = 1;
00846 } else {
00847 DebugPrint("Non-worker repairs\n");
00848 }
00849 }
00850 }
00851 return ret;
00852 }
00853
00863 static int SendMove(int sx, int sy)
00864 {
00865 int i;
00866 int flush;
00867 CUnit *unit;
00868 CUnit *transporter;
00869 int ret;
00870
00871 ret = 0;
00872
00873 if ((transporter = UnitUnderCursor) && transporter->Type->CanTransport) {
00874 for (i = 0; i < NumSelected; ++i) {
00875 if (CanTransport(transporter, Selected[i])) {
00876 SendCommandStopUnit(transporter);
00877 ret = 1;
00878 break;
00879 }
00880 }
00881 if (i == NumSelected) {
00882 transporter = NULL;
00883 }
00884 } else {
00885 transporter = NULL;
00886 }
00887
00888 flush = !(KeyModifiers & ModifierShift);
00889
00890 for (i = 0; i < NumSelected; ++i) {
00891 unit = Selected[i];
00892 if (transporter && CanTransport(transporter, unit)) {
00893 transporter->Blink = 4;
00894 SendCommandFollow(transporter, unit, 0);
00895 SendCommandBoard(unit, -1, -1, transporter, flush);
00896 ret = 1;
00897 } else {
00898 SendCommandMove(unit, sx / TileSizeX, sy / TileSizeY, flush);
00899 ret = 1;
00900 }
00901 }
00902 return ret;
00903 }
00904
00921 static int SendAttack(int sx, int sy)
00922 {
00923 int i;
00924 CUnit *unit;
00925 CUnit *dest;
00926 int ret;
00927
00928 ret = 0;
00929 dest = UnitUnderCursor;
00930 if (dest && dest->Type->Decoration) {
00931 dest = NULL;
00932 }
00933 for (i = 0; i < NumSelected; ++i) {
00934 unit = Selected[i];
00935 if (unit->Type->CanAttack) {
00936 if (!dest || (dest != unit && CanTarget(unit->Type, dest->Type))) {
00937 if (dest) {
00938 dest->Blink = 4;
00939 }
00940 SendCommandAttack(unit, sx / TileSizeX, sy / TileSizeY, dest,
00941 !(KeyModifiers & ModifierShift));
00942 ret = 1;
00943 }
00944 } else {
00945 if (CanMove(unit)) {
00946 SendCommandMove(unit, sx / TileSizeX, sy / TileSizeY,
00947 !(KeyModifiers & ModifierShift));
00948 ret = 1;
00949 }
00950 }
00951 }
00952 return ret;
00953 }
00954
00961 static int SendAttackGround(int sx, int sy)
00962 {
00963 int ret = 0;
00964
00965 for (int i = 0; i < NumSelected; ++i) {
00966 CUnit *unit = Selected[i];
00967 if (unit->Type->CanAttack) {
00968 SendCommandAttackGround(unit, sx / TileSizeX, sy / TileSizeY,
00969 !(KeyModifiers & ModifierShift));
00970 ret = 1;
00971 } else {
00972 SendCommandMove(unit, sx / TileSizeX, sy / TileSizeY,
00973 !(KeyModifiers & ModifierShift));
00974 ret = 1;
00975 }
00976 }
00977 return ret;
00978 }
00979
00986 static int SendPatrol(int sx, int sy)
00987 {
00988 int ret = 0;
00989
00990 for (int i = 0; i < NumSelected; ++i) {
00991 CUnit *unit = Selected[i];
00992 SendCommandPatrol(unit, sx / TileSizeX, sy / TileSizeY,
00993 !(KeyModifiers & ModifierShift));
00994 ret = 1;
00995 }
00996 return ret;
00997 }
00998
01007 static int SendResource(int sx, int sy)
01008 {
01009 int i;
01010 int x;
01011 int y;
01012 CUnit *unit;
01013 CUnit *dest;
01014 int ret;
01015
01016 ret = 0;
01017 dest = UnitUnderCursor;
01018 x = sx / TileSizeX;
01019 y = sy / TileSizeY;
01020
01021 for (i = 0; i < NumSelected; ++i) {
01022 unit = Selected[i];
01023 if (unit->Type->Harvester) {
01024 if (dest && dest->Type->CanHarvestFrom && unit->Type->Harvester) {
01025 dest->Blink = 4;
01026 SendCommandResource(Selected[i],dest, !(KeyModifiers & ModifierShift));
01027 ret = 1;
01028 continue;
01029 }
01030 }
01031 if (!CanMove(unit)) {
01032 if (dest && dest->Type->CanHarvestFrom) {
01033 dest->Blink = 4;
01034 SendCommandResource(unit, dest, !(KeyModifiers & ModifierShift));
01035 ret = 1;
01036 continue;
01037 }
01038 SendCommandMove(unit, x, y, !(KeyModifiers & ModifierShift));
01039 ret = 1;
01040 continue;
01041 }
01042 }
01043 return ret;
01044 }
01045
01052 static int SendUnload(int sx, int sy)
01053 {
01054 int ret = 0;
01055
01056 for (int i = 0; i < NumSelected; ++i) {
01057
01058 SendCommandUnload(Selected[i], sx / TileSizeX, sy / TileSizeY, NoUnitP,
01059 !(KeyModifiers & ModifierShift));
01060 ret = 1;
01061 }
01062 return ret;
01063 }
01064
01077 static int SendSpellCast(int sx, int sy)
01078 {
01079 CUnit *dest;
01080 int ret = 0;
01081
01082 dest = UnitUnderCursor;
01083
01084
01085
01086
01087
01088
01089 for (int i = 0; i < NumSelected; ++i) {
01090 CUnit *unit = Selected[i];
01091 if (!unit->Type->CanCastSpell) {
01092 DebugPrint("but unit %d(%s) can't cast spells?\n" _C_
01093 unit->Slot _C_ unit->Type->Name.c_str());
01094
01095 continue;
01096 }
01097 if (dest && unit == dest) {
01098
01099
01100 continue;
01101 }
01102
01103 SendCommandSpellCast(unit, sx / TileSizeX, sy / TileSizeY, dest,
01104 CursorValue, !(KeyModifiers & ModifierShift));
01105 ret = 1;
01106 }
01107 return ret;
01108 }
01109
01116 static void SendCommand(int sx, int sy)
01117 {
01118 int ret;
01119
01120 ret = 0;
01121 CurrentButtonLevel = 0;
01122 UI.ButtonPanel.Update();
01123 switch (CursorAction) {
01124 case ButtonMove:
01125 ret = SendMove(sx, sy);
01126 break;
01127 case ButtonRepair:
01128 ret = SendRepair(sx, sy);
01129 break;
01130 case ButtonAttack:
01131 ret = SendAttack(sx, sy);
01132 break;
01133 case ButtonAttackGround:
01134 ret = SendAttackGround(sx, sy);
01135 break;
01136 case ButtonPatrol:
01137 ret = SendPatrol(sx, sy);
01138 break;
01139 case ButtonHarvest:
01140 ret = SendResource(sx, sy);
01141 break;
01142 case ButtonUnload:
01143 ret = SendUnload(sx, sy);
01144 break;
01145 case ButtonSpellCast:
01146 ret = SendSpellCast(sx, sy);
01147 break;
01148 default:
01149 DebugPrint("Unsupported send action %d\n" _C_ CursorAction);
01150 break;
01151 }
01152
01153 if (ret) {
01154
01155 for (int i = 0; i < NumSelected; ++i) {
01156 if (Selected[i]->Type->Sound.Acknowledgement.Sound) {
01157 PlayUnitSound(Selected[i], VoiceAcknowledging);
01158 break;
01159 }
01160 }
01161 ShowOrdersCount = GameCycle + Preference.ShowOrders * CYCLES_PER_SECOND;
01162 }
01163 }
01164
01165
01166
01173 static void DoSelectionButtons(int num, unsigned button)
01174 {
01175 if (GameObserve || GamePaused) {
01176 return;
01177 }
01178
01179 if (num >= NumSelected || !(MouseButtons & LeftButton)) {
01180 return;
01181 }
01182
01183 CUnit *unit = Selected[num];
01184
01185 if ((KeyModifiers & ModifierControl) ||
01186 (MouseButtons & (LeftButton << MouseDoubleShift))) {
01187 if (KeyModifiers & ModifierShift) {
01188 ToggleUnitsByType(unit);
01189 } else {
01190 SelectUnitsByType(unit);
01191 }
01192 } else if (KeyModifiers & ModifierAlt) {
01193 if (KeyModifiers & ModifierShift) {
01194 AddGroupFromUnitToSelection(unit);
01195 } else {
01196 SelectGroupFromUnit(unit);
01197 }
01198 } else if (KeyModifiers & ModifierShift) {
01199 ToggleSelectUnit(unit);
01200 } else {
01201 SelectSingleUnit(unit);
01202 }
01203
01204 UI.StatusLine.Clear();
01205 ClearCosts();
01206 CurrentButtonLevel = 0;
01207 SelectionChanged();
01208 }
01209
01210
01211
01219 static void UISelectStateButtonDown(unsigned button)
01220 {
01221 if (GameObserve || GamePaused) {
01222 return;
01223 }
01224
01225
01226
01227
01228 if (CursorOn == CursorOnMap && UI.MouseViewport->IsInsideMapArea(CursorX, CursorY)) {
01229 UI.StatusLine.Clear();
01230 ClearCosts();
01231 CursorState = CursorStatePoint;
01232 GameCursor = UI.Point.Cursor;
01233 CurrentButtonLevel = 0;
01234 UI.ButtonPanel.Update();
01235
01236 if (MouseButtons & LeftButton) {
01237 const CViewport *vp = UI.MouseViewport;
01238 if (!ClickMissile.empty()) {
01239 int mx = vp->MapX * TileSizeX + CursorX - vp->X + vp->OffsetX;
01240 int my = vp->MapY * TileSizeY + CursorY - vp->Y + vp->OffsetY;
01241 MakeLocalMissile(MissileTypeByIdent(ClickMissile),
01242 mx, my, mx, my);
01243 }
01244 int sx = CursorX - vp->X + TileSizeX * vp->MapX + vp->OffsetX;
01245 int sy = CursorY - vp->Y + TileSizeY * vp->MapY + vp->OffsetY;
01246 SendCommand(sx, sy);
01247 }
01248 return;
01249 }
01250
01251
01252
01253
01254 if (CursorOn == CursorOnMinimap) {
01255 int mx = UI.Minimap.Screen2MapX(CursorX);
01256 int my = UI.Minimap.Screen2MapY(CursorY);
01257
01258 if (MouseButtons & LeftButton) {
01259 int sx = mx * TileSizeX;
01260 int sy = my * TileSizeY;
01261 UI.StatusLine.Clear();
01262 ClearCosts();
01263 CursorState = CursorStatePoint;
01264 GameCursor = UI.Point.Cursor;
01265 CurrentButtonLevel = 0;
01266 UI.ButtonPanel.Update();
01267 if (!ClickMissile.empty()) {
01268 MakeLocalMissile(MissileTypeByIdent(ClickMissile),
01269 sx + TileSizeX / 2, sy + TileSizeY / 2, 0, 0);
01270 }
01271 SendCommand(sx, sy);
01272 } else {
01273 UI.SelectedViewport->Center(mx, my, TileSizeX / 2, TileSizeY / 2);
01274 }
01275 return;
01276 }
01277
01278 if (CursorOn == CursorOnButton) {
01279
01280 if (ButtonAreaUnderCursor == ButtonAreaButton) {
01281 UI.ButtonPanel.DoClicked(ButtonUnderCursor);
01282 return;
01283 }
01284 }
01285
01286 UI.StatusLine.Clear();
01287 ClearCosts();
01288 CursorState = CursorStatePoint;
01289 GameCursor = UI.Point.Cursor;
01290 CurrentButtonLevel = 0;
01291 UI.ButtonPanel.Update();
01292 }
01293
01294
01300 void UIHandleButtonDown(unsigned button)
01301 {
01302 static bool OldShowSightRange;
01303 static bool OldShowReactionRange;
01304 static bool OldShowAttackRange;
01305 static bool OldValid = false;
01306 CUnit *uins;
01307 int i;
01308
01312 #define LongSelected (MouseButtons & ((LeftButton << MouseHoldShift)))
01313
01314 if (LongSelected) {
01315 if (!OldValid) {
01316 OldShowSightRange = Preference.ShowSightRange;
01317 OldShowAttackRange = Preference.ShowAttackRange;
01318 OldShowReactionRange = Preference.ShowReactionRange;
01319 OldValid = true;
01320
01321 Preference.ShowSightRange = true;
01322 Preference.ShowAttackRange = true;
01323 Preference.ShowReactionRange = true;
01324 }
01325 } else if (OldValid) {
01326 Preference.ShowSightRange = OldShowSightRange;
01327 Preference.ShowAttackRange = OldShowAttackRange;
01328 Preference.ShowReactionRange = OldShowReactionRange;
01329 OldValid = false;
01330 }
01331
01332
01333 if (CursorState == CursorStateRectangle) {
01334 return;
01335 }
01336
01337 HandleMouseOn(CursorX, CursorY);
01338
01339
01340
01341 if (CursorState == CursorStateSelect) {
01342 UISelectStateButtonDown(button);
01343 return;
01344 }
01345
01346 if (CursorState == CursorStatePieMenu) {
01347 if (CursorOn == CursorOnMap) {
01348 HandlePieMenuMouseSelection();
01349 return;
01350 } else {
01351
01352 CursorState = CursorStatePoint;
01353
01354 }
01355 }
01356
01357
01358
01359
01360 if (CursorOn == CursorOnMap) {
01361 Assert(UI.MouseViewport);
01362
01363 if ((MouseButtons & LeftButton) &&
01364 UI.SelectedViewport != UI.MouseViewport) {
01365 UI.SelectedViewport = UI.MouseViewport;
01366 DebugPrint("selected viewport changed to %ld.\n" _C_
01367 static_cast<long int>(UI.SelectedViewport - UI.Viewports));
01368 }
01369
01370
01371 if (CursorBuilding) {
01372
01373
01374 if (Selected[0] && (MouseButtons & LeftButton) &&
01375 UI.MouseViewport->IsInsideMapArea(CursorX, CursorY)) {
01376 int explored;
01377 int x = UI.MouseViewport->Viewport2MapX(CursorX);
01378 int y = UI.MouseViewport->Viewport2MapY(CursorY);
01379
01380
01381
01382 explored = 1;
01383 for (int j = 0; explored && j < Selected[0]->Type->TileHeight; ++j) {
01384 for (int i = 0; i < Selected[0]->Type->TileWidth; ++i) {
01385 if (!Map.IsFieldExplored(ThisPlayer, x + i, y + j)) {
01386 explored = 0;
01387 break;
01388 }
01389 }
01390 }
01391
01392 if (CanBuildUnitType(Selected[0], CursorBuilding, x, y, 0) &&
01393 (explored || ReplayRevealMap)) {
01394 PlayGameSound(GameSounds.PlacementSuccess.Sound,
01395 MaxSampleVolume);
01396 for (int i = 0; i < NumSelected; ++i) {
01397 SendCommandBuildBuilding(Selected[i], x, y, CursorBuilding,
01398 !(KeyModifiers & ModifierShift));
01399 }
01400 if (!(KeyModifiers & (ModifierAlt | ModifierShift))) {
01401 CancelBuildingMode();
01402 }
01403 } else {
01404 PlayGameSound(GameSounds.PlacementError.Sound,
01405 MaxSampleVolume);
01406 }
01407 } else {
01408 CancelBuildingMode();
01409 }
01410 return;
01411 }
01412
01413 if (MouseButtons & UI.PieMenu.MouseButton) {
01414 UnitUnderCursor = NULL;
01415 GameCursor = UI.Point.Cursor;
01416 CursorStartX = CursorX;
01417 CursorStartY = CursorY;
01418 if (NumSelected && Selected[0]->Player == ThisPlayer &&
01419 CursorState == CursorStatePoint) {
01420 CursorState = CursorStatePieMenu;
01421 }
01422 } else if (MouseButtons & LeftButton) {
01423 CursorStartX = CursorX;
01424 CursorStartY = CursorY;
01425 CursorStartScrMapX = CursorStartX - UI.MouseViewport->X +
01426 TileSizeX * UI.MouseViewport->MapX + UI.MouseViewport->OffsetX;
01427 CursorStartScrMapY = CursorStartY - UI.MouseViewport->Y +
01428 TileSizeY * UI.MouseViewport->MapY + UI.MouseViewport->OffsetY;
01429 GameCursor = UI.Cross.Cursor;
01430 CursorState = CursorStateRectangle;
01431 } else if (MouseButtons & MiddleButton) {
01432 CursorStartX = CursorX;
01433 CursorStartY = CursorY;
01434 GameCursor = UI.Scroll.Cursor;
01435 } else if (MouseButtons & RightButton) {
01436 int x;
01437 int y;
01438
01439 if (!GameObserve && !GamePaused && UI.MouseViewport->IsInsideMapArea(CursorX, CursorY)) {
01440 CUnit *unit;
01441
01442
01443
01444 x = UI.MouseViewport->Viewport2MapX(CursorX);
01445 y = UI.MouseViewport->Viewport2MapY(CursorY);
01446
01447 if (UnitUnderCursor && (unit = UnitOnMapTile(x, y)) &&
01448 !UnitUnderCursor->Type->Decoration) {
01449 unit->Blink = 4;
01450 } else {
01451 if (!ClickMissile.empty()) {
01452 MakeLocalMissile(MissileTypeByIdent(ClickMissile),
01453 UI.MouseViewport->MapX * TileSizeX +
01454 CursorX - UI.MouseViewport->X + UI.MouseViewport->OffsetX,
01455 UI.MouseViewport->MapY * TileSizeY +
01456 CursorY - UI.MouseViewport->Y + UI.MouseViewport->OffsetY, 0, 0);
01457 }
01458 }
01459 DoRightButton(x * TileSizeX, y * TileSizeY);
01460 }
01461 }
01462
01463
01464
01465 } else if (CursorOn == CursorOnMinimap) {
01466 if (MouseButtons & LeftButton) {
01467 UI.SelectedViewport->Center(
01468 UI.Minimap.Screen2MapX(CursorX), UI.Minimap.Screen2MapY(CursorY),
01469 TileSizeX / 2, TileSizeY / 2);
01470 } else if (MouseButtons & RightButton) {
01471 if (!GameObserve && !GamePaused) {
01472 if (!ClickMissile.empty()) {
01473 MakeLocalMissile(MissileTypeByIdent(ClickMissile),
01474 UI.Minimap.Screen2MapX(CursorX) * TileSizeX + TileSizeX / 2,
01475 UI.Minimap.Screen2MapY(CursorY) * TileSizeY + TileSizeY / 2, 0, 0);
01476 }
01477
01478 DoRightButton(UI.Minimap.Screen2MapX(CursorX) * TileSizeX,
01479 UI.Minimap.Screen2MapY(CursorY) * TileSizeY);
01480 }
01481 }
01482
01483
01484
01485 } else if (CursorOn == CursorOnButton) {
01486
01487
01488
01489 if (NumSelected > 1 && ButtonAreaUnderCursor == ButtonAreaSelected) {
01490 DoSelectionButtons(ButtonUnderCursor, button);
01491 } else if ((MouseButtons & LeftButton)) {
01492
01493
01494
01495 if (ButtonAreaUnderCursor == ButtonAreaMenu) {
01496 if ((ButtonUnderCursor == ButtonUnderMenu ||
01497 ButtonUnderCursor == ButtonUnderNetworkMenu) &&
01498 !GameMenuButtonClicked) {
01499 PlayGameSound(GameSounds.Click.Sound, MaxSampleVolume);
01500 GameMenuButtonClicked = true;
01501 } else if (ButtonUnderCursor == ButtonUnderNetworkDiplomacy &&
01502 !GameDiplomacyButtonClicked) {
01503 PlayGameSound(GameSounds.Click.Sound, MaxSampleVolume);
01504 GameDiplomacyButtonClicked = true;
01505 }
01506
01507
01508
01509 } else if (ButtonAreaUnderCursor == ButtonAreaSelected) {
01510
01511
01512
01513 if (ButtonUnderCursor == 0 && NumSelected == 1) {
01514 PlayGameSound(GameSounds.Click.Sound, MaxSampleVolume);
01515 UI.SelectedViewport->Center(Selected[0]->X,
01516 Selected[0]->Y, Selected[0]->IX + TileSizeX / 2,
01517 Selected[0]->IY + TileSizeY / 2);
01518 }
01519
01520
01521
01522 } else if (ButtonAreaUnderCursor == ButtonAreaTraining) {
01523 if (!GameObserve && !GamePaused &&
01524 ThisPlayer->IsTeamed(Selected[0])) {
01525 if (ButtonUnderCursor < Selected[0]->OrderCount &&
01526 Selected[0]->Orders[ButtonUnderCursor]->Action == UnitActionTrain) {
01527 DebugPrint("Cancel slot %d %s\n" _C_
01528 ButtonUnderCursor _C_
01529 Selected[0]->Orders[ButtonUnderCursor]->Type->Ident.c_str());
01530 SendCommandCancelTraining(Selected[0],
01531 ButtonUnderCursor,
01532 Selected[0]->Orders[ButtonUnderCursor]->Type);
01533 }
01534 }
01535
01536
01537
01538 } else if (ButtonAreaUnderCursor == ButtonAreaTransporting) {
01539
01540
01541
01542 if (!GameObserve && !GamePaused &&
01543 ThisPlayer->IsTeamed(Selected[0])) {
01544 if (Selected[0]->BoardCount >= ButtonUnderCursor) {
01545 uins = Selected[0]->UnitInside;
01546 for (i = ButtonUnderCursor; i; uins = uins->NextContained) {
01547 if (uins->Boarded) {
01548 --i;
01549 }
01550 }
01551 Assert(uins->Boarded);
01552 SendCommandUnload(Selected[0],
01553 Selected[0]->X, Selected[0]->Y, uins,
01554 !(KeyModifiers & ModifierShift));
01555 }
01556 }
01557 } else if (ButtonAreaUnderCursor == ButtonAreaButton) {
01558 if (!GameObserve && !GamePaused &&
01559 ThisPlayer->IsTeamed(Selected[0])) {
01560 UI.ButtonPanel.DoClicked(ButtonUnderCursor);
01561 }
01562 }
01563 } else if ((MouseButtons & MiddleButton)) {
01564
01565
01566
01567 if (ButtonAreaUnderCursor == ButtonAreaSelected &&
01568 ButtonUnderCursor == 0 && NumSelected == 1) {
01569 PlayGameSound(GameSounds.Click.Sound, MaxSampleVolume);
01570 if (UI.SelectedViewport->Unit == Selected[0]) {
01571 UI.SelectedViewport->Unit = NULL;
01572 } else {
01573 UI.SelectedViewport->Unit = Selected[0];
01574 }
01575 }
01576 } else if ((MouseButtons & RightButton)) {
01577 }
01578 }
01579 }
01580
01586 void UIHandleButtonUp(unsigned button)
01587 {
01588
01589
01590
01591 if (GameCursor == UI.Scroll.Cursor) {
01592 GameCursor = UI.Point.Cursor;
01593 return;
01594 }
01595
01596
01597
01598
01599 if (CursorState == CursorStatePieMenu) {
01600
01601 if (CursorStartX < CursorX - 1 || CursorStartX > CursorX + 1 ||
01602 CursorStartY < CursorY - 1 || CursorStartY > CursorY + 1) {
01603
01604 HandlePieMenuMouseSelection();
01605 }
01606 }
01607
01608
01609
01610
01611 if ((1 << button) == LeftButton && GameMenuButtonClicked) {
01612 GameMenuButtonClicked = false;
01613 if (ButtonAreaUnderCursor == ButtonAreaMenu) {
01614 if (ButtonUnderCursor == ButtonUnderMenu ||
01615 ButtonUnderCursor == ButtonUnderNetworkMenu) {
01616
01617 if (!IsNetworkGame()) {
01618 GamePaused = true;
01619 UI.StatusLine.Set(_("Game Paused"));
01620 }
01621 if (ButtonUnderCursor == ButtonUnderMenu) {
01622 if (UI.MenuButton.Callback) {
01623 UI.MenuButton.Callback->action("");
01624 }
01625 } else {
01626 if (UI.NetworkMenuButton.Callback) {
01627 UI.NetworkMenuButton.Callback->action("");
01628 }
01629 }
01630 return;
01631 }
01632 }
01633 }
01634
01635
01636
01637
01638 if ((1 << button) == LeftButton && GameDiplomacyButtonClicked) {
01639 GameDiplomacyButtonClicked = false;
01640 if (ButtonAreaUnderCursor == ButtonAreaMenu &&
01641 ButtonUnderCursor == ButtonUnderNetworkDiplomacy) {
01642 if (UI.NetworkDiplomacyButton.Callback) {
01643 UI.NetworkDiplomacyButton.Callback->action("");
01644 }
01645 return;
01646 }
01647 }
01648
01649
01650
01651
01652
01653 if (CursorState == CursorStateRectangle &&
01654 !(MouseButtons & LeftButton)) {
01655 int num;
01656 CUnit *unit;
01657
01658 unit = NULL;
01659
01660
01661
01662 if (CursorStartX < CursorX - 1 || CursorStartX > CursorX + 1 ||
01663 CursorStartY < CursorY - 1 || CursorStartY > CursorY + 1) {
01664 int x0;
01665 int y0;
01666 int x1;
01667 int y1;
01668
01669 x0 = CursorStartScrMapX;
01670 y0 = CursorStartScrMapY;
01671 x1 = CursorX - UI.MouseViewport->X +
01672 UI.MouseViewport->MapX * TileSizeX + UI.MouseViewport->OffsetX;
01673 y1 = CursorY - UI.MouseViewport->Y +
01674 UI.MouseViewport->MapY * TileSizeY + UI.MouseViewport->OffsetY;
01675
01676 if (x0 > x1) {
01677 int swap;
01678
01679 swap = x0;
01680 x0 = x1;
01681 x1 = swap;
01682 }
01683 if (y0 > y1) {
01684 int swap;
01685
01686 swap = y0;
01687 y0 = y1;
01688 y1 = swap;
01689 }
01690 if (KeyModifiers & ModifierShift) {
01691 if (KeyModifiers & ModifierAlt) {
01692 num = AddSelectedGroundUnitsInRectangle(x0, y0, x1, y1);
01693 } else if (KeyModifiers & ModifierControl) {
01694 num = AddSelectedAirUnitsInRectangle(x0, y0, x1, y1);
01695 } else {
01696 num = AddSelectedUnitsInRectangle(x0, y0, x1, y1);
01697 }
01698 } else {
01699 if (KeyModifiers & ModifierAlt) {
01700 num = SelectGroundUnitsInRectangle(x0, y0, x1, y1);
01701 } else if (KeyModifiers & ModifierControl) {
01702 num = SelectAirUnitsInRectangle(x0, y0, x1, y1);
01703 } else {
01704 num = SelectUnitsInRectangle(x0, y0, x1, y1);
01705 }
01706 }
01707 } else {
01708
01709
01710
01711
01712
01713 if (Map.IsFieldVisible(ThisPlayer,
01714 UI.MouseViewport->Viewport2MapX(CursorX),
01715 UI.MouseViewport->Viewport2MapY(CursorY)) || ReplayRevealMap) {
01716 unit = UnitOnScreen(
01717 CursorX - UI.MouseViewport->X + UI.MouseViewport->MapX * TileSizeX + UI.MouseViewport->OffsetX,
01718 CursorY - UI.MouseViewport->Y + UI.MouseViewport->MapY * TileSizeY + UI.MouseViewport->OffsetY);
01719 }
01720 if (unit) {
01721
01722 if ((KeyModifiers & ModifierControl)
01723 || (button & (1 << MouseDoubleShift))) {
01724 if (KeyModifiers & ModifierShift) {
01725 num = ToggleUnitsByType(unit);
01726 } else {
01727 num = SelectUnitsByType(unit);
01728 }
01729 } else if ((KeyModifiers & ModifierAlt) && unit->LastGroup) {
01730 if (KeyModifiers & ModifierShift) {
01731 num = AddGroupFromUnitToSelection(unit);
01732 } else {
01733 num = SelectGroupFromUnit(unit);
01734 }
01735
01736
01737
01738 } else if (KeyModifiers & ModifierShift &&
01739 (unit->Player == ThisPlayer || ThisPlayer->IsTeamed(unit)) &&
01740 !unit->Type->Building &&
01741 (NumSelected != 1 || !Selected[0]->Type->Building) &&
01742 (NumSelected != 1 || Selected[0]->Player == ThisPlayer ||
01743 ThisPlayer->IsTeamed(Selected[0]))) {
01744 num = ToggleSelectUnit(unit);
01745 if (!num) {
01746 SelectionChanged();
01747 }
01748 } else {
01749 SelectSingleUnit(unit);
01750 num = 1;
01751 }
01752 } else {
01753 num = 0;
01754 }
01755 }
01756
01757 if (num) {
01758 UI.StatusLine.Clear();
01759 ClearCosts();
01760 CurrentButtonLevel = 0;
01761 SelectionChanged();
01762
01763
01764
01765
01766
01767
01768
01769 if (NumSelected == 1) {
01770 if (Selected[0]->Orders[0]->Action == UnitActionBuilt) {
01771 PlayUnitSound(Selected[0], VoiceBuilding);
01772 } else if (Selected[0]->Burning) {
01773
01774 PlayGameSound(SoundForName("burning"), MaxSampleVolume);
01775 } else if (Selected[0]->Player == ThisPlayer || ThisPlayer->IsTeamed(Selected[0]) ||
01776 Selected[0]->Player->Type == PlayerNeutral) {
01777 PlayUnitSound(Selected[0], VoiceSelected);
01778 } else {
01779 PlayGameSound(GameSounds.Click.Sound, MaxSampleVolume);
01780 }
01781 if (Selected[0]->Player == ThisPlayer) {
01782 char buf[64];
01783 if (Selected[0]->Player->UnitTypesCount[Selected[0]->Type->Slot] > 1) {
01784 sprintf_s(buf, sizeof(buf), _("You have ~<%d~> %ss"),
01785 Selected[0]->Player->UnitTypesCount[Selected[0]->Type->Slot],
01786 Selected[0]->Type->Name.c_str());
01787 } else {
01788 sprintf_s(buf, sizeof(buf), _("You have ~<%d~> %s(s)"),
01789 Selected[0]->Player->UnitTypesCount[Selected[0]->Type->Slot],
01790 Selected[0]->Type->Name.c_str());
01791 }
01792 UI.StatusLine.Set(buf);
01793 }
01794 }
01795 }
01796
01797 CursorStartX = 0;
01798 CursorStartY = 0;
01799 GameCursor = UI.Point.Cursor;
01800 CursorState = CursorStatePoint;
01801 }
01802 }
01803
01809 static int GetPieUnderCursor(void)
01810 {
01811 int x = CursorX - (CursorStartX - ICON_SIZE_X / 2);
01812 int y = CursorY - (CursorStartY - ICON_SIZE_Y / 2);
01813 for (int i = 0; i < 8; ++i) {
01814 if (x > UI.PieMenu.X[i] && x < UI.PieMenu.X[i] + ICON_SIZE_X &&
01815 y > UI.PieMenu.Y[i] && y < UI.PieMenu.Y[i] + ICON_SIZE_Y) {
01816 return i;
01817 }
01818 }
01819 return -1;
01820 }
01821
01825 void DrawPieMenu(void)
01826 {
01827 int i;
01828 const ButtonAction *buttons;
01829 CViewport *vp;
01830 CPlayer *player;
01831
01832 if (CursorState != CursorStatePieMenu)
01833 return;
01834
01835 if (!(buttons = CurrentButtons)) {
01836 CursorState = CursorStatePoint;
01837 return;
01838 }
01839
01840 vp = UI.SelectedViewport;
01841 PushClipping();
01842 SetClipping(vp->X, vp->Y, vp->EndX, vp->EndY);
01843
01844
01845 if (UI.PieMenu.G) {
01846 UI.PieMenu.G->DrawFrameClip(0,
01847 CursorStartX - UI.PieMenu.G->Width / 2,
01848 CursorStartY - UI.PieMenu.G->Height / 2);
01849 }
01850 player = Selected[0]->Player;
01851
01852 for (i = 0; i < (int)UI.ButtonPanel.Buttons.size() && i < 8; ++i) {
01853 if (buttons[i].Pos != -1) {
01854 int x;
01855 int y;
01856
01857 x = CursorStartX - ICON_SIZE_X / 2 + UI.PieMenu.X[i];
01858 y = CursorStartY - ICON_SIZE_Y / 2 + UI.PieMenu.Y[i];
01859
01860 buttons[i].Icon.Icon->DrawIcon(player, x, y);
01861
01862
01863 if (UI.ButtonPanel.ShowCommandKey) {
01864 std::string text("?");
01865
01866 if (CurrentButtons[i].Key == 27) {
01867 text = "ESC";
01868 } else {
01869 text[0] = toupper(CurrentButtons[i].Key);
01870 }
01871 VideoDrawTextClip(x + 4, y + 4, GameFont, text);
01872 }
01873 }
01874 }
01875
01876 PopClipping();
01877
01878 i = GetPieUnderCursor();
01879 if (i != -1 && KeyState != KeyStateInput && buttons[i].Pos != -1) {
01880 UpdateStatusLineForButton(&buttons[i]);
01881 }
01882 }
01883
01887 static void HandlePieMenuMouseSelection(void)
01888 {
01889 if (!CurrentButtons) {
01890 return;
01891 }
01892
01893 int pie = GetPieUnderCursor();
01894 if (pie != -1) {
01895 UI.ButtonPanel.DoClicked(pie);
01896 if (CurrentButtons[pie].Action == ButtonButton) {
01897
01898
01899 CursorStartX = CursorX;
01900 CursorStartY = CursorY;
01901 } else {
01902 if (CursorState == CursorStatePieMenu) {
01903 CursorState = CursorStatePoint;
01904 }
01905 CursorOn = CursorOnUnknown;
01906 UIHandleMouseMove(CursorX, CursorY);
01907 }
01908 } else {
01909 CursorState = CursorStatePoint;
01910 CursorOn = CursorOnUnknown;
01911 UIHandleMouseMove(CursorX, CursorY);
01912 }
01913 }