Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
67ebe7f
Add Dynamic Array Accessor
FatherOfEgg Nov 2, 2025
0b3fc2e
Add some weapon related static vars
FatherOfEgg Nov 3, 2025
855a8ba
Added a clarifying comment
FatherOfEgg Nov 4, 2025
3c2acc3
Changed get_file_weapon_name hook offset
FatherOfEgg Nov 4, 2025
6cf3f7e
Update weapon hooks to use corresponding DynamicArrayAccessor
FatherOfEgg Nov 6, 2025
c78cfdc
Added shift parameter to weapon hooks to fix incorrect index
FatherOfEgg Nov 6, 2025
bcb0ca2
Add get file category hook
FatherOfEgg Nov 18, 2025
6a05134
Add a vec for base weapon kinds
FatherOfEgg Nov 18, 2025
4c7b097
Use const var
FatherOfEgg Nov 18, 2025
08a457a
Add a hook for a weapon bone stuff thing
FatherOfEgg Nov 18, 2025
2eba2c9
Add weapon vtable hook
FatherOfEgg Nov 18, 2025
4c4b796
Update how to get name and owner name when creating agent
FatherOfEgg Nov 25, 2025
52a9705
Use const instead
FatherOfEgg Nov 26, 2025
071fa6b
Renamed weapon related vars
FatherOfEgg Nov 26, 2025
2447b52
Mimic echo fighter weapons
FatherOfEgg Nov 26, 2025
e3a0a7b
Removed ffi fields from NewAgent
FatherOfEgg Nov 28, 2025
0fba5a4
Changed field names from id to kind
FatherOfEgg Nov 28, 2025
71d605c
Some refactoring and updated API
FatherOfEgg Dec 25, 2025
fabae37
Added a macro for mimicking echo weapons
FatherOfEgg Dec 25, 2025
a4382cb
Weapon kind hash hooks and whatnot
FatherOfEgg Dec 25, 2025
9a9db66
Forgot to nop something for get_file_weapon_name
FatherOfEgg Dec 25, 2025
4ed5bab
Update file category hook
FatherOfEgg Dec 25, 2025
5bc0ebc
Renamed hook
FatherOfEgg Dec 25, 2025
0740e53
Added another mimic echo weapon hook
FatherOfEgg Dec 25, 2025
ba201f7
Oopsie, used the wrong var
FatherOfEgg Dec 26, 2025
0268c14
Forgot to update the weapon kind
FatherOfEgg Dec 26, 2025
90f683d
Update file category hook thingy
FatherOfEgg Dec 26, 2025
cbb9212
Make sure to properly update weapon count
FatherOfEgg Dec 26, 2025
e1aeff8
Cloned weapons should now be able to use original code
FatherOfEgg Dec 26, 2025
8278542
If it exists, return the appropriate CloneWeaponInfo
FatherOfEgg Dec 26, 2025
3b7d459
Removed unused stuff
FatherOfEgg Dec 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions crates/smashline/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ impl Costume {
}
}

