Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/seven-mile/scripthookwar3
Another ASI Plugin for WC3, to execute jass written in C++ at runtime!
https://github.com/seven-mile/scripthookwar3
jass reverse-engineering warcraft3
Last synced: 2 months ago
JSON representation
Another ASI Plugin for WC3, to execute jass written in C++ at runtime!
- Host: GitHub
- URL: https://github.com/seven-mile/scripthookwar3
- Owner: seven-mile
- Created: 2022-01-27T06:33:25.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2022-03-21T06:02:11.000Z (almost 3 years ago)
- Last Synced: 2024-11-01T12:42:10.111Z (3 months ago)
- Topics: jass, reverse-engineering, warcraft3
- Language: C++
- Homepage:
- Size: 122 KB
- Stars: 13
- Watchers: 2
- Forks: 6
- Open Issues: 0
-
Metadata Files:
- Readme: readme.md
Awesome Lists containing this project
README
# ScriptHookWar3
### Install
This is an **ASI Plugin**! You need to install an ASI Loader first, and put the output `ScriptHookWar3.asi` in a proper directory to load it.
### Usage
#### Use NativeTrainer Directly
I've implemented a NativeTrainer, which is similar to HKE script.
To open trainer main menu, just press F5. And you can easily understand how to enable features in it.
To make a building that you are constructing complete right now, press arrow left key (<-).
That's all, enjoy!
#### Calling Jass Native Functions
With the C++ template, ScriptHookWar3 provides a graceful way to call native jass functions:
```cpp
const int PLAYERID_LOCAL = 0;
auto ply = CallFn("Player", PLAYERID_LOCAL);
auto grp = CallFn("CreateGroup");
CallFn("GroupEnumUnitsSelected", grp, ply, false);
auto unit = CallFn("FirstOfGroup", grp);
const int UNIT_TYPE_HERO = 0;
if (CallFn("IsUnitType", unit, UNIT_TYPE_HERO)) {
CallFn("AddHeroXP", unit, 1000, true);CallFn(
"DisplayTimedTextToPlayer",
CallFn("Player", 0),
0.0f,
0.0f,
10.0f,
"ScriptHookWar3: Added!"
);
} else {
CallFn(
"DisplayTimedTextToPlayer",
CallFn("Player", 0),
0.0f,
0.0f,
10.0f,
"ScriptHookWar3: The selected unit is not hero."
);
}```
#### Function Callback
1.28 update: **C++ Callback is supported!**
```cpp
auto trg = CallFn("CreateTrigger");
auto act = CallFn("TriggerAddAction", trg, []() {
DebugOutput("ScriptHookWar3: Action triggered!");
});
CallFn("TriggerRegisterPlayerChatEvent", trg, ply, "war", true);
```Yes, just pass lambda and it will work!
Oh, you don't need callback arguments, since you already have lambda capturing.
#### C++ OOP Wrapper
I wrote some class wrapper for Jass objects, so that you can use
```cpp
auto ply = JassPlayer::LocalPlayer();
if (JassHero hero = ply.GetSelectedUnits().FirstUnit()) {
hero.SetMoveSpeed(2 * hero.GetMoveSpeed());
} else {
DebugOutput("oops, it is NOT a HERO.");
}
```#### Menu Creator API
It's an extremely powerful shortcut for game menu creation.
The so-called menu is based on game-native dialog and supports ordinary action buttons, switch buttons and navigation between menus.
For example, to create a menu structure like:
```
Resource
-- Add Money
-- Add LumberSelected Unit
-- Scale up / Scale down (change its text and behavior after clicked)
```We can simply write
```cpp
// define your menus
static ScriptMenu mainMenu, resMenu, unitMenu;// define main menu layout, there're two submenus
mainMenu.AddSubMenuButton("Resource", resMenu);
mainMenu.AddSubMenuButton("Selected Unit", unitMenu);
// this button exit the menu
mainMenu.AddActionButton("Exit Menu", [](){});// define two action buttons
resMenu.AddActionButton("Add Money", []() {
// It's simple, right? I love it.
auto ply = JassPlayer::LocalPlayer();
ply.SetState(PLAYER_STATE::RESOURCE_GOLD,
ply.GetState(PLAYER_STATE::RESOURCE_GOLD) + 9999);
});
resMenu.AddActionButton("Add Lumber", []() {
auto ply = JassPlayer::LocalPlayer();
ply.SetState(PLAYER_STATE::RESOURCE_LUMBER,
ply.GetState(PLAYER_STATE::RESOURCE_LUMBER) + 9999);
});
// this button return to the previous level
resMenu.AddSubMenuButton("Return", mainMenu);
resMenu.AddActionButton("Exit Menu", [](){});unitMenu.AddSwitchButton("Scale Down", "Scale Up",
[]() {
auto unit = JassPlayer::LocalPlayer().GetSelectedUnits().FirstUnit();
unit.SetScale(1.0);
},
[]() {
auto unit = JassPlayer::LocalPlayer().GetSelectedUnits().FirstUnit();
unit.SetScale(2.0);
});
unitMenu.AddSubMenuButton("Return", mainMenu);
unitMenu.AddActionButton("Exit Menu", []() {});
```### Game Version
We only support 1.20e by now. But it's easy to adapt other versions if you just need `CallFn`(2 offsets to find: the timer code and the native function pool). The native function pool structure turns into a BST for 1.3+, which needs some extra efforts.
Anyway, I'm focusing on exploring more features rather than support more versions stably. Higher versions will come, but not now I think.
### Coming Refactor
I will refactor the code recently. The structure is kind of confusing, and performance optimization is also needed.
2.7 update: I will probably update this project to C++ 20 Module architecture ;)
### Todo
Now I'm working on providing **C++ function callback binding**. Then you can pass C++ function pointer to a function taking `code`-typed arguments, like `TriggerAddAction`, which provides important event system!
After that, I'm considering write a wrapper for `Dialog`. And maybe OOP wrapper for more jass types, if I'd love to.
1.28 update: They are close to a finish. Now I will try to build a NativeTrainer, which providing similar interface to HKE script inject. But this time the injection happens at runtime and we don't need to modify the map.