All pastes #511691 Raw Edit

Mine

public text v1 · immutable
#511691 ·published 2007-05-26 16:09 UTC
rendered paste body
<?php
//$Id: mapapi.module,v 1.1 2007/04/30 03:41:38 dmitrig01 Exp $
/*
 * @file Creates and loads maps.
 */

/*
 * Loads maps maps.  Use this instead of _mapapi_load.
 * @param $maps
 *   An array of maps
 *   A sample maps array would be
 *   @code
 *   $maps['multi_tile'] = array(
 *     'mid' => 1,
 *     'x' => 5, // Try negative values... you will see them adjust and always return
 *     'y' => 5, // The correct box bounds (defined by length_x and length_y)
 *     'length_x' => 10,
 *     'length_y' => 9, // Doesn't have to be exactly square!
 *     'tile_content' => TRUE // True/false on whether to load tile content or not.
 *    );
 *   $maps['single_tile'] = array(
 *     'mid' => 1,
 *     'x' => 5,
 *     'y' => 5,
 *     'length_x' => 10,
 *     'length_y' => 9,
 *     'tile_content' => TRUE,
 *    );
 *    @endcode
 * 
 * @todo
 *   cache the maps loaded, since it can be expensive
 */
function mapapi_load($maps) {
  // This is the array in which maps are stored.
  // The keys are the same as those of $maps
  // But the content is the tiles.
  $mapapi_array = array();
  // Loop through each map, because $maps
  // is an array of maps, not a single map
  foreach($maps as $mapapi_name => $map) {
    // Load the map, and insert it into $mapapi_array
    // with the same key as $maps
    $mapapi_array[$mapapi_name] = _mapapi_load($map);
  }
  // Return the array of maps
  return $mapapi_array;
}
/*
 * Loads a single map.
 * Internal usage only.  Use mapapi_load instead.
 * This function does all limit / boundary
 * calculation, as well as fetching the tiles.
 */
function _mapapi_load($map) {
  // We need to get the limits of the map
  // to make sure that the map array passed in's
  // area is not more than itself's area.
  // This needs to be done to eleminate errors
  // and such.
  if ($mapapi_limits_query = db_query("SELECT mid, name, limit_x, limit_y FROM {mapapi_map_definition} WHERE mid = %d", $map['mid'])) {
    // The upper limits of the map
    $mapapi_limits = db_fetch_array($mapapi_limits_query);
    // Build the dimentions of the map, respecting the limits
    // of the map defnition.
    $limits = _mapapi_make_dimentions($map, $mapapi_limits);
  }
  // If that query failed, we need to silently return null
  // and not execute the rest of the function, because
  // it would be pointless.
  else {
    return NULL;
  }

  $check_query_args = array();
  $query  = "SELECT tid, coord_x, coord_y, description FROM {mapapi_tile_definition}  WHERE ";
  // We need to respect the upper limits of the map
  // in both x and y.
  // If we don't do this, the query can go wacko
  $query .= "coord_y <= %d AND ";  $check_query_args[] = $mapapi_limits['limit_y'];
  $query .= "coord_x <= %d AND ";  $check_query_args[] = $mapapi_limits['limit_x'];
  // We need to (quite obviously) follow the upper limits
  // of the map requested.
  // We need to follow both X and Y
  $query .= "coord_y <= %d AND ";  $check_query_args[] = $limits['y']['high'];
  $query .= "coord_x <= %d AND ";  $check_query_args[] = $limits['x']['high'];
  // Ditto, but for lower limits this time
  $query .= "coord_y >= %d AND ";  $check_query_args[] = $limits['y']['low'];
  $query .= "coord_x >= %d AND ";  $check_query_args[] = $limit['x']['low'];
  // Make sure we select from the proper map (!!!)
  $query .= "mid = %d";            $check_query_args[] = $map['mid'];
  
  // Execute the query
  if ($result = db_query($query, $check_query_args)) {
    // Return some basic information about the map, 
    // might be helpful in some circumstances
    $selection = array('map_info' => $mapapi_limits, 'dimentions' => $limits);
    
    $tiles = array();
    while($row = db_fetch_array($result)){
      // Eventually, this will be the tile content, but for now, it is not
      $row['content'] = array(); 
      // Since the description can be an array, we serialize it
      $row['description'] = unserialize($row['description']);
      // We need the coordinates of the tile, to know where in the array to put them
      $coord_y = $row['coord_y'];
      $coord_x = $row['coord_x'];
      // However, the array of tiles does not need them, because it's keys are already it's coordinates.
      unset($row['coord_y']);
      unset($row['coord_x']);
      // Insert the row into the tiles array
      $tiles[$coord_x][$coord_y] = $row;
    }
    $selection['map_tiles'] = $tiles;
    return $selection;
  }
  // If no tiles were found or the query failed, then return an empty array.
  else {
    return array();
  }
}

