zone.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. //*****************************************************************************
  2. //
  3. // zone.c
  4. //
  5. // A zone is like a stand-alone module, or encounter, within the game (e.g.
  6. // a city in the world), and contains all of the NPCs, objects, rooms, scripts,
  7. // etc... needed for the zone to be complete.
  8. //
  9. //*****************************************************************************
  10. #include <sys/stat.h>
  11. #include <dirent.h>
  12. #include "mud.h"
  13. #include "storage.h"
  14. #include "utils.h"
  15. #include "auxiliary.h"
  16. #include "world.h"
  17. #include "hooks.h"
  18. #include "zone.h"
  19. //*****************************************************************************
  20. // zone type data
  21. //*****************************************************************************
  22. typedef struct {
  23. /*
  24. void *(* read_func)(STORAGE_SET *);
  25. STORAGE_SET *(* store_func)(void *);
  26. void (* delete_func)(void *);
  27. void (* key_func)(void *, const char *);
  28. */
  29. void *read_func;
  30. void *store_func;
  31. void *delete_func;
  32. void *key_func;
  33. bool forgetful;
  34. HASHTABLE *key_map;
  35. char *type;
  36. } ZONE_TYPE_DATA;
  37. ZONE_TYPE_DATA *newZoneType(const char *type, void *reader, void *storer,
  38. void *deleter, void *keysetter, bool forgetful) {
  39. ZONE_TYPE_DATA *data = malloc(sizeof(ZONE_TYPE_DATA));
  40. data->read_func = reader;
  41. data->store_func = storer;
  42. data->delete_func = deleter;
  43. data->key_func = keysetter;
  44. data->forgetful = forgetful;
  45. data->key_map = newHashtable();
  46. data->type = strdupsafe(type);
  47. return data;
  48. }
  49. void *do_zone_read(ZONE_TYPE_DATA *tdata, STORAGE_SET *set) {
  50. if(tdata->forgetful) {
  51. void *(* read_func)(const char *, STORAGE_SET *) = tdata->read_func;
  52. return read_func(tdata->type, set);
  53. }
  54. else {
  55. void *(* read_func)(STORAGE_SET *) = tdata->read_func;
  56. return read_func(set);
  57. }
  58. }
  59. void do_zone_setkey(ZONE_TYPE_DATA *tdata, void *data, const char *key) {
  60. if(tdata->forgetful) {
  61. void (* key_func)(const char *, void *, const char *) = tdata->key_func;
  62. key_func(tdata->type, data, key);
  63. }
  64. else {
  65. void (* key_func)(void *, const char *) = tdata->key_func;
  66. key_func(data, key);
  67. }
  68. }
  69. STORAGE_SET *do_zone_store(ZONE_TYPE_DATA *tdata, void *data) {
  70. if(tdata->forgetful) {
  71. STORAGE_SET *(* store_func)(const char *, void *) = tdata->store_func;
  72. return store_func(tdata->type, data);
  73. }
  74. else {
  75. STORAGE_SET *(* store_func)(void *) = tdata->store_func;
  76. return store_func(data);
  77. }
  78. }
  79. //*****************************************************************************
  80. // zone data
  81. //*****************************************************************************
  82. struct zone_data {
  83. char *key;
  84. char *name;
  85. char *editors;
  86. BUFFER *desc;
  87. WORLD_DATA *world;
  88. LIST *resettable; // a list of rooms that need to be reset on pulse
  89. HASHTABLE *type_table; // a table of our types and their functions
  90. int pulse_timer; // the timer duration
  91. int pulse; // how far down have we gone?
  92. AUX_TABLE *auxiliary_data; // additional data installed on us
  93. };
  94. ZONE_DATA *newZone(const char *key) {
  95. ZONE_DATA *zone = malloc(sizeof(ZONE_DATA));
  96. zone->type_table = newHashtable();
  97. zone->name = strdup("");
  98. zone->key = strdup(key);
  99. zone->desc = newBuffer(1);
  100. zone->editors = strdup("");
  101. zone->resettable = newList();
  102. zone->pulse_timer = -1; // never resets
  103. zone->pulse = -1;
  104. zone->world = NULL;
  105. zone->auxiliary_data = newAuxiliaryData(AUXILIARY_TYPE_ZONE);
  106. return zone;
  107. }
  108. ZONE_DATA *zoneCopy(ZONE_DATA *zone) {
  109. ZONE_DATA *newzone = newZone(zone->key);
  110. zoneCopyTo(zone, newzone);
  111. return newzone;
  112. }
  113. void zoneCopyTo(ZONE_DATA *from, ZONE_DATA *to) {
  114. zoneSetName(to, zoneGetName(from));
  115. zoneSetDesc(to, zoneGetDesc(from));
  116. zoneSetEditors(to, zoneGetEditors(from));
  117. zoneSetKey(to, zoneGetKey(from));
  118. deleteListWith(to->resettable, free);
  119. to->resettable = listCopyWith(from->resettable, strdup);
  120. to->pulse_timer = from->pulse_timer;
  121. to->pulse = from->pulse;
  122. auxiliaryDataCopyTo(from->auxiliary_data, to->auxiliary_data);
  123. }
  124. void deleteZone(ZONE_DATA *zone){
  125. if(zone->name) free(zone->name);
  126. if(zone->desc) deleteBuffer(zone->desc);
  127. if(zone->editors) free(zone->editors);
  128. if(zone->type_table) deleteHashtable(zone->type_table);
  129. if(zone->key) free(zone->key);
  130. if(zone->resettable) deleteListWith(zone->resettable, free);
  131. deleteAuxiliaryData(zone->auxiliary_data);
  132. //*******************************************************************
  133. // The only time we're deleting a zone is when we're editing the copy
  134. // in OLC. So, We don't want to delete any of the zone's content when
  135. // we delete it.
  136. //*******************************************************************
  137. free(zone);
  138. }
  139. //
  140. // Pulse a zone. i.e. decrement it's reset timer. When the timer hits 0,
  141. // set it back to the max, and reset everything in the zone
  142. void zonePulse(ZONE_DATA *zone) {
  143. zone->pulse--;
  144. if(zone->pulse == 0) {
  145. zone->pulse = zone->pulse_timer;
  146. hookRun("reset_zone", hookBuildInfo("str", zoneGetKey(zone)));
  147. }
  148. }
  149. void zoneForceReset(ZONE_DATA *zone) {
  150. zone->pulse = 1;
  151. zonePulse(zone);
  152. }
  153. //
  154. // parses out one resettable room from a storage set
  155. char *read_resettable_room(STORAGE_SET *set) {
  156. return strdup(read_string(set, "room"));
  157. }
  158. ZONE_DATA *zoneLoad(WORLD_DATA *world, const char *key) {
  159. ZONE_DATA *zone = newZone(key);
  160. char fname[SMALL_BUFFER];
  161. zone->world = world;
  162. // first, load all of the zone data
  163. sprintf(fname, "%s/zone", worldGetZonePath(world, zone->key));
  164. STORAGE_SET *set = storage_read(fname);
  165. zone->pulse_timer = read_int (set, "pulse_timer");
  166. zoneSetName(zone, read_string(set, "name"));
  167. zoneSetDesc(zone, read_string(set, "desc"));
  168. zoneSetEditors(zone,read_string(set, "editors"));
  169. // add in all of our resettable rooms
  170. deleteList(zone->resettable);
  171. zone->resettable = gen_read_list(read_list(set, "resettable"),
  172. read_resettable_room);
  173. deleteAuxiliaryData(zone->auxiliary_data);
  174. zone->auxiliary_data = auxiliaryDataRead(read_set(set, "auxiliary"),
  175. AUXILIARY_TYPE_ZONE);
  176. storage_close(set);
  177. return zone;
  178. }
  179. //
  180. // turns an entry for a resettable room into a storage set
  181. STORAGE_SET *store_resettable_room(char *key) {
  182. STORAGE_SET *set = new_storage_set();
  183. store_string(set, "room", key);
  184. return set;
  185. }
  186. //
  187. // the new zone saving function
  188. bool zoneSave(ZONE_DATA *zone) {
  189. char fname[MAX_BUFFER];
  190. // first, for our zone data
  191. sprintf(fname, "%s/zone", worldGetZonePath(zone->world, zone->key));
  192. STORAGE_SET *set = new_storage_set();
  193. store_int (set, "pulse_timer", zone->pulse_timer);
  194. store_string(set, "name", zone->name);
  195. store_string(set, "desc", bufferString(zone->desc));
  196. store_string(set, "editors", zone->editors);
  197. store_set (set, "auxiliary", auxiliaryDataStore(zone->auxiliary_data));
  198. store_list (set, "resettable", gen_store_list(zone->resettable,
  199. store_resettable_room));
  200. storage_write(set, fname);
  201. storage_close(set);
  202. return TRUE;
  203. }
  204. //*****************************************************************************
  205. // get and set functions for zones
  206. //*****************************************************************************
  207. void *zoneGetAuxiliaryData(const ZONE_DATA *zone, char *name) {
  208. return auxiliaryGet(zone->auxiliary_data, name);
  209. }
  210. int zoneGetPulseTimer(ZONE_DATA *zone) {
  211. return zone->pulse_timer;
  212. }
  213. int zoneGetPulse(ZONE_DATA *zone) {
  214. return zone->pulse;
  215. }
  216. WORLD_DATA *zoneGetWorld(ZONE_DATA *zone) {
  217. return zone->world;
  218. }
  219. const char *zoneGetName(ZONE_DATA *zone) {
  220. return zone->name;
  221. }
  222. const char *zoneGetDesc(ZONE_DATA *zone) {
  223. return bufferString(zone->desc);
  224. }
  225. const char *zoneGetEditors(ZONE_DATA *zone) {
  226. return zone->editors;
  227. }
  228. BUFFER *zoneGetDescBuffer(ZONE_DATA *zone) {
  229. return zone->desc;
  230. }
  231. LIST *zoneGetResettable(ZONE_DATA *zone) {
  232. return zone->resettable;
  233. }
  234. void zoneSetPulseTimer(ZONE_DATA *zone, int timer) {
  235. // if we normally do not reset, change that
  236. if(zone->pulse_timer < 0)
  237. zone->pulse = timer;
  238. zone->pulse_timer = timer;
  239. }
  240. void zoneSetPulse(ZONE_DATA *zone, int pulse_left) {
  241. zone->pulse = pulse_left;
  242. }
  243. void zoneSetWorld(ZONE_DATA *zone, WORLD_DATA *world) {
  244. zone->world = world;
  245. }
  246. void zoneSetName(ZONE_DATA *zone, const char *name) {
  247. if(zone->name) free(zone->name);
  248. zone->name = strdupsafe(name);
  249. }
  250. void zoneSetDesc(ZONE_DATA *zone, const char *desc) {
  251. bufferClear(zone->desc);
  252. bufferCat(zone->desc, desc);
  253. }
  254. void zoneSetEditors(ZONE_DATA *zone, const char *names) {
  255. if(zone->editors) free(zone->editors);
  256. zone->editors = strdupsafe(names);
  257. }
  258. //*****************************************************************************
  259. // the new zone type interface
  260. //*****************************************************************************
  261. //
  262. // returns a list of all the keys in the zone for the specified type. Doesn't
  263. // include the locale in the key. Just the name. List and contents must be
  264. // deleted after use.
  265. LIST *zoneGetTypeKeys(ZONE_DATA *zone, const char *type) {
  266. LIST *key_list = newList();
  267. char path[MAX_BUFFER];
  268. sprintf(path, "%s/%s", worldGetZonePath(zone->world, zone->key), type);
  269. DIR *dir = opendir(path);
  270. struct dirent *entry = NULL;
  271. if(dir != NULL) {
  272. for(entry = readdir(dir); entry; entry = readdir(dir)) {
  273. if(!startswith(entry->d_name, "."))
  274. listPut(key_list, strdup(entry->d_name));
  275. }
  276. closedir(dir);
  277. }
  278. return key_list;
  279. }
  280. //
  281. // loads the item with the specified key into memory and returns it
  282. void *zoneLoadType(ZONE_DATA *zone, const char *type, const char *key) {
  283. ZONE_TYPE_DATA *tdata = hashGet(zone->type_table, type);
  284. if(tdata == NULL)
  285. return NULL;
  286. else {
  287. char buf[MAX_BUFFER];
  288. void *data = NULL;
  289. sprintf(buf, "%s/%s/%s", worldGetZonePath(zone->world, zone->key),
  290. type, key);
  291. STORAGE_SET *set = storage_read(buf);
  292. if(set != NULL) {
  293. data = do_zone_read(tdata, set);
  294. hashPut(tdata->key_map, key, data);
  295. do_zone_setkey(tdata, data, get_fullkey(key, zone->key));
  296. storage_close(set);
  297. }
  298. return data;
  299. }
  300. }
  301. void *zoneGetType(ZONE_DATA *zone, const char *type, const char *key) {
  302. ZONE_TYPE_DATA *tdata = hashGet(zone->type_table, type);
  303. if(tdata == NULL)
  304. return NULL;
  305. else {
  306. void *data = NULL;
  307. // if we haven't loaded it into memory yet, do so
  308. if((data = hashGet(tdata->key_map, key)) == NULL)
  309. data = zoneLoadType(zone, type, key);
  310. return data;
  311. }
  312. }
  313. void zoneSaveType(ZONE_DATA *zone, const char *type, const char *key) {
  314. void *data = zoneGetType(zone, type, key);
  315. if(data != NULL) {
  316. ZONE_TYPE_DATA *tdata = hashGet(zone->type_table, type);
  317. STORAGE_SET *set = do_zone_store(tdata, data);
  318. if(set != NULL) {
  319. char buf[MAX_BUFFER];
  320. sprintf(buf,"%s/%s/%s",worldGetZonePath(zone->world,zone->key),type,key);
  321. storage_write(set, buf);
  322. storage_close(set);
  323. }
  324. }
  325. }
  326. void *zoneRemoveType(ZONE_DATA *zone, const char *type, const char *key) {
  327. ZONE_TYPE_DATA *tdata = hashGet(zone->type_table, type);
  328. if(tdata == NULL)
  329. return NULL;
  330. else {
  331. // first, delete the file for it
  332. char buf[MAX_BUFFER];
  333. sprintf(buf, "%s/%s/%s",worldGetZonePath(zone->world,zone->key),type,key);
  334. unlink(buf);
  335. // then remove it from the key map
  336. void *data = hashRemove(tdata->key_map, key);
  337. if(data != NULL)
  338. do_zone_setkey(tdata, data, "");
  339. return data;
  340. }
  341. }
  342. void zonePutType(ZONE_DATA *zone, const char *type, const char *key,
  343. void *data) {
  344. ZONE_TYPE_DATA *tdata = hashGet(zone->type_table, type);
  345. if(tdata != NULL) {
  346. hashPut(tdata->key_map, key, data);
  347. do_zone_setkey(tdata, data, get_fullkey(key, zone->key));
  348. }
  349. }
  350. void zoneAddType(ZONE_DATA *zone, const char *type, void *reader,
  351. void *storer, void *deleter, void *typesetter) {
  352. if(!hashIn(zone->type_table, type)) {
  353. hashPut(zone->type_table, type, newZoneType(type, reader, storer, deleter,
  354. typesetter, FALSE));
  355. char buf[MAX_BUFFER];
  356. sprintf(buf, "%s/%s", worldGetZonePath(zone->world, zone->key), type);
  357. mkdir(buf, S_IRWXU | S_IRWXG);
  358. }
  359. }
  360. void zoneAddForgetfulType(ZONE_DATA *zone, const char *type, void *reader,
  361. void *storer, void *deleter, void *typesetter) {
  362. if(!hashIn(zone->type_table, type)) {
  363. hashPut(zone->type_table, type, newZoneType(type, reader, storer, deleter,
  364. typesetter, TRUE));
  365. char buf[MAX_BUFFER];
  366. sprintf(buf, "%s/%s", worldGetZonePath(zone->world, zone->key), type);
  367. mkdir(buf, S_IRWXU | S_IRWXG);
  368. }
  369. }
  370. void zoneSetKey(ZONE_DATA *zone, const char *key) {
  371. if(zone->key) free(zone->key);
  372. zone->key = strdupsafe(key);
  373. }
  374. const char *zoneGetKey(ZONE_DATA *zone) {
  375. return zone->key;
  376. }