#[repr(C)]
pub struct CloneWeaponInfo {
pub kind: i32,
pub table_id: i32,
}

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub enum Acmd {
Expand Down Expand Up @@ -415,11 +421,11 @@ decl_imports! {

fn smashline_clone_weapon(
original_owner: StringFFI,
original_article_id: i32,
original_weapon_kind: i32,
new_owner: StringFFI,
new_name: StringFFI,
use_original_code: bool
) -> i32;
) -> CloneWeaponInfo;

fn smashline_update_weapon_count(
article_id: i32,
Expand Down Expand Up @@ -462,7 +468,7 @@ pub fn clone_weapon(
new_owner: impl Into<String>,
new_name: impl Into<String>,
use_original_code: bool,
) -> i32 {
) -> CloneWeaponInfo {
smashline_clone_weapon(
StringFFI::from_str(original_owner),
original_article_id,
Expand Down
96 changes: 50 additions & 46 deletions src/api.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
use std::{
ffi::CString,
num::{NonZeroU64, NonZeroUsize},
ptr::NonNull,
sync::atomic::Ordering,
};

use acmd_engine::action::ActionRegistry;
use rtld::Section;
use smashline::{
Acmd, AcmdFunction, AgentEntry, Costume, Hash40, L2CAgentBase, ObjectEvent, Priority, StatusLine, StringFFI,
Acmd, AcmdFunction, AgentEntry, CloneWeaponInfo, Costume, Hash40, L2CAgentBase, ObjectEvent, Priority, StatusLine, StringFFI,
};

use crate::{
callbacks::{StatusCallback, StatusCallbackFunction},
cloning::weapons::{NewAgent, NewArticle},
cloning::weapons::{NewWeapon, BASE_WEAPON_KIND, WEAPON_COUNT, WEAPON_KIND_HASHES, WEAPON_NAMES, WEAPON_OWNER_KINDS, WEAPON_OWNER_NAMES},
create_agent::{
AcmdScript, StatusScript, StatusScriptFunction, LOWERCASE_FIGHTER_NAMES,
LOWERCASE_WEAPON_NAMES
Expand Down Expand Up @@ -303,16 +305,16 @@ pub extern "C" fn smashline_reload_script(
#[no_mangle]
pub extern "C" fn smashline_clone_weapon(
original_owner: StringFFI,
original_article_id: i32,
original_weapon_kind: i32,
new_owner: StringFFI,
new_name: StringFFI,
use_original_code: bool,
) -> i32 {
) -> CloneWeaponInfo {
let original_owner = original_owner.as_str().unwrap().to_string();
let new_owner = new_owner.as_str().unwrap().to_string();
let new_name = new_name.as_str().unwrap().to_string();

let original_owner_id = LOWERCASE_FIGHTER_NAMES
let original_owner_kind = LOWERCASE_FIGHTER_NAMES
.iter()
.position(|name| name == original_owner)
.unwrap();
Expand All @@ -322,60 +324,62 @@ pub extern "C" fn smashline_clone_weapon(
// .position(|name| name == original_name)
// .unwrap();

let original_name = LOWERCASE_WEAPON_NAMES.get(original_article_id as usize).unwrap();
let original_name = LOWERCASE_WEAPON_NAMES.get(original_weapon_kind as usize).unwrap();

let new_owner_id = LOWERCASE_FIGHTER_NAMES
let new_owner_kind = LOWERCASE_FIGHTER_NAMES
.iter()
.position(|name| name == new_owner)
.unwrap();

let mut new_agents = crate::cloning::weapons::NEW_AGENTS.write();
let mut new_weapons = crate::cloning::weapons::NEW_WEAPONS.write();

let mut new_articles = crate::cloning::weapons::NEW_ARTICLES.write();
let articles = new_articles
.entry(new_owner_id as i32)
let weapons = new_weapons
.entry(new_owner_kind as i32)
.or_default();

if let Some(id) = articles.iter().position(|article|
article.original_owner == original_owner_id as i32 &&
article.weapon_id == original_article_id
) {
return id as i32;
}

for agents in new_agents.values() {
if let Some(agent) = agents.iter().find(|agent|
agent.owner_name == new_owner && agent.new_name == new_name
) {
let owner = LOWERCASE_FIGHTER_NAMES.get(agent.old_owner_id as usize).unwrap();
panic!(
"Weapon with the name '{}_{}' has already been cloned, but using '{}_{}' instead of '{}_{}'",
new_owner, new_name, owner, agent.old_name, original_owner, original_name
);
for (i, weapon) in weapons.iter().enumerate() {
if weapon.old_owner_kind == original_owner_kind as i32
&& weapon.owner_name == new_owner
&& weapon.new_name == new_name
&& weapon.old_name == original_name
&& weapon.old_kind == original_weapon_kind {
// TODO: Properly handle a situation where we're
// cloning a weapon, even though it already exists.
// Maybe only consider if new_name is the same?

return CloneWeaponInfo {
kind: weapon.kind,
table_id: i as i32,
};
}
}

new_agents
.entry(original_article_id as i32)
.or_default()
.push(NewAgent {
old_owner_id: original_owner_id as i32,
owner_id: new_owner_id as i32,
owner_name_ffi: format!("{new_owner}\0"),
new_name_ffi: format!("{new_name}\0"),
owner_name: new_owner,
new_name,
old_name: original_name.to_string(),
use_original_code,
});

let id = articles.len();
articles.push(NewArticle {
original_owner: original_owner_id as i32,
weapon_id: original_article_id,
let kind = WEAPON_COUNT.fetch_add(1, Ordering::Relaxed) as i32;
let table_id = weapons.len();

weapons.push(NewWeapon {
old_owner_kind: original_owner_kind as i32,
owner_kind: new_owner_kind as i32,
owner_name: new_owner.clone(),
new_name: new_name.clone(),
old_name: original_name.to_string(),
kind,
old_kind: original_weapon_kind as i32,
use_original_code,
});

id as i32
WEAPON_NAMES.write().push(CString::new(new_name.clone()).unwrap().into_raw());
WEAPON_OWNER_NAMES.write().push(CString::new(new_owner.clone()).unwrap().into_raw());
WEAPON_OWNER_KINDS.write().push(new_owner_kind as i32);
WEAPON_KIND_HASHES.write().push(Hash40::new(
&format!("weapon_kind_{}_{}", new_owner, new_name)
).0);
BASE_WEAPON_KIND.write().push(original_weapon_kind as i32);

CloneWeaponInfo {
kind,
table_id: table_id as i32,
}
}

#[no_mangle]
Expand Down
Loading