<?php

require_once (dirname(__FILE__) . "/fetch.php");

// Move file pointer to the corresponding closing bracket of the current
// element.
function move_to_closing_bracket($fp, &$char)
{
   if ($char == CLOSE_ELEMENT_CHAR) return;

   $ii = 1;
   while (($char = fgetc($fp)) != NULL && !feof($fp))
   {
      if ($char == OPEN_ELEMENT_CHAR) $ii++;
      else
      {
         if ($char == CLOSE_ELEMENT_CHAR) $ii--;
         if ($ii == 0) break;
      }
   }
}

// Store the file contents as a string, replace the specified string with a new
// string, and re-write the file.
function replace_string_in_file($file_name, $old, $new="")
{
   $file_contents = file_get_contents($file_name);
   $file_contents = str_replace($old, $new, $file_contents);

   $fp = fopen($file_name, 'w');
   
   fwrite($fp, $file_contents);
}

// Erase file contents between and including element's brackets.
function read_raw_element_string($fp, &$char)
{
   $element_open_position = ftell($fp)-1;
   move_to_closing_bracket($fp, $char);
   $element_close_position = ftell($fp);

   if (char_is_white_space($char = fgetc($fp)))
   {
      skip_white_space($fp, $char);
      $element_close_position = ftell($fp)-1;
   }

   $byte_range = $element_close_position - $element_open_position;
   fseek($fp, $element_open_position);
   $element = fread($fp, $byte_range);

   return $element;
}

// If the submitted element points to an object, convert the element to its
// raw string representation.  Otherwise, leave the string unchanged.
function convert_element_to_raw($element)
{
   if (is_object($element))
   {
      $element = $element->convert_to_raw_string();
   }

   return $element;
}

// Replace in a file the element identified by specified ID w/ a new element.
// The new element can be an object, element string, or empty.  If empty, the
// old element will be removed and replaced with nothing.
function replace_element_by_id($file_name, $id, $element="")
{
   if (file_exists($file_name))
   {
      $fp = fopen($file_name, 'r+');
      move_to_element_by_id($fp, $char, $id);
      if (feof($fp)) return;
      $old_raw_element = read_raw_element_string($fp, $char, $id);
      $new_raw_element = convert_element_to_raw($element);
      fclose($fp);

      if ($old_raw_element != NULL)
      {
         replace_string_in_file(
            $file_name, $old_raw_element, $new_raw_element);
      }
      return $old_raw_element;
   }
}

// Replace an element with a new element.  If the new element is unspecified,
// the old element will be deleted.
function run_replace($file_name, $id, $element)
{
   if (!file_exists($file_name)) return;

   replace_element_by_id($file_name, $id, $element);
   $message = "!! Removing element $id... !!\n\n";
   if ($element != NULL)
   {
      $message .= "Replacing with\n--------------\n";
      $message .= convert_element_to_raw($element);
      $message .= "\n\n";
   }
   $message .= "New file\n--------\n";
   $message .= run_parse($file_name);

   return $message;
}
<?php

require_once (dirname(__FILE__) . "/fetch.php");
require_once (dirname(__FILE__) . "/replace.php");

// Insert a string into the file, leaving the current data intact.
function insert_string_at_cursor($fp, $string)
{
   $position = ftell($fp);
   $file_meta_data = fstat($fp);
   $length = $file_meta_data["size"] - $position;

   $tail = fread($fp, $length);
   fseek($fp, $position);
   $new_content = $string . $tail;

   ftruncate($fp, $position);
   fwrite($fp, $new_content);
}

// Insert the element data at the end of the file.
function insert_element_into_file($fp, $element)
{
   fwrite($fp, $element);
}

// Insert an element into the element referenced by id.  This will create a new
// child for the referenced element.
function insert_element_into_element($fp, $element, $id)
{
   move_to_element_by_id($fp, $char, $id);
   move_to_closing_bracket($fp, $char);
   fseek($fp, ftell($fp)-1);
   insert_string_at_cursor($fp, $element);
}

