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 <sstream>
00038 #include <deque>
00039
00040 #include "stratagus.h"
00041 #include "unittype.h"
00042 #include "unit_cache.h"
00043 #include "video.h"
00044 #include "map.h"
00045 #include "patch.h"
00046 #include "patch_type.h"
00047 #include "minimap.h"
00048 #include "settings.h"
00049 #include "network.h"
00050 #include "sound_server.h"
00051 #include "ui.h"
00052 #include "interface.h"
00053 #include "font.h"
00054 #include "widgets.h"
00055 #include "editor.h"
00056 #include "results.h"
00057 #include "menus.h"
00058 #include "sound.h"
00059 #include "iolib.h"
00060 #include "iocompat.h"
00061 #include "replay.h"
00062 #include "guichan.h"
00063
00064 #include "script.h"
00065
00066 extern void DoScrollArea(int state, bool fast);
00067 extern void DrawGuichanWidgets();
00068 extern void CleanGame();
00069
00070
00071
00072
00073
00074 #define IconSpacing (IconWidth + 2)
00075 #define UNIT_ICON_X (IconSpacing)
00076 #define UNIT_ICON_Y (0)
00077 #define PATCH_ICON_X (IconSpacing * 2)
00078 #define PATCH_ICON_Y (0)
00079 #define START_ICON_X (IconSpacing * 3)
00080 #define START_ICON_Y (0)
00081
00082
00083
00084
00085
00086 CEditor Editor;
00087
00088 const char *EditorStartFile;
00089
00090 static int IconWidth;
00091 static int IconHeight;
00092
00093 static int ButtonPanelWidth;
00094 static int ButtonPanelHeight;
00095
00096 static CPatch *PatchUnderCursor;
00097 static int PatchOffsetX;
00098 static int PatchOffsetY;
00099 static bool UnitPlacedThisPress = false;
00100 static bool PatchPlacedThisPress = false;
00101 static bool UpdateMinimap = false;
00102 static bool UpdateMinimapTerrain = false;
00103 static bool DraggingPatch = false;
00104 static int VisibleIcons;
00105
00106 enum _mode_buttons_ {
00107 SelectButton = 201,
00108 UnitButton,
00109 PatchButton,
00110 StartButton
00111 };
00112
00113 enum EditorActionType
00114 {
00115 EditorActionTypePlaceUnit,
00116 EditorActionTypeRemoveUnit,
00117 };
00118
00119 struct EditorAction
00120 {
00121 EditorActionType Type;
00122 int X;
00123 int Y;
00124 CUnitType *UnitType;
00125 CPlayer *Player;
00126 };
00127
00128 static std::deque<EditorAction> EditorUndoActions;
00129 static std::deque<EditorAction> EditorRedoActions;
00130
00131 static void EditorUndoAction();
00132 static void EditorRedoAction();
00133 static void EditorAddUndoAction(EditorAction action);
00134
00135 extern gcn::Gui *Gui;
00136 static gcn::Container *editorContainer;
00137 static gcn::Slider *editorUnitSlider;
00138 static gcn::Slider *editorPatchSlider;
00139
00140 class EditorUnitSliderListener : public gcn::ActionListener
00141 {
00142 public:
00143 virtual void action(const std::string &eventId)
00144 {
00145 int iconsPerStep = VisibleIcons;
00146 int steps = (Editor.ShownUnitTypes.size() + iconsPerStep - 1) / iconsPerStep;
00147 double value = editorUnitSlider->getValue();
00148 for (int i = 1; i <= steps; ++i)
00149 {
00150 if (value <= (double)i / steps)
00151 {
00152 Editor.UnitIndex = iconsPerStep * (i - 1);
00153 break;
00154 }
00155 }
00156 }
00157 };
00158
00159 static EditorUnitSliderListener *editorUnitSliderListener;
00160
00161 class EditorPatchSliderListener : public gcn::ActionListener
00162 {
00163 public:
00164 virtual void action(const std::string &eventId)
00165 {
00166 int iconsPerStep = VisibleIcons;
00167 int steps = (Editor.ShownPatchTypes.size() + iconsPerStep - 1) / iconsPerStep;
00168 double value = editorPatchSlider->getValue();
00169 for (int i = 1; i <= steps; ++i)
00170 {
00171 if (value <= (double)i / steps)
00172 {
00173 Editor.PatchIndex = iconsPerStep * (i - 1);
00174 break;
00175 }
00176 }
00177 }
00178 };
00179
00180 static EditorPatchSliderListener *editorPatchSliderListener;
00181
00182
00183
00184
00185
00186 extern void InitDefinedVariables();
00187
00193 void SetEditorSelectIcon(const std::string &icon)
00194 {
00195 Editor.Select.Name = icon;
00196 }
00197
00203 void SetEditorUnitsIcon(const std::string &icon)
00204 {
00205 Editor.Units.Name = icon;
00206 }
00207
00213 void SetEditorPatchIcon(const std::string &icon)
00214 {
00215 Editor.Patch.Name = icon;
00216 }
00217
00223 void SetEditorStartUnit(const std::string &name)
00224 {
00225 Editor.StartUnitName = name;
00226 }
00227
00228
00229
00230
00231
00240 static void EditorActionPlaceUnit(int x, int y, CUnitType *type, CPlayer *player)
00241 {
00242 CUnit *unit;
00243 CBuildRestrictionOnTop *b;
00244
00245 if (type->Neutral)
00246 {
00247 player = &Players[PlayerNumNeutral];
00248 }
00249
00250 unit = MakeUnitAndPlace(x, y, type, player);
00251 if (unit == NoUnitP)
00252 {
00253 DebugPrint("Unable to allocate Unit");
00254 return;
00255 }
00256
00257 b = OnTopDetails(unit, NULL);
00258 if (b && b->ReplaceOnBuild)
00259 {
00260 int n;
00261 CUnit *table[UnitMax];
00262
00263 n = UnitCache.Select(x, y, table, UnitMax);
00264 while (n--)
00265 {
00266 if (table[n]->Type == b->Parent)
00267 {
00268
00269 memcpy(unit->ResourcesHeld, table[n]->ResourcesHeld, sizeof(unit->ResourcesHeld));
00270 table[n]->Remove(NULL);
00271 UnitLost(table[n]);
00272 UnitClearOrders(table[n]);
00273 table[n]->Release();
00274 break;
00275 }
00276 }
00277 }
00278
00279 UpdateMinimap = true;
00280 }
00281
00290 static void EditorPlaceUnit(int x, int y, CUnitType *type, CPlayer *player)
00291 {
00292 EditorAction editorAction;
00293 editorAction.Type = EditorActionTypePlaceUnit;
00294 editorAction.X = x;
00295 editorAction.Y = y;
00296 editorAction.UnitType = type;
00297 editorAction.Player = player;
00298
00299 EditorActionPlaceUnit(x, y, type, player);
00300 EditorAddUndoAction(editorAction);
00301 }
00302
00306 static void EditorActionRemoveUnit(CUnit *unit)
00307 {
00308 unit->Remove(NULL);
00309 UnitLost(unit);
00310 UnitClearOrders(unit);
00311 unit->Release();
00312 UI.StatusLine.Set(_("Unit deleted"));
00313 UpdateMinimap = true;
00314 }
00315
00319 static void EditorRemoveUnit(CUnit *unit)
00320 {
00321 EditorAction editorAction;
00322 editorAction.Type = EditorActionTypeRemoveUnit;
00323 editorAction.X = unit->X;
00324 editorAction.Y = unit->Y;
00325 editorAction.UnitType = unit->Type;
00326 editorAction.Player = unit->Player;
00327
00328 EditorActionRemoveUnit(unit);
00329 EditorAddUndoAction(editorAction);
00330 }
00331
00332
00333
00334
00335
00336 static void EditorUndoAction()
00337 {
00338 if (EditorUndoActions.empty())
00339 {
00340 return;
00341 }
00342
00343 EditorAction action = EditorUndoActions.back();
00344 EditorUndoActions.pop_back();
00345
00346 switch (action.Type)
00347 {
00348 case EditorActionTypePlaceUnit:
00349 {
00350 CUnit *unit = UnitOnMapTile(action.X, action.Y, action.UnitType->UnitType);
00351 EditorActionRemoveUnit(unit);
00352 break;
00353 }
00354
00355 case EditorActionTypeRemoveUnit:
00356 EditorActionPlaceUnit(action.X, action.Y, action.UnitType, action.Player);
00357 break;
00358 }
00359
00360 EditorRedoActions.push_back(action);
00361 }
00362
00363 static void EditorRedoAction()
00364 {
00365 if (EditorRedoActions.empty())
00366 {
00367 return;
00368 }
00369
00370 EditorAction action = EditorRedoActions.back();
00371 EditorRedoActions.pop_back();
00372
00373 switch (action.Type)
00374 {
00375 case EditorActionTypePlaceUnit:
00376 EditorActionPlaceUnit(action.X, action.Y, action.UnitType, action.Player);
00377 break;
00378
00379 case EditorActionTypeRemoveUnit:
00380 {
00381 CUnit *unit = UnitOnMapTile(action.X, action.Y, action.UnitType->UnitType);
00382 EditorActionRemoveUnit(unit);
00383 break;
00384 }
00385 }
00386
00387 EditorUndoActions.push_back(action);
00388 }
00389
00390 static void EditorAddUndoAction(EditorAction action)
00391 {
00392 EditorRedoActions.clear();
00393 EditorUndoActions.push_back(action);
00394 }
00395
00396
00397
00398
00399
00405 static int CalculateVisibleIcons()
00406 {
00407 int i;
00408 int x;
00409 int count;
00410
00411 i = 0;
00412 count = 0;
00413 x = UI.ButtonPanel.Y + 24;
00414 while (x < UI.ButtonPanel.Y + ButtonPanelHeight - IconHeight)
00415 {
00416 ++i;
00417 x += IconHeight + 2;
00418 }
00419 x = UI.ButtonPanel.X + 10;
00420 while (x < UI.ButtonPanel.X + ButtonPanelWidth - IconWidth)
00421 {
00422 count += i;
00423 x += IconWidth + 8;
00424 }
00425 return count;
00426 }
00427
00432 static void CalculateMaxIconSize()
00433 {
00434 const CUnitType *type;
00435 const CIcon *icon;
00436
00437 IconWidth = 0;
00438 IconHeight = 0;
00439 for (int i = 0; i < (int)Editor.UnitTypes.size(); ++i)
00440 {
00441 type = UnitTypeByIdent(Editor.UnitTypes[i]);
00442 Assert(type && type->Icon.Icon);
00443 icon = type->Icon.Icon;
00444 if (IconWidth < icon->G->Width)
00445 {
00446 IconWidth = icon->G->Width;
00447 }
00448 if (IconHeight < icon->G->Height)
00449 {
00450 IconHeight = icon->G->Height;
00451 }
00452 }
00453 }
00454
00455
00459 static void RecalculateShownUnits()
00460 {
00461 const CUnitType *type;
00462
00463 Editor.ShownUnitTypes.clear();
00464
00465 for (int i = 0; i < (int)Editor.UnitTypes.size(); ++i)
00466 {
00467 type = UnitTypeByIdent(Editor.UnitTypes[i]);
00468 Editor.ShownUnitTypes.push_back(type);
00469 }
00470
00471 if (Editor.UnitIndex >= (int)Editor.ShownUnitTypes.size())
00472 {
00473 Editor.UnitIndex = Editor.ShownUnitTypes.size() / VisibleIcons * VisibleIcons;
00474 }
00475
00476 Editor.CursorUnitIndex = -1;
00477 Editor.SelectedUnitIndex = -1;
00478 }
00479
00480
00481 static MenuScreen *editAiMenu;
00482 static gcn::Label *editAiLabel;
00483 static gcn::CheckBox *editAiCheckBox;
00484 static gcn::Button *editAiOKButton;
00485 static gcn::Button *editAiCancelButton;
00486
00487 static void CleanEditAi()
00488 {
00489 delete editAiMenu;
00490 editAiMenu = NULL;
00491 delete editAiLabel;
00492 editAiLabel = NULL;
00493 delete editAiCheckBox;
00494 editAiCheckBox = NULL;
00495 delete editAiOKButton;
00496 editAiOKButton = NULL;
00497 delete editAiCancelButton;
00498 editAiCancelButton = NULL;
00499 }
00500
00501
00502
00503
00504
00508 static void DrawPlayers()
00509 {
00510 int x = UI.InfoPanel.X + 8;
00511 int y = UI.InfoPanel.Y + 4 + IconHeight + 10;
00512
00513 for (int i = 0; i < PlayerMax; ++i)
00514 {
00515 if (i == Editor.CursorPlayer && Map.Info.PlayerType[i] != PlayerNobody)
00516 {
00517 Video.DrawRectangle(ColorWhite, x + i * 20, y, 20, 20);
00518 }
00519 Video.DrawRectangle(
00520 i == Editor.CursorPlayer && Map.Info.PlayerType[i] != PlayerNobody ?
00521 ColorWhite : ColorGray,
00522 x + i * 20, y, 19, 19);
00523 if (Map.Info.PlayerType[i] != PlayerNobody)
00524 {
00525 Video.FillRectangle(Players[i].Color, x + 1 + i * 20, y + 1,
00526 17, 17);
00527 }
00528 if (i == Editor.SelectedPlayer)
00529 {
00530 Video.DrawRectangle(ColorGreen, x + 1 + i * 20, y + 1, 17, 17);
00531 }
00532 std::ostringstream o;
00533 o << i;
00534 VideoDrawTextCentered(x + i * 20 + 9, y + 3, SmallFont, o.str());
00535 }
00536
00537 x = UI.InfoPanel.X + 4;
00538 y += 18 * 1 + 4;
00539 if (Editor.SelectedPlayer != -1)
00540 {
00541 std::ostringstream o;
00542 o << _("Player") << " " << Editor.SelectedPlayer << " ";
00543
00544 switch (Map.Info.PlayerType[Editor.SelectedPlayer])
00545 {
00546 case PlayerNeutral:
00547 o << _("Neutral");
00548 break;
00549 case PlayerNobody:
00550 default:
00551 o << _("Nobody");
00552 break;
00553 case PlayerPerson:
00554 o << _("Person");
00555 break;
00556 case PlayerComputer:
00557 case PlayerRescuePassive:
00558 case PlayerRescueActive:
00559 o << _("Computer");
00560 break;
00561 }
00562
00563 VideoDrawText(x, y, GameFont, o.str());
00564 }
00565 }
00566
00567
00571 static void DrawUnitIcons()
00572 {
00573 int x;
00574 int y;
00575 int i;
00576 CIcon *icon;
00577
00578 x = UI.InfoPanel.X + 10;
00579 y = UI.InfoPanel.Y + 140;
00580
00581
00582
00583
00584 y = UI.ButtonPanel.Y + 24;
00585 i = Editor.UnitIndex;
00586 while (y < UI.ButtonPanel.Y + ButtonPanelHeight - IconHeight)
00587 {
00588 if (i >= (int)Editor.ShownUnitTypes.size())
00589 {
00590 break;
00591 }
00592 x = UI.ButtonPanel.X + 10;
00593 while (x < UI.ButtonPanel.X + ButtonPanelWidth - IconWidth)
00594 {
00595 if (i >= (int) Editor.ShownUnitTypes.size())
00596 {
00597 break;
00598 }
00599 icon = Editor.ShownUnitTypes[i]->Icon.Icon;
00600 icon->DrawIcon(Players + Editor.SelectedPlayer, x, y);
00601
00602 Video.DrawRectangleClip(ColorGray, x, y, icon->G->Width, icon->G->Height);
00603 if (i == Editor.SelectedUnitIndex)
00604 {
00605 Video.DrawRectangleClip(ColorGreen, x + 1, y + 1,
00606 icon->G->Width - 2, icon->G->Height - 2);
00607 }
00608 if (i == Editor.CursorUnitIndex)
00609 {
00610 Video.DrawRectangleClip(ColorWhite, x - 1, y - 1,
00611 icon->G->Width + 2, icon->G->Height + 2);
00612 }
00613
00614 x += IconWidth + 8;
00615 ++i;
00616 }
00617 y += IconHeight + 2;
00618 }
00619 }
00620
00624 static void DrawPatchIcons()
00625 {
00626 int x;
00627 int y;
00628 int i;
00629 CGraphic *g;
00630
00631 x = UI.InfoPanel.X + 10;
00632 y = UI.InfoPanel.Y + 140;
00633
00634
00635
00636
00637 y = UI.ButtonPanel.Y + 24;
00638 i = Editor.PatchIndex;
00639 while (y < UI.ButtonPanel.Y + ButtonPanelHeight - IconHeight)
00640 {
00641 if (i >= (int)Editor.ShownPatchTypes.size())
00642 {
00643 break;
00644 }
00645 x = UI.ButtonPanel.X + 10;
00646 while (x < UI.ButtonPanel.X + ButtonPanelWidth - IconWidth)
00647 {
00648 if (i >= (int) Editor.ShownPatchTypes.size())
00649 {
00650 break;
00651 }
00652 g = Editor.ShownPatchTypes[i].G;
00653 g->DrawClip(x, y);
00654
00655 Video.DrawRectangleClip(ColorGray, x, y, IconWidth, IconHeight);
00656 if (i == Editor.SelectedPatchIndex)
00657 {
00658 Video.DrawRectangleClip(ColorGreen, x + 1, y + 1,
00659 IconWidth - 2, IconHeight - 2);
00660 }
00661 if (i == Editor.CursorPatchIndex)
00662 {
00663 Video.DrawRectangleClip(ColorWhite, x - 1, y - 1,
00664 IconWidth + 2, IconHeight + 2);
00665 }
00666
00667 x += IconWidth + 8;
00668 ++i;
00669 }
00670 y += IconHeight + 2;
00671 }
00672 }
00673
00677 static void DrawEditorPanel()
00678 {
00679 int x;
00680 int y;
00681 CIcon *icon;
00682
00683 x = UI.InfoPanel.X + 4;
00684 y = UI.InfoPanel.Y + 4;
00685
00686
00687
00688
00689
00690 icon = Editor.Select.Icon;
00691 icon->DrawUnitIcon(Players, UI.SingleSelectedButton->Style,
00692 (ButtonUnderCursor == SelectButton ? IconActive : 0) |
00693 (Editor.State == EditorSelecting ? IconSelected : 0),
00694 x, y, "");
00695
00696 icon = Editor.Units.Icon;
00697 icon->DrawUnitIcon(Players, UI.SingleSelectedButton->Style,
00698 (ButtonUnderCursor == UnitButton ? IconActive : 0) |
00699 (Editor.State == EditorEditUnit ? IconSelected : 0),
00700 x + UNIT_ICON_X, y + UNIT_ICON_Y, "");
00701
00702 icon = Editor.Patch.Icon;
00703 icon->DrawUnitIcon(Players, UI.SingleSelectedButton->Style,
00704 (ButtonUnderCursor == PatchButton ? IconActive : 0) |
00705 (Editor.State == EditorEditPatch ? IconSelected : 0),
00706 x + PATCH_ICON_X, y + PATCH_ICON_Y, "");
00707
00708 icon = Editor.StartUnit->Icon.Icon;
00709 icon->DrawUnitIcon(Players, UI.SingleSelectedButton->Style,
00710 (ButtonUnderCursor == StartButton ? IconActive : 0) |
00711 (Editor.State == EditorSetStartLocation ? IconSelected : 0),
00712 x + START_ICON_X, y + START_ICON_Y, "");
00713
00714 switch (Editor.State)
00715 {
00716 case EditorSelecting:
00717 break;
00718 case EditorEditPatch:
00719 DrawPatchIcons();
00720 break;
00721 case EditorSetStartLocation:
00722 DrawPlayers();
00723 break;
00724 case EditorEditUnit:
00725 DrawPlayers();
00726 DrawUnitIcons();
00727 break;
00728 }
00729 }
00730
00734 static void DrawMapCursor()
00735 {
00736 if (!CursorBuilding)
00737 {
00738 switch (Editor.State)
00739 {
00740 case EditorSelecting:
00741 case EditorEditPatch:
00742 break;
00743 case EditorEditUnit:
00744 if (Editor.SelectedUnitIndex != -1)
00745 {
00746 CursorBuilding = const_cast<CUnitType *> (Editor.ShownUnitTypes[Editor.SelectedUnitIndex]);
00747 }
00748 break;
00749 case EditorSetStartLocation:
00750 CursorBuilding = const_cast<CUnitType *>(Editor.StartUnit);
00751 break;
00752 }
00753 }
00754
00755
00756
00757
00758 if (UI.MouseViewport && !CursorBuilding)
00759 {
00760 int x, y;
00761
00762 x = UI.MouseViewport->Viewport2MapX(CursorX);
00763 y = UI.MouseViewport->Viewport2MapY(CursorY);
00764 x = UI.MouseViewport->Map2ViewportX(x);
00765 y = UI.MouseViewport->Map2ViewportY(y);
00766
00767 if (Editor.State == EditorEditPatch)
00768 {
00769 if (Editor.SelectedPatchIndex != -1)
00770 {
00771
00772 const CPatchType *patchType = Editor.ShownPatchTypes[Editor.SelectedPatchIndex].PatchType;
00773 PushClipping();
00774 SetClipping(UI.MouseViewport->X, UI.MouseViewport->Y,
00775 UI.MouseViewport->EndX, UI.MouseViewport->EndY);
00776 Video.DrawRectangleClip(ColorWhite, x, y,
00777 patchType->getTileWidth() * TileSizeX,
00778 patchType->getTileHeight() * TileSizeY);
00779 PopClipping();
00780 }
00781 }
00782 else
00783 {
00784
00785
00786
00787
00788 if (!UnitUnderCursor)
00789 {
00790 PushClipping();
00791 SetClipping(UI.MouseViewport->X, UI.MouseViewport->Y,
00792 UI.MouseViewport->EndX, UI.MouseViewport->EndY);
00793 Video.DrawRectangleClip(ColorWhite, x, y, TileSizeX, TileSizeY);
00794 PopClipping();
00795 }
00796 }
00797 }
00798 }
00799
00803 static void DrawStartLocations()
00804 {
00805 for (const CViewport *vp = UI.Viewports; vp < UI.Viewports + UI.NumViewports; ++vp)
00806 {
00807 PushClipping();
00808 SetClipping(vp->X, vp->Y, vp->EndX, vp->EndY);
00809
00810 for (int i = 0; i < PlayerMax; ++i)
00811 {
00812 if (Map.Info.PlayerType[i] != PlayerNobody && Map.Info.PlayerType[i] != PlayerNeutral)
00813 {
00814 int x = vp->Map2ViewportX(Players[i].StartX);
00815 int y = vp->Map2ViewportY(Players[i].StartY);
00816
00817 DrawUnitType(Editor.StartUnit, Editor.StartUnit->Sprite, i, 0, x, y);
00818 }
00819 }
00820
00821 PopClipping();
00822 }
00823 }
00824
00830 static void ShowUnitInfo(const CUnit *unit)
00831 {
00832 std::ostringstream o;
00833
00834 o << "#" << UnitNumber(unit) << " '" << unit->Type->Name
00835 << "' - " << _("Player") << ": " << unit->Player->Index;
00836
00837 if (unit->Type->CanHarvestFrom)
00838 {
00839 int res = unit->Type->ProductionCosts[0] ? 0 : 1;
00840 o << " - " << _("Amount of") << " " << DefaultResourceNames[res] << ": "
00841 << unit->ResourcesHeld[res] / CYCLES_PER_SECOND;
00842 }
00843
00844 UI.StatusLine.Set(o.str());
00845 }
00846
00852 static void ShowPatchInfo(const CPatch *patch)
00853 {
00854 std::ostringstream o;
00855
00856 o << _("Patch") << ": " << patch->getType()->getName() << " - ("
00857 << patch->getX() << ", " << patch->getY() << ")";
00858
00859 UI.StatusLine.Set(o.str());
00860 }
00861
00865 static void EditorUpdateDisplay()
00866 {
00867 DrawMapArea();
00868
00869 DrawStartLocations();
00870
00871
00872
00873
00874 for (int i = 0; i < (int)UI.Fillers.size(); ++i)
00875 {
00876 UI.Fillers[i].G->DrawClip(UI.Fillers[i].X, UI.Fillers[i].Y);
00877 }
00878
00879 if (CursorOn == CursorOnMap && Gui->getTop() == editorContainer)
00880 {
00881 DrawMapCursor();
00882 }
00883
00884
00885
00886
00887 DrawMenuButton(UI.MenuButton.Style,
00888 (ButtonAreaUnderCursor == ButtonAreaMenu
00889 && ButtonUnderCursor == ButtonUnderMenu ? MI_FLAGS_ACTIVE : 0) |
00890 (GameMenuButtonClicked ? MI_FLAGS_CLICKED : 0),
00891 UI.MenuButton.X, UI.MenuButton.Y,
00892 UI.MenuButton.Text);
00893
00894
00895
00896
00897 if (UI.SelectedViewport)
00898 {
00899 UI.Minimap.Draw(UI.SelectedViewport->MapX, UI.SelectedViewport->MapY);
00900 UI.Minimap.DrawCursor(UI.SelectedViewport->MapX,
00901 UI.SelectedViewport->MapY);
00902 }
00903
00904
00905
00906 if (UI.ButtonPanel.G)
00907 {
00908 UI.ButtonPanel.G->DrawClip(UI.ButtonPanel.X, UI.ButtonPanel.Y);
00909 }
00910 DrawEditorPanel();
00911
00912
00913
00914
00915 UI.StatusLine.Draw();
00916
00917 DrawGuichanWidgets();
00918
00919 DrawCursor();
00920
00921
00922 Invalidate();
00923 RealizeVideoMemory();
00924 }
00925
00926
00927
00928
00929
00933 static void EditorCallbackButtonUp(unsigned button)
00934 {
00935 if (GameCursor == UI.Scroll.Cursor)
00936 {
00937
00938 GameCursor = UI.Point.Cursor;
00939 return;
00940 }
00941
00942 if ((1 << button) == LeftButton && GameMenuButtonClicked)
00943 {
00944 GameMenuButtonClicked = false;
00945 if (ButtonUnderCursor == ButtonUnderMenu)
00946 {
00947 if (UI.MenuButton.Callback)
00948 {
00949 UI.MenuButton.Callback->action("");
00950 }
00951 }
00952 }
00953 if ((1 << button) == LeftButton)
00954 {
00955 PatchPlacedThisPress = false;
00956 UnitPlacedThisPress = false;
00957 DraggingPatch = false;
00958 }
00959 }
00960
00966 static void EditorCallbackButtonDown(unsigned button)
00967 {
00968 if ((button >> MouseHoldShift) != 0)
00969 {
00970
00971 return;
00972 }
00973
00974
00975
00976
00977 if (CursorOn == CursorOnButton && ButtonAreaUnderCursor == ButtonAreaMenu &&
00978 (MouseButtons & LeftButton) && !GameMenuButtonClicked)
00979 {
00980 PlayGameSound(GameSounds.Click.Sound, MaxSampleVolume);
00981 GameMenuButtonClicked = true;
00982 return;
00983 }
00984
00985
00986
00987
00988 if (CursorOn == CursorOnMinimap)
00989 {
00990
00991 if (MouseButtons & LeftButton)
00992 {
00993 UI.SelectedViewport->Set(
00994 UI.Minimap.Screen2MapX(CursorX) - UI.SelectedViewport->MapWidth / 2,
00995 UI.Minimap.Screen2MapY(CursorY) - UI.SelectedViewport->MapHeight / 2,
00996 TileSizeX / 2, TileSizeY / 2);
00997 }
00998 return;
00999 }
01000
01001
01002
01003
01004 if (CursorOn == CursorOnButton)
01005 {
01006 CursorBuilding = NULL;
01007 switch (ButtonUnderCursor)
01008 {
01009 case SelectButton :
01010 Editor.State = EditorSelecting;
01011 Editor.ShowPatchOutlines = false;
01012 editorUnitSlider->setVisible(false);
01013 editorPatchSlider->setVisible(false);
01014 return;
01015 case UnitButton:
01016 Editor.State = EditorEditUnit;
01017 Editor.ShowPatchOutlines = false;
01018 editorUnitSlider->setVisible(true);
01019 editorPatchSlider->setVisible(false);
01020 return;
01021 case PatchButton :
01022 if (EditorEditPatch)
01023 {
01024 Editor.State = EditorEditPatch;
01025 Editor.ShowPatchOutlines = true;
01026 }
01027 editorUnitSlider->setVisible(false);
01028 editorPatchSlider->setVisible(true);
01029 return;
01030 case StartButton:
01031 Editor.State = EditorSetStartLocation;
01032 Editor.ShowPatchOutlines = false;
01033 editorUnitSlider->setVisible(false);
01034 editorPatchSlider->setVisible(false);
01035 return;
01036 default:
01037 break;
01038 }
01039 }
01040
01041
01042
01043
01044 if (Editor.State == EditorEditUnit || Editor.State == EditorSetStartLocation)
01045 {
01046
01047 if (Editor.CursorPlayer != -1)
01048 {
01049 if (Map.Info.PlayerType[Editor.CursorPlayer] != PlayerNobody)
01050 {
01051 Editor.SelectedPlayer = Editor.CursorPlayer;
01052 ThisPlayer = Players + Editor.SelectedPlayer;
01053 }
01054 return;
01055 }
01056 }
01057
01058
01059
01060
01061 if (Editor.State == EditorEditUnit)
01062 {
01063
01064 if (Editor.CursorUnitIndex != -1)
01065 {
01066 Editor.SelectedUnitIndex = Editor.CursorUnitIndex;
01067 CursorBuilding = const_cast<CUnitType *>(Editor.ShownUnitTypes[Editor.CursorUnitIndex]);
01068 return;
01069 }
01070 }
01071
01072
01073
01074
01075 if (Editor.State == EditorEditPatch)
01076 {
01077
01078 if (Editor.CursorPatchIndex != -1)
01079 {
01080 Editor.SelectedPatchIndex = Editor.CursorPatchIndex;
01081 return;
01082 }
01083 }
01084
01085
01086
01087
01088 if (CursorOn == CursorOnMap)
01089 {
01090
01091 CViewport *vp = GetViewport(CursorX, CursorY);
01092 if ((MouseButtons & LeftButton) && UI.SelectedViewport != vp)
01093 {
01094 UI.SelectedViewport = vp;
01095 }
01096
01097 if (MouseButtons & LeftButton)
01098 {
01099 int cursorMapX = UI.MouseViewport->Viewport2MapX(CursorX);
01100 int cursorMapY = UI.MouseViewport->Viewport2MapY(CursorY);
01101
01102 if (Editor.State == EditorSelecting)
01103 {
01104 if (PatchUnderCursor)
01105 {
01106
01107 PatchOffsetX = cursorMapX - PatchUnderCursor->getX();
01108 PatchOffsetY = cursorMapY - PatchUnderCursor->getY();
01109 DraggingPatch = true;
01110 }
01111 }
01112 else if (Editor.State == EditorEditPatch)
01113 {
01114 if (!PatchPlacedThisPress && Editor.SelectedPatchIndex != -1)
01115 {
01116
01117 const CPatchType *patchType = Editor.ShownPatchTypes[Editor.SelectedPatchIndex].PatchType;
01118 PatchUnderCursor = Map.PatchManager.add(patchType->getName(), cursorMapX, cursorMapY);
01119 PatchPlacedThisPress = true;
01120 UpdateMinimapTerrain = true;
01121 }
01122 }
01123 else if (Editor.State == EditorEditUnit)
01124 {
01125 if (!UnitPlacedThisPress && CursorBuilding)
01126 {
01127
01128 if (CanBuildUnitType(NULL, CursorBuilding, cursorMapX, cursorMapY, 1))
01129 {
01130 PlayGameSound(GameSounds.PlacementSuccess.Sound,
01131 MaxSampleVolume);
01132 EditorPlaceUnit(cursorMapX, cursorMapY,
01133 CursorBuilding, Players + Editor.SelectedPlayer);
01134 UnitPlacedThisPress = true;
01135 UI.StatusLine.Clear();
01136 }
01137 else
01138 {
01139 UI.StatusLine.Set(_("Unit can't be placed here."));
01140 PlayGameSound(GameSounds.PlacementError.Sound,
01141 MaxSampleVolume);
01142 }
01143 }
01144 }
01145 else if (Editor.State == EditorSetStartLocation)
01146 {
01147 Players[Editor.SelectedPlayer].StartX = cursorMapX;
01148 Players[Editor.SelectedPlayer].StartY = cursorMapY;
01149 }
01150 }
01151 else if (MouseButtons & MiddleButton)
01152 {
01153
01154 CursorStartX = CursorX;
01155 CursorStartY = CursorY;
01156 GameCursor = UI.Scroll.Cursor;
01157 }
01158 }
01159 }
01160
01167 static void EditorCallbackKeyDown(unsigned key, unsigned keychar)
01168 {
01169 if (HandleKeyModifiersDown(key, keychar))
01170 {
01171 return;
01172 }
01173
01174 switch (key)
01175 {
01176 case 'f':
01177 if (!(KeyModifiers & (ModifierAlt | ModifierControl)))
01178 {
01179 break;
01180 }
01181 ToggleFullScreen();
01182 break;
01183
01184 case 'v':
01185 if (KeyModifiers & ModifierControl)
01186 {
01187 CycleViewportMode(-1);
01188 }
01189 else
01190 {
01191 CycleViewportMode(1);
01192 }
01193 break;
01194
01195 case 'x':
01196 if (!(KeyModifiers & (ModifierAlt | ModifierControl)))
01197 {
01198 break;
01199 }
01200 Exit(0);
01201
01202 case 'z':
01203 if (KeyModifiers & ModifierControl)
01204 {
01205 EditorUndoAction();
01206 }
01207 break;
01208 case 'y':
01209 if (KeyModifiers & ModifierControl)
01210 {
01211 EditorRedoAction();
01212 }
01213 break;
01214
01215 case SDLK_BACKSPACE:
01216 case SDLK_DELETE:
01217 if (PatchUnderCursor)
01218 {
01219 int cursorMapX = UI.SelectedViewport->Viewport2MapX(CursorX);
01220 int cursorMapY = UI.SelectedViewport->Viewport2MapY(CursorY);
01221 Map.PatchManager.remove(PatchUnderCursor);
01222 PatchUnderCursor = Map.PatchManager.getPatch(cursorMapX, cursorMapY);
01223 UI.StatusLine.Set(_("Patch deleted"));
01224 UpdateMinimapTerrain = true;
01225 }
01226 else if (UnitUnderCursor)
01227 {
01228 EditorRemoveUnit(UnitUnderCursor);
01229 }
01230 break;
01231
01232 case SDLK_UP:
01233 case SDLK_KP8:
01234 KeyScrollState |= ScrollUp;
01235 break;
01236 case SDLK_DOWN:
01237 case SDLK_KP2:
01238 KeyScrollState |= ScrollDown;
01239 break;
01240 case SDLK_LEFT:
01241 case SDLK_KP4:
01242 KeyScrollState |= ScrollLeft;
01243 break;
01244 case SDLK_RIGHT:
01245 case SDLK_KP6:
01246 KeyScrollState |= ScrollRight;
01247 break;
01248
01249 case '0': case '1': case '2':
01250 case '3': case '4': case '5':
01251 case '6': case '7': case '8':
01252 if (UnitUnderCursor && Map.Info.PlayerType[(int)key - '0'] != PlayerNobody)
01253 {
01254 UnitUnderCursor->ChangeOwner(&Players[(int)key - '0']);
01255 UI.StatusLine.Set(_("Unit owner modified"));
01256 UpdateMinimap = true;
01257 }
01258 break;
01259
01260 default:
01261 HandleCommandKey(key);
01262 return;
01263 }
01264 return;
01265 }
01266
01273 static void EditorCallbackKeyUp(unsigned key, unsigned keychar)
01274 {
01275 if (HandleKeyModifiersUp(key, keychar))
01276 {
01277 return;
01278 }
01279
01280 switch (key)
01281 {
01282 case SDLK_UP:
01283 case SDLK_KP8:
01284 KeyScrollState &= ~ScrollUp;
01285 break;
01286 case SDLK_DOWN:
01287 case SDLK_KP2:
01288 KeyScrollState &= ~ScrollDown;
01289 break;
01290 case SDLK_LEFT:
01291 case SDLK_KP4:
01292 KeyScrollState &= ~ScrollLeft;
01293 break;
01294 case SDLK_RIGHT:
01295 case SDLK_KP6:
01296 KeyScrollState &= ~ScrollRight;
01297 break;
01298 default:
01299 break;
01300 }
01301 }
01302
01306 static void EditorCallbackKeyRepeated(unsigned key, unsigned keychar)
01307 {
01308 switch (key)
01309 {
01310 case 'z':
01311 if (KeyModifiers & ModifierControl)
01312 {
01313 EditorUndoAction();
01314 }
01315 break;
01316 case 'y':
01317 if (KeyModifiers & ModifierControl)
01318 {
01319 EditorRedoAction();
01320 }
01321 break;
01322 }
01323 }
01324
01331 static void EditorCallbackMouse(int x, int y)
01332 {
01333 int i;
01334 int bx, by;
01335 static int LastMapX = 0;
01336 static int LastMapY = 0;
01337 enum _cursor_on_ OldCursorOn;
01338 int cursorMapX, cursorMapY;
01339
01340 HandleCursorMove(&x, &y);
01341
01342
01343
01344
01345 if (GameCursor == UI.Scroll.Cursor)
01346 {
01347 MouseScrollMap(x, y);
01348 return;
01349 }
01350
01351 cursorMapX = UI.SelectedViewport->Viewport2MapX(CursorX);
01352 cursorMapY = UI.SelectedViewport->Viewport2MapY(CursorY);
01353
01354
01355 if (LastMapX != cursorMapX || LastMapY != cursorMapY)
01356 {
01357 LastMapX = cursorMapX;
01358 LastMapY = cursorMapY;
01359 UnitPlacedThisPress = false;
01360 }
01361
01362
01363
01364
01365 if (CursorOn == CursorOnMap && (MouseButtons & LeftButton) &&
01366 (Editor.State == EditorSelecting || Editor.State == EditorEditUnit))
01367 {
01368 int moveX = 0;
01369 int moveY = 0;
01370
01371
01372
01373
01374 if (CursorX <= UI.SelectedViewport->X)
01375 moveX = -1;
01376 else if (CursorX >= UI.SelectedViewport->EndX)
01377 moveX = +1;
01378 if (CursorY <= UI.SelectedViewport->Y)
01379 moveY = -1;
01380 else if (CursorY >= UI.SelectedViewport->EndY)
01381 moveY = +1;
01382
01383 if (moveX != 0 || moveY != 0)
01384 {
01385 UI.SelectedViewport->Set(
01386 UI.SelectedViewport->MapX + moveX,
01387 UI.SelectedViewport->MapY + moveY,
01388 UI.SelectedViewport->OffsetX,
01389 UI.SelectedViewport->OffsetY);
01390 }
01391
01392
01393
01394
01395 RestrictCursorToViewport();
01396
01397 if (Editor.State == EditorSelecting && PatchUnderCursor != NULL)
01398 {
01399
01400 Map.PatchManager.move(PatchUnderCursor, cursorMapX - PatchOffsetX, cursorMapY - PatchOffsetY);
01401 ShowPatchInfo(PatchUnderCursor);
01402 UpdateMinimapTerrain = true;
01403 }
01404 else if (Editor.State == EditorEditUnit && CursorBuilding)
01405 {
01406 if (!UnitPlacedThisPress)
01407 {
01408 if (CanBuildUnitType(NULL, CursorBuilding, cursorMapX, cursorMapY, 1))
01409 {
01410 EditorPlaceUnit(cursorMapX, cursorMapY, CursorBuilding, Players + Editor.SelectedPlayer);
01411 UnitPlacedThisPress = true;
01412 UI.StatusLine.Clear();
01413 }
01414 }
01415 }
01416 return;
01417 }
01418
01419
01420
01421
01422 if (CursorOn == CursorOnMinimap && (MouseButtons & LeftButton))
01423 {
01424 RestrictCursorToMinimap();
01425 UI.SelectedViewport->Set(
01426 UI.Minimap.Screen2MapX(CursorX) - UI.SelectedViewport->MapWidth / 2,
01427 UI.Minimap.Screen2MapY(CursorY) - UI.SelectedViewport->MapHeight / 2,
01428 0, 0);
01429 return;
01430 }
01431
01432 OldCursorOn = CursorOn;
01433
01434 MouseScrollState = ScrollNone;
01435 GameCursor = UI.Point.Cursor;
01436 CursorOn = CursorOnUnknown;
01437 Editor.CursorPlayer = -1;
01438 Editor.CursorUnitIndex = -1;
01439 Editor.CursorPatchIndex = -1;
01440 ButtonUnderCursor = -1;
01441
01442
01443
01444
01445 if (x >= UI.Minimap.X && x < UI.Minimap.X + UI.Minimap.W &&
01446 y >= UI.Minimap.Y && y < UI.Minimap.Y + UI.Minimap.H)
01447 {
01448 CursorOn = CursorOnMinimap;
01449 }
01450
01451
01452
01453
01454 if (Editor.State == EditorEditUnit || Editor.State == EditorSetStartLocation)
01455 {
01456
01457 if (UI.ButtonPanel.X + 4 < CursorX && CursorX < UI.ButtonPanel.X + 176 - 4 &&
01458 UI.ButtonPanel.Y + 4 < CursorY && CursorY < UI.ButtonPanel.Y + 24)
01459 {
01460 return;
01461 }
01462 bx = UI.InfoPanel.X + 8;
01463 by = UI.InfoPanel.Y + 4 + IconHeight + 10;
01464 for (i = 0; i < PlayerMax; ++i)
01465 {
01466 if (bx < x && x < bx + 20 && by < y && y < by + 20)
01467 {
01468 if (Map.Info.PlayerType[i] != PlayerNobody)
01469 {
01470 std::ostringstream o;
01471 o << _("Select player #") << i;
01472 UI.StatusLine.Set(o.str());
01473 }
01474 else
01475 {
01476 UI.StatusLine.Clear();
01477 }
01478 Editor.CursorPlayer = i;
01479 return;
01480 }
01481 bx += 20;
01482 }
01483
01484 i = Editor.UnitIndex;
01485 by = UI.ButtonPanel.Y + 24;
01486 while (by < UI.ButtonPanel.Y + ButtonPanelHeight - IconHeight)
01487 {
01488 if (i >= (int)Editor.ShownUnitTypes.size())
01489 {
01490 break;
01491 }
01492 bx = UI.ButtonPanel.X + 10;
01493 while (bx < UI.ButtonPanel.X + 146)
01494 {
01495 if (i >= (int)Editor.ShownUnitTypes.size())
01496 {
01497 break;
01498 }
01499 if (bx < x && x < bx + IconWidth &&
01500 by < y && y < by + IconHeight)
01501 {
01502 std::ostringstream o;
01503 o << Editor.ShownUnitTypes[i]->Ident << " \""
01504 << Editor.ShownUnitTypes[i]->Name << "\"";
01505 UI.StatusLine.Set(o.str());
01506 Editor.CursorUnitIndex = i;
01507 return;
01508 }
01509 bx += IconWidth + 8;
01510 i++;
01511 }
01512 by += IconHeight + 2;
01513 }
01514 }
01515
01516
01517
01518
01519 if (Editor.State == EditorEditPatch)
01520 {
01521 i = Editor.PatchIndex;
01522 by = UI.ButtonPanel.Y + 24;
01523 while (by < UI.ButtonPanel.Y + ButtonPanelHeight - IconHeight)
01524 {
01525 if (i >= (int)Editor.ShownPatchTypes.size())
01526 {
01527 break;
01528 }
01529 bx = UI.ButtonPanel.X + 10;
01530 while (bx < UI.ButtonPanel.X + 146)
01531 {
01532 if (i >= (int)Editor.ShownPatchTypes.size())
01533 {
01534 break;
01535 }
01536 if (bx < x && x < bx + IconWidth &&
01537 by < y && y < by + IconHeight)
01538 {
01539 CPatchType *patchType = Editor.ShownPatchTypes[i].PatchType;
01540 std::ostringstream ostr;
01541 ostr << patchType->getName() << " ("
01542 << patchType->getTileWidth() << "x"
01543 << patchType->getTileHeight() << ")";
01544 UI.StatusLine.Set(ostr.str());
01545 Editor.CursorPatchIndex = i;
01546 PatchUnderCursor = NULL;
01547 return;
01548 }
01549 bx += IconWidth + 8;
01550 i++;
01551 }
01552 by += IconHeight + 2;
01553 }
01554 }
01555
01556
01557
01558
01559 if (UI.InfoPanel.X + 4 < CursorX &&
01560 CursorX < UI.InfoPanel.X + 4 + Editor.Select.Icon->G->Width &&
01561 UI.InfoPanel.Y + 4 < CursorY &&
01562 CursorY < UI.InfoPanel.Y + 4 + Editor.Select.Icon->G->Width)
01563 {
01564
01565 ButtonAreaUnderCursor = -1;
01566 ButtonUnderCursor = SelectButton;
01567 CursorOn = CursorOnButton;
01568 UI.StatusLine.Set(_("Select mode"));
01569 return;
01570 }
01571 if (UI.InfoPanel.X + 4 + UNIT_ICON_X < CursorX &&
01572 CursorX < UI.InfoPanel.X + 4 + UNIT_ICON_X + Editor.Units.Icon->G->Width &&
01573 UI.InfoPanel.Y + 4 + UNIT_ICON_Y < CursorY &&
01574 CursorY < UI.InfoPanel.Y + 4 + UNIT_ICON_Y + Editor.Units.Icon->G->Height)
01575 {
01576 ButtonAreaUnderCursor = -1;
01577 ButtonUnderCursor = UnitButton;
01578 CursorOn = CursorOnButton;
01579 UI.StatusLine.Set(_("Unit mode"));
01580 return;
01581 }
01582 if (UI.InfoPanel.X + 4 + PATCH_ICON_X < CursorX &&
01583 CursorX < UI.InfoPanel.X + 4 + PATCH_ICON_X + Editor.Patch.Icon->G->Width &&
01584 UI.InfoPanel.Y + 4 + PATCH_ICON_Y < CursorY &&
01585 CursorY < UI.InfoPanel.Y + 4 + PATCH_ICON_Y + Editor.Patch.Icon->G->Height)
01586 {
01587 ButtonAreaUnderCursor = -1;
01588 ButtonUnderCursor = PatchButton;
01589 CursorOn = CursorOnButton;
01590 UI.StatusLine.Set(_("Patch mode"));
01591 return;
01592 }
01593 if (UI.InfoPanel.X + 4 + START_ICON_X < CursorX &&
01594 CursorX < UI.InfoPanel.X + 4 + START_ICON_X + Editor.StartUnit->Icon.Icon->G->Width &&
01595 UI.InfoPanel.Y + 4 + START_ICON_Y < CursorY &&
01596 CursorY < UI.InfoPanel.Y + 4 + START_ICON_Y + Editor.StartUnit->Icon.Icon->G->Height)
01597 {
01598 ButtonAreaUnderCursor = -1;
01599 ButtonUnderCursor = StartButton;
01600 CursorOn = CursorOnButton;
01601 UI.StatusLine.Set(_("Set start location mode"));
01602 return;
01603 }
01604 if (UI.MenuButton.X != -1)
01605 {
01606 if (x >= UI.MenuButton.X &&
01607 x <= UI.MenuButton.X + UI.MenuButton.Style->Width &&
01608 y > UI.MenuButton.Y &&
01609 y <= UI.MenuButton.Y + UI.MenuButton.Style->Height)
01610 {
01611 ButtonAreaUnderCursor = ButtonAreaMenu;
01612 ButtonUnderCursor = ButtonUnderMenu;
01613 CursorOn = CursorOnButton;
01614 return;
01615 }
01616 }
01617
01618
01619
01620
01621 if (x >= UI.Minimap.X && x < UI.Minimap.X + UI.Minimap.W &&
01622 y >= UI.Minimap.Y && y < UI.Minimap.Y + UI.Minimap.H)
01623 {
01624 CursorOn = CursorOnMinimap;
01625 return;
01626 }
01627
01628
01629
01630
01631 PatchUnderCursor = NULL;
01632 UnitUnderCursor = NULL;
01633 if (x >= UI.MapArea.X && x <= UI.MapArea.EndX &&
01634 y >= UI.MapArea.Y && y <= UI.MapArea.EndY)
01635 {
01636 CViewport *vp = GetViewport(x, y);
01637 if (UI.MouseViewport != vp)
01638 {
01639
01640 UI.MouseViewport = vp;
01641 }
01642 CursorOn = CursorOnMap;
01643
01644 if (Editor.State != EditorEditPatch)
01645 {
01646
01647 UnitUnderCursor = UnitOnScreen(
01648 CursorX - UI.MouseViewport->X + UI.MouseViewport->MapX * TileSizeX + UI.MouseViewport->OffsetX,
01649 CursorY - UI.MouseViewport->Y + UI.MouseViewport->MapY * TileSizeY + UI.MouseViewport->OffsetY);
01650
01651 if (UnitUnderCursor)
01652 {
01653 ShowUnitInfo(UnitUnderCursor);
01654 return;
01655 }
01656 }
01657
01658
01659 PatchUnderCursor = Map.PatchManager.getPatch(cursorMapX, cursorMapY);
01660 if (PatchUnderCursor)
01661 {
01662 ShowPatchInfo(PatchUnderCursor);
01663 HandleMouseScrollArea(x, y);
01664 return;
01665 }
01666 }
01667
01668
01669
01670
01671 if (HandleMouseScrollArea(x, y))
01672 {
01673 return;
01674 }
01675
01676
01677
01678 UI.StatusLine.Clear();
01679 }
01680
01684 static void EditorCallbackExit()
01685 {
01686 }
01687
01691 static void CreatePatchIcons()
01692 {
01693 std::vector<std::string> patchTypeNames;
01694 std::vector<std::string>::iterator i;
01695
01696
01697 Map.PatchManager.loadAll();
01698
01699
01700 patchTypeNames = Map.PatchManager.getPatchTypeNames();
01701 for (i = patchTypeNames.begin(); i != patchTypeNames.end(); ++i)
01702 {
01703 CPatchType *patchType = Map.PatchManager.getPatchType(*i);
01704 CGraphic *g = patchType->getGraphic()->Clone();
01705
01706 g->Resize(IconWidth, IconHeight);
01707
01708 CPatchIcon patchIcon(patchType, g);
01709 Editor.ShownPatchTypes.push_back(patchIcon);
01710 }
01711 }
01712
01716 static void CleanPatchIcons()
01717 {
01718 for (size_t i = 0; i < Editor.ShownPatchTypes.size(); ++i)
01719 {
01720 CGraphic::Free(Editor.ShownPatchTypes[i].G);
01721 }
01722 Editor.ShownPatchTypes.clear();
01723 }
01724
01728 void CEditor::Init()
01729 {
01730 int i;
01731 char *file;
01732 char buf[PATH_MAX];
01733 CFile clf;
01734
01735
01736
01737
01738
01739 file = LibraryFileName(EditorStartFile, buf, sizeof(buf));
01740 if (clf.open(file, CL_OPEN_READ) != -1)
01741 {
01742 clf.close();
01743 ShowLoadProgress("Script %s", file);
01744 LuaLoadFile(file);
01745 CclGarbageCollect(0);
01746 }
01747
01748 ThisPlayer = &Players[0];
01749
01750 FlagRevealMap = 1;
01751 Map.NoFogOfWar = true;
01752
01753
01754 if (!*CurrentMapPath)
01755 {
01756 InitUnitTypes(1);
01757
01758
01759
01760 InitPlayers();
01761 for (i = 0; i < PlayerMax; ++i)
01762 {
01763 if (i == PlayerNumNeutral)
01764 {
01765 CreatePlayer(PlayerNeutral);
01766 Map.Info.PlayerType[i] = PlayerNeutral;
01767 Map.Info.PlayerSide[i] = 0;
01768 }
01769 else
01770 {
01771 CreatePlayer(PlayerNobody);
01772 Map.Info.PlayerType[i] = PlayerNobody;
01773 }
01774 }
01775
01776 Map.Fields = new CMapField[Map.Info.MapWidth * Map.Info.MapHeight];
01777 Map.Visible[0] = new unsigned[Map.Info.MapWidth * Map.Info.MapHeight / 2];
01778 memset(Map.Visible[0], 0, Map.Info.MapWidth * Map.Info.MapHeight / 2 * sizeof(unsigned));
01779 UnitCache.Init(Map.Info.MapWidth, Map.Info.MapHeight);
01780
01781 GameSettings.Resources = SettingsPresetMapDefault;
01782 CreateGame("", &Map);
01783 }
01784 else
01785 {
01786 CreateGame(CurrentMapPath, &Map);
01787 }
01788
01789 ReplayRevealMap = 1;
01790 FlagRevealMap = 0;
01791 Editor.SelectedPlayer = PlayerNumNeutral;
01792 Editor.PatchOutlineColor = ColorBlack;
01793 Editor.SelectedPatchIndex = -1;
01794
01795
01796
01797
01798 for (i = 0; i < PlayerMax; ++i)
01799 {
01800 if (Map.Info.PlayerType[i] != PlayerNobody)
01801 {
01802
01803 if (Editor.SelectedPlayer == PlayerNumNeutral)
01804 {
01805 Editor.SelectedPlayer = i;
01806 break;
01807 }
01808 }
01809 }
01810
01811 ButtonPanelWidth = 200;
01812 ButtonPanelHeight = 160 + (Video.Height - 480);
01813
01814 CalculateMaxIconSize();
01815 VisibleIcons = CalculateVisibleIcons();
01816
01817 if (!StartUnitName.empty())
01818 {
01819 StartUnit = UnitTypeByIdent(StartUnitName);
01820 }
01821 Select.Icon = NULL;
01822 Select.Load();
01823 Units.Icon = NULL;
01824 Units.Load();
01825 Patch.Icon = NULL;
01826 Patch.Load();
01827
01828 CreatePatchIcons();
01829
01830 RecalculateShownUnits();
01831
01832 EditorUndoActions.clear();
01833 EditorRedoActions.clear();
01834
01835 EditorCallbacks.ButtonPressed = EditorCallbackButtonDown;
01836 EditorCallbacks.ButtonReleased = EditorCallbackButtonUp;
01837 EditorCallbacks.MouseMoved = EditorCallbackMouse;
01838 EditorCallbacks.MouseExit = EditorCallbackExit;
01839 EditorCallbacks.KeyPressed = EditorCallbackKeyDown;
01840 EditorCallbacks.KeyReleased = EditorCallbackKeyUp;
01841 EditorCallbacks.KeyRepeated = EditorCallbackKeyRepeated;
01842 EditorCallbacks.NetworkEvent = NetworkEvent;
01843 }
01844
01855 int EditorSaveMap(const std::string &file)
01856 {
01857 std::string fullName;
01858
01859 fullName = StratagusLibPath + "/" + file;
01860 if (SaveStratagusMap(fullName, &Map) == -1)
01861 {
01862 fprintf(stderr, "Cannot save map\n");
01863 return -1;
01864 }
01865
01866 return 0;
01867 }
01868
01869
01870
01871
01872
01876 static void EditorMainLoop()
01877 {
01878 bool OldCommandLogDisabled = CommandLogDisabled;
01879 const EventCallback *old_callbacks = GetCallbacks();
01880
01881 CommandLogDisabled = true;
01882 SetCallbacks(&EditorCallbacks);
01883
01884 gcn::Widget *oldTop = Gui->getTop();
01885
01886 editorContainer = new gcn::Container();
01887 editorContainer->setDimension(gcn::Rectangle(0, 0, Video.Width, Video.Height));
01888 editorContainer->setOpaque(false);
01889 Gui->setTop(editorContainer);
01890
01891 editorUnitSliderListener = new EditorUnitSliderListener();
01892 editorPatchSliderListener = new EditorPatchSliderListener();
01893
01894 editorUnitSlider = new gcn::Slider();
01895 editorUnitSlider->setBaseColor(gcn::Color(38, 38, 78));
01896 editorUnitSlider->setForegroundColor(gcn::Color(200, 200, 120));
01897 editorUnitSlider->setBackgroundColor(gcn::Color(200, 200, 120));
01898 editorUnitSlider->setSize(176, 16);
01899 editorUnitSlider->setVisible(false);
01900 editorUnitSlider->addActionListener(editorUnitSliderListener);
01901
01902 editorPatchSlider = new gcn::Slider();
01903 editorPatchSlider->setBaseColor(gcn::Color(38, 38, 78));
01904 editorPatchSlider->setForegroundColor(gcn::Color(200, 200, 120));
01905 editorPatchSlider->setBackgroundColor(gcn::Color(200, 200, 120));
01906 editorPatchSlider->setSize(176, 16);
01907 editorPatchSlider->setVisible(false);
01908 editorPatchSlider->addActionListener(editorPatchSliderListener);
01909
01910 editorContainer->add(editorUnitSlider, UI.ButtonPanel.X + 2, UI.ButtonPanel.Y + 4);
01911 editorContainer->add(editorPatchSlider, UI.ButtonPanel.X + 2, UI.ButtonPanel.Y + 4);
01912
01913 UpdateMinimap = true;
01914
01915 while (1)
01916 {
01917 Editor.MapLoaded = false;
01918 Editor.Running = EditorEditing;
01919
01920 Editor.Init();
01921
01922
01923 InterfaceState = IfaceStateNormal;
01924
01925 SetVideoSync();
01926
01927 GameCursor = UI.Point.Cursor;
01928 InterfaceState = IfaceStateNormal;
01929 Editor.State = EditorSelecting;
01930 UI.SelectedViewport = UI.Viewports;
01931
01932 while (Editor.Running)
01933 {
01934 CheckMusicFinished();
01935
01936 if ((FrameCounter % (5 * FRAMES_PER_SECOND)) == 0)
01937 {
01938 if (UpdateMinimapTerrain && !DraggingPatch)
01939 {
01940 UI.Minimap.UpdateTerrain();
01941 UpdateMinimapTerrain = false;
01942 UpdateMinimap = true;
01943 }
01944 if (UpdateMinimap)
01945 {
01946 UI.Minimap.Update();
01947 UpdateMinimap = false;
01948 }
01949 }
01950
01951 EditorUpdateDisplay();
01952
01953
01954
01955
01956 if (UI.MouseScroll && MouseScrollState != ScrollNone)
01957 {
01958 DoScrollArea(MouseScrollState, 0);
01959 }
01960 if (UI.KeyScroll && KeyScrollState != ScrollNone)
01961 {
01962 DoScrollArea(KeyScrollState, (KeyModifiers & ModifierControl) != 0);
01963 if (CursorOn == CursorOnMap && (MouseButtons & LeftButton) &&
01964 Editor.State == EditorEditUnit)
01965 {
01966 EditorCallbackButtonDown(0);
01967 }
01968 }
01969
01970 WaitEventsOneFrame();
01971 }
01972
01973 if (!Editor.MapLoaded)
01974 {
01975 break;
01976 }
01977
01978 CleanModules();
01979 InitDefinedVariables();
01980
01981 LoadCcl();
01982
01983 PreMenuSetup();
01984
01985 InterfaceState = IfaceStateMenu;
01986 GameCursor = UI.Point.Cursor;
01987
01988 Video.ClearScreen();
01989 Invalidate();
01990 }
01991
01992 CommandLogDisabled = OldCommandLogDisabled;
01993 SetCallbacks(old_callbacks);
01994 Gui->setTop(oldTop);
01995 delete editorContainer;
01996 delete editorUnitSliderListener;
01997 delete editorPatchSliderListener;
01998 delete editorUnitSlider;
01999 delete editorPatchSlider;
02000 }
02001
02007 void StartEditor(const std::string &filename)
02008 {
02009 std::string nc, rc;
02010 bool newMap;
02011
02012 GetDefaultTextColors(nc, rc);
02013
02014 DebugPrint("StartEditor - %s\n" _C_ !filename.empty() ? filename.c_str() : "new map");
02015
02016 newMap = filename.empty();
02017 if (!newMap)
02018 {
02019 if (strcpy_s(CurrentMapPath, sizeof(CurrentMapPath), filename.c_str()) != 0)
02020 {
02021 newMap = true;
02022 }
02023 }
02024
02025 if (newMap)
02026 {
02027
02028 strcpy_s(CurrentMapPath, sizeof(CurrentMapPath), "");
02029 Map.Info.Description.clear();
02030
02031 if (Map.Info.MapWidth < 32)
02032 {
02033 fprintf(stderr, "Invalid map width, using default value\n");
02034 Map.Info.MapWidth = 32;
02035 }
02036 else if (Map.Info.MapWidth > MaxMapWidth)
02037 {
02038 fprintf(stderr, "Invalid map width, using default value\n");
02039 Map.Info.MapWidth = MaxMapWidth;
02040 }
02041 if (Map.Info.MapHeight < 32)
02042 {
02043 fprintf(stderr, "Invalid map height, using default value\n");
02044 Map.Info.MapHeight = 32;
02045 }
02046 else if (Map.Info.MapHeight > MaxMapHeight)
02047 {
02048 fprintf(stderr, "Invalid map height, using default value\n");
02049 Map.Info.MapHeight = MaxMapHeight;
02050 }
02051 }
02052
02053
02054 EditorMainLoop();
02055
02056
02057 Video.ClearScreen();
02058 Invalidate();
02059
02060 CleanPatchIcons();
02061 CleanGame();
02062 CleanPlayers();
02063 CleanEditAi();
02064
02065 SetDefaultTextColors(nc, rc);
02066 }
02067