PDA

View Full Version : What have you been up to?



guiismiti
20th March 2017, 14:23
Anybody still modding for CoD2?

voron00
20th March 2017, 15:46
Yes. 0123456789

Ni3ls
20th March 2017, 18:24
+1 987654321

guiismiti
20th March 2017, 18:37
Zombies? Jumping?

voron00
20th March 2017, 22:13
DeathRun...

IzNoGoD
20th March 2017, 22:54
codjumper modding.

Lonsofore
21st March 2017, 01:39
tdm, dm, ctf, hq, htf on the one server

kung foo man
22nd March 2017, 17:24
In the last days I've reimplemented the CoDScript style "threads" (coroutines) inside JavaScript/Duktape. As test engine I use ET:Legacy, because that's like CoD 0.5, lol.

In the grand scheme, I wanna reimplement CoDScript as a whole and add JavaScript even on the client side, so it's possible to script the clients as server admin at runtime. And since ET has Quake3 heritage, the Quake Virtual Machine is available aswell... endless possibilities, I feel like in the beginning days of CoD2 scripting.

All the JavaScript code I've put together in last days, it's the basemod "algorithm" to move brushes:



// 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.getForward = function() { return entity_get_forward (this.id); }
this.getClassname = function() { return entity_get_classname (this.id); }
}

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 {
wait(0.10);
printf("Second print, id=%\n", this.id);
printf("THIS THIS this is %\n", this.id)
wait(0.15);


var nadeid = spawngrenade();
var nade = new Entity(nadeid);

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);


brush_moving.setOrigin(finalpos);
if (1) {
//moveto(brush_moving, finalpos, 150);
}

} else if (this.attackButtonPressed()) {

var pos = this.getEye();
var forward = this.getForward();

var newpos = vec3_new();



vec3_copy(pos, newpos);
vec3_scale(forward, 1024, forward); // scale forward by 1024
vec3_add(newpos, forward, newpos);


var tmp = bullettrace(pos, newpos, "useless", nade);


if (tmp["fraction"] != 0) {


//var_dump(pos);
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"];
}

//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;
}

//e1 = new Entity(1)
//e2 = new Entity(2)
//e3 = new Entity(3)
//entities = [e1, e2, e3]
//
//e1.thread(doshit)
//e2.thread(doshit)
////Duktape.info(e1.threads[1])
////Duktape.Thread.current()
//runframe()
//runframe()
//runframe()
//runframe()
//runframe()
//runframe()
//runframe()
//runframe()
//runframe()
//runframe()



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);

printf("Client connected: %\n", clientNum);
}



print("lib.js loaded\n");


Pretty awesome how powerful Duktape/JavaScript is. Comparing this JavaScript Entity class to CoDScript:



ent.thread(doshit)(1,22,333); // js
ent thread doshit (1,22,333); // codscript


And best of all, it's all open source and highly extendable/hackable.