/**
 * Figure out dimentions of a map, around the x and y.
 */
function _mapapi_make_dimentions($map, $limits) {
  // Determine number of tiles to go to 
  // each direction away from the center.
  // Up and down should be equal length
  // as well as left and right
  $x_spacer = floor($map['length_x'] / 2);
  $y_spacer = floor($map['length_y'] / 2);

  // Determine X boundaries
  $x_low = $map['x'] - $x_spacer;
  $x_high = $map['x'] + $x_spacer;

  // Determine Y boundaries
  $y_low = $map['y'] - $y_spacer;
  $y_high = $map['y'] + $y_spacer;
  
  // If the map's left boundary
  // is below 0, then something
  // needs to be done!
  // The whole map needs to move
  // right, so the width stays the
  // same.
  if ($x_low < 0) {
    // Increase $x_high by the
    // amount below 0 $x_low is
    // So as an example
    // if $x_low is -3
    // and $x_high is 5
    // then the height of the
    // map is 8.
    // So $x_low becomes 0
    // and $x_high becomes 8.
    // We also need to compensate
    // for if the height of the 
    // new $x_high is higher than  
    // the limit of the map.
    $x_high = min($x_high - $x_low, $limits['limit_x']);
    $x_low = 0;
  }
  // Even if the boundaries are above 0
  // we still need to make sure that the 
  // upper boundaries don't exceed the
  // upper boundaries of the map.
  if ($x_high > $limits['limit_x']) {
    // This still needs to be above 0.
    // That is why the max function is used
    $x_low = max($x_low - ($x_high - $limits['limit_x']), 0);
    $x_high = $limits['limit_x'];
  }
  
  // If the map's left boundary
  // is below 0, then something
  // needs to be done!
  // The whole map needs to move
  // right, so the width stays the
  // same.
  if ($y_low < 0) {
    // Increase $y_high by the
    // amount below 0 $y_low is
    // So as an example
    // if $y_low is -3
    // and $y_high is 5
    // then the height of the
    // map is 8.
    // So $y_low becomes 0
    // and $y_high becomes 8.
    // We also need to compensate
    // for if the height of the 
    // new $y_high is higher than  
    // the limit of the map.
    $y_high = min($y_high - $y_low, $limits['limit_y']);
    $y_low = 0;
  }
  // Even if the boundaries are above 0
  // we still need to make sure that the 
  // upper boundaries don't exceed the
  // upper boundaries of the map.
  if ($y_high > $limits['limit_y']) {
    // This still needs to be above 0.
    // That is why the may function is used
    $y_low = max($y_low - ($y_high - $limits['limit_y']), 0);
    $y_high = $limits['limit_y'];
  }

  $dimentions = array();
  $dimentions['x'] = array('low' => $x_low  , 'high' => $x_high);
  $dimentions['y'] = array('low' => $y_low , 'high' => $y_high);
  return $dimentions;
}

/*
 * Wrapper function
 * Call mapapi_save('tile', $data)
 * to save a tile, mapapi_save('map', $data),
 * etc.
 * Use this function to save stuff, don't
 * call the mapapi_*_save function individually.
 * However, that is where the documentation for 
 * the format is is.
 * It returns an array of the status.
 * The elements are $status['function']
 * which refers to the function name,
 * $status['overall'], which is either true
 * or false, depending on the success of the function
 * and $status['message'], which can give information
 * about different errors.
 * Functions can also define additional elements
 * to add to the array, like the success of 
 * different elements.
 */
