3 #include <uniconfroot.h>
8 #include "twccontainer.h"
9 #include "twcgenerator.h"
14 #define RANDOMIZE_SECTORS 1
16 TWCGenerator::TWCGenerator() : all_sectors(), planet_sectors(), port_sectors(), log("Generator", WvLog::Info
)
18 log(WvLog::Info
, "And there was light...\n");
22 TWCGenerator::~TWCGenerator()
26 log(WvLog::Info
, "Universe Generator collapsing in upon itself...\n");
30 unsigned int TWCGenerator::Connect(unsigned int from
, unsigned int to
, unsigned int dist
)
32 if(from
>= all_sectors
.Count() || to
>= all_sectors
.Count())
34 log(WvLog::Error
, "Out of range.\n");
38 if(IsConnected(from
, to
))
40 log(WvLog::Info
, "Sector %s is already conected to Sector %s\n", from
, to
);
41 return GENERATOR_SUCCESS
;
45 log(WvLog::Info
, "Connecting Sector %s to Sector %s\n", from
, to
);
46 all_sectors
[from
]->AddExit(all_sectors
[to
], dist
);
47 return GENERATOR_SUCCESS
;
52 unsigned int TWCGenerator::ConnectAllSectors(float stdev
, float prob_bi_dir
, unsigned int max_distance
)
54 log(WvLog::Info
, "Connecting Sectors.\n");
56 // connect all of the sectors in 'all_sectors' in order, thereby
57 // establishing a uni-directional, circular path through them.
58 for (unsigned int n
= 0; n
< all_sectors
.Count() - 1; ++n
)
60 log(WvLog::Debug1
, "Connecting sector %s to sector %s\n", n
, n
+1);
62 if(Connect(n
, n
+1, 1) != GENERATOR_SUCCESS
)
66 // all_sectors[i]->AddExit(all_sectors[i+1], 1);
68 // complete the circle...
70 if(all_sectors
.Count() > 1)
72 log(WvLog::Debug1
, "Connecting sector %s to sector %s\n", all_sectors
.Count()-1, 0);
74 if(Connect(all_sectors
.Count() - 1, 0, 1) != GENERATOR_SUCCESS
)
80 // for each sector, establish a uni-directional link with other sectors
81 // (the number of connections is dictated by a pdf)
82 // (for now, just have each sector connected to 'degree'
84 for (unsigned int n
= 0; n
< all_sectors
.Count(); ++n
)
86 log(WvLog::Debug
, "Generating random connections for sector %s.\n", n
);
88 unsigned int j
= abs((int)(box_muller(0, stdev
/2)));
90 // eliminate the chance that the generator will try to establish more
91 // exits than exist sectors
92 if(j
>= all_sectors
.Count() - 1)
94 // -1 because it can't connect to itself
95 j
= all_sectors
.Count() - 1;
98 // now, subtract the number of pre-existing connections
99 if(all_sectors
[n
]->NumExits() > j
)
105 j
-= all_sectors
[n
]->NumExits();
108 log(WvLog::Debug1
, "This sector will have %s additional exit(s).\n", j
);
112 unsigned int rnd
= (rand() % (all_sectors
.Count() - 1));
114 // don't let the sector connect to itself
120 // don't let the sector have multiple connections to the same
122 while(IsConnected(n
, rnd
) == true)
124 log(WvLog::Debug1
, "<!> Sector %s and sector %s are already connected. Try again.\n", n
, rnd
);
125 log(WvLog::Debug1
, "<!> -->Need to establish %s more connections.\n", j
);
127 rnd
= (rand() % (all_sectors
.Count() - 1));
135 dist
= max_distance
==0?0:(rand() % max_distance
) + 1;
137 log(WvLog::Debug1
, "Connecting sector %s to sector %s\n", n
, rnd
);
138 if(Connect(n
, rnd
, dist
) != GENERATOR_SUCCESS
)
144 if(IsConnected(n
, rnd
) == false)
146 log(WvLog::Error
, "Internal error. Aborting.\n");
150 // check for a bi-directional link
151 if(ranf() <= prob_bi_dir
&& IsConnected(rnd
, n
) == false)
153 log(WvLog::Debug1
, "A bidirectional link will be made...");
154 log(WvLog::Debug1
, "Connecting sector %s to sector %s\n", rnd
, n
);
155 if(Connect(rnd
, n
, dist
) != GENERATOR_SUCCESS
)
160 if(IsConnected(rnd
, n
) == false)
162 log(WvLog::Error
, "Internal error. Aborting.\n");
171 #if RANDOMIZE_SECTORS
172 // now, re-arrange the sectors to randomize their effective sector
173 // numbers (which are determined by their offset into the array).
175 log(WvLog::Debug1
, "Reordering sectors...\n");
177 for (unsigned int n
= 0; n
< all_sectors
.Count() * 2; ++n
)
179 unsigned int rnd
= rand() % (all_sectors
.Count());
181 log(WvLog::Debug1
, "%s ", rnd
);
183 all_sectors
.Add(all_sectors
.Remove(all_sectors
[rnd
]));
186 log(WvLog::Debug1
, "\n");
190 // renumber the sectors, starting at ID #1
191 for (unsigned int n
= 0; n
< all_sectors
.Count(); ++n
)
193 all_sectors
[n
]->id
= n
+1;
197 return GENERATOR_SUCCESS
;
201 unsigned int TWCGenerator::GenerateSectors(unsigned int num
)
203 log(WvLog::Info
, "Generating %s Sectors.\n", num
);
207 log(WvLog::Error
, "How can I create 0 sectors?\n");
208 return GENERATOR_FAILURE
;
210 else if(all_sectors
.Count() != 0)
212 log(WvLog::Error
, "Sectors have already been generated.\n");
213 return GENERATOR_FAILURE
;
218 log(WvLog::Debug1
, "Generating sector %s\n", --num
);
220 all_sectors
.Add(new Sector(num
));
223 return GENERATOR_SUCCESS
;
227 void TWCGenerator::Purge(void)
229 log(WvLog::Info
, "Purging existing universe...\n");
231 port_sectors
.Purge();
232 planet_sectors
.Purge();
234 // destroy all of the sectors contained in 'all_sectors'
235 while(all_sectors
.Count() != 0)
237 delete(all_sectors
.Remove(all_sectors
[0]));
241 static int numcmp(const UniConf
&a
, const UniConf
&b
)
243 return (a
.key().printable().num() > b
.key().printable().num());
246 WvString
strip_slash(WvStringParm keyname
)
248 if (*keyname
.cstr() == '/')
251 newname
.setsize(keyname
.len());
252 strcpy(newname
.edit(), keyname
.cstr() + 1);
259 void TWCGenerator::DumpToFile(char* galaxy_file
)
261 UniConfRoot
cfg(WvString("ini:%s", galaxy_file
));
263 int num_old_ports
= cfg
["global"]["ports"].getmeint();
265 cfg
["global"]["sectors"].setmeint(all_sectors
.Count());
266 cfg
["global"]["planets"].setmeint(planet_sectors
.Count());
267 cfg
["global"]["ports"].setmeint(port_sectors
.Count());
269 // erase all of the existing, relevant entries
270 // i.e.sectors, planets, ports
271 cfg
["sectors"].remove();
272 cfg
["planets"].remove();
275 for (int n
= num_old_ports
- port_sectors
.Count(); n
>= 0; --n
)
277 cfg
["ports"][num_old_ports
--].remove();
280 // keep all other port info (buying, selling info)
281 // (Note: port location will be overwritten)
283 // iterate and place all ships in sector 1
284 // [sectors/1].ships ={...}
285 // [ships/n].location = 1
287 UniConf::SortedIter
s(cfg
["ships"], numcmp
);
288 for (s
.rewind(); s
.next();)
290 int id
= strip_slash(s
->key()).num();
291 ships
.append(WvString("%s ", id
));
292 s()["location"].setme(1);
294 log(WvLog::Info
, "Setting location of ship %s to %s\n",
295 id
, cfg
["ships"][WvString("%s",id
)]["location"].getmeint());
298 ships
.edit()[ships
.len() - 1] = '\0';
299 cfg
["sectors"][1]["ships"].setme(ships
);
301 for (unsigned int from
= 0; from
< all_sectors
.Count(); ++from
)
304 WvString
distances("");
306 // all sectors should have at least one exit.
307 if (all_sectors
[from
]->exits
.Count() == 0)
309 log (WvLog::Error
, "Sector %s has no exits!\n", WvString(all_sectors
[from
]->id
));
313 for (unsigned int exit_num
= 0; exit_num
< all_sectors
[from
]->exits
.Count(); ++exit_num
)
315 unsigned int to
= (all_sectors
[from
]->exits
)[exit_num
]->destination
->id
;
316 unsigned int distance
= (all_sectors
[from
]->exits
)[exit_num
]->distance
;
318 log (WvLog::Info
, "Sector %s is connected to Sector %s with distance %s\n",
319 WvString(all_sectors
[from
]->id
),
323 exits
.append(WvString("%s ", to
));
324 distances
.append(WvString("%s ", distance
));
326 exits
.edit()[exits
.len() - 1] = '\0';
327 distances
.edit()[distances
.len() - 1] = '\0';
329 //wvcon->print("Exits are: %s\n", exits);
330 //wvcon->print("Distances are: %s\n", distances);
331 cfg
["sectors"][WvString("%s", all_sectors
[from
]->id
)]["exits"].setme(exits
);
332 cfg
["sectors"][WvString("%s", all_sectors
[from
]->id
)]["distances"].setme(distances
);
335 for (unsigned int from
= 0; from
< planet_sectors
.Count(); ++from
)
337 cfg
["sectors"][WvString("%s", planet_sectors
[from
]->id
)]["planet"].setmeint(from
+ 1);
338 cfg
["planets"][WvString("%s", from
+ 1)]["name"].setme(WvString("Planet %s", from
+ 1));
339 cfg
["planets"][WvString("%s", from
+ 1)]["class"].setme("M");
342 for (unsigned int from
= 0; from
< port_sectors
.Count(); ++from
)
344 cfg
["sectors"][WvString("%s", port_sectors
[from
]->id
)]["port"].setmeint(from
+ 1);
345 cfg
["ports"][WvString("%s", from
+ 1)]["type"].setmeint(1);
346 cfg
["ports"][WvString("%s", from
+ 1)]["name"].setme(WvString("Port %s", from
+ 1));
347 cfg
["ports"][WvString("%s", from
+ 1)]["location"].setme(WvString("%s", port_sectors
[from
]->id
));
353 bool TWCGenerator::IsConnected(unsigned int from
, unsigned int to
)
355 return IsConnected(from
, to
, NULL
);
358 bool TWCGenerator::IsConnected(unsigned int from
, unsigned int to
, unsigned int *distance
)
360 if(from
>= all_sectors
.Count() || to
>= all_sectors
.Count())
365 return (IsConnected(all_sectors
[from
], all_sectors
[to
], distance
));
368 bool TWCGenerator::IsConnected(Sector
*from
, Sector
*to
)
370 return (IsConnected(from
, to
, NULL
));
373 bool TWCGenerator::IsConnected(Sector
*from
, Sector
*to
, unsigned int *distance
)
383 return (from
->DoesExitExist(to
, distance
));
386 void TWCGenerator::PlaceRandomPlanets(unsigned int num
)
388 log(WvLog::Info
, "Randomly placing %s planets.\n", num
);
390 if(num
> all_sectors
.Count())
392 log(WvLog::Error
, "Cannot place %s planets in %s sectors.\n", num
, all_sectors
.Count());
396 // place planets randomly -- later on I'll fix this up to make sure that they're
397 // fairly well distributed over the sector-space
400 unsigned int tmp
= rand() % (all_sectors
.Count());
403 while(planet_sectors
.Contains(&index
, all_sectors
[tmp
]))
405 tmp
= rand() % (all_sectors
.Count());
408 log(WvLog::Info
, "Placing planet at sector %s\n", tmp
);
413 printf("all_sectors[%d] = %p, planet_sectors[%d] = %p\n",
414 tmp
, all_sectors
[tmp
],
415 planet_sectors
.Count() - 1, planet_sectors
[planet_sectors
.Count()-1]);
422 void TWCGenerator::PlacePlanet(unsigned int sector
)
424 planet_sectors
.Add(all_sectors
[sector
]);
427 void TWCGenerator::PlacePortsAtPlanets()
429 // for each of the planets, place a port of type 'type'
430 for (int n
= planet_sectors
.Count() - 1; n
>= 0; --n
)
432 port_sectors
.Add(planet_sectors
[n
]);