shark_artificial_intelligence.lslp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. /*
  2. * shark attack.lsl
  3. * Part of the Sloodle project (www.sloodle.org)
  4. *
  5. * Copyright (c) 2011-06 contributors (see below)
  6. * Released under the GNU GPL v3
  7. * -------------------------------------------
  8. *
  9. * This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation, either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. *
  22. * All scripts must maintain this copyrite information, including the contributer information listed
  23. *
  24. * DESCRIPTION
  25. * This script is the artificial intellegence for the sharks in the pool.
  26. *
  27. *
  28. * This script causes a shark to swim around
  29. *
  30. * Contributors:
  31. * Paul Preibisch
  32. * Edmund Edgar
  33. * screams sound file comes from http://www.freesound.org/people/thanvannispen/sounds/9431/ and is licensed under Creative Commons with Attribution:
  34. Than van Nispen tot Pannerden - Composer for (non-linear) Media
  35. */
  36. integer SLOODLE_CHANNEL_OBJECT_DIALOG = -3857343;//configuration channel
  37. integer SLOODLE_CHANNEL_ENEMY_ATTACK= -163928666;//Channel to communicate on when attack occurs by an enemy
  38. integer SLOODLE_CHANNEL_ENEMY_AIM = -163928665;//Channel to communicate on when enemy is aming at target, ie:delivering a laserbeam
  39. float POOL_WIDTH=6;
  40. float POOL_HEIGHT=6.525;
  41. vector PUSH_STRENGTH=<25,15,10>;
  42. // maximum swim distance for swimming up or down from last center
  43. float height = 1.0;
  44. // delay in seconds for next movement
  45. float delay = 3.0;
  46. // internal channel for communication
  47. integer CHANNEL = -87;
  48. integer MAX=30;
  49. // last center position
  50. vector center;
  51. integer target_id;
  52. list screams;
  53. integer BLOOD=-999922110;
  54. integer NOBLOOD=-999922111;
  55. integer counter =0;
  56. vector deathTarget;//the location of an avatar we want to attack
  57. key deathKey;//the key of the avatar we will attack
  58. integer attackTimes=0;
  59. integer screamCounter=0;
  60. vector rezzer_position_offset;
  61. rotation rezzer_rotation_offset;
  62. key rezzer_uuid=NULL_KEY;
  63. integer isconfigured;
  64. integer boundary_set;
  65. integer SLOODLE_CHANNEL_POOL_BOUNDARIES_QUERY= -163928000;//sharks whisper on this channel requesting the boundaries from the shark pool
  66. integer SLOODLE_CHANNEL_POOL_BOUNDARIES_RESPONSE= -163928001;//pool whispers on this channel telling sharks the boundaries from the shark pool
  67. integer RANDOM_POS_SENSOR_RATE=5;
  68. vector POOL_CENTER; //this is the location of the center of the pool and is determined by sensing an object called "Shark Pool"
  69. list BOUNDING_BOX_POOL;
  70. vector BOUNDING_BOX_MIN_CORNER;
  71. vector BOUNDING_BOX_MAX_CORNER;
  72. integer timeToMove=4;//this will get reset to a new value each time the shark moves, and will determined the next time that the shark shall move - so the shark doesnt move at predicatable intervals
  73. integer MAX_WAIT_TILL_MOVE_TIME=6;
  74. integer MIN_WAIT_TILL_MOVE_TIME=2;
  75. integer timeToMove_counter=0;
  76. integer SAFETY_EDGE=2; //an extra padding so sharks noses dont stick out of the side of the pool
  77. //sloodle_set_pos is an SL/OPENSIM friendly way of moving non-physical objects around
  78. sloodle_set_pos(vector targetposition){
  79. integer counter=0;
  80. while ((llVecDist(llGetPos(), targetposition) > 0.001)&&(counter<50)) {
  81. counter+=1;
  82. llSetPos(targetposition);
  83. }
  84. }
  85. debug (string message ){
  86. list params = llGetPrimitiveParams ([PRIM_MATERIAL ]);
  87. if (llList2Integer (params ,0)==PRIM_MATERIAL_FLESH){
  88. llOwnerSay(llGetScriptName ()+": " +message );
  89. }
  90. }
  91. //sloodle_handle_command, is what we use to interpret data that comes through linked messages from our sloodle_rezzer_objects script (who talks to the server)
  92. integer sloodle_handle_command(string str){
  93. list bits = llParseString2List(str,["|"],[]);
  94. integer numbits = llGetListLength(bits);
  95. string name;
  96. name = llList2String(bits,0);
  97. //set:position|<18.31369, 15.54828, 3.15605>|<0.00000, 0.00000, 0.25705, 0.96640>|0df19640-c2e9-43c1-4359-b805ef08dad0
  98. if (name == "set:position") {
  99. rezzer_position_offset = (vector)llList2String(bits,1);
  100. rezzer_rotation_offset = (rotation)llList2String(bits,2);
  101. rezzer_uuid = llList2Key(bits,3);
  102. }
  103. if (rezzer_uuid!=NULL_KEY) return TRUE; else return FALSE;
  104. }
  105. float randBetween(float min, float max){
  106. return llFrand(max - min) + min;
  107. }
  108. integer random_integer( integer min, integer max ){ return min + (integer)( llFrand ( max - min + 1 ) );}
  109. //blood causes the shark to rez a bullet, which has particle effects for blood
  110. blood(key av){
  111. llMessageLinked(LINK_SET, BLOOD, "", av);
  112. }
  113. noblood(){
  114. llMessageLinked(LINK_SET, NOBLOOD, "", NULL_KEY);
  115. }
  116. //getScreeam is used to play random sounds
  117. string getScream(){
  118. screams = ["SND_SCREAM1","SND_SCREAM2","SND_SCREAM3","SND_SCREAM4"];
  119. integer screamLen = llGetListLength(screams);
  120. screamCounter++;
  121. if (screamCounter>screamLen-1){
  122. screamCounter=0;
  123. }
  124. return llList2String(screams,screamCounter);
  125. }
  126. vector swim_in_boundary(vector dest, vector pos){
  127. if (dest.x > BOUNDING_BOX_MAX_CORNER.x-SAFETY_EDGE){
  128. dest.x=pos.x;
  129. }
  130. if (dest.x < BOUNDING_BOX_MIN_CORNER.x+SAFETY_EDGE){
  131. dest.x=pos.x;
  132. }
  133. if (dest.y > BOUNDING_BOX_MAX_CORNER.y-SAFETY_EDGE){
  134. dest.y=pos.y;
  135. }
  136. if (dest.y < BOUNDING_BOX_MIN_CORNER.y+SAFETY_EDGE){
  137. dest.y=pos.y;
  138. }
  139. if (dest.z > BOUNDING_BOX_MAX_CORNER.z-0.5){
  140. dest.z=pos.z;
  141. }
  142. if (dest.z < BOUNDING_BOX_MIN_CORNER.z+0.5){
  143. dest.z=pos.z;
  144. }
  145. return dest;
  146. }
  147. integer is_in_boundary(vector dest){
  148. integer inBoundary =TRUE;
  149. if (dest.x > BOUNDING_BOX_MAX_CORNER.x-SAFETY_EDGE){
  150. inBoundary = TRUE;
  151. }
  152. if (dest.x < BOUNDING_BOX_MIN_CORNER.x+SAFETY_EDGE){
  153. inBoundary = FALSE;
  154. }
  155. if (dest.y > BOUNDING_BOX_MAX_CORNER.y-SAFETY_EDGE){
  156. inBoundary = FALSE;
  157. }
  158. if (dest.y < BOUNDING_BOX_MIN_CORNER.y+SAFETY_EDGE){
  159. inBoundary = FALSE;
  160. }
  161. if (dest.z > BOUNDING_BOX_MAX_CORNER.z-0.5){
  162. inBoundary = FALSE;
  163. }
  164. if (dest.z < BOUNDING_BOX_MIN_CORNER.z+0.5){
  165. inBoundary = FALSE;
  166. }
  167. if (inBoundary){
  168. debug("avatar is in the boundary");
  169. }else{
  170. debug("avatar is NOT in the boundary");
  171. }
  172. return inBoundary;
  173. }
  174. default{
  175. state_entry()
  176. {
  177. llTriggerSound("SND_JAWS", 1);
  178. isconfigured=FALSE;
  179. noblood(); //turn off particle effects
  180. counter=0;
  181. }
  182. link_message(integer sender_num, integer num, string str, key id) {
  183. // Split the data up into lines
  184. list lines = llParseStringKeepNulls(str, ["\n"], []);
  185. integer numlines = llGetListLength(lines);
  186. if (num == SLOODLE_CHANNEL_OBJECT_DIALOG) {
  187. // Split the message into lines
  188. integer i = 0;
  189. for (i=0; i < numlines; i++) {
  190. isconfigured = sloodle_handle_command(llList2String(lines, i));
  191. if (isconfigured){
  192. state get_boundary;
  193. }
  194. }
  195. }
  196. }
  197. }
  198. state get_boundary{
  199. on_rez(integer start_param) {
  200. llResetScript();
  201. }
  202. state_entry() {
  203. //llSensorRepeat("Shark Pool", "",PASSIVE, 10, TWO_PI, 5);
  204. debug("in get_boundary");
  205. llSetTimerEvent(2);
  206. }
  207. timer() {
  208. debug("trying to find: Shark Pool");
  209. llSensor("Shark Pool", "", SCRIPTED, 10, TWO_PI);
  210. }
  211. sensor(integer num_detected) {
  212. debug("found pool!");
  213. POOL_CENTER = llDetectedPos(0);
  214. BOUNDING_BOX_POOL= llGetBoundingBox(llDetectedKey(0));
  215. vector pool_lower_corner = llList2Vector(BOUNDING_BOX_POOL,0);
  216. vector pool_upper_corner = llList2Vector(BOUNDING_BOX_POOL,1);
  217. BOUNDING_BOX_MIN_CORNER =POOL_CENTER+pool_lower_corner;
  218. BOUNDING_BOX_MAX_CORNER =POOL_CENTER+pool_upper_corner;
  219. POOL_WIDTH=pool_upper_corner.x+(-1*pool_lower_corner.x);
  220. POOL_HEIGHT=pool_upper_corner.z+(-1*pool_lower_corner.z);
  221. debug("found bounding box - height: "+(string)POOL_HEIGHT+" width: "+(string)POOL_WIDTH);
  222. state ready;
  223. }
  224. }
  225. state ready{
  226. on_rez(integer start_param) {
  227. llResetScript();
  228. }
  229. state_entry() {
  230. llListen(232323, "", "","");
  231. debug("in the ready state");
  232. llSetTimerEvent(1); //the timer event is set so that our shark moves around the pool every second
  233. noblood();//TURN off blood;
  234. deathKey=NULL_KEY;
  235. deathTarget = ZERO_VECTOR;
  236. llSetText("", <0,0,1>, 1);
  237. llSetBuoyancy(0.9);
  238. llSensorRepeat("", "", AGENT, POOL_WIDTH/2, PI,timeToMove); //start searching for victems to eat!
  239. }
  240. listen(integer channel, string name, key id, string message) {
  241. //if pool moves
  242. if (channel==232323){
  243. llSleep(3);
  244. state get_boundary;
  245. }
  246. }
  247. sensor(integer num_detected) {
  248. integer i;
  249. //we found a victem so look at them and attack
  250. for (i=0;i<num_detected;i++){
  251. vector victim_pos=llDetectedPos(i);
  252. if (is_in_boundary(victim_pos)==FALSE){
  253. return;
  254. }
  255. deathTarget = llDetectedPos(i);
  256. deathKey = llDetectedKey(i);
  257. vector pos = llGetPos();
  258. vector delta = pos - deathTarget;
  259. float angle = llAtan2(delta.y, delta.x) + PI / 2.0;
  260. rotation rot = llEuler2Rot(<0, 0, angle>);
  261. llRotLookAt(rot, 1.0, 1.0);
  262. llMessageLinked(LINK_SET, SLOODLE_CHANNEL_ENEMY_AIM, "", deathKey);
  263. state attack;
  264. }
  265. }
  266. timer(){
  267. timeToMove_counter++;
  268. if (timeToMove_counter<timeToMove){
  269. debug("timeToMove_counter is: "+(string)timeToMove_counter + " < "+(string)(timeToMove));
  270. return;
  271. }
  272. //set a new time which we should move next, do this so shark doesnt move so predicatbly
  273. timeToMove=random_integer(MIN_WAIT_TILL_MOVE_TIME,MAX_WAIT_TILL_MOVE_TIME);
  274. timeToMove_counter=0;
  275. // get current position
  276. vector pos = llGetPos();
  277. // calculate random next position
  278. vector dest = pos;
  279. dest.x += randBetween(-POOL_WIDTH/2, POOL_WIDTH/2);
  280. dest.y += randBetween(-POOL_WIDTH/2, POOL_WIDTH/2);
  281. dest.z += randBetween(-POOL_HEIGHT/2, POOL_HEIGHT/2);
  282. dest = swim_in_boundary(dest,pos);
  283. // calculate new rotation and move to target
  284. vector delta = pos - dest;
  285. float angle = llAtan2(delta.y, delta.x) + PI / 2.0;
  286. rotation rot = llEuler2Rot(<0, 0, angle>);
  287. llRotLookAt(rot, 1.0, 1.0);
  288. sloodle_set_pos(dest);
  289. }
  290. }
  291. state attack{
  292. on_rez(integer start_param) {
  293. llResetScript();
  294. }
  295. state_entry() {
  296. llListen(232323, "", "", "");
  297. debug("in the attack state");
  298. attackTimes = 0;
  299. target_id = llTarget(deathTarget, 0.5);
  300. llTriggerSound("SND_JAWS", 1);
  301. sloodle_set_pos(deathTarget);
  302. llSensorRepeat("", "", AGENT, 10, PI,3);
  303. llSetTimerEvent(10);
  304. }
  305. listen(integer channel, string name, key id, string message) {
  306. //if pool moves
  307. if (channel==232323){
  308. llSleep(3);
  309. state get_boundary;
  310. }
  311. }
  312. sensor(integer num_detected) {
  313. integer i;
  314. for (i=0;i<num_detected;i++){
  315. deathTarget =llDetectedPos(i);
  316. if (is_in_boundary(deathTarget)==FALSE){
  317. debug("not attacking because not in boundary");
  318. return;
  319. }
  320. deathKey = llDetectedKey(i);
  321. target_id = llTarget(deathTarget, 0.5);
  322. vector pos = llGetPos();
  323. vector delta = pos - deathTarget;
  324. float angle = llAtan2(delta.y, delta.x) + PI / 2.0;
  325. rotation rot = llEuler2Rot(<0, 0, angle>);
  326. llRotLookAt(rot, 1.0, 1.0);
  327. llLookAt( deathTarget + <0.0, 0.0, 1.0>, 3.0, 1.0 );
  328. sloodle_set_pos(deathTarget);
  329. }
  330. }
  331. timer() {
  332. llSetTimerEvent(0);
  333. vector dest=POOL_CENTER;
  334. sloodle_set_pos(dest);
  335. state ready;
  336. }
  337. at_target(integer tnum, vector targetpos, vector ourpos) {
  338. if (tnum == target_id){
  339. debug("at the target");
  340. // llRezObject("redBubbles", llGetPos(), llGetVel(), ZERO_ROTATION, 0);
  341. llRezObject("blood_bath", llGetPos(), llGetVel(), ZERO_ROTATION, 0);
  342. llMessageLinked(LINK_SET, SLOODLE_CHANNEL_ENEMY_ATTACK, "", deathKey);
  343. llTriggerSound(getScream(), 1);
  344. llTriggerSound("SND_BITE", 1);
  345. attackTimes++;
  346. blood(deathKey);
  347. llPushObject(deathKey,PUSH_STRENGTH,PUSH_STRENGTH, TRUE);
  348. llTargetRemove(target_id);
  349. if (attackTimes>5) {
  350. attackTimes= 0;
  351. debug("attackTimes >5 going to ready state");
  352. state ready;
  353. }
  354. }
  355. }
  356. }
  357. // Please leave the following line intact to show where the script lives in Git:
  358. // SLOODLE LSL Script Git Location: mod/gaming-1.0/objects/shark/assets/shark_artificial_intelligence.lslp