function mapapi_save($type, $data) {
  if(function_exists("mapapi_$type"."_save")) {
    return call_user_func("mapapi_$type"."_save", $data);
  }
  else {
    return false;
  }
}

/**
 * Internal usage only.  Use mapapi_save('tile', $data);
 * This function saves tiles. $args has no practical use now, it is reserved for later addons.
 *
 * Usage
 * @code
 * $save_format = array(
 *   'mid' => 1,
 *   'tid' => 1,
 *   'coord_x' => '5',
 *   'coord_y' => '7',
 *   'description' => array(),
 *   'content' => array(),
 * );
 * @endcode
 *
 * @param $data
 * @param $args
 * @return mixed
 */
function mapapi_tile_save($data, $args = array()) {
  // We return this at the end of the function execution.
  // It must be an array because we are saving tiles and then content, 
  // and the coder may want a status marker on both of those.
  // There is also the overall value, to check if both succeded.
  // this may be easier to test for, however, the individual
  // ones may be easier for debugging.  The overall does not
  // include if there is a message.
  // There is also the message.  This is for things like 
  // "mid is not valid" or "not all parameters were passed in."
  // This is also useful for deveopers.
  // The last one is the function, which notes what function
  // the error came from (if there is an error)
  // Default false values will be changed to true later on,
  // if the function succeds.
  $status['tile'] = FALSE;
  $status['content'] = FALSE;
  $status['message'] = "";
  $status['function'] = "mapapi_tile_save";
  $status['overall'] = FALSE;
  
  // Check if we have all required data
  // We need to check the map ID, the x
  // coordinate, and the y coordinate
  if (!isset($data['mid']) || !isset($data['coord_x']) || !isset($data['coord_y'])) {
    // The status is still all false, so return it.
    // We need to set the message to "not enough parameters,"
    // indicating not enough data was passed in.
    $status['message'] = "Not enough parameters.  Parameters sent in were <pre>". $data ."</pre> ";
    $status['message'] .= "You need to pass in the mid of the map to be saved to, ";
    $status['message'] .= "and the x and y coordinates of the tile to save.";
    return $status;
  }
  // If the x or y coordinates are less than 0, which
  // is not allowed, throw an error
  else if ($data['coord_x'] < 0 || $data['coord_y'] < 0) {
    // Set a very descriptive status message.
    // We need to alert the user on if both
    // or one, and we need to include which one,
    // of the parameters were lower than 0
    if ($data['coord_x'] < 0 && $data['coord_y'] < 0) {
      $status['message'] = "Both the x and y coordinates passed into the function were";
      $status['message'] .= "less than 0, which is not allowed.";
    }
    else if ($data['coord_x'] < 0) {
      $status['message'] = "The x coordinate passed into the function were";
      $status['message'] .= "less than 0, which is not allowed.";
    }
    else if ($data['coord_y'] < 0) {
      $status['message'] = "The y coordinate passed into the function were";
      $status['message'] .= "less than 0, which is not allowed.";
    }
    return $status;
  }
  // Now we must test if mid is valid.
  $test_mid_query = "SELECT mid FROM mapapi_map_definition WHERE mid = %d";
  if ($result = db_query($test_mid_query, $data['mid'])){
    if (db_num_rows($result) > 0){
      // The map is valid so we don't do anything
    }
    else {
      $status['message'] = "The mid is invalid";
      // Not valid map! We musn't save anything
      return $status; 
    }
  }
  
  // Check if tile exists
  $query  = "SELECT tid FROM {mapapi_tile_definition} WHERE "; $query_args = array();
  $query .= "coord_x = %d ";                                   $query_args[] = $data['coord_x'];
  $query .= "AND coord_y = %d ";                               $query_args[] = $data['coord_y'];
  $query .= "AND mid = %d ";                                   $query_args[] = $data['mid'];
  
  // If it exists, we update the tile instead of
  // saving it.
  if ($result = db_query($query, $query_args)) {
    if (db_num_rows($result) > 0) {
      $status['message'] = 'Tile found.  Updating it.  ';
      $tid = db_fetch_array($result);
      // Maybe tid was already passed, but we dont care beacuse $tid is guaranteed to always be more correct
      $data['tid'] = $tid['tid'];
      // No need to see if data definition or data content are set! That check is done inside the tile and content functions
      // Update the tile
      _mapapi_tile_update($data, $status);
      // The tile content must also be saved
    	mapapi_content_save($data, $status);
    }
    else {
      $status['message'] = 'Tile not found.  Adding a new one.  ';
      // If this is a new tile then tid should not be set! 
      // In the admin UI there will be no way to set tid.
      $data['tid'] = db_next_id("mapapi_tile_tid");
      // No need to see if data definition or data content are set! That check is done inside the tile and content functions
      // Insert the tile
      // If it succeeds, save the content as well.
      if(_mapapi_tile_insert($data, $status)){
        mapapi_content_save($data, $status);
      }
    }
  }
  else {
    $status['message'] = "The query to check of the tile is updated failed!";
  }
  
  return $status;
}

