/** * @brief Try to autoplace an item at a position * when right-click was used in the inventory. * @param[in] node The context node * @param[in] mouseX X mouse coordinates. * @param[in] mouseY Y mouse coordinates. */ static void UI_ContainerNodeAutoPlace (uiNode_t* node, int mouseX, int mouseY) { if (!ui_inventory) return; /* don't allow this in tactical missions */ if (CL_BattlescapeRunning()) return; const int sel = cl_selected->integer; if (sel < 0) return; assert(EXTRADATA(node).super.container); int fromX, fromY; Item* ic = UI_BaseInventoryNodeGetItem(node, mouseX, mouseY, &fromX, &fromY); Com_DPrintf(DEBUG_CLIENT, "UI_ContainerNodeAutoPlace: item %i/%i selected from scrollable container.\n", fromX, fromY); if (!ic) return; UI_ContainerNodeAutoPlaceItem(node, ic); /* Update display of scroll buttons. */ UI_BaseInventoryNodeUpdateScroll(node); }
/** * @brief Called by the client when the user type a key * @param[in] key key code, either K_ value or lowercase ascii * @param[in] unicode translated meaning of keypress in unicode * @return true, if we used the event * @todo think about what we should do when the mouse is captured */ bool UI_KeyPressed (unsigned int key, unsigned short unicode) { int windowId; int lastWindowId; if (UI_DNDIsDragging()) { if (key == K_ESCAPE) UI_DNDAbort(); return false; } if (key == K_ESCAPE && CL_BattlescapeRunning() && selActor && CL_ActorFireModeActivated(selActor->actorMode)) { /* Cancel firing with Escape, needed for Android, where right mouse click is bound to multitouch, which is non-obvious */ CL_ActorSetMode(selActor, M_MOVE); return true; } /* translate event into the node with focus */ if (focusNode && UI_Node_KeyPressed(focusNode, key, unicode)) { return true; } /* else use common behaviour */ switch (key) { case K_TAB: if (UI_FocusNextActionNode()) return true; break; case K_ENTER: case K_KP_ENTER: if (UI_FocusExecuteActionNode()) return true; break; case K_ESCAPE: if (UI_GetMouseCapture() != nullptr) { UI_MouseRelease(); return true; } UI_PopWindowWithEscKey(); return true; } lastWindowId = UI_GetLastFullScreenWindow(); if (lastWindowId < 0) return false; /* check "active" window from top to down */ for (windowId = ui_global.windowStackPos - 1; windowId >= lastWindowId; windowId--) { const uiNode_t* window = ui_global.windowStack[windowId]; if (!window) return false; if (UI_KeyPressedInWindow(key, window)) return true; if (UI_WindowIsModal(window)) break; } return false; }
/** * @brief Draw a preview of the DND item dropped into the node */ static void UI_ContainerNodeDrawDropPreview (uiNode_t *target) { item_t previewItem; int checkedTo; vec3_t origine; /* no preview into scrollable list */ if (UI_IsScrollContainerNode(target)) return; /* copy the DND item to not change the original one */ previewItem = *UI_DNDGetItem(); previewItem.rotated = false; checkedTo = INVSH_CheckToInventory(ui_inventory, previewItem.item, EXTRADATA(target).container, dragInfoToX, dragInfoToY, dragInfoIC); switch (checkedTo) { case INV_DOES_NOT_FIT: return; case INV_FITS: break; case INV_FITS_BOTH: /** @todo enable Shift-rotate for battlescape too when issues are solved */ if (!Key_IsDown(K_SHIFT) || CL_BattlescapeRunning()) break; case INV_FITS_ONLY_ROTATED: previewItem.rotated = true; } /* Hack, no preview for armour, we don't want it out of the armour container (and armour container is not visible) */ if (INV_IsArmour(previewItem.item)) return; UI_GetNodeAbsPos(target, origine); origine[2] = -40; /* Get center of single container for placement of preview item */ if (EXTRADATA(target).container->single) { origine[0] += target->box.size[0] / 2.0; origine[1] += target->box.size[1] / 2.0; /* This is a "grid" container - we need to calculate the item-position * (on the screen) from stored placement in the container and the * calculated rotation info. */ } else { if (previewItem.rotated) { origine[0] += (dragInfoToX + previewItem.item->sy / 2.0) * C_UNIT; origine[1] += (dragInfoToY + previewItem.item->sx / 2.0) * C_UNIT; } else { origine[0] += (dragInfoToX + previewItem.item->sx / 2.0) * C_UNIT; origine[1] += (dragInfoToY + previewItem.item->sy / 2.0) * C_UNIT; } } UI_DrawItem(NULL, origine, &previewItem, -1, -1, scale, colorPreview); }
/** * @brief Draws the 3D-cursor in battlemode and the icons/info next to it. */ static void SCR_DrawCursor (void) { if (scr_showcursor->integer == 0) return; if (!scr_cursor->integer) return; if (scr_cursor->modified) { scr_cursor->modified = qfalse; SCR_TouchPics(); } if (!cursorImage[0]) return; if (!UI_DNDIsDragging()) { const char *pic; image_t *image; if (cls.team != cl.actTeam && CL_BattlescapeRunning()) pic = "pics/cursors/wait"; else pic = cursorImage; image = R_FindImage(pic, it_pic); if (image) R_DrawImage(mousePosX - image->width / 2, mousePosY - image->height / 2, image); if (IN_GetMouseSpace() == MS_WORLD && CL_BattlescapeRunning()) { HUD_UpdateCursor(); } } else { UI_DrawCursor(); } }
/** * @brief Finishes the current turn of the player in battlescape and starts the turn for the next team. */ static void CL_NextRound_f (void) { /* can't end round if we are not in battlescape */ if (!CL_BattlescapeRunning()) return; /* can't end round if we're not active */ if (!cls.isOurRound()) { HUD_DisplayMessage(_("It is not your turn!")); return; } /* send endround */ dbuffer msg; NET_WriteByte(&msg, clc_endround); NET_WriteMsg(cls.netStream, msg); }
/** * @brief Draws the rectangle in a 'free' style on position posx/posy (pixel) in the size sizex/sizey (pixel) */ static void UI_DrawFree (containerIndex_t container, const uiNode_t *node, int posx, int posy, int sizex, int sizey, bool showTUs) { const vec4_t color = { 0.0f, 1.0f, 0.0f, 0.7f }; invDef_t* inv = INVDEF(container); vec2_t nodepos; UI_GetNodeAbsPos(node, nodepos); UI_DrawFill(posx, posy, sizex, sizey, color); /* if showTUs is true (only the first time in none single containers) * and we are connected to a game */ if (showTUs && CL_BattlescapeRunning()) { UI_DrawString("f_verysmall", ALIGN_UL, nodepos[0] + 3, nodepos[1] + 3, nodepos[0] + 3, node->box.size[0] - 6, 0, va(_("In: %i Out: %i"), inv->in, inv->out)); } }
/** * @brief Finishes the current round of the player in battlescape and starts the round for the next team. */ static void CL_NextRound_f (void) { struct dbuffer *msg; /* can't end round if we are not in battlescape */ if (!CL_BattlescapeRunning()) return; /* can't end round if we're not active */ if (cls.team != cl.actTeam) { HUD_DisplayMessage(_("This isn't your round")); return; } /* send endround */ msg = new_dbuffer(); NET_WriteByte(msg, clc_endround); NET_WriteMsg(cls.netStream, msg); }
/** * @brief Try to autoplace an item at a position * when right-click was used in the inventory. * @param[in] node The context node * @param[in] mouseX X mouse coordinates. * @param[in] mouseY Y mouse coordinates. */ static void UI_ContainerNodeAutoPlace (uiNode_t* node, int mouseX, int mouseY) { if (!ui_inventory) return; /* don't allow this in tactical missions */ if (CL_BattlescapeRunning()) return; const int sel = cl_selected->integer; if (sel < 0) return; assert(EXTRADATA(node).container); invList_t *ic = UI_ContainerNodeGetItemAtPosition(node, mouseX, mouseY); if (!ic) return; UI_ContainerNodeAutoPlaceItem(node, ic); }
/** * @todo only call/register it when we are on the battlescape */ static void CL_HudRadarUp_f (void) { if (!CL_BattlescapeRunning()) return; UI_CloseWindow("radarmenu"); }
/** * @todo only call/register it when we are on the battlescape */ static void CL_HudRadarDown_f (void) { if (!CL_BattlescapeRunning()) return; UI_PushWindow("radarmenu", NULL, NULL); }
/** * @brief Call into the source when the DND end */ bool uiContainerNode::onDndFinished (uiNode_t *source, bool isDropped) { item_t *dragItem = UI_DNDGetItem(); const invDef_t *sourceContainer = EXTRADATACONST(source).container; /* if the target can't finalize the DND we stop */ if (!isDropped) { return false; } assert(sourceContainer); /* on tactical mission */ if (CL_BattlescapeRunning()) { const uiNode_t *target = UI_DNDGetTargetNode(); const invDef_t *targetContainer = EXTRADATACONST(target).container; assert(targetContainer); CL_ActorInvMove(selActor, sourceContainer->id, dragInfoFromX, dragInfoFromY, targetContainer->id, dragInfoToX, dragInfoToY); } else { uiNode_t *target = UI_DNDGetTargetNode(); if (target) { invList_t *fItem; invList_t *tItem; bool moved = false; const invDef_t *targetContainer = EXTRADATACONST(target).container; assert(targetContainer); if (UI_IsScrollContainerNode(source)) { fItem = UI_ContainerNodeGetExistingItem(sourceContainer, dragItem->item, MAX_FILTERTYPES); } else fItem = INVSH_SearchInInventory(ui_inventory, sourceContainer, dragInfoFromX, dragInfoFromY); assert(fItem); /** @todo We must split the move in two. Here, we should not know how to add the item to the target (see dndDrop) */ /* Remove ammo on removing weapon from a soldier */ if (UI_IsScrollContainerNode(target) && fItem->item.ammo && fItem->item.ammo != fItem->item.item && fItem->item.ammoLeft) INV_UnloadWeapon(fItem, ui_inventory, targetContainer); /* rotate on Shift */ /** @todo enable Shift-rotate for battlescape too when issues are solved */ fItem->item.rotated = Key_IsDown(K_SHIFT) && !CL_BattlescapeRunning(); /* move the item */ moved = INV_MoveItem(ui_inventory, targetContainer, dragInfoToX, dragInfoToY, sourceContainer, fItem, &tItem); /* No need to continue move wasn't successful */ if (!moved) return false; /* Add ammo on adding weapon to a soldier */ if (UI_IsScrollContainerNode(source) && ((fItem->item.item->weapon && !fItem->item.ammoLeft) || fItem->item.item->oneshot)) INV_LoadWeapon(tItem, ui_inventory, sourceContainer, targetContainer); /* Run onChange events */ if (source->onChange) UI_ExecuteEventActions(source, source->onChange); if (source != target && target->onChange) UI_ExecuteEventActions(target, target->onChange); } } dragInfoFromX = -1; dragInfoFromY = -1; return true; }