home · contact · privacy
Addendum to previous commit: Added files mentioned but forgotten.
[plomrogue] / src / objects_on_map.c
index eedf800dca3b1ee58f80cbacc616cac9bddaa1be..a7d9c32a75b4e78a9b9e3ff7970aa618bd03c560 100644 (file)
@@ -2,15 +2,87 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include "yx_uint16.h"
+#include "readwrite.h"
 #include "roguelike.h"
+#include "map.h"
 
-extern char is_passable (struct Map * map, struct yx_uint16 pos) {
-// Check if coordinate on (or beyond) map is accessible to actor movement.
-  char passable = 0;
-  if (0 <= pos.x && pos.x < map->size.x && 0 <= pos.y && pos.y < map->size.y)
-    if ('.' == map->cells[pos.y * map->size.x + pos.x])
-      passable = 1;
-  return passable; }
+static struct ChainMapObject * get_next_cmo (void *, char *, size_t, struct ChainMapObject *);
+
+extern void readwrite_map_objects_dummy (void * dummy, FILE * file) {
+// Dummy function for calls of (write|read)_map_objects on map objects without specific attributes.
+  ; }
+
+extern void write_map_objects_monsterdata (void * start, FILE * file) {
+// Write to file data specific tto map objects of type monster.
+  struct Monster * monster = (struct Monster *) start;
+  fputc(monster->hitpoints, file); }
+
+extern void write_map_objects (void * start, FILE * file, void (* f) (void *, FILE *) ) {
+// Write into file the map object chain starting at start, use f() for object-type specific data.
+  struct ChainMapObject * cmo;
+  for (cmo = start; cmo != 0; cmo = cmo->next) {
+    write_uint16_bigendian(cmo->pos.y + 1, file);
+    write_uint16_bigendian(cmo->pos.x + 1, file);
+    fputc(cmo->name, file);
+    f (cmo, file); }
+  write_uint16_bigendian(0, file); }
+
+extern void read_map_objects_monsterdata (void * start, FILE * file) {
+// Read from file data speciifc to map objects of type monster.
+  struct Monster * monster = (struct Monster *) start;
+  monster->hitpoints = fgetc(file); }
+
+static struct ChainMapObject * get_next_cmo (void * start, char * still_at_start, size_t size, struct ChainMapObject * cmo) {
+// Return pointer to map object of size "size". If first in chain ("still_at_start"), make "start" point to it.
+  if (*still_at_start) {
+    struct ChainMapObject * * z = start;
+    cmo = malloc(size);
+    * z = cmo;
+    *still_at_start = 0; }
+  else {
+    cmo->next = malloc(size);
+    cmo = cmo->next; }
+  return cmo; }
+
+extern void read_map_objects (void * start, FILE * file, size_t size, void (* f) (void *, FILE *) ) {
+// Read from file chain of map objects starting at start, use f() for object-type specific data.
+  struct ChainMapObject * cmo;
+  uint16_t test;
+  char still_at_start = 1;
+  while (1) {
+    test = read_uint16_bigendian(file);
+    if (0 == test)
+      break;
+    cmo = get_next_cmo(start, &still_at_start, size, cmo);
+    cmo->pos.y = test - 1;
+    cmo->pos.x = read_uint16_bigendian(file) - 1;
+    cmo->name = fgetc(file);
+    f (cmo, file); }
+  if (!still_at_start)
+    cmo->next = 0; }
+
+extern void build_map_objects_monsterdata (void * start) {
+// Build data specific to map objects of type monster.
+  struct Monster * monster = (struct Monster *) start;
+  monster->cmo.name = 'A' + (rrand(0, 0) % 8);
+  monster->hitpoints = 5; }
+
+extern void build_map_objects_itemdata (void * start) {
+// Build data speciifc to map objects of type data.
+  struct Item * item = (struct Item *) start;
+  item->cmo.name = '#' + (rrand(0, 0) % 4); }
+
+extern void build_map_objects (void * start, unsigned char n, size_t size, void (* f) (void *), struct Map * map) {
+// Build chain of n map objects starting at start, use f() for object-specific data.
+  unsigned char i;
+  struct ChainMapObject * cmo;
+  char still_at_start = 1;
+  for (i = 0; i < n; i++) {
+    cmo = get_next_cmo(start, &still_at_start, size, cmo);
+    cmo->pos = find_passable_pos(map);
+    f (cmo); }
+  if (!still_at_start)
+    cmo->next = 0; }
 
 extern struct yx_uint16 find_passable_pos (struct Map * map) {
 // Return a random passable position on map.
@@ -20,30 +92,51 @@ extern struct yx_uint16 find_passable_pos (struct Map * map) {
       pos.x = rrand(0, 0) % map->size.x; }
   return pos; }
 
+extern char is_passable (struct Map * map, struct yx_uint16 pos) {
+// Check if coordinate on (or beyond) map is accessible to actor movement.
+  char passable = 0;
+  if (0 <= pos.x && pos.x < map->size.x && 0 <= pos.y && pos.y < map->size.y)
+    if ('.' == map->cells[pos.y * map->size.x + pos.x])
+      passable = 1;
+  return passable; }
+
 extern void move_monster (struct World * world, struct Monster * monster) {
 // Move monster in random direction, trigger fighting when hindered by player/monster.
   char d = rrand(0, 0) % 5;
-  struct yx_uint16 t = mv_yx_in_dir (d, monster->pos);
+  struct yx_uint16 t = mv_yx_in_dir (d, monster->cmo.pos);
   if (yx_uint16_cmp (t, world->player->pos)) {
     update_log (world, "\nThe monster hits you.");
+    world->player->hitpoints--;
+    if (0 == world->player->hitpoints)
+      update_log (world, "\nYou are dead.");
     return; }
   struct Monster * other_monster;
-  for (other_monster = world->monster; other_monster != 0; other_monster = other_monster->next) {
+  for (other_monster = world->monster; other_monster != 0; other_monster = other_monster->cmo.next) {
     if (other_monster == monster)
       continue;
-    if (yx_uint16_cmp (t, other_monster->pos)) {
-      update_log (world, "\nMonster hits monster.");
+    if (yx_uint16_cmp (t, other_monster->cmo.pos)) {
+      update_log (world, "\nMonster bumps into monster.");
       return; } }
   if (is_passable(world->map, t))
-    monster->pos = t; }
+    monster->cmo.pos = t; }
 
 extern void move_player (struct World * world, char d) {
 // Move player in direction d, update log and turn over to the enemy.
   struct yx_uint16 t = mv_yx_in_dir (d, world->player->pos);
   struct Monster * monster;
-  for (monster = world->monster; monster != 0; monster = monster->next)
-    if (yx_uint16_cmp (t, monster->pos)) {
+  for (monster = world->monster; monster != 0; monster = monster->cmo.next)
+    if (yx_uint16_cmp (t, monster->cmo.pos)) {
       update_log (world, "\nYou hit the monster.");
+      monster->hitpoints--;
+      if (0 == monster->hitpoints) {
+        update_log (world, "\nYou kill the monster.");
+        if (world->monster == monster)
+          world->monster = world->monster->cmo.next;
+        else {
+          struct Monster * m_prev;
+          for (m_prev = world->monster; m_prev->cmo.next != monster; m_prev = m_prev->cmo.next);
+          m_prev->cmo.next = monster->cmo.next; }
+        free(monster); }
       turn_over (world, d);
       return; }
   char * msg = calloc(25, sizeof(char));