function _mapapi_tile_insert($data, &$status){
  // We check if the tid and description are set.
  // The other items are checked by mapapi_tile_save
  if (!isset($data['tid']) || !isset($data['description'])) {
    // We don't need to alter $status, because
    // it is set to false by default.
    // However, we do need to return false,
    // so the if statement in mapapi_tile_save
    // won't go through
    return FALSE;
  }
  
  // This is the big query.
  $query  = "INSERT INTO {mapapi_tile_definition} (mid, tid, coord_x, coord_y, description) VALUES (%d, %d, %d, %d, '%s')";
  $query_args = array();
  $query_args[] = $data['mid'];
  $query_args[] = $data['tid'];
  $query_args[] = $data['coord_x'];
  $query_args[] = $data['coord_y'];
  // The description is serialized, because
  // it can contain lots of information,
  // like the terrain.
  $query_args[] = serialize($data['description']);
  
  if (db_query($query, $query_args)) {
    $status['tile'] = TRUE;
    return TRUE;
  }
  // The status does not need to be set to false,
  // because it is false by default.
  return FALSE;
}

// Updates tile description only! (because to update X or Y means that we just insert a new tile and should use _mapapi_tile_insert
function _mapapi_tile_update($data, &$status) {
  // Check if the description is set.
  // The other items are checked by mapapi_tile_save
  if (!isset($data['description'])) {
    // We don't need to alter $status['tile'], 
    // because it is set to false by default.
    // $status['message'] does need to be
    // set to something more descriptive.
    // At this point, $status['message']
    // needs to be appended to, because
    // it already has some information
    // in it.
    // $status['function'] needs to be
    // set to _mapapi_tile_update to
    // alert the user that the error
    // occered here.
    // We need to return false,
    // so the if statement in mapapi_tile_save
    // won't go through.
    $status['message'] .= "Not enough parameters.  Parameters sent in were <pre>". print_r($data, 1) ."</pre> ";
    $status['message'] .= "You need to pass in the mid of the map to be saved to, ";
    $status['message'] .= "and the x and y coordinates of the tile to save.";
    
    $status['function'] = '_mapapi_tile_update';
    return FALSE;
  }
  // The query itself...
  $update_query  = "UPDATE {mapapi_tile_definition} SET description = '%s' WHERE tid = %d";
  if (db_query($update_query, serialize($data['description']), $data['tid'])) {
    $status['tile'] = TRUE;
    return TRUE;
  }
  else {
    return FALSE;
  }
}


