id = intval( $id ); $this->code = $code; $this->name = $name; $this->is_hostile = boolval( $is_hostile ); $this->can_be_attacked = boolval( $can_be_attacked ); $this->xp_value = intval( $xp_value ); $this->description = $description; $this->stats = json_decode( $stats, true ); $this->inventory = json_decode( $inventory, true ); $this->image_url = $image_url; } public static function get_enemy_definition_by_id( $id ): ?Enemy_Definition { global $wpdb; $result = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM " . $wpdb->prefix . "adventurebook_enemy_definitions WHERE id = %d", $id ), ARRAY_A );// phpcs:ignore WordPress.DB.DirectDatabaseQuery if ( $result === null ) { return null; } return new Enemy_Definition( $result['id'], $result['code'], $result['name'], $result['is_hostile'], $result['can_be_attacked'], $result['xp_value'], $result['description'], $result['stats'], $result['inventory'], $result['image_url'] ); } public static function get_enemy_definition_by_code( $code ): ?Enemy_Definition { global $wpdb; $result = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM " . $wpdb->prefix . "adventurebook_enemy_definitions WHERE code = %s", $code ), ARRAY_A );// phpcs:ignore WordPress.DB.DirectDatabaseQuery if ( $result === null ) { return null; } return new Enemy_Definition( $result['id'], $result['code'], $result['name'], $result['is_hostile'], $result['can_be_attacked'], $result['xp_value'], $result['description'], $result['stats'], $result['inventory'], $result['image_url'] ); } public function save_to_db(): void { global $wpdb; $table_name = $wpdb->prefix . 'adventurebook_enemy_definitions'; // if id is 0, insert a new row if ( $this->id === 0 ) { Enemy_Definition::create_enemy_definition( $this->code, $this->name, $this->is_hostile, $this->can_be_attacked, $this->xp_value, $this->description, $this->stats, $this->inventory, $this->image_url ); return; } $wpdb->update( $table_name, array(// phpcs:ignore WordPress.DB.DirectDatabaseQuery 'code' => $this->code, 'name' => $this->name, 'is_hostile' => $this->is_hostile, 'can_be_attacked'=> $this->can_be_attacked, 'xp_value' => $this->xp_value, 'description' => $this->description, 'stats' => json_encode( $this->stats ), 'inventory' => json_encode( $this->inventory ), 'image_url' => $this->image_url, ), array( 'id' => $this->id ) ); } /** * Get all enemy definitions that are linked to the given adventurebook id * This means that an enemy_spawn with this enemy_definition_id has a Wordpress page_id whose parent is the given adventurebook id (WP post parent) * each enemy_definition.code should be unique, the result should not contain duplicates * * @param int $adventurebook_id The adventurebook id * @return Enemy_Definition[] Array of Enemy_Definition objects */ public static function get_all_enemy_definitions_by_adventurebook_id( int $adventurebook_id ): array { global $wpdb; $results = $wpdb->get_results( $wpdb->prepare( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching "SELECT DISTINCT ed.* FROM " . $wpdb->prefix . "adventurebook_enemy_definitions ed JOIN " . $wpdb->prefix . "adventurebook_enemy_spawns es ON ed.code = es.code JOIN " . $wpdb->prefix . "posts p ON es.page_id = p.ID WHERE p.post_parent = %d", $adventurebook_id ), ARRAY_A );// phpcs:ignore WordPress.DB.DirectDatabaseQuery return self::create_enemy_definitions_from_results( $results ); } public static function create_enemy_definitions_from_results($results): array { $enemy_definitions = array(); foreach ( $results as $result ) { $enemy_definitions[] = new Enemy_Definition( $result['id'], $result['code'], $result['name'], $result['is_hostile'], $result['can_be_attacked'], $result['xp_value'], $result['description'], $result['stats'], $result['inventory'], $result['image_url'] ); } return $enemy_definitions; } public static function get_all_enemy_definitions(): array { global $wpdb; $results = $wpdb->get_results( "SELECT * FROM " . $wpdb->prefix . "adventurebook_enemy_definitions", ARRAY_A );// phpcs:ignore WordPress.DB.DirectDatabaseQuery $enemy_definitions = Enemy_Definition::create_enemy_definitions_from_results( $results ); // sort by name usort( $enemy_definitions, function ( $a, $b ) { return strcmp( $a->name, $b->name ); } ); return $enemy_definitions; } public static function create_enemy_definition( $code, $name, $is_hostile, $can_be_attacked, $xp_value, $description, $stats, $inventory, $image_url ): void { global $wpdb; $table_name = $wpdb->prefix . 'adventurebook_enemy_definitions'; $wpdb->insert( $table_name, array(// phpcs:ignore WordPress.DB.DirectDatabaseQuery 'code' => $code, 'name' => $name, 'is_hostile' => $is_hostile, 'can_be_attacked' => $can_be_attacked, 'xp_value' => $xp_value, 'description' => $description, 'stats' => json_encode( $stats ), 'inventory' => json_encode( $inventory ), 'image_url' => $image_url, ) ); } public static function delete_enemy_definition( $id ): void { global $wpdb; $table_name = $wpdb->prefix . 'adventurebook_enemy_definitions'; $wpdb->delete( $table_name, array( 'id' => $id ) );// phpcs:ignore WordPress.DB.DirectDatabaseQuery } public static function delete_enemy_definition_by_code( $code ): void { global $wpdb; // first, remove all enemy spawns with this code Enemy_Spawn::delete_enemy_spawn_points_by_code( $code ); // then, remove all enemies with this code $table_name = $wpdb->prefix . 'adventurebook_enemy_definitions'; $wpdb->delete( $table_name, array( 'code' => $code ) );// phpcs:ignore WordPress.DB.DirectDatabaseQuery } public function get_html(): string { $html = '
'; // Bild $html .= '
'; $html .= $this->image_url ? '' : ''; $html .= '
'; $html .= '
' . esc_html( $this->name ) . '
'; // if an admin is logged in, show an edit button with a link to the item definition edit page if ( current_user_can( 'manage_options' ) ) { $edit_url = admin_url( 'admin.php?page=adventurebook-enemies&action=edit&id=' . $this->id ); $html .= ' [EDIT]'; } $html .= '
' . esc_html( $this->description ) . '
'; $html .= '
'; return $html; } /** * Get the inventory as a comma-separated string * the JSON is in the form [{"x":m:n:o},{"y":m:n:o},...] * we need x:m:n:o,y:m:n:o,... * * @return string Comma-separated list of item codes */ public function get_inventory_as_string(): string { // if inventory is null or empty, return empty string if ( empty( $this->inventory ) ) { return ''; } return implode( ',', $this->inventory ); } /** * converts the inventory ["x:m:n:o","y:m:n:o",...] to an array of key value strings * $item['item_code'] = 'item_code', $item['percent'] = m, $item['min'] = n, $item['max'] = o * * @return array Inventory as array of strings */ public function get_inventory_as_array(): array { $inventory_array = array(); // check if inventory is empty or is [''] if ( empty( $this->inventory ) ) { return $inventory_array; } foreach ( $this->inventory as $inventory_item ) { $parts = explode( ':', $inventory_item ); if ( count( $parts ) === 4 ) { $inventory_array[] = array( 'item_code' => $parts[0], 'percent' => intval( $parts[1] ), 'min' => intval( $parts[2] ), 'max' => intval( $parts[3] ), ); } } return $inventory_array; } public function get_loottable_item_definitions() : array { $item_definitions = array(); if ( empty( $this->inventory ) ) { return $item_definitions; } foreach ( $this->inventory as $inventory_item ) { // each inventory item is in the form x:m:n:o // we need to extract the item code x $parts = explode( ':', $inventory_item ); $item_code = $parts[0]; // get the item definition by code $item_definition = Item_Definition::get_item_definition_by_code( $item_code ); if ( $item_definition ) { $item_definitions[] = $item_definition; } } return $item_definitions; } public function getInventoryAsHTML(): string { if ( empty( $this->inventory ) ) { return '

No items

'; } $html = ''; foreach ( $this->inventory as $inventory_item ) { // each inventory item is in the form x:m:n:o // we need to extract the item code x $parts = explode( ':', $inventory_item ); $item_code = $parts[0]; // get the item definition by code if($item_code == 'money') { $html .= '
  • Money ('.$parts[1].'%) '.$parts[2].'-'.$parts[3].'
  • '; continue; } $item_definition = Item_Definition::get_item_definition_by_code( $item_code ); if ( $item_definition ) { $html .= '
  • ' . esc_html( $item_definition->name ) . ' ('.$parts[1].'%) '.$parts[2].'-'.$parts[3].'
  • '; } } return $html; } /** Get the total combat strength of the combatant. * This is the sum of Attack, Damage, Initiative, Defense and Armor values. * * It is used for comparing combatants in combat. * * @return int The total combat strength. */ public function get_combat_strength() : int { return $this->get_stat( 'Attack' ) + $this->get_stat( 'Damage' ) + $this->get_stat( 'Initiative' ) + $this->get_stat( 'Defense' ) + $this->get_stat( 'Armor' ); } public function get_stat( string $stat_name ): int { return $this->stats[ $stat_name ] ?? 0; } public function get_stat_as_string( string $stat_name ): string { return isset( $this->stats[ $stat_name ] ) ? strval( $this->stats[ $stat_name ] ) : ''; } }