1 #include "simulation/ElementCommon.h"
2 
3 int Element_FIRE_update(UPDATE_FUNC_ARGS);
4 static int update(UPDATE_FUNC_ARGS);
5 static int graphics(GRAPHICS_FUNC_ARGS);
6 
Element_SPRK()7 void Element::Element_SPRK()
8 {
9 	Identifier = "DEFAULT_PT_SPRK";
10 	Name = "SPRK";
11 	Colour = PIXPACK(0xFFFF80);
12 	MenuVisible = 1;
13 	MenuSection = SC_ELEC;
14 	Enabled = 1;
15 
16 	Advection = 0.0f;
17 	AirDrag = 0.00f * CFDS;
18 	AirLoss = 0.90f;
19 	Loss = 0.00f;
20 	Collision = 0.0f;
21 	Gravity = 0.0f;
22 	Diffusion = 0.00f;
23 	HotAir = 0.001f	* CFDS;
24 	Falldown = 0;
25 
26 	Flammable = 0;
27 	Explosive = 0;
28 	Meltable = 0;
29 	Hardness = 1;
30 	PhotonReflectWavelengths = 0x00000000;
31 
32 	Weight = 100;
33 
34 	HeatConduct = 251;
35 	Description = "Electricity. The basis of all electronics in TPT, travels along wires and other conductive elements.";
36 
37 	Properties = TYPE_SOLID|PROP_LIFE_DEC;
38 
39 	LowPressure = IPL;
40 	LowPressureTransition = NT;
41 	HighPressure = IPH;
42 	HighPressureTransition = NT;
43 	LowTemperature = ITL;
44 	LowTemperatureTransition = NT;
45 	HighTemperature = ITH;
46 	HighTemperatureTransition = NT;
47 
48 	Update = &update;
49 	Graphics = &graphics;
50 }
51 
update(UPDATE_FUNC_ARGS)52 static int update(UPDATE_FUNC_ARGS)
53 {
54 	int r, rx, ry, nearp, pavg, ct = parts[i].ctype, sender, receiver;
55 	Element_FIRE_update(UPDATE_FUNC_SUBCALL_ARGS);
56 
57 	if (parts[i].life<=0)
58 	{
59 		if (ct==PT_WATR||ct==PT_SLTW||ct==PT_PSCN||ct==PT_NSCN||ct==PT_ETRD||ct==PT_INWR)
60 			parts[i].temp = R_TEMP + 273.15f;
61 		if (ct<=0 || ct>=PT_NUM || !sim->elements[parts[i].ctype].Enabled)
62 			ct = PT_METL;
63 		parts[i].ctype = PT_NONE;
64 		parts[i].life = 4;
65 		if (ct == PT_WATR)
66 			parts[i].life = 64;
67 		else if (ct == PT_SLTW)
68 			parts[i].life = 54;
69 		else if (ct == PT_SWCH)
70 			parts[i].life = 14;
71 		if (sim->part_change_type(i,x,y,ct))
72 			return 1;
73 		return 0;
74 	}
75 	//Some functions of SPRK based on ctype (what it is on)
76 	switch(ct)
77 	{
78 	case PT_SPRK:
79 		sim->kill_part(i);
80 		return 1;
81 	case PT_NTCT:
82 	case PT_PTCT:
83 		int Element_NTCT_update(UPDATE_FUNC_ARGS);
84 		Element_NTCT_update(UPDATE_FUNC_SUBCALL_ARGS);
85 		break;
86 	case PT_ETRD:
87 		if (parts[i].life==1)
88 		{
89 			int Element_ETRD_nearestSparkablePart(Simulation *sim, int targetId);
90 			nearp = Element_ETRD_nearestSparkablePart(sim, i);
91 			if (nearp!=-1 && sim->parts_avg(i, nearp, PT_INSL)!=PT_INSL)
92 			{
93 				sim->CreateLine(x, y, (int)(parts[nearp].x+0.5f), (int)(parts[nearp].y+0.5f), PT_PLSM);
94 				parts[i].life = 20;
95 				sim->part_change_type(i,x,y,ct);
96 				ct = parts[i].ctype = PT_NONE;
97 				sim->part_change_type(nearp,(int)(parts[nearp].x+0.5f),(int)(parts[nearp].y+0.5f),PT_SPRK);
98 				parts[nearp].life = 9;
99 				parts[nearp].ctype = PT_ETRD;
100 			}
101 		}
102 		break;
103 	case PT_NBLE:
104 		if (parts[i].life<=1 && !(parts[i].tmp&0x1))
105 		{
106 			parts[i].life = RNG::Ref().between(50, 199);
107 			sim->part_change_type(i,x,y,PT_PLSM);
108 			parts[i].ctype = PT_NBLE;
109 			if (parts[i].temp > 5273.15)
110 				parts[i].tmp |= 0x4;
111 			parts[i].temp = 3500;
112 			sim->pv[y/CELL][x/CELL] += 1;
113 		}
114 		break;
115 	case PT_TESC:
116 		if (parts[i].tmp>300)
117 			parts[i].tmp=300;
118 		for (rx=-1; rx<2; rx++)
119 			for (ry=-1; ry<2; ry++)
120 				if (BOUNDS_CHECK && (rx || ry))
121 				{
122 					r = pmap[y+ry][x+rx];
123 					if (r)
124 						continue;
125 					if (parts[i].tmp>4 && RNG::Ref().chance(1, parts[i].tmp*parts[i].tmp/20+6))
126 					{
127 						int p = sim->create_part(-1, x+rx*2, y+ry*2, PT_LIGH);
128 						if (p!=-1)
129 						{
130 							parts[p].life = RNG::Ref().between(0, 2+parts[i].tmp/15) + parts[i].tmp/7;
131 							if (parts[i].life>60)
132 								parts[i].life=60;
133 							parts[p].temp=parts[p].life*parts[i].tmp/2.5;
134 							parts[p].tmp2=1;
135 							parts[p].tmp=atan2(-ry, (float)rx)/M_PI*360;
136 							parts[i].temp-=parts[i].tmp*2+parts[i].temp/5; // slight self-cooling
137 							if (fabs(sim->pv[y/CELL][x/CELL])!=0.0f)
138 							{
139 								if (fabs(sim->pv[y/CELL][x/CELL])<=0.5f)
140 									sim->pv[y/CELL][x/CELL]=0;
141 								else
142 									sim->pv[y/CELL][x/CELL]-=(sim->pv[y/CELL][x/CELL]>0)?0.5:-0.5;
143 							}
144 						}
145 					}
146 				}
147 		break;
148 	case PT_IRON:
149 		for (rx=-1; rx<2; rx++)
150 			for (ry=-1; ry<2; ry++)
151 				if (BOUNDS_CHECK && (rx || ry))
152 				{
153 					r = pmap[y+ry][x+rx];
154 					if (!r)
155 						continue;
156 					if (TYP(r)==PT_DSTW || TYP(r)==PT_SLTW || TYP(r)==PT_WATR)
157 					{
158 						int rndstore = RNG::Ref().gen()%100;
159 						if (!rndstore)
160 							sim->part_change_type(ID(r),x+rx,y+ry,PT_O2);
161 						else if (3 > rndstore)
162 							sim->part_change_type(ID(r),x+rx,y+ry,PT_H2);
163 					}
164 				}
165 		break;
166 	case PT_TUNG:
167 		if(parts[i].temp < 3595.0){
168 			parts[i].temp += RNG::Ref().between(-4, 15);
169 		}
170 	default:
171 		break;
172 	}
173 	for (rx=-2; rx<3; rx++)
174 		for (ry=-2; ry<3; ry++)
175 			if (BOUNDS_CHECK && (rx || ry))
176 			{
177 				r = pmap[y+ry][x+rx];
178 				if (!r)
179 					continue;
180 				receiver = TYP(r);
181 				sender = ct;
182 				pavg = sim->parts_avg(ID(r), i,PT_INSL);
183 				//receiver is the element SPRK is trying to conduct to
184 				//sender is the element the SPRK is on
185 				//First, some checks usually for (de)activation of elements
186 				switch (receiver)
187 				{
188 				case PT_SWCH:
189 					if (pavg!=PT_INSL && parts[i].life<4)
190 					{
191 						if(sender==PT_PSCN && parts[ID(r)].life<10) {
192 							parts[ID(r)].life = 10;
193 						}
194 						else if (sender==PT_NSCN)
195 						{
196 							parts[ID(r)].ctype = PT_NONE;
197 							parts[ID(r)].life = 9;
198 						}
199 					}
200 					break;
201 				case PT_SPRK:
202 					if (pavg!=PT_INSL && parts[i].life<4)
203 					{
204 						if (parts[ID(r)].ctype==PT_SWCH)
205 						{
206 							if (sender==PT_NSCN)
207 							{
208 								sim->part_change_type(ID(r),x+rx,y+ry,PT_SWCH);
209 								parts[ID(r)].ctype = PT_NONE;
210 								parts[ID(r)].life = 9;
211 							}
212 						}
213 						else if(parts[ID(r)].ctype==PT_NTCT||parts[ID(r)].ctype==PT_PTCT)
214 							if (sender==PT_METL)
215 							{
216 								parts[ID(r)].temp = 473.0f;
217 							}
218 					}
219 					continue;
220 				case PT_PUMP: case PT_GPMP: case PT_HSWC: case PT_PBCN:
221 					if (parts[i].life<4)// PROP_PTOGGLE, Maybe? We seem to use 2 different methods for handling actived elements, this one seems better. Yes, use this one for new elements, PCLN is different for compatibility with existing saves
222 					{
223 						if (sender==PT_PSCN) parts[ID(r)].life = 10;
224 						else if (sender==PT_NSCN && parts[ID(r)].life>=10) parts[ID(r)].life = 9;
225 					}
226 					continue;
227 				case PT_LCRY:
228 					if (abs(rx)<2&&abs(ry)<2 && parts[i].life<4)
229 					{
230 						if (sender==PT_PSCN && parts[ID(r)].tmp == 0) parts[ID(r)].tmp = 2;
231 						else if (sender==PT_NSCN && parts[ID(r)].tmp == 3) parts[ID(r)].tmp = 1;
232 					}
233 					continue;
234 				case PT_PPIP:
235 					if (parts[i].life == 3 && pavg!=PT_INSL)
236 					{
237 						void Element_PPIP_flood_trigger(Simulation * sim, int x, int y, int sparkedBy);
238 						if (sender == PT_NSCN || sender == PT_PSCN || sender == PT_INST)
239 							Element_PPIP_flood_trigger(sim, x+rx, y+ry, sender);
240 					}
241 					continue;
242 				case PT_NTCT: case PT_PTCT: case PT_INWR:
243 					if (sender==PT_METL && pavg!=PT_INSL && parts[i].life<4)
244 					{
245 						parts[ID(r)].temp = 473.0f;
246 						if (receiver==PT_NTCT||receiver==PT_PTCT)
247 							continue;
248 					}
249 					break;
250 				case PT_EMP:
251 					if (!parts[ID(r)].life && parts[i].life > 0 && parts[i].life < 4)
252 					{
253 						sim->emp_trigger_count++;
254 						sim->emp_decor += 3;
255 						if (sim->emp_decor > 40)
256 							sim->emp_decor = 40;
257 						parts[ID(r)].life = 220;
258 					}
259 					continue;
260 				}
261 
262 				if (pavg == PT_INSL) continue; //Insulation blocks everything past here
263 				if (!((sim->elements[receiver].Properties&PROP_CONDUCTS)||receiver==PT_INST||receiver==PT_QRTZ)) continue; //Stop non-conducting receivers, allow INST and QRTZ as special cases
264 				if (abs(rx)+abs(ry)>=4 &&sender!=PT_SWCH&&receiver!=PT_SWCH) continue; //Only switch conducts really far
265 				if (receiver==sender && receiver!=PT_INST && receiver!=PT_QRTZ) goto conduct; //Everything conducts to itself, except INST.
266 
267 				//Sender cases, where elements can have specific outputs
268 				switch (sender)
269 				{
270 				case PT_INST:
271 					if (receiver==PT_NSCN)
272 						goto conduct;
273 					continue;
274 				case PT_SWCH:
275 					if (receiver==PT_PSCN||receiver==PT_NSCN||receiver==PT_WATR||receiver==PT_SLTW||receiver==PT_NTCT||receiver==PT_PTCT||receiver==PT_INWR)
276 						continue;
277 					break;
278 				case PT_ETRD:
279 					if (receiver==PT_METL||receiver==PT_BMTL||receiver==PT_BRMT||receiver==PT_LRBD||receiver==PT_RBDM||receiver==PT_PSCN||receiver==PT_NSCN)
280 						goto conduct;
281 					continue;
282 				case PT_NTCT:
283 					if (receiver==PT_PSCN || (receiver==PT_NSCN && parts[i].temp>373.0f))
284 						goto conduct;
285 					continue;
286 				case PT_PTCT:
287 					if (receiver==PT_PSCN || (receiver==PT_NSCN && parts[i].temp<373.0f))
288 						goto conduct;
289 					continue;
290 				case PT_INWR:
291 					if (receiver==PT_NSCN || receiver==PT_PSCN)
292 						goto conduct;
293 					continue;
294 				default:
295 					break;
296 				}
297 				//Receiving cases, where elements can have specific inputs
298 				switch (receiver)
299 				{
300 				case PT_QRTZ:
301 					if ((sender==PT_NSCN||sender==PT_METL||sender==PT_PSCN||sender==PT_QRTZ) && (parts[ID(r)].temp<173.15||sim->pv[(y+ry)/CELL][(x+rx)/CELL]>8))
302 						goto conduct;
303 					continue;
304 				case PT_NTCT:
305 					if (sender==PT_NSCN || (sender==PT_PSCN&&parts[ID(r)].temp>373.0f))
306 						goto conduct;
307 					continue;
308 				case PT_PTCT:
309 					if (sender==PT_NSCN || (sender==PT_PSCN&&parts[ID(r)].temp<373.0f))
310 						goto conduct;
311 					continue;
312 				case PT_INWR:
313 					if (sender==PT_NSCN || sender==PT_PSCN)
314 						goto conduct;
315 					continue;
316 				case PT_INST:
317 					if (sender==PT_PSCN)
318 						goto conduct;
319 					continue;
320 				case PT_NBLE:
321 					if (!(parts[i].tmp&0x1))
322 						goto conduct;
323 					continue;
324 				case PT_PSCN:
325 					if (sender!=PT_NSCN)
326 						goto conduct;
327 					continue;
328 				default:
329 					break;
330 				}
331 			conduct:
332 				//Yay, passed normal conduction rules, check a few last things and change receiver to spark
333 				if (receiver==PT_WATR||receiver==PT_SLTW) {
334 					if (parts[ID(r)].life==0 && parts[i].life<3)
335 					{
336 						sim->part_change_type(ID(r),x+rx,y+ry,PT_SPRK);
337 						if (receiver==PT_WATR) parts[ID(r)].life = 6;
338 						else parts[ID(r)].life = 5;
339 						parts[ID(r)].ctype = receiver;
340 					}
341 				}
342 				else if (receiver==PT_INST) {
343 					if (parts[ID(r)].life==0 && parts[i].life<4)
344 					{
345 						sim->FloodINST(x+rx,y+ry);//spark the wire
346 					}
347 				}
348 				else if (parts[ID(r)].life==0 && parts[i].life<4) {
349 					parts[ID(r)].life = 4;
350 					parts[ID(r)].ctype = receiver;
351 					sim->part_change_type(ID(r),x+rx,y+ry,PT_SPRK);
352 					if (parts[ID(r)].temp+10.0f<673.0f&&!sim->legacy_enable&&(receiver==PT_METL||receiver==PT_BMTL||receiver==PT_BRMT||receiver==PT_PSCN||receiver==PT_NSCN||receiver==PT_ETRD||receiver==PT_NBLE||receiver==PT_IRON))
353 						parts[ID(r)].temp = parts[ID(r)].temp+10.0f;
354 				}
355 				else if (!parts[ID(r)].life && sender==PT_ETRD && parts[i].life==5) //ETRD is odd and conducts to others only at life 5, this could probably be somewhere else
356 				{
357 					sim->part_change_type(i,x,y,sender);
358 					parts[i].ctype = PT_NONE;
359 					parts[i].life = 20;
360 					parts[ID(r)].life = 4;
361 					parts[ID(r)].ctype = receiver;
362 					sim->part_change_type(ID(r),x+rx,y+ry,PT_SPRK);
363 				}
364 			}
365 	return 0;
366 }
367 
graphics(GRAPHICS_FUNC_ARGS)368 static int graphics(GRAPHICS_FUNC_ARGS)
369 {
370 	*firea = 60;
371 	*firer = *colr/2;
372 	*fireg = *colg/2;
373 	*fireb = *colb/2;
374 	*pixel_mode |= FIRE_SPARK;
375 	return 1;
376 }
377