killcounters, redbox mode, failing unseal test, and random debug strings

This commit is contained in:
andy 2021-12-19 19:44:27 +00:00
parent ca44dcf689
commit 117a2daa31
9 changed files with 224 additions and 4 deletions

View File

@ -186,6 +186,10 @@ impl<R: Rng + SeedableRng> DropTable<R> {
pub fn get_box_drop(&mut self, map_area: &MapArea, object: &MapObject) -> Option<ItemDropType> {
self.box_table.get_drop(map_area, object, &mut self.rng)
}
pub fn get_rare_drop(&mut self, map_area: &MapArea, monster: &MonsterType) -> Option<ItemDropType> {
self.rare_table.get_rare_drop(map_area, monster, &mut self.rng)
}
}
@ -205,4 +209,11 @@ mod test {
.into_iter().choose(&mut rng).unwrap();
DropTable::<rand_chacha::ChaCha20Rng>::new(episode, difficulty, section_id);
}
#[test]
fn test_sjs_drop() {
let mut drop_table = DropTable::<rand_chacha::ChaCha20Rng>::new(Episode::Two, Difficulty::Ultimate, SectionID::Skyly);
let drop = drop_table.get_rare_drop(&MapArea::Seaside, &MonsterType::GiGue);
println!("drop: {:?}", drop);
}
}

View File

@ -167,4 +167,14 @@ impl RareDropTable {
}).next()
})
}
pub fn get_rare_drop<R: Rng>(&self, map_area: &MapArea, monster: &MonsterType, rng: &mut R) -> Option<ItemDropType> {
self.rates.get(monster)
.and_then(|drop_rates| {
drop_rates.iter()
.filter_map(|drop_rate| {
Some(self.apply_item_stats(map_area, drop_rate.item, rng))
}).next()
})
}
}

View File

@ -320,6 +320,16 @@ impl Maps {
self.object_data = objects;
}
pub fn get_enemy_id_by_monster_type(&self, monster: MonsterType) -> Option<u16> {
let (id, _) = self.enemy_data
.iter()
.enumerate()
.filter(|(_i, &m)| m.is_some())
.find(|(_i, &m)| m.unwrap().monster == monster)?;
Some(id as u16)
}
pub fn get_rare_monster_list(&self) -> Vec<u16> {
let mut rare_monsters = vec![0xFFFF; 16];
let shiny: Vec<(usize, &Option<MapEnemy>)> = self.enemy_data.iter()

View File

@ -79,6 +79,7 @@ pub async fn request_item<EG>(id: ClientId,
where
EG: EntityGateway
{
println!("src::ship::packet::handler::request_item() - requesting an item!");
let room_id = client_location.get_room(id).map_err(|err| -> ClientLocationError { err.into() })?;
let room = rooms.get_mut(room_id.0)
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?
@ -86,7 +87,9 @@ where
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?;
let monster = room.maps.enemy_by_id(request_item.enemy_id as usize)?;
println!("room id: {:?}, monster: {:?}", room_id, monster);
if monster.dropped_item {
println!("monster {:?} already dropped an item!", monster);
return Err(ShipError::MonsterAlreadyDroppedItem(id, request_item.enemy_id).into())
}
@ -94,9 +97,16 @@ where
let client_and_drop = clients_in_area.into_iter()
.filter_map(|area_client| {
room.drop_table.get_drop(&monster.map_area, &monster.monster).map(|item_drop_type| {
(area_client, item_drop_type)
})
if room.redbox {
println!("red box mode is currently enabled. dropping red box!");
room.drop_table.get_rare_drop(&monster.map_area, &monster.monster).map(|item_drop_type| {
(area_client, item_drop_type)
})
} else {
room.drop_table.get_drop(&monster.map_area, &monster.monster).map(|item_drop_type| {
(area_client, item_drop_type)
})
}
});
let mut item_drop_packets = Vec::new();

View File

@ -203,6 +203,7 @@ pub struct RoomState {
pub rare_monster_table: Box<RareMonsterAppearTable>,
pub quest_group: QuestCategoryType,
pub quests: Vec<quests::QuestList>,
pub redbox: bool,
// items on ground
// enemy info
}
@ -316,6 +317,11 @@ impl RoomState {
map_areas: MapAreaLookup::new(&room_mode.episode()),
quest_group: QuestCategoryType::Standard,
quests: room_quests,
redbox: false,
})
}
pub fn toggle_redbox_mode(&mut self) {
self.redbox = !self.redbox;
}
}

View File