function mapapi_tile_delete($tid) {
  // The status vairable is an array,
  // indecating the different status
  // items.  
  // It is a keyed array containing
  // information about the success
  // of the query, any debug messages,
  // this function name
  $status['query'] = FALSE;
  $status['message'] = "";
  $status['function'] = "mapapi_tile_save";
  $status['overall'] = FALSE;
  $del_tile_content_query = "DELETE FROM {mapapi_tile_content} WHERE tid = %d";
  if(!db_query($del_tile_content_query, $tid)){
    //do something because deleting tile failed!
    $query_status = false;
  }
  $del_tile_definition_query = "DELETE FROM {mapapi_tile_definition} WHERE tid = %d";
  if(!db_query($del_tile_definition_query, $tid)){
    //handle failed query
    $query_status = false;
  }
  return $query_status;
}
/**
 * inserts tile content
 *
 * @param $data
 * @param $status
 * 
 * $content_format = array(
 *   'tid' => 1,
 *   'data' => array()
 * );
 * @return bool
 */
function mapapi_content_save($data, &$status){
  // Check if the content is set.
  // The other items are checked by mapapi_tile_save
  if(!isset($data['content'])) {
    return FALSE;
  }
  $content_query = "REPLACE INTO {mapapi_tile_content} (tid, mid, content) VALUES (%d, %d, '%s')";
  $content_args[] = $data['tid'];
  $content_args[] = $data['mid'];
  $content_args[] = serialize($data['content']);
  if(db_query($content_query, $content_args)){
    return true;
  }
  return false;
}


function mapapi_content_delete($tid){  
  $content_query = "DELETE FROM {mapapi_tile_content} WHERE tid = %d";
  if(db_query($content_query,$tid)){
    return true;
  }
  return false;
}


/**
 * Saves map data. $args has no practical use now, reserved for later addons
 * @example 
 *  $map_format = array(
 *    'mid' => 1, //optional
 *    'limit_x' => '6',
 *    'limit_y' => '7',
 *    'name' => 'New map name', //optional
 *  );
 *
 * @param array $data
 * @param array $args
 */
function mapapi_map_save($data,$args = array()){
  if(!isset($data['mid']) && isset($data['name'])){
    //find the mid by map name
    $query = "SELECT mid FROM {mapapi_map_definition} WHERE name LIKE ('%s')"; $query_arg[] = db_escape_string($data['name']);
    $success = false;
    if($result = db_query($query, $query_arg)){
      $success = true;
    }
    if($success && db_num_rows($result) > 0){
      $mid = db_fetch_array($result);
      $data['mid'] = $mid['mid'];
    } else {
      $data['mid'] = db_next_id("mapapi_map_definition");    
    }  
  } else {  
    $data['mid'] = db_next_id("mapapi_map_definition");    
  }
  return _mapapi_map_save($data,$args);
}

function _mapapi_map_save($data,$args = array()) {
  //make sure $data is of correct format
  if(!isset($data['mid']) || !isset($data['limit_x']) || !isset($data['limit_y']) || !isset($data['name'])){
    return false;
  }
  $insert_query  = "REPLACE INTO {mapapi_map_definition} (mid, limit_x, limit_y, name) VALUES (%d, %d, %d, '%s')";
  $insert_query_args = array();
  $insert_query_args[] = $data['mid'];
  $insert_query_args[] = $data['limit_x'];
  $insert_query_args[] = $data['limit_y'];
  $insert_query_args[] = db_escape_string($data['name']);
  if(db_query($insert_query,$insert_query_args)){
    return true;      //successful insert
  } else {
    return false;    // unsuccessful insert
  }
}
function mapapi_map_delete($mid){
  $query_status = true;       //return at the end of the function, This is not very descriptive at which stage this was set to false
  //delete tile contents
  $content_query = "DELETE FROM {mapapi_tile_content} WHERE {mapapi_tile_content}.mid = %d";
  if(!db_query($content_query,$mid)){
    $query_status = false;
  }
//  delete tiles
  $tiles_query = "DELETE FROM {mapapi_tile_definition} WHERE mid = %d";
  if(!db_query($tiles_query,$mid)){
    $query_status = false;    
  }
  //delete map
  $map_query = "DELETE FROM {mapapi_map_definition} WHERE mid = %d";
  if(!db_query($map_query,$mid)){
    $query_status = false;
  }
  return $query_status; //all data from this particular $mid was deleted
}