So a big reason why I'm rewriting the engine from scratch is to get a much more robust system for modding. The plan is for pretty much anything game-specific to be done in scripts, and all those scripts should be possible to modify. We don't yet have the script system in the editor that we had in Hammerwatch, but when we do I plan to implement all the script nodes as modifiable code.
Since I've mostly worked on the engine I don't have a lot of scripts to show, but as an example here is a hit-scan skill used both by player weapons and by some of our enemies:
class Hitscan : IAction
{
array<IEffect@>@ m_effects;
int m_rays;
int m_rangeMin;
int m_rangeMax;
float m_spread;
float m_spreadMin;
float m_spreadMax;
int m_spreadTime;
int m_spreadTimeC;
int m_spreadCooldown;
string m_shootFx;
string m_hitFx;
string m_missFx;
Hitscan(SValue& params)
{
@m_effects = LoadEffects(this, params);
m_rays = GetParami(this, params, "rays", false, 1);
SValue@ spread = GetParamd(this, params, "spread", false);
if (spread !is null)
{
m_spreadMin = GetParami(this, spread, "min") * PI / 180.0;
m_spreadMax = GetParami(this, spread, "max") * PI / 180.0;
m_spreadTime = GetParami(this, spread, "time");
m_spreadCooldown = GetParami(this, params, "cooldown", false, 100);
}
else
m_spread = GetParami(this, params, "spread", false) * PI / 180.0;
SValue@ range = GetParamd(this, params, "range", false);
if (range !is null)
{
m_rangeMin = GetParami(this, range, "min");
m_rangeMax = GetParami(this, range, "max");
}
else
{
m_rangeMin = GetParami(this, params, "range");
m_rangeMax = -1;
}
m_shootFx = GetParams(this, params, "shoot-fx", false);
m_hitFx = GetParams(this, params, "hit-fx", false);
m_missFx = GetParams(this, params, "miss-fx", false);
}
bool DoAction(Actor@ owner, vec2 pos, vec2 dir)
{
if (m_spreadTime > 0)
{
m_spread = lerp(m_spreadMin, m_spreadMax, min(1.0, m_spreadTimeC / float(m_spreadTime)));
m_spreadTimeC = min(m_spreadTime, m_spreadTimeC + m_spreadCooldown);
}
if (m_shootFx != "")
PlayEffect(m_shootFx, pos);
dir = normalize(dir);
for (int i = 0; i < m_rays; i++)
{
vec2 shootPos = dir;
if (m_spread > 0)
{
float ang = atan(shootPos.y, shootPos.x) + (randf() - 0.5) * m_spread;
shootPos = vec2(cos(ang), sin(ang));
}
if (m_rangeMin < m_rangeMax)
shootPos *= m_rangeMin + randi(m_rangeMax - m_rangeMin);
else
{
shootPos *= m_rangeMin;
}
shootPos += pos;
RaycastResult res = g_scene.RaycastClosest(pos, shootPos, ~0);
if (res.unit !is null)
{
Actor@ a = cast<Actor>(res.unit.GetScriptBehavior());
if (a !is null && a.Team != owner.Team)
ApplyEffects(m_effects, owner, a, xy(a.m_unit.GetPosition()), dir, 1.0);
if (m_hitFx != "")
PlayEffect(m_hitFx, res.point);
}
else if (m_missFx != "")
PlayEffect(m_missFx, shootPos);
}
return true;
}
void Update(int dt, int cooldown)
{
if (cooldown <= 0)
m_spreadTimeC = 0;
}
}
And here is how we use it in our enemy unit file xmls:
<array name="actions">
<dict>
<string name="class">Hitscan</string>
<int name="range">175</int>
<int name="rays">10</int>
<dict name="effect">
<string name="class">Damage</string>
<int name="dmg">8</int>
</dict>
<dict name="spread">
<int name="min">25</int>
<int name="max">50</int>
<int name="time">3000</int>
</dict>
<string name="hit-fx">units/hit_smoke.unit</string>
<string name="miss-fx">units/miss_smoke.unit</string>
</dict>
</array>
It's still early in the development, so this will of course change, but that's what we have right now.
I'm stuck in the menu, the music plays full speed but the graphic output is lagging and has a terrible frame-rate (probably 1 frame per 20 seconds.) Any suggestions? It ran fine when I first got it, and I already re-installed it to see if that would fix any problems. Unfortunately, it did not.
Have you tried turning off the steam overlay in Hammerwatch? It has caused problems for some people on Mac. And have you updated your graphics drivers?