Example #1
0
/**
 * Checks whether a collision occurs between self and other if self
 * moves from (x,y) to (new_x, new_y) in direction d.
 *
 * If other is a tile event, also indicates if the player can use it
 * as a "bridge" to step across without hitting the underlying tile
 * layer.
 */
static CollisionResult TestCollisionDuringMove(
	int x,
	int y,
	int new_x,
	int new_y,
	int d,
	const Game_Character& self,
	const Game_Event& other
) {
	if (!other.GetActive()) {
		return NoCollision;
	}

	if (&self == &other) {
		return NoCollision;
	}

	if (other.GetThrough()) {
		return NoCollision;
	}

	if (!other.IsInPosition(x, y) && !other.IsInPosition(new_x, new_y)) {
		return NoCollision;
	}

	if (&self != Main_Data::game_player.get()) {
		if (other.IsInPosition(new_x, new_y) && (self.IsOverlapForbidden() || other.IsOverlapForbidden())) {
			return Collision;
		}
	}

	if (other.IsInPosition(new_x, new_y) && self.GetLayer() == other.GetLayer()) {
		return Collision;
	}

	if (other.GetLayer() == RPG::EventPage::Layers_below) {
		int tile_id = other.GetTileId();
		if ((passages_up[tile_id] & Passable::Above) != 0) {
			return NoCollision;
		}
		if (other.IsInPosition(x,y) && (passages_up[tile_id] & DirToMask(d)) != 0) {
			return CanStepOffCurrentTile;
		}
		else if (other.IsInPosition(new_x, new_y) && (passages_up[tile_id] & DirToMask(Game_Character::ReverseDir(d))) != 0) {
			return CanStepOntoNewTile;
		} else {
			return Collision;
		}
	}

	return NoCollision;
}
Example #2
0
void Game_Screen::ShowBattleAnimation(int animation_id, int target_id, bool global) {
	data.battleanim_id = animation_id;
	data.battleanim_target = target_id;
	data.battleanim_global = global;

	Game_Character* target = Game_Character::GetCharacter(target_id, target_id);

	animation.reset(new BattleAnimation(target->GetScreenX(), target->GetScreenY(),
										&Data::animations[animation_id - 1]));
	animation->SetVisible(true);
	// FIXME: target
	// FIXME: global
}
Example #3
0
bool Game_Map::MakeWay(int x, int y, int d, const Game_Character& self, bool force_through) {
	int new_x = RoundX(x + (d == Game_Character::Right ? 1 : d == Game_Character::Left ? -1 : 0));
	int new_y = RoundY(y + (d == Game_Character::Down ? 1 : d == Game_Character::Up ? -1 : 0));

	if (!Game_Map::IsValid(new_x, new_y))
		return false;

	if (self.GetThrough() || force_through) return true;

	// A character can move to a position with an impassable tile by
	// standing on top of an event below it. These flags track whether
	// we stepped off an event and therefore don't need to check the
	// passability of the tile layer below.
	bool stepped_off_event = false;
	bool stepped_onto_event = false;

	for (Game_Event& other : GetEvents()) {
		CollisionResult result = TestCollisionDuringMove(x, y, new_x, new_y, d, self, other);
		if (result == Collision) {
			// Try updating the offending event to give it a chance to move out of the
			// way and recheck.
			other.UpdateParallel();
			if (TestCollisionDuringMove(x, y, new_x, new_y, d, self, other) == Collision) {
				return false;
			}
		}
		else if (result == CanStepOffCurrentTile) {
			stepped_off_event = true;
		} else if (result == CanStepOntoNewTile) {
			stepped_onto_event = true;
		}
	}

	if (vehicles[0]->IsInPosition(new_x, new_y) || vehicles[1]->IsInPosition(new_x, new_y)) {
		return false;
	}

	if (Main_Data::game_player->IsInPosition(new_x, new_y)
			&& !Main_Data::game_player->GetThrough()
			&& self.GetLayer() == RPG::EventPage::Layers_same) {
		// Update the Player to see if they'll move and recheck.
		Main_Data::game_player->Update(!first_frame);
		if (Main_Data::game_player->IsInPosition(new_x, new_y)) {
			return false;
		}
	}

	return
		(stepped_off_event || IsPassableTile(DirToMask(d), x + y * GetWidth()))
		&& (stepped_onto_event || IsPassableTile(DirToMask(Game_Character::ReverseDir(d)), new_x + new_y * GetWidth()));
}
bool Game_Interpreter_Map::CommandEnemyEncounter(RPG::EventCommand const& com) { // code 10710
	if (Game_Message::visible) {
		return false;
	}

	Game_Temp::battle_troop_id = ValueOrVariable(com.parameters[0],
		com.parameters[1]);
	Game_Character *player = Main_Data::game_player.get();
	Game_Battle::SetTerrainId(Game_Map::GetTerrainTag(player->GetX(), player->GetY()));

	switch (com.parameters[2]) {
	case 0:
		Game_Map::SetupBattle();
		break;
	case 1:
		Game_Temp::battle_background = com.string;

		if (Player::IsRPG2k())
			Game_Temp::battle_formation = 0;
		else
			Game_Temp::battle_formation = com.parameters[7];
		break;
	case 2:
		Game_Battle::SetTerrainId(com.parameters[8]);
		break;
	default:
		return false;
	}
	Game_Temp::battle_escape_mode = com.parameters[3]; // 0 disallow, 1 end event processing, 2 victory/escape custom handler
	Game_Temp::battle_defeat_mode = com.parameters[4]; // 0 game over, 1 victory/defeat custom handler
	Game_Temp::battle_first_strike = com.parameters[5] != 0;

	if (Player::IsRPG2k())
		Game_Battle::SetBattleMode(0);
	else
		Game_Battle::SetBattleMode(com.parameters[6]); // 0 normal, 1 initiative, 2 surround, 3 back attack, 4 pincer

	Game_Temp::battle_result = Game_Temp::BattleVictory;
	scene_call = Scene::Battle;

	SetContinuation(static_cast<ContinuationFunction>(&Game_Interpreter_Map::ContinuationEnemyEncounter));
	return false;
}
bool Game_Interpreter_Map::CommandFlashSprite(RPG::EventCommand const& com) { // code 11320
	int event_id = com.parameters[0];
	Color color(com.parameters[1] * 255 / 31,
		com.parameters[2] * 255 / 31,
		com.parameters[3] * 255 / 31,
		com.parameters[4] * 255 / 31);

	int tenths = com.parameters[5];
	bool wait = com.parameters[6] > 0;
	Game_Character* event = GetCharacter(event_id);

	if (event != NULL) {
		event->Flash(color, tenths * DEFAULT_FPS / 10);

		if (wait)
			SetupWait(tenths);
	}

	return true;
}
Example #6
0
void Game_Map::ShowBattleAnimation(int animation_id, int target_id, bool global) {
	const RPG::Animation* anim = ReaderUtil::GetElement(Data::animations, animation_id);
	if (!anim) {
		Output::Warning("ShowBattleAnimation: Invalid battle animation ID %d", animation_id);
		return;
	}

	Main_Data::game_data.screen.battleanim_id = animation_id;
	Main_Data::game_data.screen.battleanim_target = target_id;
	Main_Data::game_data.screen.battleanim_global = global;

	Game_Character* chara = Game_Character::GetCharacter(target_id, target_id);

	if (chara) {
		chara->SetFlashTimeLeft(0); // Any flash always ends
		if (global) {
			animation.reset(new BattleAnimationGlobal(*anim));
		} else {
			animation.reset(new BattleAnimationChara(*anim, *chara));
		}
	}
}
// Command control vars
bool Game_Interpreter::CommandControlVariables(RPG::EventCommand const& com) { // Code ControlVars
	int i, value = 0;
	Game_Actor* actor;
	Game_Character* character;

	switch (com.parameters[4]) {
		case 0:
			// Constant
			value = com.parameters[5];
			break;
		case 1:
			// Var A ops B
			value = Game_Variables[com.parameters[5]];
			break;
		case 2:
			// Number of var A ops B
			value = Game_Variables[Game_Variables[com.parameters[5]]];
			break;
		case 3:
			// Random between range
			int a, b;
			a = max(com.parameters[5], com.parameters[6]);
			b = min(com.parameters[5], com.parameters[6]);
			value = rand() % (a-b+1)+b;
			break;
		case 4:
			// Items
			switch (com.parameters[6]) {
				case 0:
					// Number of items posessed
					value = Game_Party::ItemNumber(com.parameters[5]);
					break;
				case 1:
					// How often the item is equipped
					value = Game_Party::ItemNumber(com.parameters[5], true);
					break;
			}
			break;
		case 5:
			// Hero
			actor = Game_Actors::GetActor(com.parameters[5]);
			if (actor != NULL) {
				switch (com.parameters[6]) {
					case 0:
						// Level
						value = actor->GetLevel();
						break;
					case 1:
						// Experience
						value = actor->GetExp();
						break;
					case 2:
						// Current HP
						value = actor->GetHp();
						break;
					case 3:
						// Current MP
						value = actor->GetSp();
						break;
					case 4:
						// Max HP
						value = actor->GetMaxHp();
						break;
					case 5:
						// Max MP
						value = actor->GetMaxSp();
						break;
					case 6:
						// Attack
						value = actor->GetAtk();
						break;
					case 7:
						// Defense
						value = actor->GetDef();
						break;
					case 8:
						// Intelligence
						value = actor->GetSpi();
						break;
					case 9:
						// Agility
						value = actor->GetAgi();
						break;
					case 10:
						// Weapon ID
						value = actor->GetWeaponId();
						break;
					case 11:
						// Shield ID
						value = actor->GetShieldId();
						break;
					case 12:
						// Armor ID
						value = actor->GetArmorId();
						break;
					case 13:
						// Helmet ID
						value = actor->GetHelmetId();
						break;
					case 14:
						// Accesory ID
						value = actor->GetAccessoryId();
						break;
				}
			}
			break;
		case 6:
			// Characters
			if (com.parameters[6] != 0){
				character = GetCharacter(com.parameters[5]);
			} else {
				// Special case for Player Map ID
				character = NULL;
				value = Game_Map::GetMapId();
			}
			// Other cases
			if (character != NULL) {
				switch (com.parameters[6]) {
					case 1:
						// X Coordinate
						value = character->GetX();
						break;
					case 2:
						// Y Coordinate
						value = character->GetY();
						break;
					case 3:
						// TODO Orientation
						// Needs testing
						value = character->GetDirection();
						break;
					case 4:
						// Screen X
						value = character->GetScreenX();
						break;
					case 5:
						// Screen Y
						value = character->GetScreenY();
				}
			}
			break;
		case 7:
			// More
			switch (com.parameters[5]) {
				case 0:
					// Gold
					value = Game_Party::GetGold();
					break;
				case 1:
					value = Game_Party::ReadTimer(Game_Party::Timer1);
					break;
				case 2:
					// Number of heroes in party
					value = Game_Party::GetActors().size();
					break;
				case 3:
					// Number of saves
					value = Game_System::GetSaveCount();
					break;
				case 4:
					// Number of battles
					value = Game_Party::GetBattleCount();
					break;
				case 5:
					// Number of wins
					value = Game_Party::GetWinCount();
					break;
				case 6:
					// Number of defeats
					value = Game_Party::GetDefeatCount();
					break;
				case 7:
					// Number of escapes (aka run away)
					value = Game_Party::GetRunCount();
					break;
				case 8:
					// TODO: MIDI play position
					break;
				case 9:
					value = Game_Party::ReadTimer(Game_Party::Timer2);
					break;
			}
			break;
		default:
			;
	}

	switch (com.parameters[0]) {
		case 0:
		case 1:
			// Single and Var range
			for (i = com.parameters[1]; i <= com.parameters[2]; i++) {
				switch (com.parameters[3]) {
					case 0:
						// Assignement
						Game_Variables[i] = value;
						break;
					case 1:
						// Addition
						Game_Variables[i] += value;
						break;
					case 2:
						// Subtraction
						Game_Variables[i] -= value;
						break;
					case 3:
						// Multiplication
						Game_Variables[i] *= value;
						break;
					case 4:
						// Division
						if (value != 0) {
							Game_Variables[i] /= value;
						}
						break;
					case 5:
						// Module
						if (value != 0) {
							Game_Variables[i] %= value;
						} else {
							Game_Variables[i] = 0;
						}
				}
				if (Game_Variables[i] > MaxSize) {
					Game_Variables[i] = MaxSize;
				}
				if (Game_Variables[i] < MinSize) {
					Game_Variables[i] = MinSize;
				}
			}
			break;

		case 2:
			switch (com.parameters[3]) {
				case 0:
					// Assignement
					Game_Variables[com.parameters[1]] = value;
					break;
				case 1:
					// Addition
					Game_Variables[com.parameters[1]] += value;
					break;
				case 2:
					// Subtraction
					Game_Variables[com.parameters[1]] -= value;
					break;
				case 3:
					// Multiplication
					Game_Variables[com.parameters[1]] *= value;
					break;
				case 4:
					// Division
					if (value != 0) {
						Game_Variables[com.parameters[1]] /= value;
					}
					break;
				case 5:
					// Module
					if (value != 0) {
						Game_Variables[com.parameters[1]] %= value;
					}
			}
			if (Game_Variables[com.parameters[1]] > MaxSize) {
				Game_Variables[com.parameters[1]] = MaxSize;
			}
			if (Game_Variables[com.parameters[1]] < MinSize) {
				Game_Variables[com.parameters[1]] = MinSize;
			}
	}

	Game_Map::SetNeedRefresh(true);
	return true;
}
Example #8
0
bool Game_Map::MakeWay(const Game_Character& self, int x, int y) {
	// Moving to same tile (used for jumps) always succeeds
	if (x == self.GetX() && y == self.GetY()) {
		return true;
	}
	if (!self.IsJumping() && x != self.GetX() && y != self.GetY()) {
		// Handle diagonal stepping.
		// Must be able to step on at least one of the 2 adjacent tiles and also the target tile.
		// Verified behavior: Always checks vertical first, only checks horizontal if vertical fails.
		bool vertical_ok = MakeWay(self, self.GetX(), y);
		if (!vertical_ok) {
			bool horizontal_ok = MakeWay(self, x, self.GetY());
			if (!horizontal_ok) {
				return false;
			}
		}
	}

	// Infer directions before we do any rounding.
	const auto bit_from = GetPassableMask(self.GetX(), self.GetY(), x, y);
	const auto bit_to = GetPassableMask(x, y, self.GetX(), self.GetY());

	// Now round for looping maps.
	x = Game_Map::RoundX(x);
	y = Game_Map::RoundY(y);

	// Note, even for diagonal, if the tile is invalid we still check vertical/horizontal first!
	if (!Game_Map::IsValid(x, y)) {
		return false;
	}

	if (self.GetThrough()) {
		return true;
	}

	const auto vehicle_type = static_cast<Game_Vehicle::Type>(self.GetVehicleType());

	bool self_conflict = false;
	if (!self.IsJumping()) {
		// Check for self conflict.
		// If this event has a tile graphic and the tile itself has passage blocked in the direction
		// we want to move, flag it as "self conflicting" for use later.
		if (self.GetLayer() == RPG::EventPage::Layers_below && self.GetTileId() != 0) {
			int tile_id = self.GetTileId();
			if ((passages_up[tile_id] & bit_from) == 0) {
				self_conflict = true;
			}
		}

		if (vehicle_type == Game_Vehicle::None) {
			// Check that we are allowed to step off of the current tile.
			// Note: Vehicles can always step off a tile.
			if (!IsPassableTile(&self, bit_from, self.GetX(), self.GetY())) {
				return false;
			}
		}
	}

	if (vehicle_type != Game_Vehicle::Airship) {
		// Check for collision with events on the target tile.
		for (auto& other: GetEvents()) {
			if (MakeWayCollideEvent(x, y, self, other, self_conflict)) {
				return false;
			}
		}
		auto& player = Main_Data::game_player;
		if (player->GetVehicleType() == Game_Vehicle::None) {
			if (MakeWayCollideEvent(x, y, self, *Main_Data::game_player, self_conflict)) {
				return false;
			}
		}
		for (auto vid: { Game_Vehicle::Boat, Game_Vehicle::Ship}) {
			auto& other = vehicles[vid - 1];
			if (other->IsInCurrentMap()) {
				if (MakeWayCollideEvent(x, y, self, *other, self_conflict)) {
					return false;
				}
			}
		}
		auto& airship = vehicles[Game_Vehicle::Airship - 1];
		if (airship->IsInCurrentMap() && self.GetType() != Game_Character::Player) {
			if (MakeWayCollideEvent(x, y, self, *airship, self_conflict)) {
				return false;
			}
		}
	}

	int bit = bit_to;
	if (self.IsJumping()) {
		bit = Passable::Down | Passable::Up | Passable::Left | Passable::Right;
	}

	return IsPassableTile(&self, bit, x, y);
}
Example #9
0
static bool WouldCollide(const Game_Character& self, const Game_Character& other, bool self_conflict) {
	if (self.GetThrough() || other.GetThrough()) {
		return false;
	}

	if (self.IsFlying() || other.IsFlying()) {
		return false;
	}

	if (!self.IsActive() || !other.IsActive()) {
		return false;
	}

	if (self.GetType() == Game_Character::Event
			&& other.GetType() == Game_Character::Event
			&& (self.IsOverlapForbidden() || other.IsOverlapForbidden())) {
		return true;
	}

	if (other.GetLayer() == RPG::EventPage::Layers_same && self_conflict) {
		return true;
	}

	if (self.GetLayer() == other.GetLayer()) {
		return true;
	}

	return false;
}