Created
March 23, 2017 18:10
-
-
Save kungfooman/ba75d5bac0261f6ba78e468df40e1650 to your computer and use it in GitHub Desktop.
ET JavaScript Dynamic Brushes and Safe/Load position mod
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// MIT License, have fun | |
function sprintf() { | |
var ret = ""; | |
var param = 1; // maps to first % | |
var msg = arguments[0]; | |
for (var i=0; i<msg.length; i++) { | |
if (msg[i] == "%") { | |
// %% will be printed as normal % | |
if (msg[i+1] == "%") { | |
ret += "%"; | |
i++; | |
} else | |
ret += arguments[param++]; | |
} else { | |
ret += msg[i]; | |
} | |
} | |
return ret; | |
} | |
function printf() { | |
var ret = ""; | |
var param = 1; // maps to first % | |
var msg = arguments[0]; | |
for (var i=0; i<msg.length; i++) { | |
if (msg[i] == "%") { | |
// %% will be printed as normal % | |
if (msg[i+1] == "%") { | |
ret += "%"; | |
i++; | |
} else | |
ret += arguments[param++]; | |
} else { | |
ret += msg[i]; | |
} | |
} | |
log(ret); | |
return ret.length; | |
} | |
function require(filename) { | |
var content = file_get_contents( filename ); | |
try { | |
eval.bind( get_global() )(content); | |
} catch (e) { | |
printf("require(%): error %\n", filename, e.stack); | |
} | |
} | |
if (typeof date_start == "undefined") | |
date_start = Date.now(); | |
// time since loading this file for first time | |
function now() { | |
return Date.now() - date_start; | |
} | |
print = function() { | |
for (var i=0; i<arguments.length; i++) { | |
log(arguments[i]); | |
} | |
} | |
function var_dump(ret) { | |
switch (typeof ret) { | |
case "number": { | |
print("ret = ", ret, ";"); | |
break; | |
} | |
case "string": { | |
print("ret = \"", ret, "\";"); | |
break; | |
} | |
case "function": { | |
// print infos like byte codes or length of byte codes | |
print("Function: ", ret); | |
break; | |
} | |
case "boolean": { | |
print("ret = ", ret, ";"); | |
break; | |
} | |
case "object": { | |
if (ret.constructor.name == "Array") { | |
print("ret = [\n"); | |
for (var i=0; i<ret.length; i++) { | |
if (typeof ret[i] == "object") | |
printf("\t%: % {...},\n", i, ret[i].constructor.name); | |
else | |
printf("\t%: %,\n", i, ret[i]); | |
} | |
print("];\n"); | |
} | |
// An array still can have properties, so print them aswell: | |
{ | |
printf("% {\n", ret.constructor.name); | |
for (var i in ret) { | |
if (typeof ret[i] == "object") | |
printf("\t%: % {...},\n", i, ret[i].constructor.name); | |
else | |
printf("\t%: %,\n", i, ret[i]); | |
} | |
print("};\n"); | |
} | |
break; | |
} | |
case "undefined": { | |
// print infos like byte codes or length of byte codes | |
print("undefined;"); | |
break; | |
} | |
default: | |
print("Unhandled type: ", typeof ret); | |
} | |
} | |
handle_input = function(code, global) { | |
try { | |
var ret = eval.bind(global)(code); | |
log("> "); | |
var_dump(ret); | |
log("\n"); | |
} catch (e) { | |
print("handle_input> error: ", e.stack, "\n"); | |
} | |
//repl_settext("asdddd"); | |
} | |
//global = get_global(); | |
//printf("Global: %", global); | |
//var_dump(global); | |
consolecommand = function() { | |
var args = getargs(); | |
var cmdline = ""; | |
for (var i=1; i<args.length; i++) | |
cmdline += args[i] + " "; | |
//printf("cmdline: %\n", cmdline); | |
handle_input(cmdline, get_global()); | |
} | |
//function ThreadState() | |
function wait(time) { Duktape.Thread.yield( ["wait", time * 1000] ); } | |
function waittillframeend() { Duktape.Thread.yield( ["waittillframeend" ] ); } | |
function waittill(what) { Duktape.Thread.yield( ["waittill", what ] ); } | |
if (typeof level == "undefined") { | |
level = {}; | |
level.time = 0; | |
} | |
function Entity(id) { | |
this.id = id; | |
this.threads = []; | |
this.thread = function(func) { | |
var self = this; | |
return function() { | |
var t = new Duktape.Thread(function(args) { | |
func.bind(self)(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]); | |
//func.apply(self, arguments) // waiting for: https://github.com/svaarala/duktape/issues/1420 | |
}); | |
t.nextrun = level.time; | |
t.parameters = arguments; | |
self.threads.push(t) | |
} | |
} | |
this.runframe = function() { | |
// iterate backwards over it, so we can delete finished threads instantly via ID | |
for (var i=this.threads.length-1; i>=0; i--) { | |
var thread = this.threads[i]; | |
var state = Duktape.info(thread); | |
//printf("entid=% threadid=% state=%,%\n", this.id, i, state[0], state[1]); | |
if (thread.nextrun > level.time) { | |
//printf("entid=% threadid=%> No run yet: nextrun in %\n", this.id, i, thread.nextrun - level.time) | |
continue; | |
} | |
try { | |
var whatnow = Duktape.Thread.resume(thread, thread.parameters); | |
var state = Duktape.info(thread); | |
//printf("AFTER RESUME: entid=% threadid=% state=%,%\n", this.id, i, state[0], state[1]); | |
switch (whatnow[0]) { | |
case "wait": thread.nextrun += whatnow[1]; break; | |
} | |
//printf("whatnow: %\n", whatnow); | |
} catch (e) { | |
this.threads.splice(i, 1); // delete thread from array | |
//printf("Entity::runframe> Finished Thread id=% entityid=% level.time=%\n", i, this.id, level.time); | |
} | |
} | |
} | |
this.useButtonPressed = function() { return entity_usebuttonpressed (this.id); } | |
this.sprintButtonPressed = function() { return entity_sprintbuttonpressed(this.id); } | |
this.attackButtonPressed = function() { return entity_attackbuttonpressed(this.id); } | |
this.getEye = function() { return entity_get_eye (this.id); } | |
this.getOrigin = function() { return entity_get_origin (this.id); } | |
this.setOrigin = function(origin) { return entity_set_origin (this.id, origin[0], origin[1], origin[2]); } | |
this.getAngles = function() { return entity_get_angles (this.id); } | |
this.setAngles = function(angles) { return entity_set_angles (this.id, angles[0], angles[1], angles[2]); } | |
this.getForward = function() { return entity_get_forward (this.id); } | |
this.getClassname = function() { return entity_get_classname (this.id); } | |
this.moveTo = function(pos, durationSeconds) { return entity_moveto (this.id, pos[0], pos[1], pos[2], durationSeconds); } | |
this.solid = function() { return entity_solid (this.id); } | |
this.notSolid = function() { return entity_notsolid (this.id); } | |
this.printf = function() { | |
var msg = sprintf.apply(undefined, arguments); | |
sendservercommand(this.id, "print \"" + msg + "\""); | |
} | |
} | |
function vec3_new() { | |
return new Float32Array(3); | |
} | |
function vec3_scale(vec, scalar, output) { | |
output[0] = vec[0] * scalar; | |
output[1] = vec[1] * scalar; | |
output[2] = vec[2] * scalar; | |
} | |
function vec3_copy(from_, to) { | |
to[0] = from_[0]; | |
to[1] = from_[1]; | |
to[2] = from_[2]; | |
} | |
function vec3_add(a, b, c) { | |
c[0] = a[0] + b[0]; | |
c[1] = a[1] + b[1]; | |
c[2] = a[2] + b[2]; | |
} | |
function vec3_sub(a, b, ret) { | |
ret[0] = a[0] - b[0]; | |
ret[1] = a[1] - b[1]; | |
ret[2] = a[2] - b[2]; | |
} | |
function vec3_length(a) { | |
return Math.sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]); | |
} | |
function vec3_distance(a, b) { | |
var delta = vec3_new(); | |
vec3_sub(b, a, delta); | |
return vec3_length(delta); | |
} | |
function bullettrace(from, to, hit_players, entity_to_ignore) { | |
var tmp = trace(from[0], from[1], from[2], to[0], to[1], to[2], entity_to_ignore.id); | |
return { | |
position: tmp.endpos, | |
fraction: tmp.fraction, | |
entity: new Entity(tmp.entityNum) | |
} | |
} | |
doshit = function(a, b, c) { | |
try { | |
var nadeid = spawngrenade(); | |
var nade = new Entity(nadeid); | |
nade.notSolid(); | |
var brush_distance = 1024; | |
var brush_selected = 0; | |
var grenade_oldpos = vec3_new(); | |
var brush_oldpos = vec3_new(); | |
var brush_moving = undefined; | |
while (1) { | |
//printf("this.id====%\n", this.id); | |
if ( ! this.attackButtonPressed()) { | |
brush_selected = 0; | |
} | |
if (brush_selected) { | |
var change = 15; | |
if (brush_distance > 150) change = 20; | |
if (brush_distance > 300) change = 40; | |
if (brush_distance > 600) change = 60; | |
if (this.sprintButtonPressed()) brush_distance += change; | |
if (this.useButtonPressed() ) brush_distance -= change; | |
var pos = this.getEye(); | |
var forward = this.getForward(); | |
var newnadepos = vec3_new(); | |
vec3_copy(pos, newnadepos); | |
vec3_scale(forward, brush_distance, forward); | |
vec3_add(newnadepos, forward, newnadepos); | |
nade.setOrigin(newnadepos); | |
var delta_grenade = vec3_new(); | |
// a - b = c | |
vec3_sub(newnadepos, grenade_oldpos, delta_grenade); | |
var finalpos = vec3_new(); | |
vec3_add(brush_oldpos, delta_grenade, finalpos); | |
if (1) { | |
brush_moving.moveTo(finalpos, 0.15); // 0.15 feels somewhat smooth, but 0.05 isn't too bad as well | |
} else { | |
brush_moving.setOrigin(finalpos); | |
} | |
} else if (this.attackButtonPressed()) { | |
var pos = this.getEye(); | |
var forward = this.getForward(); | |
var newpos = vec3_new(); | |
vec3_copy(pos, newpos); | |
vec3_scale(forward, 1024*10, forward); | |
vec3_add(newpos, forward, newpos); | |
var tmp = bullettrace(pos, newpos, "useless", nade); | |
if (tmp["fraction"] != 0) { | |
//printf("classname: %\n", tmp["entity"].getClassname()); | |
//nade.setOrigin(tmp["position"]); | |
if (tmp["entity"].getClassname() == "func_plat") { | |
brush_selected = 1; | |
brush_distance = vec3_distance(pos, tmp["position"]); | |
vec3_copy(tmp["position"], grenade_oldpos); | |
vec3_copy(tmp["entity"].getOrigin(), brush_oldpos); | |
brush_moving = tmp["entity"]; | |
this.printf("Selected Brush ID: %\n", brush_moving.id); | |
} | |
//printf("asd: % asd[0]=%\n", asd, asd[0]); | |
} | |
} | |
wait(0.05); | |
} | |
} catch (e) { | |
printf("Error: % %\n", e, e.stack); | |
} | |
} | |
function callback_runframe(levelTime) { | |
runframe(); | |
} | |
function runframe() { | |
for (var i=0; i</*entities.length*/1024; i++) { | |
if (entities[i] != undefined) | |
entities[i].runframe() | |
} | |
level.time += 50; | |
} | |
lastpos = undefined; | |
lastangles = undefined; | |
thread_loadpos = function() { | |
var lastpress = 0; | |
while (1) { | |
while ( ! this.useButtonPressed()) { wait(0.05); } | |
while ( this.useButtonPressed()) { wait(0.05); } | |
var time = level.time - lastpress; | |
if (time <= 400) | |
{ | |
if (typeof lastpos != "undefined") { | |
this.setOrigin(lastpos); | |
this.setAngles(lastangles); | |
} else { | |
this.printf("You have no last position saved"); | |
} | |
this.printf("thread_loadpos> Last press: %, save pos: %", time, lastpos); | |
} | |
lastpress = level.time; | |
wait(0.05); | |
} | |
} | |
thread_savepos = function() { | |
var lastpress = 0; | |
while (1) { | |
while ( ! this.sprintButtonPressed()) { wait(0.05); } | |
while ( this.sprintButtonPressed()) { wait(0.05); } | |
var time = level.time - lastpress; | |
if (time <= 400) | |
{ | |
lastpos = this.getOrigin(); | |
lastangles = this.getAngles(); | |
this.printf("thread_savepos> Last press: time=%", time); | |
} | |
lastpress = level.time; | |
wait(0.05); | |
} | |
} | |
if (typeof entities == "undefined") | |
entities = Array(1024); | |
function callback_clientconnected(clientNum) { | |
entities[clientNum] = new Entity(clientNum); | |
var ent = entities[clientNum]; | |
ent.thread(doshit)(1,22,333); | |
ent.thread(thread_loadpos)(); | |
ent.thread(thread_savepos)(); | |
//ent thread doshit (1,22,333); | |
printf("Client connected: %\n", clientNum); | |
} | |
print("lib.js loaded\n"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment