1 #include <algorithm>
2 #include "simulation/ElementCommon.h"
3
4 static void initDeltaPos();
5 static void changeType(ELEMENT_CHANGETYPE_FUNC_ARGS);
6
Element_ETRD()7 void Element::Element_ETRD()
8 {
9 Identifier = "DEFAULT_PT_ETRD";
10 Name = "ETRD";
11 Colour = PIXPACK(0x404040);
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.000f * CFDS;
24 Falldown = 0;
25
26 Flammable = 0;
27 Explosive = 0;
28 Meltable = 0;
29 Hardness = 1;
30
31 Weight = 100;
32
33 HeatConduct = 251;
34 Description = "Electrode. Creates a surface that allows Plasma arcs. (Use sparingly)";
35
36 Properties = TYPE_SOLID|PROP_CONDUCTS|PROP_LIFE_DEC;
37
38 LowPressure = IPL;
39 LowPressureTransition = NT;
40 HighPressure = IPH;
41 HighPressureTransition = NT;
42 LowTemperature = ITL;
43 LowTemperatureTransition = NT;
44 HighTemperature = ITH;
45 HighTemperatureTransition = NT;
46
47 ChangeType = &changeType;
48
49 initDeltaPos();
50 }
51
changeType(ELEMENT_CHANGETYPE_FUNC_ARGS)52 static void changeType(ELEMENT_CHANGETYPE_FUNC_ARGS)
53 {
54 if (sim->etrd_count_valid)
55 {
56 if (from == PT_ETRD && sim->parts[i].life == 0)
57 sim->etrd_life0_count--;
58 if (to == PT_ETRD && sim->parts[i].life == 0)
59 sim->etrd_life0_count++;
60 }
61 }
62
63 class ETRD_deltaWithLength
64 {
65 public:
ETRD_deltaWithLength(ui::Point a,int b)66 ETRD_deltaWithLength(ui::Point a, int b):
67 d(a),
68 length(b)
69 {
70
71 }
72
73 ui::Point d;
74 int length;
75 };
76
77 const int maxLength = 12;
78 std::vector<ETRD_deltaWithLength> deltaPos;
79
initDeltaPos()80 static void initDeltaPos()
81 {
82 deltaPos.clear();
83 for (int ry = -maxLength; ry <= maxLength; ry++)
84 for (int rx = -maxLength; rx <= maxLength; rx++)
85 {
86 ui::Point d(rx, ry);
87 if (std::abs(d.X) + std::abs(d.Y) <= maxLength)
88 deltaPos.push_back(ETRD_deltaWithLength(d, std::abs(d.X) + std::abs(d.Y)));
89 }
90 std::stable_sort(deltaPos.begin(), deltaPos.end(), [](const ETRD_deltaWithLength &a, const ETRD_deltaWithLength &b) {
91 return a.length < b.length;
92 });
93 }
94
Element_ETRD_nearestSparkablePart(Simulation * sim,int targetId)95 int Element_ETRD_nearestSparkablePart(Simulation *sim, int targetId)
96 {
97 if (!sim->elementCount[PT_ETRD])
98 return -1;
99 if (sim->etrd_count_valid && sim->etrd_life0_count <= 0)
100 return -1;
101
102 Particle *parts = sim->parts;
103 int foundDistance = XRES + YRES;
104 int foundI = -1;
105 ui::Point targetPos = ui::Point(parts[targetId].x, parts[targetId].y);
106
107 if (sim->etrd_count_valid)
108 {
109 // countLife0 doesn't need recalculating, so just focus on finding the nearest particle
110
111 // If the simulation contains lots of particles, check near the target position first since going through all particles will be slow.
112 // Threshold = number of positions checked, *2 because it's likely to access memory all over the place (less cache friendly) and there's extra logic needed
113 // TODO: probably not optimal if excessive stacking is used
114 if (sim->parts_lastActiveIndex > (int)deltaPos.size()*2)
115 {
116 for (std::vector<ETRD_deltaWithLength>::iterator iter = deltaPos.begin(), end = deltaPos.end(); iter != end; ++iter)
117 {
118 ETRD_deltaWithLength delta = (*iter);
119 ui::Point checkPos = targetPos + delta.d;
120 int checkDistance = delta.length;
121 if (foundDistance < checkDistance)
122 {
123 // deltaPos is sorted in order of ascending length, so foundDistance < checkDistance means all later items are further away.
124 break;
125 }
126 if (sim->InBounds(checkPos.X, checkPos.Y) && checkDistance <= foundDistance)
127 {
128 int r = sim->pmap[checkPos.Y][checkPos.X];
129 if (r && TYP(r) == PT_ETRD && !parts[ID(r)].life && ID(r) != targetId && checkDistance < foundDistance)
130 {
131 foundDistance = checkDistance;
132 foundI = ID(r);
133 }
134 }
135 }
136 }
137 // If neighbor search didn't find a suitable particle, search all particles
138 if (foundI < 0)
139 {
140 for (int i = 0; i <= sim->parts_lastActiveIndex; i++)
141 {
142 if (parts[i].type == PT_ETRD && !parts[i].life)
143 {
144 ui::Point checkPos = ui::Point(parts[i].x-targetPos.X, parts[i].y-targetPos.Y);
145 int checkDistance = std::abs(checkPos.X) + std::abs(checkPos.Y);
146 if (checkDistance < foundDistance && i != targetId)
147 {
148 foundDistance = checkDistance;
149 foundI = i;
150 }
151 }
152 }
153 }
154 }
155 else
156 {
157 // Recalculate countLife0, and search for the closest suitable particle
158 int countLife0 = 0;
159 for (int i = 0; i <= sim->parts_lastActiveIndex; i++)
160 {
161 if (parts[i].type == PT_ETRD && !parts[i].life)
162 {
163 countLife0++;
164 ui::Point checkPos = ui::Point(parts[i].x-targetPos.X, parts[i].y-targetPos.Y);
165 int checkDistance = std::abs(checkPos.X) + std::abs(checkPos.Y);
166 if (checkDistance < foundDistance && i != targetId)
167 {
168 foundDistance = checkDistance;
169 foundI = i;
170 }
171 }
172 }
173 sim->etrd_life0_count = countLife0;
174 sim->etrd_count_valid = true;
175 }
176 return foundI;
177 }
178