/////////////////////////////////////////////////////////////////////////// // Copyright (C) Wizardry and Steamworks 2013 - License: GNU GPLv3 // // Please see: http://www.gnu.org/licenses/gpl.html for legal details, // // rights of fair usage, the disclaimer and warranty conditions. // /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// // CONFIGURATION // /////////////////////////////////////////////////////////////////////////// key CONTROLLING_AVATAR = "a5eff01c-442f-11e3-aa1f-8fe2e364ba2a"; /////////////////////////////////////////////////////////////////////////// // INTERNALS // /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// vector wasStringToVector(string in) { list v = llParseString2List(in, ["<", ",", ">"], []); return <llList2Float(v, 0), llList2Float(v, 1), llList2Float(v, 2)>; } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2011 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// moveTo(vector position) { llTargetRemove(_gia); _gia = llTarget(position, 1); vector pointTo = position - llGetPos(); llOwnerSay("@setrot:" + (string)llAtan2(pointTo.x, pointTo.y) + "=force"); llMoveToTarget(position, 3); } integer _gia = 0; list _gla = []; integer lines = 0; vector next = ZERO_VECTOR; default { state_entry() { llListen(1, "", CONTROLLING_AVATAR, "pathon"); } listen(integer channel, string name, key id, string message) { if(message != "pathon") return; state closest; } } state setup { state_entry() { llInstantMessage(CONTROLLING_AVATAR, "Reading path, please wait..."); llListen(1, "", CONTROLLING_AVATAR, "pathoff"); if(llGetInventoryType("[WaS-K]:Avatar Puppeteer:Data") == INVENTORY_NOTECARD) jump schedule; llSay(DEBUG_CHANNEL, "Puppet notecard not found."); return; @schedule; llGetNumberOfNotecardLines("[WaS-K]:Avatar Puppeteer:Data"); } listen(integer channel, string name, key id, string message) { if(message != "pathoff") return; state stop; } dataserver(key id, string data) { lines = (integer)data; state read; } } state read { state_entry() { llListen(1, "", CONTROLLING_AVATAR, "pathoff"); llGetNotecardLine("[WaS-K]:Avatar Puppeteer:Data", lines--); } listen(integer channel, string name, key id, string message) { if(message != "pathoff") return; state stop; } dataserver(key id, string data) { list i = llParseString2List(data, ["#"], []); next = wasStringToVector(llList2String(i, 0)); if(lines == 0) state setup; if(next == ZERO_VECTOR) { llGetNotecardLine("[WaS-K]:Avatar Puppeteer:Data", lines--); return; } float wait = llList2Float(i, 1); if(wait == 0) state walk; llSetTimerEvent(wait); } timer() { state walk; } } state walk { state_entry() { llListen(1, "", CONTROLLING_AVATAR, "pathoff"); moveTo(next); } listen(integer channel, string name, key id, string message) { if(message != "pathoff") return; state stop; } at_target(integer tnum, vector targetpos, vector ourpos) { if(tnum != _gia) return; state read; } } state stop { state_entry() { llInstantMessage(CONTROLLING_AVATAR, "Pathfinding stopped..."); llStopMoveToTarget(); llTargetRemove(_gia); llListen(1, "", CONTROLLING_AVATAR, "pathon"); } listen(integer channel, string name, key id, string message) { if(message != "pathon") return; _gia = 1; state closest; } } //ok, so this could be done by reading all the points and just going through //all of them just once, instead of using the dataserver and looping over it //on the other hand, using a list will increase memory consumption and given //that most simulators are already eaten up and scripts race each other for //memory, let's just go for an average O(n^{notecard length)}) algorithm. //this should also allow longer notecards and thus longer paths which would //not be possible by loading all the coordinates in lists. //exit to read state closest { state_entry() { llListen(1, "", CONTROLLING_AVATAR, "pathoff"); llInstantMessage(CONTROLLING_AVATAR, "Finding closest point, please wait..."); lines = 0; if(llGetInventoryType("[WaS-K]:Avatar Puppeteer:Data") == INVENTORY_NOTECARD) jump schedule; llSay(DEBUG_CHANNEL, "Puppet notecard not found."); return; @schedule; llGetNotecardLine("[WaS-K]:Avatar Puppeteer:Data", ++lines); } listen(integer channel, string name, key id, string message) { if(message != "pathoff") return; state stop; } dataserver(key id, string data) { if(data == EOF) { // point not found ++_gia; state loop_closest; return; } if(data == "") jump continue; vector n = wasStringToVector(llList2String(llParseString2List(data, ["#"], []), 0)); if(n == ZERO_VECTOR) jump continue; if(llVecDist(n, llGetPos()) > _gia) jump continue; // point found in vicinity - switch to read. llInstantMessage(CONTROLLING_AVATAR, "Pathfinding started..."); state read; @continue; llGetNotecardLine("[WaS-K]:Avatar Puppeteer:Data", ++lines); } } state loop_closest { state_entry() { state closest; } }