fire.lsl 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812
  1. // :SHOW:1
  2. // :CATEGORY:Fire
  3. // :NAME:Realfire by Rene
  4. // :AUTHOR:Rene10957 Resident
  5. // :KEYWORDS: light,lamp,lighting
  6. // :CREATED:2015-06-11 14:37:29
  7. // :EDITED:2015-06-12 11:25:11
  8. // :ID:1078
  9. // :NUM:1765
  10. // :REV:3.0.1
  11. // :WORLD:Second Life, Opensim
  12. // :DESCRIPTION:
  13. // Main script for Realfire
  14. // :CODE:
  15. // :LICENSE: CC0 (Public Domain). To the extent possible under law, Rene10957 has waived all copyright and related or neighboring rights.For more information, see http://creativecommons.org/publicdomain/zero/1.0/.
  16. string title = "RealFire"; // title
  17. string version = "3.0.1"; // version
  18. string notecard = "config"; // notecard name
  19. // Constants
  20. integer _PUBLIC_ = 1; // public access bit
  21. integer _GROUP_ = 2; // group access bit
  22. integer _OWNER_ = 4; // owner access bit
  23. integer _GRPOWN_ = 6; // group + owner
  24. integer smokeChannel = -15790; // smoke channel
  25. float minParticle = 0.0625; // smallest possible particle dimension (SL limit = 0.03125)
  26. float maxRed = 1.0; // max. red
  27. float maxGreen = 1.0; // max. green
  28. float maxBlue = 1.0; // max. blue
  29. float maxIntensity = 1.0; // max. light intensity
  30. float maxRadius = 20.0; // max. light radius
  31. float maxFalloff = 2.0; // max. light falloff
  32. float maxVolume = 1.0; // max. volume for sound
  33. // Notecard variables
  34. integer verbose = FALSE; // show more/less info during startup
  35. integer switchAccess; // access level for switch
  36. integer menuAccess; // access level for menu
  37. integer msgNumber; // number part of incoming link messages
  38. string msgSwitch; // string part of incoming link message: switch (on/off)
  39. string msgOn; // string part of incoming link message: switch on
  40. string msgOff; // string part of incoming link message: switch off
  41. string msgMenu; // string part of incoming link message: show menu
  42. string extButton; // "Close" replaced by button text (sends link message)
  43. integer extNumber; // number part of outgoing link message
  44. integer switchNumber; // number part of outgoing on/off messages
  45. integer burnDown = FALSE; // burn down or burn continuously
  46. float burnTime; // time to burn in seconds before starting to die
  47. float dieTime; // time it takes to die in seconds
  48. integer loop = FALSE; // restart after burning down
  49. integer changeLight = FALSE; // change light with fire
  50. integer changeSmoke = FALSE; // change smoke with fire
  51. integer changeVolume = FALSE; // change volume with fire
  52. integer singleFire = FALSE; // single fire or multiple fires
  53. integer defSize; // default fire size (percentage)
  54. float minSize; // min. fire size (percentage)
  55. vector defStartColor; // default start (bottom) color (percentage R,G,B)
  56. vector defEndColor; // default end (top) color (percentage R,G,B)
  57. integer defVolume; // default volume for sound (percentage)
  58. integer defSmoke = FALSE; // default smoke on/off
  59. integer defSound = FALSE; // default sound on/off
  60. integer defIntensity; // default light intensity (percentage)
  61. integer defRadius; // default light radius (percentage)
  62. integer defFalloff; // default light falloff (percentage)
  63. // Particle parameters (general)
  64. float age = 1.0; // particle lifetime
  65. float rate = 0.1; // particle burst rate
  66. integer count = 10; // particle count
  67. vector startColor = <1, 1, 0>; // particle start color
  68. vector endColor = <1, 0, 0>; // particle end color
  69. float startAlpha = 1.0; // particle start alpha
  70. float endAlpha = 0.0; // particle end alpha
  71. // Particle parameters (resizing)
  72. vector startScale = <0.4, 2, 0>;// particle start size (100%)
  73. vector endScale = <0.4, 2, 0>; // particle end size (100%)
  74. float minSpeed = 0.0; // particle min. burst speed (100%)
  75. float maxSpeed = 0.04; // particle max. burst speed (100%)
  76. float burstRadius = 0.4; // particle burst radius (100%)
  77. vector partAccel = <0, 0, 10>; // particle accelleration (100%)
  78. // Variables
  79. key owner; // object owner
  80. integer line; // notecard line
  81. integer loading = FALSE; // notecard loading
  82. integer menuChannel; // main menu channel
  83. integer startColorChannel; // start color menu channel
  84. integer endColorChannel; // end color menu channel
  85. integer menuHandle; // handle for main menu listener
  86. integer startColorHandle; // handle for start color menu listener
  87. integer endColorHandle; // handle for end color menu listener
  88. integer perRedStart; // percent red for startColor
  89. integer perGreenStart; // percent green for startColor
  90. integer perBlueStart; // percent blue for startColor
  91. integer perRedEnd; // percent red for endColor
  92. integer perGreenEnd; // percent green for endColor
  93. integer perBlueEnd; // percent blue for endColor
  94. integer perSize; // percent particle size
  95. integer perVolume; // percent volume
  96. integer on = FALSE; // fire on/off
  97. integer burning = FALSE; // burning constantly
  98. integer smokeOn = FALSE; // smoke on/off
  99. integer soundOn = FALSE; // sound on/off
  100. integer menuOpen = FALSE; // a menu is open or canceled (ignore button)
  101. float time; // timer interval in seconds
  102. float percent; // percentage of perSize (changed by burning down)
  103. float percentSmoke; // percentage of smoke
  104. float decPercent; // how much to burn down (%) every timer interval
  105. vector lightColor; // light color
  106. float lightIntensity; // light intensity (changed by burning down)
  107. float lightRadius; // light radius (changed by burning down)
  108. float lightFalloff; // light falloff
  109. float soundVolume; // sound volume (changed by burning down)
  110. string sound; // first sound in inventory
  111. string texture; // first texture in inventory
  112. float startIntensity; // start value of lightIntensity (before burning down)
  113. float startRadius; // start value of lightRadius (before burning down)
  114. float startVolume; // start value of volume (before burning down)
  115. // Functions
  116. string getName(integer link)
  117. {
  118. string str = llStringTrim(llGetLinkName(link), STRING_TRIM);
  119. return llToLower(str);
  120. }
  121. string getGroup()
  122. {
  123. string str = llStringTrim(llGetObjectDesc(), STRING_TRIM);
  124. if (llToLower(str) == "(no description)" || str == "") str = "Default";
  125. return str;
  126. }
  127. toggleFire()
  128. {
  129. if (on) stopSystem(); else startSystem();
  130. }
  131. toggleSmoke()
  132. {
  133. if (smokeOn) {
  134. sendMessage(0);
  135. smokeOn = FALSE;
  136. }
  137. else {
  138. if (changeSmoke) sendMessage(llRound(percentSmoke)); else sendMessage(100);
  139. smokeOn = TRUE;
  140. }
  141. }
  142. toggleSound()
  143. {
  144. if (soundOn) {
  145. llStopSound();
  146. soundOn = FALSE;
  147. }
  148. else {
  149. if (sound) llLoopSound(sound, soundVolume);
  150. soundOn = TRUE;
  151. }
  152. }
  153. updateSize(float size)
  154. {
  155. vector start; // start scale
  156. vector end; // end scale
  157. float radius; // burst radius
  158. float min = minSpeed / 100.0 * size; // min. burst speed
  159. float max = maxSpeed / 100.0 * size; // max. burst speed
  160. vector push = partAccel / 100.0 * size; // accelleration
  161. if (size < minSize) {
  162. start = startScale / 100.0 * minSize;
  163. end = endScale / 100.0 * minSize;
  164. radius = burstRadius / 100.0 * minSize;
  165. }
  166. else {
  167. start = startScale / 100.0 * size;
  168. end = endScale / 100.0 * size;
  169. radius = burstRadius / 100.0 * size;
  170. }
  171. if (size > (float)defSize) {
  172. lightIntensity = startIntensity;
  173. lightRadius = startRadius;
  174. percentSmoke = 100.0;
  175. soundVolume = startVolume;
  176. }
  177. else {
  178. size *= 100.0 / (float)defSize;
  179. if (changeLight) {
  180. lightIntensity = percentage(size, startIntensity);
  181. lightRadius = percentage(size + 50.0 - size / 2.0, startRadius);
  182. }
  183. else {
  184. lightIntensity = startIntensity;
  185. lightRadius = startRadius;
  186. }
  187. if (changeSmoke) percentSmoke = size; else percentSmoke = 100.0;
  188. if (changeVolume) soundVolume = percentage(size, startVolume); else soundVolume = startVolume;
  189. }
  190. updateColor();
  191. updateParticles(start, end, min, max, radius, push);
  192. if (smokeOn) sendMessage(llRound(percentSmoke));
  193. if (sound) if (soundOn) llAdjustSoundVolume(soundVolume);
  194. }
  195. updateColor()
  196. {
  197. startColor.x = percentage((float)perRedStart, maxRed);
  198. startColor.y = percentage((float)perGreenStart, maxGreen);
  199. startColor.z = percentage((float)perBlueStart, maxBlue);
  200. endColor.x = percentage((float)perRedEnd, maxRed);
  201. endColor.y = percentage((float)perGreenEnd, maxGreen);
  202. endColor.z = percentage((float)perBlueEnd, maxBlue);
  203. lightColor = (startColor + endColor) / 2.0; // light color = average of start & end color
  204. }
  205. integer accessGranted(key user, integer access)
  206. {
  207. integer bitmask = _PUBLIC_;
  208. if (user == owner) bitmask += _OWNER_;
  209. if (llSameGroup(user)) bitmask += _GROUP_;
  210. return (bitmask & access);
  211. }
  212. integer checkAccess(string par, string val)
  213. {
  214. if (llToLower(val) == "public") return _PUBLIC_;
  215. if (llToLower(val) == "group") return _GROUP_;
  216. if (llToLower(val) == "owner") return _OWNER_;
  217. if (llToLower(val) == "group+owner") return _GRPOWN_;
  218. llWhisper(0, "[Notecard] " + par + " out of range, corrected to PUBLIC");
  219. return _PUBLIC_;
  220. }
  221. integer checkInt(string par, integer val, integer min, integer max)
  222. {
  223. if (val < min || val > max) {
  224. if (val < min) val = min;
  225. else if (val > max) val = max;
  226. llWhisper(0, "[Notecard] " + par + " out of range, corrected to " + (string)val);
  227. }
  228. return val;
  229. }
  230. vector checkVector(string par, vector val)
  231. {
  232. if (val == ZERO_VECTOR) {
  233. val = <100,100,100>;
  234. llWhisper(0, "[Notecard] " + par + " out of range, corrected to " + (string)val);
  235. }
  236. return val;
  237. }
  238. integer checkYesNo(string par, string val)
  239. {
  240. if (llToLower(val) == "yes") return TRUE;
  241. if (llToLower(val) == "no") return FALSE;
  242. llWhisper(0, "[Notecard] " + par + " out of range, corrected to NO");
  243. return FALSE;
  244. }
  245. loadNotecard()
  246. {
  247. verbose = TRUE;
  248. switchAccess = _PUBLIC_;
  249. menuAccess = _PUBLIC_;
  250. msgNumber = 10959;
  251. msgSwitch = "switch";
  252. msgOn = "on";
  253. msgOff = "off";
  254. msgMenu = "menu";
  255. extButton = "";
  256. extNumber = 10960;
  257. switchNumber = 10961;
  258. burnDown = FALSE;
  259. burnTime = 300.0;
  260. dieTime = 300.0;
  261. loop = FALSE;
  262. changeLight = TRUE;
  263. changeSmoke = TRUE;
  264. changeVolume = TRUE;
  265. singleFire = TRUE;
  266. defSize = 25;
  267. defStartColor = <100,100,0>;
  268. defEndColor = <100,0,0>;
  269. defVolume = 100;
  270. defSmoke = TRUE;
  271. defSound = TRUE;
  272. defIntensity = 100;
  273. defRadius = 50;
  274. defFalloff = 40;
  275. line = 0;
  276. if (!burnDown) burnTime = 315360000; // 10 years
  277. time = dieTime / 100.0; // try to get a one percent timer interval
  278. if (time < 1.0) time = 1.0; // but never smaller than one second
  279. decPercent = 100.0 / (dieTime / time); // and burn down decPercent% every time
  280. startIntensity = percentage(defIntensity, maxIntensity);
  281. startRadius = percentage(defRadius, maxRadius);
  282. lightFalloff = percentage(defFalloff, maxFalloff);
  283. startVolume = percentage(defVolume, maxVolume);
  284. if (llGetInventoryType(notecard) == INVENTORY_NOTECARD) {
  285. loading = TRUE;
  286. llSetText("Loading notecard...", <1,1,1>, 1.0);
  287. llGetNotecardLine(notecard, line);
  288. }
  289. else {
  290. reset(); // initial values for menu
  291. if (on) startSystem();
  292. if (verbose) {
  293. llWhisper(0, "Notecard \"" + notecard + "\" not found or empty, using defaults");
  294. llWhisper(0, "Touch to start/stop fire");
  295. llWhisper(0, "Long touch to show menu");
  296. if (sound) llWhisper(0, "Sound in object inventory: Yes");
  297. else llWhisper(0, "Sound in object inventory: No");
  298. llWhisper(0, title + " " + version + " ready");
  299. }
  300. }
  301. }
  302. readNotecard (string ncLine)
  303. {
  304. string ncData = llStringTrim(ncLine, STRING_TRIM);
  305. if (llStringLength(ncData) > 0 && llGetSubString(ncData, 0, 0) != "#") {
  306. list ncList = llParseString2List(ncData, ["=","#"], []); // split into parameter, value, comment
  307. string par = llStringTrim(llList2String(ncList, 0), STRING_TRIM);
  308. string val = llStringTrim(llList2String(ncList, 1), STRING_TRIM);
  309. string lcpar = llToLower(par);
  310. if (lcpar == "verbose") verbose = checkYesNo(par, val);
  311. else if (lcpar == "switchaccess") switchAccess = checkAccess(par, val);
  312. else if (lcpar == "menuaccess") menuAccess = checkAccess(par, val);
  313. else if (lcpar == "msgnumber") msgNumber = (integer)val;
  314. else if (lcpar == "msgswitch") msgSwitch = val;
  315. else if (lcpar == "msgon") msgOn = val;
  316. else if (lcpar == "msgoff") msgOff = val;
  317. else if (lcpar == "msgmenu") msgMenu = val;
  318. else if (lcpar == "extbutton") extButton = llGetSubString(val, 0, 23);
  319. else if (lcpar == "extnumber") extNumber = (integer)val;
  320. else if (lcpar == "switchnumber") switchNumber = (integer)val;
  321. else if (lcpar == "burndown") burnDown = checkYesNo(par, val);
  322. else if (lcpar == "burntime") burnTime = (float)checkInt(par, (integer)val, 1, 315360000); // 10 years
  323. else if (lcpar == "dietime") dieTime = (float)checkInt(par, (integer)val, 1, 315360000); // 10 years
  324. else if (lcpar == "loop") loop = checkYesNo(par, val);
  325. else if (lcpar == "changelight") changeLight = checkYesNo(par, val);
  326. else if (lcpar == "changesmoke") changeSmoke = checkYesNo(par, val);
  327. else if (lcpar == "changevolume") changeVolume = checkYesNo(par, val);
  328. else if (lcpar == "singlefire") singleFire = checkYesNo(par, val);
  329. else if (lcpar == "size") defSize = checkInt(par, (integer)val, 5, 100);
  330. else if (lcpar == "topcolor") defEndColor = checkVector(par, (vector)val);
  331. else if (lcpar == "bottomcolor") defStartColor = checkVector(par, (vector)val);
  332. else if (lcpar == "volume") defVolume = checkInt(par, (integer)val, 5, 100);
  333. else if (lcpar == "smoke") defSmoke = checkYesNo(par, val);
  334. else if (lcpar == "sound") defSound = checkYesNo(par, val);
  335. else if (lcpar == "intensity") defIntensity = checkInt(par, (integer)val, 0, 100);
  336. else if (lcpar == "radius") defRadius = checkInt(par, (integer)val, 0, 100);
  337. else if (lcpar == "falloff") defFalloff = checkInt(par, (integer)val, 0, 100);
  338. else llWhisper(0, "Unknown parameter in notecard line " + (string)(line + 1) + ": " + par);
  339. }
  340. line++;
  341. llGetNotecardLine(notecard, line);
  342. }
  343. menuDialog (key id)
  344. {
  345. menuOpen = TRUE;
  346. string strSmoke = "OFF"; if (smokeOn) strSmoke = "ON";
  347. string strSound = "NONE"; if (sound) if (soundOn) strSound = "ON"; else strSound = "OFF";
  348. string strButton = "Close"; if (extButton) strButton = extButton;
  349. menuChannel = (integer)(llFrand(-1000000000.0) - 1000000000.0);
  350. llListenRemove(menuHandle);
  351. menuHandle = llListen(menuChannel, "", "", "");
  352. llSetTimerEvent(0);
  353. llSetTimerEvent(120);
  354. llDialog(id, title + " " + version +
  355. "\n\nSize: " + (string)perSize + "%\t\tVolume: " + (string)perVolume + "%" +
  356. "\nSmoke: " + strSmoke + "\t\tSound: " + strSound, [
  357. "Smoke", "Sound", strButton,
  358. "-Volume", "+Volume", "Reset",
  359. "-Fire", "+Fire", "Color",
  360. "Small", "Medium", "Large" ],
  361. menuChannel);
  362. }
  363. startColorDialog (key id)
  364. {
  365. menuOpen = TRUE;
  366. startColorChannel = (integer)(llFrand(-1000000000.0) - 1000000000.0);
  367. llListenRemove(startColorHandle);
  368. startColorHandle = llListen(startColorChannel, "", "", "");
  369. llSetTimerEvent(0);
  370. llSetTimerEvent(120);
  371. llDialog(id, "Bottom color" +
  372. "\n\nRed: " + (string)perRedStart + "%" +
  373. "\nGreen: " + (string)perGreenStart + "%" +
  374. "\nBlue: " + (string)perBlueStart + "%", [
  375. "Top color", "One color", "Main menu",
  376. "-Blue", "+Blue", "B min/max",
  377. "-Green", "+Green", "G min/max",
  378. "-Red", "+Red", "R min/max" ],
  379. startColorChannel);
  380. }
  381. endColorDialog (key id)
  382. {
  383. menuOpen = TRUE;
  384. endColorChannel = (integer)(llFrand(-1000000000.0) - 1000000000.0);
  385. llListenRemove(endColorHandle);
  386. endColorHandle = llListen(endColorChannel, "", "", "");
  387. llSetTimerEvent(0);
  388. llSetTimerEvent(120);
  389. llDialog(id, "Top color" +
  390. "\n\nRed: " + (string)perRedEnd + "%" +
  391. "\nGreen: " + (string)perGreenEnd + "%" +
  392. "\nBlue: " + (string)perBlueEnd + "%", [
  393. "Bottom color", "One color", "Main menu",
  394. "-Blue", "+Blue", "B min/max",
  395. "-Green", "+Green", "G min/max",
  396. "-Red", "+Red", "R min/max" ],
  397. endColorChannel);
  398. }
  399. float percentage (float per, float num)
  400. {
  401. return num / 100.0 * per;
  402. }
  403. integer min (integer x, integer y)
  404. {
  405. if (x < y) return x; else return y;
  406. }
  407. integer max (integer x, integer y)
  408. {
  409. if (x > y) return x; else return y;
  410. }
  411. reset()
  412. {
  413. smokeOn = defSmoke;
  414. soundOn = defSound;
  415. perSize = defSize;
  416. perVolume = defVolume;
  417. perRedStart = (integer)defStartColor.x;
  418. perGreenStart = (integer)defStartColor.y;
  419. perBlueStart = (integer)defStartColor.z;
  420. perRedEnd = (integer)defEndColor.x;
  421. perGreenEnd = (integer)defEndColor.y;
  422. perBlueEnd = (integer)defEndColor.z;
  423. }
  424. startSystem()
  425. {
  426. if (!on) llMessageLinked(LINK_SET, switchNumber, (string)TRUE, getGroup());
  427. on = TRUE;
  428. burning = TRUE;
  429. percent = 100.0;
  430. percentSmoke = 100.0;
  431. smokeOn = !smokeOn;
  432. toggleSmoke();
  433. startVolume = percentage(perVolume, maxVolume);
  434. lightIntensity = startIntensity;
  435. lightRadius = startRadius;
  436. soundVolume = startVolume;
  437. updateSize((float)perSize);
  438. llStopSound();
  439. if (sound) if (soundOn) llLoopSound(sound, soundVolume);
  440. llSetTimerEvent(0);
  441. llSetTimerEvent(burnTime);
  442. if (menuOpen) {
  443. llListenRemove(menuHandle);
  444. llListenRemove(startColorHandle);
  445. llListenRemove(endColorHandle);
  446. menuOpen = FALSE;
  447. }
  448. }
  449. stopSystem()
  450. {
  451. if (on) llMessageLinked(LINK_SET, switchNumber, (string)FALSE, getGroup());
  452. on = FALSE;
  453. burning = FALSE;
  454. percent = 0.0;
  455. percentSmoke = 0.0;
  456. llSetTimerEvent(0);
  457. updateParticles(ZERO_VECTOR, ZERO_VECTOR, 0, 0, 0, ZERO_VECTOR);
  458. llStopSound();
  459. sendMessage(0);
  460. if (menuOpen) {
  461. llListenRemove(menuHandle);
  462. llListenRemove(startColorHandle);
  463. llListenRemove(endColorHandle);
  464. menuOpen = FALSE;
  465. }
  466. }
  467. updateParticles(vector start, vector end, float min, float max, float radius, vector push)
  468. {
  469. list particles = [
  470. PSYS_SRC_PATTERN, PSYS_SRC_PATTERN_EXPLODE,
  471. PSYS_SRC_TEXTURE, texture,
  472. PSYS_PART_START_COLOR, startColor,
  473. PSYS_PART_END_COLOR, endColor,
  474. PSYS_PART_START_ALPHA, startAlpha,
  475. PSYS_PART_END_ALPHA, endAlpha,
  476. PSYS_PART_START_SCALE, start,
  477. PSYS_PART_END_SCALE, end,
  478. PSYS_PART_MAX_AGE, age,
  479. PSYS_SRC_BURST_RATE, rate,
  480. PSYS_SRC_BURST_PART_COUNT, count,
  481. PSYS_SRC_BURST_SPEED_MIN, min,
  482. PSYS_SRC_BURST_SPEED_MAX, max,
  483. PSYS_SRC_BURST_RADIUS, radius,
  484. PSYS_SRC_ACCEL, push,
  485. PSYS_PART_FLAGS,
  486. 0 |
  487. PSYS_PART_EMISSIVE_MASK |
  488. PSYS_PART_FOLLOW_VELOCITY_MASK |
  489. PSYS_PART_INTERP_COLOR_MASK |
  490. PSYS_PART_INTERP_SCALE_MASK ];
  491. if (singleFire) {
  492. if (on) {
  493. llParticleSystem(particles);
  494. llSetPrimitiveParams([PRIM_POINT_LIGHT, TRUE, lightColor, lightIntensity, lightRadius, lightFalloff]);
  495. }
  496. else {
  497. llParticleSystem([]);
  498. llSetPrimitiveParams([PRIM_POINT_LIGHT, FALSE, ZERO_VECTOR, 0, 0, 0]);
  499. }
  500. return;
  501. }
  502. integer i;
  503. integer number = llGetNumberOfPrims();
  504. integer link = llGetLinkNumber();
  505. string name = getName(link);
  506. for (i = number; i >= 0; --i) {
  507. if (name == getName(i)) {
  508. if (i == link || getName(i) != "object") {
  509. if (on) {
  510. llLinkParticleSystem(i, particles);
  511. llSetLinkPrimitiveParamsFast(i, [
  512. PRIM_POINT_LIGHT, TRUE, lightColor, lightIntensity, lightRadius, lightFalloff]);
  513. }
  514. else {
  515. llLinkParticleSystem(i, []);
  516. llSetLinkPrimitiveParamsFast(i, [PRIM_POINT_LIGHT, FALSE, ZERO_VECTOR, 0, 0, 0]);
  517. }
  518. }
  519. }
  520. }
  521. }
  522. sendMessage(integer size)
  523. {
  524. llMessageLinked(LINK_ALL_OTHERS, smokeChannel, (string)size, getGroup());
  525. }
  526. default
  527. {
  528. state_entry()
  529. {
  530. minSize = 100.0 / (startScale.x / minParticle); // smallest possible fire size (percentage)
  531. owner = llGetOwner();
  532. sound = llGetInventoryName(INVENTORY_SOUND, 0); // get first sound from inventory
  533. texture = llGetInventoryName(INVENTORY_TEXTURE, 0); // get first texture from inventory
  534. if (sound) llPreloadSound(sound);
  535. stopSystem();
  536. loadNotecard();
  537. }
  538. on_rez(integer start_param)
  539. {
  540. llResetScript();
  541. }
  542. touch_start(integer total_number)
  543. {
  544. llResetTime();
  545. }
  546. touch_end(integer total_number)
  547. {
  548. if (loading) {
  549. llWhisper(0, "Notecard is still loading");
  550. return;
  551. }
  552. key user = llDetectedKey(0);
  553. if (llGetTime() > 1.0) {
  554. if (accessGranted(user, menuAccess)) {
  555. startSystem();
  556. menuDialog(user);
  557. }
  558. else llInstantMessage(user, "[Menu] Access denied");
  559. }
  560. else {
  561. if (accessGranted(user, switchAccess)) toggleFire();
  562. else llInstantMessage(user, "[Switch] Access denied");
  563. }
  564. }
  565. listen(integer channel, string name, key id, string msg)
  566. {
  567. if (channel == menuChannel) {
  568. llListenRemove(menuHandle);
  569. if (msg == "Small") perSize = 25;
  570. else if (msg == "Medium") perSize = 50;
  571. else if (msg == "Large") perSize = 75;
  572. else if (msg == "-Fire") perSize = max(perSize - 5, 5);
  573. else if (msg == "+Fire") perSize = min(perSize + 5, 100);
  574. else if (msg == "-Volume") {
  575. perVolume = max(perVolume - 5, 5);
  576. startVolume = percentage(perVolume, maxVolume);
  577. }
  578. else if (msg == "+Volume") {
  579. perVolume = min(perVolume + 5, 100);
  580. startVolume = percentage(perVolume, maxVolume);
  581. }
  582. else if (msg == "Smoke") toggleSmoke();
  583. else if (msg == "Sound") toggleSound();
  584. else if (msg == "Color") endColorDialog(id);
  585. else if (msg == "Reset") { reset(); startSystem(); }
  586. else if (msg == extButton) llMessageLinked(LINK_SET, extNumber, msg, id);
  587. if (msg != "Color" && msg != "Close" && msg != extButton) {
  588. if (msg != "Smoke" && msg != "Sound" && msg != "Reset") updateSize((float)perSize);
  589. menuDialog(id);
  590. }
  591. else {
  592. llSetTimerEvent(0); // stop dialog timer
  593. llSetTimerEvent(burnTime); // restart burn timer
  594. menuOpen = FALSE;
  595. }
  596. }
  597. else if (channel == startColorChannel) {
  598. llListenRemove(startColorHandle);
  599. if (msg == "-Red") perRedStart = max(perRedStart - 10, 0);
  600. else if (msg == "-Green") perGreenStart = max(perGreenStart - 10, 0);
  601. else if (msg == "-Blue") perBlueStart = max(perBlueStart - 10, 0);
  602. else if (msg == "+Red") perRedStart = min(perRedStart + 10, 100);
  603. else if (msg == "+Green") perGreenStart = min(perGreenStart + 10, 100);
  604. else if (msg == "+Blue") perBlueStart = min(perBlueStart + 10, 100);
  605. else if (msg == "R min/max") { if (perRedStart) perRedStart = 0; else perRedStart = 100; }
  606. else if (msg == "G min/max") { if (perGreenStart) perGreenStart = 0; else perGreenStart = 100; }
  607. else if (msg == "B min/max") { if (perBlueStart) perBlueStart = 0; else perBlueStart = 100; }
  608. else if (msg == "Top color") endColorDialog(id);
  609. else if (msg == "Main menu") menuDialog(id);
  610. else if (msg == "One color") {
  611. perRedEnd = perRedStart;
  612. perGreenEnd = perGreenStart;
  613. perBlueEnd = perBlueStart;
  614. }
  615. if (msg != "Top color" && msg != "Main menu") {
  616. updateSize((float)perSize);
  617. startColorDialog(id);
  618. }
  619. }
  620. else if (channel == endColorChannel) {
  621. llListenRemove(endColorHandle);
  622. if (msg == "-Red") perRedEnd = max(perRedEnd - 10, 0);
  623. else if (msg == "-Green") perGreenEnd = max(perGreenEnd - 10, 0);
  624. else if (msg == "-Blue") perBlueEnd = max(perBlueEnd - 10, 0);
  625. else if (msg == "+Red") perRedEnd = min(perRedEnd + 10, 100);
  626. else if (msg == "+Green") perGreenEnd = min(perGreenEnd + 10, 100);
  627. else if (msg == "+Blue") perBlueEnd = min(perBlueEnd + 10, 100);
  628. else if (msg == "R min/max") { if (perRedEnd) perRedEnd = 0; else perRedEnd = 100; }
  629. else if (msg == "G min/max") { if (perGreenEnd) perGreenEnd = 0; else perGreenEnd = 100; }
  630. else if (msg == "B min/max") { if (perBlueEnd) perBlueEnd = 0; else perBlueEnd = 100; }
  631. else if (msg == "Bottom color") startColorDialog(id);
  632. else if (msg == "Main menu") menuDialog(id);
  633. else if (msg == "One color") {
  634. perRedStart = perRedEnd;
  635. perGreenStart = perGreenEnd;
  636. perBlueStart = perBlueEnd;
  637. }
  638. if (msg != "Bottom color" && msg != "Main menu") {
  639. updateSize((float)perSize);
  640. endColorDialog(id);
  641. }
  642. }
  643. }
  644. link_message(integer sender_number, integer number, string msg, key id)
  645. {
  646. if (number != msgNumber) return;
  647. if (loading) {
  648. llWhisper(0, "Notecard is still loading");
  649. return;
  650. }
  651. if (id) {} else {
  652. llWhisper(0, "A valid avatar key must be provided in the link message");
  653. return;
  654. }
  655. if (msg == msgSwitch) {
  656. if (accessGranted(id, switchAccess)) toggleFire();
  657. else llInstantMessage(id, "[Switch] Access denied");
  658. }
  659. else if (msg == msgOn) {
  660. if (accessGranted(id, switchAccess)) startSystem();
  661. else llInstantMessage(id, "[Switch] Access denied");
  662. }
  663. else if (msg == msgOff) {
  664. if (accessGranted(id, switchAccess)) stopSystem();
  665. else llInstantMessage(id, "[Switch] Access denied");
  666. }
  667. else if (msg == msgMenu) {
  668. if (accessGranted(id, menuAccess)) {
  669. startSystem();
  670. menuDialog(id);
  671. }
  672. else llInstantMessage(id, "[Menu] Access denied");
  673. }
  674. }
  675. dataserver(key req, string data)
  676. {
  677. if (data == EOF) {
  678. if (!burnDown) burnTime = 315360000; // 10 years
  679. time = dieTime / 100.0; // try to get a one percent timer interval
  680. if (time < 1.0) time = 1.0; // but never smaller than one second
  681. decPercent = 100.0 / (dieTime / time); // and burn down decPercent% every time
  682. defStartColor.x = checkInt("ColorOn (RED)", (integer)defStartColor.x, 0, 100);
  683. defStartColor.y = checkInt("ColorOn (GREEN)", (integer)defStartColor.y, 0, 100);
  684. defStartColor.z = checkInt("ColorOn (BLUE)", (integer)defStartColor.z, 0, 100);
  685. defEndColor.x = checkInt("ColorOff (RED)", (integer)defEndColor.x, 0, 100);
  686. defEndColor.y = checkInt("ColorOff (GREEN)", (integer)defEndColor.y, 0, 100);
  687. defEndColor.z = checkInt("ColorOff (BLUE)", (integer)defEndColor.z, 0, 100);
  688. startIntensity = percentage(defIntensity, maxIntensity);
  689. startRadius = percentage(defRadius, maxRadius);
  690. lightFalloff = percentage(defFalloff, maxFalloff);
  691. startVolume = percentage(defVolume, maxVolume);
  692. reset(); // initial values for menu
  693. if (on) startSystem();
  694. if (verbose) {
  695. llWhisper(0, "Touch to start/stop fire");
  696. llWhisper(0, "Long touch to show menu");
  697. if (sound) llWhisper(0, "Sound in object inventory: Yes");
  698. else llWhisper(0, "Sound in object inventory: No");
  699. llWhisper(0, title + " " + version + " ready");
  700. }
  701. loading = FALSE;
  702. llSetText("", ZERO_VECTOR, 0.0);
  703. }
  704. else {
  705. readNotecard(data);
  706. }
  707. }
  708. changed(integer change)
  709. {
  710. if (change & CHANGED_INVENTORY) {
  711. sound = llGetInventoryName(INVENTORY_SOUND, 0); // get first sound from inventory
  712. texture = llGetInventoryName(INVENTORY_TEXTURE, 0); // get first texture from inventory
  713. if (sound) llPreloadSound(sound);
  714. loadNotecard();
  715. }
  716. }
  717. timer()
  718. {
  719. if (menuOpen) {
  720. llListenRemove(menuHandle);
  721. llListenRemove(startColorHandle);
  722. llListenRemove(endColorHandle);
  723. llSetTimerEvent(0); // stop dialog timer
  724. llSetTimerEvent(burnTime); // restart burn timer
  725. menuOpen = FALSE;
  726. return;
  727. }
  728. if (burning) {
  729. llSetTimerEvent(0);
  730. llSetTimerEvent(time);
  731. burning = FALSE;
  732. }
  733. if (percent >= decPercent) {
  734. percent -= decPercent;
  735. updateSize(percent / (100.0 / (float)perSize));
  736. }
  737. else {
  738. if (loop) startSystem();
  739. else stopSystem();
  740. }
  741. }
  742. }