1/*
2 * LegacyClonk
3 *
4 * Copyright (c) 1998-2000, Matthes Bender (RedWolf Design)
5 * Copyright (c) 2017-2021, The LegacyClonk Team and contributors
6 *
7 * Distributed under the terms of the ISC license; see accompanying file
8 * "COPYING" for details.
9 *
10 * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11 * See accompanying file "TRADEMARK" for details.
12 *
13 * To redistribute this file separately, substitute the full license texts
14 * for the above references.
15 */
16
17/* 32-bit value to identify object definitions */
18
19#pragma once
20
21#include "Standard.h"
22#include "StdAdaptors.h"
23
24#include <string>
25#include <string_view>
26
27// Use 64 Bit for C4ID (on x86_64) to pass 64 bit for each script function
28// parameter
29using C4ID = unsigned long;
30
31constexpr C4ID C4Id(const std::string_view str)
32{
33 using namespace std::string_view_literals;
34 // longer is allowed for backward compatibility reasons, as this is used by the C4Id script function
35 if (str.size() < 4 || str == "NONE"sv)
36 {
37 return 0;
38 }
39
40 C4ID id{0};
41 bool numeric = true;
42 for (const auto c : str)
43 {
44 if (!Inside(ival: c, lbound: '0', rbound: '9'))
45 {
46 numeric = false;
47 break;
48 }
49
50 id *= 10;
51 id += c - '0';
52 }
53
54 if (numeric)
55 {
56 return id;
57 }
58 else
59 {
60 id = 0;
61 }
62
63 for (std::size_t i = 4; i > 0; --i)
64 {
65 id <<= 8;
66 id |= static_cast<C4ID>(str[i - 1]);
67 }
68 return id;
69}
70
71constexpr bool LooksLikeID(const std::string_view str)
72{
73 if (str.size() != 4)
74 {
75 return false;
76 }
77
78 for (const auto c : str)
79 {
80 if (!(Inside(ival: c, lbound: 'A', rbound: 'Z') || Inside(ival: c, lbound: '0', rbound: '9') || (c == '_')))
81 {
82 return false;
83 }
84 }
85 return true;
86}
87
88constexpr C4ID operator""_id(const char *str, std::size_t n)
89{
90 using namespace std::string_literals;
91 const std::string_view idStr{str, n};
92
93 if (n != 4)
94 {
95 throw std::runtime_error{"Invalid ID: "s + str + "; Must be 4 characters long."s};
96 }
97
98 if (!LooksLikeID(str: idStr))
99 {
100 throw std::runtime_error{"Invalid character in ID: "s + str + "; Only A-Z, 0-9 and _ are allowed."s};
101 }
102
103 return C4Id(str: idStr);
104}
105
106constexpr C4ID C4ID_None = "NONE"_id,
107 C4ID_Clonk = "CLNK"_id,
108 C4ID_Flag = "FLAG"_id,
109 C4ID_Conkit = "CNKT"_id,
110 C4ID_Gold = "GOLD"_id,
111 C4ID_Meteor = "METO"_id,
112 C4ID_Linekit = "LNKT"_id,
113 C4ID_PowerLine = "PWRL"_id,
114 C4ID_SourcePipe = "SPIP"_id,
115 C4ID_DrainPipe = "DPIP"_id,
116 C4ID_Energy = "ENRG"_id,
117 C4ID_CnMaterial = "CNMT"_id,
118 C4ID_FlagRemvbl = "FGRV"_id,
119 C4ID_TeamHomebase = "THBA"_id,
120 C4ID_Contents = 0x00002710; // 10000
121
122void GetC4IdText(C4ID id, char *sBuf);
123const char *C4IdText(C4ID id);
124bool LooksLikeID(C4ID id);
125
126// * C4ID Adaptor
127struct C4IDAdapt
128{
129 C4ID &rValue;
130
131 explicit C4IDAdapt(C4ID &rValue) : rValue(rValue) {}
132
133 inline void CompileFunc(StdCompiler *pComp) const
134 {
135 char cC4ID[5];
136 if (pComp->isDecompiler())
137 GetC4IdText(id: rValue, sBuf: cC4ID);
138
139 pComp->Value(rStruct: mkStringAdapt(szString: cC4ID, iMaxLength: 4, eRawType: StdCompiler::RCT_ID));
140
141 if (pComp->isCompiler())
142 {
143 if (strlen(s: cC4ID) != 4)
144 rValue = C4ID_None;
145 else
146 rValue = C4Id(str: cC4ID);
147 }
148 }
149
150 // Operators for default checking/setting
151 inline bool operator==(const C4ID &nValue) const { return rValue == nValue; }
152 inline C4IDAdapt &operator=(const C4ID &nValue) { rValue = nValue; return *this; }
153};
154
155inline C4IDAdapt mkC4IDAdapt(C4ID &rValue) { return C4IDAdapt(rValue); }
156