@ -542,6 +542,7 @@ impl<EG: EntityGateway> ShipServerState<EG> {
handler::direct_message::guildcard_send(id, guildcard_send, target, &block.client_location, &self.clients)
},
GameMessage::RequestItem(request_item) => {
println!("someone requested an item from the ship!");
handler::direct_message::request_item(id, request_item, &mut self.entity_gateway, &block.client_location, &mut self.clients, &mut block.rooms, &mut self.item_manager).await?
},
GameMessage::PickupItem(pickup_item) => {

View File

@ -3,8 +3,8 @@
use elseware::common::serverstate::{ClientId, ServerState};
use elseware::entity::gateway::EntityGateway;
use elseware::entity::account::{UserAccountEntity, NewUserAccountEntity, NewUserSettingsEntity};
use elseware::entity::character::{CharacterEntity, NewCharacterEntity};
use elseware::entity::item::{Meseta, BankName};
use elseware::entity::character::{CharacterEntity, NewCharacterEntity, SectionID};
use elseware::ship::ship::{ShipServerState, RecvShipPacket};
use elseware::ship::room::Difficulty;
@ -34,6 +34,26 @@ pub async fn new_user_character<EG: EntityGateway>(entity_gateway: &mut EG, user
(user, character)
}
pub async fn new_user_character_with_sid<EG: EntityGateway>(entity_gateway: &mut EG, username: &str, password: &str, sid: SectionID) -> (UserAccountEntity, CharacterEntity) {
let new_user = NewUserAccountEntity {
email: format!("{}@pso.com", username),
username: username.into(),
password: bcrypt::hash(password, 5).unwrap(),
guildcard: 1,
activated: true,
..NewUserAccountEntity::default()
};
let user = entity_gateway.create_user(new_user).await.unwrap();
let new_settings = NewUserSettingsEntity::new(user.id);
let _settings = entity_gateway.create_user_settings(new_settings).await.unwrap();
let mut new_character = NewCharacterEntity::new(user.id);
new_character.section_id = sid;
let character = entity_gateway.create_character(new_character).await.unwrap();
(user, character)
}
pub async fn log_in_char<EG: EntityGateway>(ship: &mut ShipServerState<EG>, id: ClientId, username: &str, password: &str) {
let username = username.to_string();
let password = password.to_string();
@ -84,6 +104,21 @@ pub async fn create_room_with_difficulty<EG: EntityGateway>(ship: &mut ShipServe
ship.handle(id, &RecvShipPacket::DoneBursting(DoneBursting {})).await.unwrap().for_each(drop);
}
pub async fn create_ep2_room_with_difficulty<EG: EntityGateway>(ship: &mut ShipServerState<EG>, id: ClientId, name: &str, password: &str, difficulty: Difficulty) {
ship.handle(id, &RecvShipPacket::CreateRoom(CreateRoom {
unknown: [0; 2],
name: utf8_to_utf16_array!(name, 16),
password: utf8_to_utf16_array!(password, 16),
difficulty: difficulty.into(),
battle: 0,
challenge: 0,
episode: 2,
single_player: 0,
padding: [0; 3],
})).await.unwrap().for_each(drop);
ship.handle(id, &RecvShipPacket::DoneBursting(DoneBursting {})).await.unwrap().for_each(drop);
}
pub async fn join_room<EG: EntityGateway>(ship: &mut ShipServerState<EG>, id: ClientId, room_id: u32) {
ship.handle(id, &RecvShipPacket::MenuSelect(MenuSelect {
menu: ROOM_MENU_ID,

View File

@ -34,6 +34,7 @@ async fn test_equip_unit_from_equip_menu() {
item::unit::Unit{
unit: item::unit::UnitType::KnightPower,
modifier: None,
kills: None,
}),
}).await.unwrap());
@ -43,6 +44,7 @@ async fn test_equip_unit_from_equip_menu() {
item::unit::Unit{
unit: item::unit::UnitType::KnightPower,
modifier: Some(item::unit::UnitModifier::Plus),
kills: None,
}),
}).await.unwrap());
@ -111,6 +113,7 @@ async fn test_unequip_armor_with_units() {
item::unit::Unit{
unit: item::unit::UnitType::KnightPower,
modifier: None,
kills: None,
}),
}).await.unwrap());
@ -120,6 +123,7 @@ async fn test_unequip_armor_with_units() {
item::unit::Unit{
unit: item::unit::UnitType::KnightPower,
modifier: Some(item::unit::UnitModifier::Plus),
kills: None,
}),
}).await.unwrap());
@ -179,6 +183,7 @@ async fn test_sort_items() {
item::unit::Unit{
unit: item::unit::UnitType::KnightPower,
modifier: None,
kills: None,
}),
}).await.unwrap());
@ -188,6 +193,7 @@ async fn test_sort_items() {
item::unit::Unit{
unit: item::unit::UnitType::KnightPower,
modifier: Some(item::unit::UnitModifier::Plus),
kills: None,
}),
}).await.unwrap());

