1 /* ResidualVM - A 3D game interpreter
2  *
3  * ResidualVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the AUTHORS
5  * file distributed with this source distribution.
6  *
7  * Additional copyright for this file:
8  * Copyright (C) 1999-2000 Revolution Software Ltd.
9  * This code is based on source code created by Revolution Software,
10  * used with permission.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25  *
26  */
27 
28 #include "engines/icb/p4.h"
29 #include "engines/icb/common/px_globalvariables.h"
30 
31 namespace ICB {
32 
CpxGlobalScriptVariables()33 CpxGlobalScriptVariables::CpxGlobalScriptVariables() {
34 	m_no_vars = 0;
35 	m_sorted = 0;
36 
37 	int32 i;
38 	for (i = 0; i < MAX_global_vars; i++) {
39 		m_vars[i].hash = 666;
40 		m_vars[i].value = 666;
41 		m_varInit[i] = GLOBAL_VAR_NOT_SET;
42 	}
43 }
44 
FindVariable(uint32 hash)45 int32 CpxGlobalScriptVariables::FindVariable(uint32 hash) {
46 	int32 index = -1;
47 
48 	if (m_sorted == 0) {
49 		SortVariables();
50 	} else {
51 		// Use binary search system to find the variables
52 		// The variables are stored in ascending hash sorted order
53 		int32 min = 0;
54 		int32 max = m_no_vars;
55 		index = ((max - min) >> 1);
56 		CpxVariable *pvar = m_vars + index;
57 
58 		// Start at the middle of the list
59 		while (pvar->hash != hash) {
60 			// Not found
61 			if ((index == min) || (index == max)) {
62 				index = -1;
63 				break;
64 			}
65 
66 			// Is it further up the table ?
67 			if (hash > pvar->hash) {
68 				min = index;
69 				// Go down from min so we creep towards maximum
70 				index = max - ((max - min) >> 1);
71 			} else {
72 				max = index;
73 				// Go up from min so we creep towards minimum
74 				index = min + ((max - min) >> 1);
75 			}
76 			pvar = m_vars + index;
77 
78 			if (max == min)
79 				Fatal_error("GlobalVars Binary search failed max==min %d number %d", max, m_no_vars);
80 		}
81 
82 //#define CHECK_BINARY_SEARCH
83 #ifdef CHECK_BINARY_SEARCH
84 		uint32 i;
85 		int32 oldi = 0;
86 		// Check the binarry search worked
87 		for (i = 0; i < m_no_vars; i++) {
88 			if (m_vars[i].hash == hash) {
89 				oldi = i;
90 				break;
91 			}
92 		}
93 		if (oldi != index) {
94 			Fatal_error("Binary search failed");
95 		}
96 #endif
97 	}
98 
99 	return index;
100 }
101 
InitVariable(uint32 hash,int32 value,const char * name)102 void CpxGlobalScriptVariables::InitVariable(uint32 hash, int32 value, const char *name) {
103 	// If the variable exists then it has already been initialised
104 
105 	int32 i = FindVariable(hash);
106 	if (i == -1) {
107 		m_vars[m_no_vars].hash = hash;
108 		m_vars[m_no_vars].value = value;
109 		if (name) {
110 			Tdebug("gtable.txt", "%s , %d , 0x%X", name, value, hash);
111 		}
112 		m_no_vars++;
113 		// The list is no int32er sorted !
114 		m_sorted = 0;
115 	} else {
116 		// The variable has been set, so initing it is an error
117 		//		Fatal_error( "Global variable with hash 0x%08x has already been initialised",hash); // Game engine error
118 		m_vars[i].value = value;
119 	}
120 }
121 
SetVariable(uint32 hash,int32 value)122 void CpxGlobalScriptVariables::SetVariable(uint32 hash, int32 value) {
123 	// Set a variable
124 	// You can't set a variable that has not been initialised
125 	// Has the variable been defined already
126 	int32 i = FindVariable(hash);
127 	if (i != -1) {
128 		// Once a variable is set then flag it as such
129 		m_varInit[i] = GLOBAL_VAR_SET;
130 
131 		// Ok, just return the value
132 		m_vars[i].value = value;
133 	} else {
134 		// The variable hasn't been set, so accessing it is an error
135 		Fatal_error("SetVariable::Global variable with hash 0x%08x has been accessed before it was initialised", hash); // Game engine error
136 	}
137 }
138 
139 // warn = 1
140 // Give a warning if someone Get's the value before Setting it
141 // i.e. they are relying on the initialisation code which is bad
142 // warn = 0
143 // Don't give the warning - this is needed for save games which Get all global's !
GetVariable(uint32 hash,const char * name,int32 warn)144 int32 CpxGlobalScriptVariables::GetVariable(uint32 hash, const char *name, int32 warn) {
145 	// Has the variable been defined already
146 	int32 i = FindVariable(hash);
147 	if (i != -1) {
148 		if (warn == 1) {
149 			// Give a warning if someone Get's the value before Setting it
150 			// i.e. they are relying on the initialisation code which is bad
151 			// Once a variable is set then flag it as such
152 			if (m_varInit[i] == GLOBAL_VAR_NOT_SET) {
153 				// Only give the warning once
154 				m_varInit[i] = GLOBAL_VAR_SET;
155 
156 				if (name) {
157 					{ Message_box("GetVariable::Global variable '%s' hash 0x%08X value %d accessed before it was set", name, hash, m_vars[i].value); }
158 				} else {
159 					{ Message_box("GetVariable::Global variable hash 0x%08X value %d accessed before it was set", hash, m_vars[i].value); }
160 				}
161 			}
162 		}
163 
164 		// Ok, just return the value
165 		return m_vars[i].value;
166 	} else {
167 		// The variable hasn't been set, so accessing it is an error
168 		Fatal_error("GetVariable::Global variable with hash 0x%08X has been accessed before it was initialised", hash); // Game engine error
169 		return 0;
170 	}
171 }
172 
173 //
174 // Sort the variables so searching for them is quicker !
175 // The search method can then use a binary chop system
176 //
SortVariables()177 void CpxGlobalScriptVariables::SortVariables() {
178 	uint32 i;
179 	uint32 j;
180 	CpxVariable temp;
181 	uint8 temp8;
182 
183 	// Sort the variable in ascending order
184 	// e.g. lowest -> highest
185 	for (i = 0; i < m_no_vars; i++) {
186 		for (j = i + 1; j < m_no_vars; j++) {
187 			if (m_vars[i].hash > m_vars[j].hash) {
188 				temp = m_vars[i];
189 				m_vars[i] = m_vars[j];
190 				m_vars[j] = temp;
191 
192 				temp8 = m_varInit[i];
193 				m_varInit[i] = m_varInit[j];
194 				m_varInit[j] = temp8;
195 			}
196 		}
197 	}
198 	// The list is now sorted
199 	m_sorted = 1;
200 }
201 
202 } // End of namespace ICB
203