00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "../ui_main.h"
00026 #include "../ui_parse.h"
00027 #include "../ui_tooltip.h"
00028 #include "../ui_nodes.h"
00029 #include "../ui_render.h"
00030 #include "ui_node_base.h"
00031 #include "ui_node_abstractnode.h"
00032
00033 #include "../../client.h"
00034 #include "../../campaign/cp_campaign.h"
00035
00036 #define EXTRADATA_TYPE baseExtraData_t
00037 #define EXTRADATA(node) UI_EXTRADATA(node, baseExtraData_t)
00038
00042 static void UI_AbstractBaseNodeLoaded (uiNode_t * node)
00043 {
00044 const int id = EXTRADATA(node).baseid;
00045 if (id < 0 || id >= MAX_BASES) {
00046 Com_Printf("UI_AbstractBaseNodeLoaded: Invalid baseid given %i", id);
00047 }
00048 }
00049
00053 static void UI_BaseLayoutNodeDraw (uiNode_t * node)
00054 {
00055 base_t *base;
00056 int height, width, y;
00057 int row, col;
00058 const vec4_t c_gray = {0.5, 0.5, 0.5, 1.0};
00059 vec2_t nodepos;
00060 int totalMarge;
00061
00062 if (EXTRADATA(node).baseid >= MAX_BASES || EXTRADATA(node).baseid < 0)
00063 return;
00064
00065 totalMarge = node->padding * (BASE_SIZE + 1);
00066 width = (node->size[0] - totalMarge) / BASE_SIZE;
00067 height = (node->size[1] - totalMarge) / BASE_SIZE;
00068
00069 UI_GetNodeAbsPos(node, nodepos);
00070
00071 base = B_GetBaseByIDX(EXTRADATA(node).baseid);
00072
00073 y = nodepos[1] + node->padding;
00074 for (row = 0; row < BASE_SIZE; row++) {
00075 int x = nodepos[0] + node->padding;
00076 for (col = 0; col < BASE_SIZE; col++) {
00077 if (base->map[row][col].blocked) {
00078 UI_DrawFill(x, y, width, height, c_gray);
00079 } else if (base->map[row][col].building) {
00080
00081 if (base->founded)
00082 UI_DrawFill(x, y, width, height, node->color);
00083 }
00084 x += width + node->padding;
00085 }
00086 y += height + node->padding;
00087 }
00088 }
00089
00091 #define BASE_IMAGE_OVERLAY 20
00092
00101 static void UI_BaseMapGetCellAtPos (const uiNode_t *node, int x, int y, int *col, int *row)
00102 {
00103 assert(col);
00104 assert(row);
00105 UI_NodeAbsoluteToRelativePos(node, &x, &y);
00106 if (x < 0 || y < 0 || x >= node->size[0] || y >= node->size[1]) {
00107 *col = -1;
00108 *row = -1;
00109 return;
00110 }
00111 *col = x / (node->size[0] / BASE_SIZE);
00112 *row = y / (node->size[0] / BASE_SIZE);
00113 assert(*col >= 0 && *col < BASE_SIZE);
00114 assert(*row >= 0 && *row < BASE_SIZE);
00115 }
00116
00121 static inline qboolean UI_BaseMapIsCellFree (const base_t *base, int col, int row)
00122 {
00123 return col >= 0 && col < BASE_SIZE
00124 && row >= 0 && row < BASE_SIZE
00125 && base->map[row][col].building == NULL
00126 && !base->map[row][col].blocked;
00127 }
00128
00132 static void UI_BaseMapNodeDraw (uiNode_t * node)
00133 {
00134 int width, height, row, col;
00135 char image[MAX_QPATH];
00136 const building_t *building;
00137 const building_t *secondBuilding = NULL;
00138 const base_t *base = B_GetCurrentSelectedBase();
00139 qboolean used[MAX_BUILDINGS];
00140
00141 if (!base) {
00142 UI_PopWindow(qfalse);
00143 return;
00144 }
00145
00146
00147 memset(used, 0, sizeof(used));
00148
00149 width = node->size[0] / BASE_SIZE;
00150 height = node->size[1] / BASE_SIZE + BASE_IMAGE_OVERLAY;
00151
00152 for (row = 0; row < BASE_SIZE; row++) {
00153 for (col = 0; col < BASE_SIZE; col++) {
00154 vec2_t pos;
00155 UI_GetNodeAbsPos(node, pos);
00156 pos[0] += col * width;
00157 pos[1] += row * (height - BASE_IMAGE_OVERLAY);
00158
00159
00160 image[0] = '\0';
00161 if (base->map[row][col].blocked) {
00162 building = NULL;
00163 Q_strncpyz(image, "base/invalid", sizeof(image));
00164 } else if (!base->map[row][col].building) {
00165 building = NULL;
00166 Q_strncpyz(image, "base/grid", sizeof(image));
00167 } else {
00168 building = base->map[row][col].building;
00169 secondBuilding = NULL;
00170 assert(building);
00171
00172
00173
00174
00175 if (!B_BuildingGetUsed(used, building->idx)) {
00176 if (building->needs)
00177 B_BuildingSetUsed(used, building->idx);
00178 if (building->image)
00179 Q_strncpyz(image, building->image, sizeof(image));
00180 } else {
00181 secondBuilding = B_GetBuildingTemplate(building->needs);
00182 if (!secondBuilding)
00183 Com_Error(ERR_DROP, "Error in ufo-scriptfile - could not find the needed building");
00184 Q_strncpyz(image, secondBuilding->image, sizeof(image));
00185 }
00186 }
00187
00188
00189 if (image[0] != '\0')
00190 UI_DrawNormImageByName(pos[0], pos[1], width, height, 0, 0, 0, 0, image);
00191
00192
00193 if (building && !secondBuilding) {
00194 switch (building->buildingStatus) {
00195 case B_STATUS_DOWN:
00196 case B_STATUS_CONSTRUCTION_FINISHED:
00197 break;
00198 case B_STATUS_UNDER_CONSTRUCTION:
00199 {
00200 const int time = building->buildTime - (ccs.date.day - building->timeStart);
00201 UI_DrawString("f_small", ALIGN_UL, pos[0] + 10, pos[1] + 10, pos[0] + 10, node->size[0], 0, va(ngettext("%i day left", "%i days left", time), time), 0, 0, NULL, qfalse, 0);
00202 break;
00203 }
00204 default:
00205 break;
00206 }
00207 }
00208 }
00209 }
00210
00211 if (!node->state)
00212 return;
00213
00214 UI_BaseMapGetCellAtPos(node, mousePosX, mousePosY, &col, &row);
00215 if (col == -1)
00216 return;
00217
00218
00219 if (ccs.baseAction == BA_NEWBUILDING) {
00220 qboolean isLarge;
00221 assert(base->buildingCurrent);
00223 if (!UI_BaseMapIsCellFree(base, col, row))
00224 return;
00225
00226 isLarge = base->buildingCurrent->needs != NULL;
00227
00228
00229 if (isLarge) {
00230 if (UI_BaseMapIsCellFree(base, col + 1, row)) {
00231
00232 } else if (UI_BaseMapIsCellFree(base, col - 1, row)) {
00233
00234 col--;
00235 } else {
00236 col = -1;
00237 }
00238 }
00239 if (col != -1) {
00240 vec2_t pos;
00241 UI_GetNodeAbsPos(node, pos);
00242 if (isLarge) {
00243 UI_DrawNormImageByName(pos[0] + col * width, pos[1] + row * (height - BASE_IMAGE_OVERLAY), width + width, height, 0, 0, 0, 0, "base/hover2");
00244 } else
00245 UI_DrawNormImageByName(pos[0] + col * width, pos[1] + row * (height - BASE_IMAGE_OVERLAY), width, height, 0, 0, 0, 0, "base/hover");
00246 }
00247 }
00248 }
00249
00256 static void UI_BaseMapNodeDrawTooltip (uiNode_t *node, int x, int y)
00257 {
00258 int col, row;
00259 building_t *building;
00260 const int itemToolTipWidth = 250;
00261 char *tooltipText;
00262 base_t *base = B_GetCurrentSelectedBase();
00263
00264 UI_BaseMapGetCellAtPos(node, x, y, &col, &row);
00265 if (col == -1)
00266 return;
00267
00268 building = base->map[row][col].building;
00269 if (!building)
00270 return;
00271
00272 tooltipText = _(building->name);
00273 if (!B_CheckBuildingDependencesStatus(base, building))
00274 tooltipText = va("%s\n%s %s", tooltipText, _("not operational, depends on"), _(building->dependsBuilding->name));
00275 UI_DrawTooltip(tooltipText, x, y, itemToolTipWidth);
00276 }
00277
00285 static void UI_BaseMapNodeClick (uiNode_t *node, int x, int y)
00286 {
00287 int row, col;
00288 base_t *base = B_GetCurrentSelectedBase();
00289
00290 assert(base);
00291 assert(node);
00292 assert(node->root);
00293
00294 UI_BaseMapGetCellAtPos(node, x, y, &col, &row);
00295 if (col == -1)
00296 return;
00297
00298 if (ccs.baseAction == BA_NEWBUILDING) {
00299 assert(base->buildingCurrent);
00300 if (!base->map[row][col].building && !base->map[row][col].blocked) {
00301 if (!base->buildingCurrent->needs
00302 || (col < BASE_SIZE - 1 && !base->map[row][col + 1].building && !base->map[row][col + 1].blocked)
00303 || (col > 0 && !base->map[row][col - 1].building && !base->map[row][col - 1].blocked))
00304
00305 B_SetBuildingByClick(base, base->buildingCurrent, row, col);
00306 }
00307 return;
00308 }
00309
00310 if (base->map[row][col].building) {
00311 const building_t *entry = base->map[row][col].building;
00312 if (!entry)
00313 Com_Error(ERR_DROP, "UI_BaseMapNodeClick: no entry at %i:%i", x, y);
00314
00315 assert(!base->map[row][col].blocked);
00316
00317 B_BuildingOpenAfterClick(base, entry);
00318 ccs.baseAction = BA_NONE;
00319 return;
00320 }
00321 }
00322
00330 static void UI_BaseMapNodeRightClick (uiNode_t *node, int x, int y)
00331 {
00332 int row, col;
00333 base_t *base = B_GetCurrentSelectedBase();
00334
00335 assert(base);
00336 assert(node);
00337 assert(node->root);
00338
00339 UI_BaseMapGetCellAtPos(node, x, y, &col, &row);
00340 if (col == -1)
00341 return;
00342
00343 if (base->map[row][col].building) {
00344 building_t *entry = base->map[row][col].building;
00345 if (!entry)
00346 Sys_Error("UI_BaseMapNodeRightClick: no entry at %i:%i\n", x, y);
00347
00348 assert(!base->map[row][col].blocked);
00349 B_MarkBuildingDestroy(base, entry);
00350 return;
00351 }
00352 }
00353
00362 static void UI_BaseMapNodeMiddleClick (uiNode_t *node, int x, int y)
00363 {
00364 int row, col;
00365 base_t *base = B_GetCurrentSelectedBase();
00366
00367 assert(base);
00368 assert(node);
00369 assert(node->root);
00370
00371 UI_BaseMapGetCellAtPos(node, x, y, &col, &row);
00372 if (col == -1)
00373 return;
00374
00375 if (base->map[row][col].building) {
00376 building_t *entry = base->map[row][col].building;
00377 if (!entry)
00378 Com_Error(ERR_DROP, "UI_BaseMapNodeMiddleClick: no entry at %i:%i", x, y);
00379
00380 assert(!base->map[row][col].blocked);
00381 B_DrawBuilding(base, entry);
00382 return;
00383 }
00384 }
00385
00389 static void UI_BaseLayoutNodeLoading (uiNode_t *node)
00390 {
00391 node->padding = 3;
00392 Vector4Set(node->color, 1, 1, 1, 1);
00393 }
00394
00395 static const value_t properties[] = {
00396
00397 {"baseid", V_INT, UI_EXTRADATA_OFFSETOF(baseExtraData_t, baseid), MEMBER_SIZEOF(baseExtraData_t, baseid)},
00398 {NULL, V_NULL, 0, 0}
00399 };
00400
00401 void UI_RegisterAbstractBaseNode (uiBehaviour_t *behaviour)
00402 {
00403 behaviour->name = "abstractbase";
00404 behaviour->isAbstract = qtrue;
00405 behaviour->properties = properties;
00406 behaviour->loaded = UI_AbstractBaseNodeLoaded;
00407 behaviour->extraDataSize = sizeof(EXTRADATA_TYPE);
00408 }
00409
00410 void UI_RegisterBaseMapNode (uiBehaviour_t *behaviour)
00411 {
00412 behaviour->name = "basemap";
00413 behaviour->extends = "abstractbase";
00414 behaviour->draw = UI_BaseMapNodeDraw;
00415 behaviour->leftClick = UI_BaseMapNodeClick;
00416 behaviour->rightClick = UI_BaseMapNodeRightClick;
00417 behaviour->drawTooltip = UI_BaseMapNodeDrawTooltip;
00418 behaviour->middleClick = UI_BaseMapNodeMiddleClick;
00419 }
00420
00421 void UI_RegisterBaseLayoutNode (uiBehaviour_t *behaviour)
00422 {
00423 behaviour->name = "baselayout";
00424 behaviour->extends = "abstractbase";
00425 behaviour->draw = UI_BaseLayoutNodeDraw;
00426 behaviour->loading = UI_BaseLayoutNodeLoading;
00427 }