// Move to the position either before or after the element currently under the
// cursor.
function move_cursor_based_on_insertion_method($fp, $char, $before)
{
   if ($before == False)
   {
      move_to_closing_bracket($fp, $char);
   }
   else
   {
      fseek($fp, ftell($fp)-1);
   }
}

// Insert an element before or after the element referenced by id.
function insert_element_at_id($fp, $element, $id, $before=False)
{
   move_to_element_by_id($fp, $char, $id);
   move_cursor_based_on_insertion_method($fp, $char, $before);
   insert_string_at_cursor($fp, $element);
}

// Open file for writing or appending based on where the new element will be
// inserted.
function open_file_based_on_method($file_name, $id)
{
   if ($id != NULL)
   {
      $fp = fopen($file_name, 'r+');
   }
   else
   {
      $fp = fopen($file_name, 'a');
   }

   return $fp;
}

// Choose one of three methods for insertion based on the existence and values
// of the id and child parameters.
function apply_insertion_method($fp, $raw_element, $id, $child, $before)
{
   if ($child == True)
   {
      insert_element_into_element($fp, $raw_element, $id);
   }
   elseif ($id != NULL)
   {
      insert_element_at_id($fp, $raw_element, $id, $before);
   }
   else
   {
      insert_element_into_file($fp, $raw_element);
   }
}   

// Insert an element into the specified file.  The before parameter indicates
// whether or not the incoming element should be placed before the referenced
// element.
function insert_element(
   $file_name, $element, $id=NULL, $child=False, $before=False)
{
   $fp = open_file_based_on_method($file_name, $id);
   $raw_element = convert_element_to_raw($element);
   apply_insertion_method($fp, $raw_element, $id, $child, $before);
}

// Insert an element into the specified file.  Return relevant messages for
// verbose output.
function run_insert($file_name, $element, $id=NULL, $child=False, $before=False)
{
   $message = "Inserting\n---------\n";
   $message .= convert_element_to_raw($element) . "\n\n";

   $child = ($child && $child != '0') ? True : False;
   $before = ($before && $before != '0') ? True : False;
   insert_element($file_name, $element, $id, $child, $before);

   $message .= "New File\n--------\n";
   $message .= run_parse($file_name);

   return $message;
}
3.85.80.239
3.85.80.239
3.85.80.239
 
June 29, 2013

A few weeks ago, for Fishing Jam, I made a fishing simulation from what was originally designed to be a time attack arcade game. In the program, Dark Stew, the player controls Aphids, an anthropod who fishes for aquatic creatures living in nine pools of black water.



Fishing means waiting by the pool with the line in. The longer you wait before pulling the line out, the more likely a creature will appear. Aside from walking, it's the only interaction in the game. The creatures are drawings of things you maybe could find underwater in a dream.

The background music is a mix of clips from licensed to share songs on the Free Music Archive. Particularly, Seed64 is an album I used a lot of songs from. The full list of music credits is in the game's README file.

I'm still planning to use the original design in a future version. There would be a reaction-based mini game for catching fish, and the goal would be to catch as many fish as possible within the time limit. I also want to add details and obstacles to the background, which is now a little boring, being a plain, tiled, white floor.

If you want to look at all the drawings or hear the music in the context of the program, there are Windows and source versions available. The source should work on any system with Python and Pygame. If it doesn't, bug reports are much appreciated. Comments are also welcome :)

Dark Stew: Windows, Pygame Source

I wrote in my last post that I would be working on an old prototype about searching a cloud for organisms for Fishing Jam. I decided to wait a while before developing that game, tentatively titled Xenographic Barrier. Its main interactive element is a first-person scope/flashlight, so I'd like to make a Wii version of it.

I'm about to start working on a complete version of Ball & Cup. If I make anything interesting for it, I'll post something. There are a lot of other things I want to write about, like game analyses, my new GP2X and arcades in Korea, and there's still music to release. Lots of fun stuff coming!