Skip to content

Another ASI Plugin for WC3, to execute jass written in C++ at runtime!

Notifications You must be signed in to change notification settings

seven-mile/ScriptHookWar3

Repository files navigation

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:

const int PLAYERID_LOCAL = 0;
auto ply = CallFn<JassPlayer>("Player", PLAYERID_LOCAL);
auto grp = CallFn<JassGroup>("CreateGroup");
CallFn<void>("GroupEnumUnitsSelected", grp, ply, false);
auto unit = CallFn<JassUnit>("FirstOfGroup", grp);
const int UNIT_TYPE_HERO = 0;
if (CallFn<bool>("IsUnitType", unit, UNIT_TYPE_HERO)) {
  CallFn<void>("AddHeroXP", unit, 1000, true);

  CallFn<void>(
    "DisplayTimedTextToPlayer",
    CallFn<JassPlayer>("Player", 0),
    0.0f,
    0.0f,
    10.0f,
    "ScriptHookWar3: Added!"
  );
} else {
  CallFn<void>(
    "DisplayTimedTextToPlayer",
    CallFn<JassPlayer>("Player", 0),
    0.0f,
    0.0f,
    10.0f,
    "ScriptHookWar3: The selected unit is not hero."
  );
}

Function Callback

1.28 update: C++ Callback is supported!

auto trg = CallFn<JassTrigger>("CreateTrigger");
auto act = CallFn<JassTriggerAction>("TriggerAddAction", trg, []() {
  DebugOutput("ScriptHookWar3: Action triggered!");
});
CallFn<JassEvent>("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

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 Lumber

Selected Unit
-- Scale up / Scale down (change its text and behavior after clicked)

We can simply write

// 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<RetTy>(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.

About

Another ASI Plugin for WC3, to execute jass written in C++ at runtime!

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published