tron@2186: /* $Id$ */ tron@2186: truelight@988: #include "stdafx.h" Darkvater@1891: #include "openttd.h" truelight@988: #include "table/strings.h" tron@2163: #include "functions.h" tron@2154: #include "player.h" truelight@988: #include "signs.h" truelight@988: #include "saveload.h" truelight@988: #include "command.h" tron@2153: #include "variables.h" truelight@988: truelight@4349: static Sign *_new_sign; tron@2789: truelight@1283: /** truelight@1283: * Called if a new block is added to the sign-pool truelight@1283: */ truelight@1283: static void SignPoolNewBlock(uint start_item) truelight@1283: { truelight@4349: Sign *si; truelight@1283: truelight@4346: /* We don't use FOR_ALL here, because FOR_ALL skips invalid items. truelight@4346: * TODO - This is just a temporary stage, this will be removed. */ tron@4979: for (si = GetSign(start_item); si != NULL; si = (si->index + 1U < GetSignPoolSize()) ? GetSign(si->index + 1U) : NULL) si->index = start_item++; truelight@1283: } truelight@1283: truelight@1283: /* Initialize the sign-pool */ matthijs@5216: DEFINE_OLD_POOL(Sign, Sign, SignPoolNewBlock, NULL) truelight@1283: truelight@988: /** truelight@988: * truelight@988: * Update the coordinate of one sign truelight@988: * truelight@988: */ truelight@4349: static void UpdateSignVirtCoords(Sign *si) truelight@988: { truelight@4349: Point pt = RemapCoords(si->x, si->y, si->z); truelight@4349: SetDParam(0, si->str); truelight@4349: UpdateViewportSignPos(&si->sign, pt.x, pt.y - 6, STR_2806); truelight@988: } truelight@988: truelight@988: /** truelight@988: * truelight@990: * Update the coordinates of all signs truelight@988: * truelight@988: */ tron@1093: void UpdateAllSignVirtCoords(void) truelight@988: { truelight@4349: Sign *si; truelight@988: truelight@4349: FOR_ALL_SIGNS(si) UpdateSignVirtCoords(si); truelight@988: truelight@988: } truelight@988: truelight@988: /** truelight@988: * truelight@988: * Marks the region of a sign as dirty truelight@988: * truelight@4349: * @param si Pointer to the Sign truelight@988: */ truelight@4349: static void MarkSignDirty(Sign *si) truelight@988: { truelight@988: MarkAllViewportsDirty( truelight@4349: si->sign.left - 6, truelight@4349: si->sign.top - 3, truelight@4349: si->sign.left + si->sign.width_1 * 4 + 12, truelight@4349: si->sign.top + 45); truelight@988: } truelight@988: truelight@988: /** truelight@988: * truelight@988: * Allocates a new sign truelight@988: * truelight@988: * @return The pointer to the new sign, or NULL if there is no more free space truelight@988: */ truelight@4349: static Sign *AllocateSign(void) truelight@988: { truelight@4349: Sign *si; truelight@4346: truelight@4346: /* We don't use FOR_ALL here, because FOR_ALL skips invalid items. truelight@4346: * TODO - This is just a temporary stage, this will be removed. */ tron@4979: for (si = GetSign(0); si != NULL; si = (si->index + 1U < GetSignPoolSize()) ? GetSign(si->index + 1U) : NULL) { truelight@4349: if (!IsValidSign(si)) { truelight@4349: uint index = si->index; truelight@1575: truelight@4349: memset(si, 0, sizeof(Sign)); truelight@4349: si->index = index; truelight@1575: truelight@4349: return si; truelight@1575: } truelight@1575: } truelight@988: truelight@1283: /* Check if we can add a block to the pool */ tron@4979: if (AddBlockToPool(&_Sign_pool)) truelight@1283: return AllocateSign(); truelight@1283: truelight@988: return NULL; truelight@988: } truelight@988: truelight@4400: void DestroySign(Sign *si) truelight@4400: { truelight@4400: DeleteName(si->str); truelight@4400: } truelight@4400: truelight@4400: /** truelight@4400: * Place a sign at the given coordinates. Ownership of sign has Darkvater@1793: * no effect whatsoever except for the colour the sign gets for easy recognition, Darkvater@1793: * but everybody is able to rename/remove it. tron@3491: * @param tile tile to place sign at Darkvater@1793: * @param p1 unused Darkvater@1793: * @param p2 unused truelight@988: */ tron@3491: int32 CmdPlaceSign(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) truelight@988: { truelight@4349: Sign *si; truelight@988: truelight@988: /* Try to locate a new sign */ truelight@4349: si = AllocateSign(); truelight@4349: if (si == NULL) return_cmd_error(STR_2808_TOO_MANY_SIGNS); truelight@988: truelight@988: /* When we execute, really make the sign */ truelight@988: if (flags & DC_EXEC) { tron@3491: int x = TileX(tile) * TILE_SIZE; tron@3491: int y = TileY(tile) * TILE_SIZE; tron@3491: truelight@4349: si->str = STR_280A_SIGN; truelight@4349: si->x = x; truelight@4349: si->y = y; truelight@4349: si->owner = _current_player; // owner of the sign; just eyecandy truelight@4349: si->z = GetSlopeZ(x,y); truelight@4349: UpdateSignVirtCoords(si); truelight@4349: MarkSignDirty(si); truelight@1575: InvalidateWindow(WC_SIGN_LIST, 0); truelight@1575: _sign_sort_dirty = true; truelight@4349: _new_sign = si; truelight@988: } truelight@988: truelight@988: return 0; truelight@988: } truelight@988: Darkvater@1793: /** Rename a sign. If the new name of the sign is empty, we assume Darkvater@1793: * the user wanted to delete it. So delete it. Ownership of signs Darkvater@1793: * has no meaning/effect whatsoever except for eyecandy tron@3491: * @param tile unused Darkvater@1793: * @param p1 index of the sign to be renamed/removed Darkvater@1793: * @param p2 unused truelight@988: */ tron@3491: int32 CmdRenameSign(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) truelight@988: { truelight@4352: if (!IsValidSignID(p1)) return CMD_ERROR; Darkvater@1837: Darkvater@1837: /* If _cmd_text 0 means the new text for the sign is non-empty. Darkvater@1793: * So rename the sign. If it is empty, it has no name, so delete it */ Darkvater@1837: if (_cmd_text[0] != '\0') { truelight@988: /* Create the name */ tron@1820: StringID str = AllocateName(_cmd_text, 0); Darkvater@1793: if (str == 0) return CMD_ERROR; truelight@988: truelight@988: if (flags & DC_EXEC) { truelight@4349: Sign *si = GetSign(p1); truelight@988: truelight@988: /* Delete the old name */ truelight@4349: DeleteName(si->str); truelight@988: /* Assign the new one */ truelight@4349: si->str = str; truelight@4349: si->owner = _current_player; truelight@988: Darkvater@1793: /* Update; mark sign dirty twice, because it can either becom longer, or shorter */ truelight@4349: MarkSignDirty(si); truelight@4349: UpdateSignVirtCoords(si); truelight@4349: MarkSignDirty(si); truelight@1575: InvalidateWindow(WC_SIGN_LIST, 0); truelight@1575: _sign_sort_dirty = true; truelight@988: } else { truelight@988: /* Free the name, because we did not assign it yet */ truelight@988: DeleteName(str); truelight@988: } Darkvater@1793: } else { /* Delete sign */ truelight@988: if (flags & DC_EXEC) { truelight@4349: Sign *si = GetSign(p1); truelight@988: truelight@4384: MarkSignDirty(si); truelight@4384: DeleteSign(si); truelight@988: truelight@1575: InvalidateWindow(WC_SIGN_LIST, 0); truelight@1575: _sign_sort_dirty = true; truelight@988: } truelight@988: } truelight@988: truelight@988: return 0; truelight@988: } truelight@988: truelight@988: /** truelight@988: * truelight@988: * Callback function that is called after a sign is placed truelight@988: * truelight@988: */ tron@1977: void CcPlaceSign(bool success, TileIndex tile, uint32 p1, uint32 p2) truelight@988: { truelight@988: if (success) { truelight@4349: ShowRenameSignWindow(_new_sign); truelight@988: ResetObjectToPlace(); truelight@988: } truelight@988: } truelight@988: truelight@988: /** truelight@988: * truelight@988: * PlaceProc function, called when someone pressed the button if the truelight@988: * sign-tool is selected truelight@988: * truelight@988: */ tron@1977: void PlaceProc_Sign(TileIndex tile) truelight@988: { tron@2783: DoCommandP(tile, 0, 0, CcPlaceSign, CMD_PLACE_SIGN | CMD_MSG(STR_2809_CAN_T_PLACE_SIGN_HERE)); truelight@988: } truelight@988: truelight@988: /** truelight@988: * truelight@988: * Initialize the signs truelight@988: * truelight@988: */ tron@1093: void InitializeSigns(void) truelight@988: { tron@4979: CleanPool(&_Sign_pool); tron@4979: AddBlockToPool(&_Sign_pool); truelight@988: } truelight@988: Darkvater@1881: static const SaveLoad _sign_desc[] = { truelight@4349: SLE_VAR(Sign, str, SLE_UINT16), truelight@4349: SLE_CONDVAR(Sign, x, SLE_FILE_I16 | SLE_VAR_I32, 0, 4), truelight@4349: SLE_CONDVAR(Sign, y, SLE_FILE_I16 | SLE_VAR_I32, 0, 4), truelight@4349: SLE_CONDVAR(Sign, x, SLE_INT32, 5, SL_MAX_VERSION), truelight@4349: SLE_CONDVAR(Sign, y, SLE_INT32, 5, SL_MAX_VERSION), truelight@4349: SLE_CONDVAR(Sign, owner, SLE_UINT8, 6, SL_MAX_VERSION), truelight@4349: SLE_VAR(Sign, z, SLE_UINT8), truelight@988: SLE_END() truelight@988: }; truelight@988: truelight@988: /** truelight@988: * truelight@988: * Save all signs truelight@988: * truelight@988: */ tron@1093: static void Save_SIGN(void) truelight@988: { truelight@4349: Sign *si; truelight@988: truelight@4349: FOR_ALL_SIGNS(si) { truelight@4349: SlSetArrayIndex(si->index); truelight@4349: SlObject(si, _sign_desc); truelight@988: } truelight@988: } truelight@988: truelight@988: /** truelight@988: * truelight@988: * Load all signs truelight@988: * truelight@988: */ tron@1093: static void Load_SIGN(void) truelight@988: { truelight@988: int index; truelight@988: while ((index = SlIterateArray()) != -1) { truelight@4349: Sign *si; truelight@988: tron@4979: if (!AddBlockIfNeeded(&_Sign_pool, index)) truelight@1283: error("Signs: failed loading savegame: too many signs"); truelight@1283: truelight@4349: si = GetSign(index); truelight@4349: SlObject(si, _sign_desc); truelight@988: } truelight@1575: truelight@1575: _sign_sort_dirty = true; truelight@988: } truelight@988: truelight@988: const ChunkHandler _sign_chunk_handlers[] = { truelight@988: { 'SIGN', Save_SIGN, Load_SIGN, CH_ARRAY | CH_LAST}, truelight@988: };