131
tests/test_unseal_items.rs Normal file
View File

@ -0,0 +1,131 @@
/* TODO:
1. test to check if sjs/lame/limiter drop with Some() kill counter enabled
2. test to make sure other items drop with None kill counter
3. test kill counters get incremented per kill
4. test unsealing item:
- client item id does not change
- unsealed item no longer has kill counter
5. test reject unsealing item if not enough kills (can this even happen?)
*/
use elseware::common::serverstate::{ClientId, ServerState};
use elseware::entity::gateway::{EntityGateway, InMemoryGateway};
use elseware::entity::item;
use elseware::ship::ship::{ShipServerState, RecvShipPacket};
use elseware::entity::character::{SectionID};
use elseware::ship::room::{Difficulty};
use elseware::ship::map::area::{MapArea};
use elseware::ship::monster::{MonsterType};
use libpso::packet::ship::*;
use libpso::packet::messages::*;
#[path = "common.rs"]
mod common;
use common::*;
#[async_std::test]
async fn test_item_drops_with_kill_counter() {
let mut entity_gateway = InMemoryGateway::default();
let (_user1, _char1) = new_user_character_with_sid(&mut entity_gateway, "a1", "a", SectionID::Skyly).await;
let mut ship = Box::new(ShipServerState::builder()
.gateway(entity_gateway.clone())
.build());
log_in_char(&mut ship, ClientId(1), "a1", "a").await;
join_lobby(&mut ship, ClientId(1)).await;
create_ep2_room_with_difficulty(&mut ship, ClientId(1), "room", "", Difficulty::Ultimate).await;
// ship.handle(ClientId(1), &RecvShipPacket()).await.unwrap().for_each(drop);
// ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerWarpingToFloor(PlayerWarpingToFloor{
// client: 0,
// target: 0,
// area: 9, // seaside
// data: 0,
// })))).await.unwrap().for_each(drop);
// ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerWarping(PlayerWarping{
// client: 0,
// target: 0,
// })))).await.unwrap().for_each(drop);
// ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerLoadedIn(PlayerLoadedIn{
// client: 0,
// target: 0,
// unknown1: [0,0],
// rotation: 0,
// area: 9,
// room: 1,
// x: 100.0,
// y: 10.0,
// z: -20.0,
// })))).await.unwrap().for_each(drop);
// ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerChangedMap2(PlayerChangedMap2{
// client: 0,
// target: 0,
// map_area: 9,
// _unknown1: 0,
// })))).await.unwrap().for_each(drop);
// ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerSpawnedIntoArea(PlayerSpawnedIntoArea{
// client: 0,
// target: 0,
// })))).await.unwrap().for_each(drop);
// ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::PlayerDoneChangingMap(PlayerDoneChangingMap{
// client: 0,
// target: 0,
// })))).await.unwrap().for_each(drop);
let room = ship.blocks.0[0].rooms[0].as_mut().unwrap();
room.toggle_redbox_mode(); // enable redbox mode for sjs
println!("room redbox mode: {:?}", room.redbox);
println!("room.mode: {:?}", room.mode);
println!("killing gigue for sjs!");
let gigue_id = room.maps.get_enemy_id_by_monster_type(MonsterType::GiGue).unwrap();
println!("found gigue id: {:?}!", gigue_id);
let pkts = ship.handle(ClientId(1), &RecvShipPacket::Message(Message::new(GameMessage::RequestItem(RequestItem {
client: 0,
target: 0,
map_area: 9, // seaside
pt_index: 55, // gigue ?
enemy_id: gigue_id,
x: 0.0,
y: 0.0,
z: 0.0,
}))))
.await
.unwrap()
.collect::<Vec<_>>(); // this should return 1 packet (ItemDrop)?
println!("packets returned: {:?}", pkts);
assert!(false);
}
// #[async_std::test]
// async fn test_all_equipped_kill_counters_increase_per_kill() {
// let mut entity_gateway = InMemoryGateway::default();
// let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
// }
// #[async_std::test]
// async fn test_non_equipped_kill_counter_does_not_increase() {
// let mut entity_gateway = InMemoryGateway::default();
// let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
// }
// #[async_std::test]
// async fn test_kill_counter_increase_only_for_final_hit() { // don't share kills among players
// let mut entity_gateway = InMemoryGateway::default();
// let (_user1, _char1) = new_user_character(&mut entity_gateway, "a1", "a").await;
// }