KeeperS Karu Posted February 19 Share Posted February 19 (edited) Heyla and good evening! So I'm not the biggest fan of first person mode, otherwise known as mouselook mode on SL. Unfortunately, every melee weapon script I've found tends to only be truly effective in mouselook mode, as it requires you to hold the left mouse button down while also pressing the directional keys to swing the weapon. In third person mode, you need that button for mouse steering, or movement will be awkward. Because I haven't been able to find a script that made the use of melee weapons in third person mode viable, I decided to mess around with a freebie melee weapon script and see if I can find something that works. And I think I did. In third person mode, instead of holding down the left mouse button in combination with the directional keys to activate the weapon swings, the player will hold down the forward button in conjunction with the left, right, and back movement buttons to swing the weapon. The left mouse button, of course, is reserved for mouse steering. It wasn't my first choice of key combos. I wanted to hold down the right mouse button instead of the left mouse button to activate the swings in third person mode, but the right mouse button isn't available (unless that's changed since last I checked?). Anyhow, I thought I'd post the modified script on here and get some feedback on how the controls feel in third person, see if there are any tweaks and suggestions you all might have to make third person melee combat a viable option for those who hate being in mouselook mode. I do want to make note of the fact that I am very much a newbie in scripting. I know just enough to get by and am using what I learned in my QBASIC class over 20 years ago to organize things to the best of my ability. This is not going to be a brilliant script by any means. If you have suggestions to make this into something good enough to be passed around to others who could use it, I'm definitely all ears. Thanks for reading and your feedback, Keeper S. Karu (KeeperS Karu) P.S. Contact me in-world for a copy of the dummy melee weapon if you don't want to mess with putting something together. It's put together with my own animations and ready for playing around with. The Controls: Forward Double-Tapped --> Forward Strike Forward + Left --> Left Strike Forward + Left Double-Tapped --> Alternate Left Strike Forward + Right --> Right Strike Forward + Right Double-Tapped --> Alternate Right Strike Forward + Back --> My dummy weapon uses a kick animation for this one; could probably use another strike animation for this Forward + Back Double-Tapped --> Uh, I didn't realize I never took that into account; might be my first tweak to the script Tweak 1: Forward + Back --> Forward Strike Forward + Back Double-Tapped --> Kick The Script (Tweak 1): //PREAMBLE: Module Names //Module 1: Defining Global String Variables - Animation Names //Module 2: Defining Global String Variables - Sound Effect Names //Module 3: Defining Global String Variables - Bloodsplatter Object Name //Module 4: Defining Global Integer Variables - Attack Types //Module 5: The Double Tap Code //Module 5A: Defining the Double-Tap Global Vairables //Module 5B: Obtaining the Time the Key Was Pressed //Module 5C: Comparing the Time Between Key Presses //Module 5D: Resetting the storedTime Variable //Module 5E: Double Tap //Module 6: The Sword Script //Module 6A: The Default State of the Sword Object When the Script Is First Executed //Module 6a: The Sword's Status When the Script is Reset - It Cannot Be Grabbed and Physically Dragged //Module 6b: Actions to Take When the Sword is Attached and Detached From the Avatar //Module 6c: If Permission Has Been Given, Take Over Keyboard Functions //Module 6d: Defining the Keyboard Controls //Module 6e: Actions to Perform When the Timer Event is Triggered //Module 6f: Actions to Perform if There's a Valid Target within the Predefined Sensor Range //Module 1: Defining Global String Variables - Animation Names string fwdanim = "overhead_strike_exaggerated"; string bckanim = "high_kick"; string rotrightanim = "diagonal_left_strike_exag"; string rotleftanim = "diagonal_right_strike_exag"; string straferightanim = "upward_left_strike_exag"; string strafeleftanim = "upward_right_strike_exag"; string pgdwnanim = "basic_angle_block"; string pgupanim = "backflip"; //Module 2: Defining Global String Variables - Sound Effects Names string swdswing = "swordswing01"; string swdconnectflsh = "sword_flesh_01"; //string block swing; - If different from the other sound effects, enter them, here, as well as in the appropriate area of the code, below string blockconnect = "sword05"; //string kick swing; - If different from the other sound effects, enter them, here, as well as in the appropriate area of the code, below string kickconnect = "Punch04"; //Module 3: Defining Global String Variables - Bloodsplatter Object Name string bloodsplatter = "!bloodsplatter"; //Module 4: Defining Global Integer Variables - Attack Types integer SWORDFWD = 1; integer SWORDRGT = 2; integer SWORDLFT = 3; integer BLOCK = 4; integer KICK = 5; integer SPECIALATK = 6; integer strike_type; //Module 5: The Double Tap Code //Module 5A: Defining the Double-Tap Global Vairables float strTime; float time; float storedTime; float recentTime; string anim = "hover"; float interval = 1.0; //Module 5B: Obtaining the Time the Key Was Pressed getSeconds() { string timestamp = llGetTimestamp(); string subTime = llGetSubString(timestamp, 19, 25); float wallclock = llGetWallclock(); strTime = (float)subTime + wallclock; } //Module 5C: Comparing the Time Between Key Presses compareTimes(float stored, float recent) { time = recent - stored; } //Module 5D: Resetting the storedTime Variable resetStored() { storedTime = 0; } //Module 5E: Double Tap FStrike() { if ( time <= interval | time > interval ) { llStartAnimation(fwdanim); llSetTimerEvent(0.75); strike_type = SWORDFWD; } } BStrike() { if ( time <= interval ) { llStartAnimation(bckanim); llSetTimerEvent(0.25); strike_type = KICK; } else { llStartAnimation(fwdanim); llSetTimerEvent(0.25); strike_type = KICK; } } RLeft() { if ( time <= interval ) { llStartAnimation(rotleftanim); llSetTimerEvent(0.75); strike_type = SWORDLFT; } else { llStartAnimation(strafeleftanim); llSetTimerEvent(0.75); strike_type = SWORDLFT; } } SLeft() { if ( time <= interval ) { llStartAnimation(strafeleftanim); llSetTimerEvent(0.75); strike_type = SWORDLFT; } else { llStartAnimation(rotleftanim); llSetTimerEvent(0.75); strike_type = SWORDLFT; } } RRight() { if( time <= interval) { llStartAnimation(rotrightanim); llSetTimerEvent(0.75); strike_type = SWORDRGT; } else { llStartAnimation(straferightanim); llSetTimerEvent(0.75); strike_type = SWORDRGT; } } SRight() { if ( time <= interval ) { llStartAnimation(straferightanim); llSetTimerEvent(0.75); strike_type = SWORDRGT; } else { llStartAnimation(rotrightanim); llSetTimerEvent(0.75); strike_type = SWORDRGT; } } //Module 6: The Sword Script //Module 6A: The Default State of the Sword Object When the Script Is First Executed default { //Module 6a: The Sword's Status When the Script is Reset - It Cannot Be Grabbed and Physically Dragged state_entry() { llSetStatus(STATUS_BLOCK_GRAB, TRUE); } //Module 6b: Actions to Take When the Sword is Attached and Detached From the Avatar attach(key on) { if (on != NULL_KEY) { integer perm = llGetPermissions(); if (perm != (PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION)) { llRequestPermissions(on, PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION); } else { llTakeControls(CONTROL_ML_LBUTTON | CONTROL_LBUTTON | CONTROL_UP | CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_RIGHT, TRUE, TRUE); } } else { llSay(0, "releasing controls"); llReleaseControls(); } } //Module 6c: If Permission Has Just Been Given, Take Over Keyboard Functions run_time_permissions(integer perm) { if (perm) { llTakeControls(CONTROL_ML_LBUTTON | CONTROL_LBUTTON | CONTROL_UP | CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_RIGHT | CONTROL_DOWN, TRUE, TRUE); } } //Module 6d: Defining the Keyboard Controls control(key owner, integer held, integer change) { if (held & (CONTROL_ML_LBUTTON | CONTROL_FWD)) { if (change & held & CONTROL_UP) { llApplyImpulse(<0,0,3.5>,FALSE); llStartAnimation(pgupanim); llSetTimerEvent(0.25); strike_type = SPECIALATK; } if (change & held & CONTROL_FWD) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); FStrike(); storedTime = recentTime; } if (change & held & CONTROL_ROT_LEFT) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); SLeft(); storedTime = recentTime; } if (change & held & CONTROL_LEFT) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); RLeft(); storedTime = recentTime; } if (change & held & CONTROL_ROT_RIGHT) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); SRight(); storedTime = recentTime; } if (change & held & CONTROL_RIGHT) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); RRight(); storedTime = recentTime; } if (change & held & CONTROL_BACK) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); BStrike(); storedTime = recentTime; } } if (~held & change & (CONTROL_ML_LBUTTON | CONTROL_FWD)) { llStopAnimation(pgdwnanim); } if (held & change & CONTROL_DOWN) { llStartAnimation(pgdwnanim); llTriggerSound(swdswing, 1.0); llSetTimerEvent(0.01); strike_type = BLOCK; llMoveToTarget(llGetPos(), 0.25); llSleep(1.0); llStopMoveToTarget(); } if (~held & change & CONTROL_DOWN) { llStopAnimation(pgdwnanim); } } //Module 6e: Actions to Perform When the Timer Event is Triggered timer() { if (strike_type == SWORDFWD) { llTriggerSound(swdswing, 1.0); llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5); } if (strike_type == SWORDRGT) { llTriggerSound(swdswing, 1.0); llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO); } if (strike_type == SWORDLFT) { llTriggerSound(swdswing, 1.0); llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO); } if (strike_type == BLOCK) { llSensor("", "", ACTIVE | AGENT, 2.0, PI_BY_TWO); } if (strike_type == KICK) { llTriggerSound(swdswing, 1.0); llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5); } if (strike_type == SPECIALATK) { llTriggerSound(swdswing, 1.0); llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5); } llSetTimerEvent(0.0); } //Module 6f: Actions to Perform if There's a Valid Target within the Predefined Sensor Range sensor(integer tnum) { vector dir = llDetectedPos(0) - llGetPos(); dir.z = 0.0; dir = llVecNorm(dir); rotation rot = llGetRot(); if (strike_type == SWORDFWD) { llTriggerSound(swdconnectflsh, 1.0); llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE); dir += llRot2Up(rot); dir *= 200.0; llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE); } else if (strike_type == SWORDRGT) { llTriggerSound(swdconnectflsh, 1.0); llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE); dir += dir; dir *= 100.0; llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE); } else if (strike_type == SWORDLFT) { llTriggerSound(swdconnectflsh, 1.0); llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE); dir -= llRot2Left(rot); dir *= 100.0; llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE); } else if (strike_type == KICK) { llTriggerSound(kickconnect, 1.0); dir += dir; dir *= 100.0; llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE); } else if (strike_type == BLOCK) { llTriggerSound(blockconnect, 1.0); } else if (strike_type == SPECIALATK) { llTriggerSound(swdswing, 1.0); llPushObject(llDetectedKey(0), <0,0,150>, ZERO_VECTOR, FALSE); } strike_type= 0; } } The Script: //PREAMBLE: Module Names //Module 1: Defining Global String Variables - Animation Names //Module 2: Defining Global String Variables - Sound Effect Names //Module 3: Defining Global String Variables - Bloodsplatter Object Name //Module 4: Defining Global Integer Variables - Attack Types //Module 5: The Double Tap Code //Module 5A: Defining the Double-Tap Global Vairables //Module 5B: Obtaining the Time the Key Was Pressed //Module 5C: Comparing the Time Between Key Presses //Module 5D: Resetting the storedTime Variable //Module 5E: Double Tap //Module 6: The Sword Script //Module 6A: The Default State of the Sword Object When the Script Is First Executed //Module 6a: The Sword's Status When the Script is Reset - It Cannot Be Grabbed and Physically Dragged //Module 6b: Actions to Take When the Sword is Attached and Detached From the Avatar //Module 6c: If Permission Has Been Given, Take Over Keyboard Functions //Module 6d: Defining the Keyboard Controls //Module 6e: Actions to Perform When the Timer Event is Triggered //Module 6f: Actions to Perform if There's a Valid Target within the Predefined Sensor Range //Module 1: Defining Global String Variables - Animation Names string fwdanim = "overhead_strike_exaggerated"; string bckanim = "high_kick"; string rotrightanim = "diagonal_left_strike_exag"; string rotleftanim = "diagonal_right_strike_exag"; string straferightanim = "upward_left_strike_exag"; string strafeleftanim = "upward_right_strike_exag"; string pgdwnanim = "basic_angle_block"; string pgupanim = "backflip"; //Module 2: Defining Global String Variables - Sound Effects Names string swdswing = "swordswing01"; string swdconnectflsh = "sword_flesh_01"; //string block swing; - If different from the other sound effects, enter them, here, as well as in the appropriate area of the code, below string blockconnect = "sword05"; //string kick swing; - If different from the other sound effects, enter them, here, as well as in the appropriate area of the code, below string kickconnect = "Punch04"; //Module 3: Defining Global String Variables - Bloodsplatter Object Name string bloodsplatter = "!bloodsplatter"; //Module 4: Defining Global Integer Variables - Attack Types integer SWORDFWD = 1; integer SWORDRGT = 2; integer SWORDLFT = 3; integer BLOCK = 4; integer KICK = 5; integer SPECIALATK = 6; integer strike_type; //Module 5: The Double Tap Code //Module 5A: Defining the Double-Tap Global Vairables float strTime; float time; float storedTime; float recentTime; string anim = "hover"; float interval = 1.0; //Module 5B: Obtaining the Time the Key Was Pressed getSeconds() { string timestamp = llGetTimestamp(); string subTime = llGetSubString(timestamp, 19, 25); float wallclock = llGetWallclock(); strTime = (float)subTime + wallclock; } //Module 5C: Comparing the Time Between Key Presses compareTimes(float stored, float recent) { time = recent - stored; } //Module 5D: Resetting the storedTime Variable resetStored() { storedTime = 0; } //Module 5E: Double Tap FStrike() { if ( time <= interval | time > interval ) { llStartAnimation(fwdanim); llSetTimerEvent(0.75); strike_type = SWORDFWD; } } RLeft() { if ( time <= interval ) { llStartAnimation(rotleftanim); llSetTimerEvent(0.75); strike_type = SWORDLFT; } else { llStartAnimation(strafeleftanim); llSetTimerEvent(0.75); strike_type = SWORDLFT; } } SLeft() { if ( time <= interval ) { llStartAnimation(strafeleftanim); llSetTimerEvent(0.75); strike_type = SWORDLFT; } else { llStartAnimation(rotleftanim); llSetTimerEvent(0.75); strike_type = SWORDLFT; } } RRight() { if( time <= interval) { llStartAnimation(rotrightanim); llSetTimerEvent(0.75); strike_type = SWORDRGT; } else { llStartAnimation(straferightanim); llSetTimerEvent(0.75); strike_type = SWORDRGT; } } SRight() { if ( time <= interval ) { llStartAnimation(straferightanim); llSetTimerEvent(0.75); strike_type = SWORDRGT; } else { llStartAnimation(rotrightanim); llSetTimerEvent(0.75); strike_type = SWORDRGT; } } //Module 6: The Sword Script //Module 6A: The Default State of the Sword Object When the Script Is First Executed default { //Module 6a: The Sword's Status When the Script is Reset - It Cannot Be Grabbed and Physically Dragged state_entry() { llSetStatus(STATUS_BLOCK_GRAB, TRUE); } //Module 6b: Actions to Take When the Sword is Attached and Detached From the Avatar attach(key on) { if (on != NULL_KEY) { integer perm = llGetPermissions(); if (perm != (PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION)) { llRequestPermissions(on, PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION); } else { llTakeControls(CONTROL_ML_LBUTTON | CONTROL_LBUTTON | CONTROL_UP | CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_RIGHT, TRUE, TRUE); } } else { llSay(0, "releasing controls"); llReleaseControls(); } } //Module 6c: If Permission Has Just Been Given, Take Over Keyboard Functions run_time_permissions(integer perm) { if (perm) { llTakeControls(CONTROL_ML_LBUTTON | CONTROL_LBUTTON | CONTROL_UP | CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_RIGHT | CONTROL_DOWN, TRUE, TRUE); } } //Module 6d: Defining the Keyboard Controls control(key owner, integer held, integer change) { if (held & (CONTROL_ML_LBUTTON | CONTROL_FWD)) { if (change & held & CONTROL_UP) { llApplyImpulse(<0,0,3.5>,FALSE); llStartAnimation(pgupanim); llSetTimerEvent(0.25); strike_type = SPECIALATK; } if (change & held & CONTROL_FWD) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); FStrike(); storedTime = recentTime; } if (change & held & CONTROL_ROT_LEFT) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); SLeft(); storedTime = recentTime; } if (change & held & CONTROL_LEFT) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); RLeft(); storedTime = recentTime; } if (change & held & CONTROL_ROT_RIGHT) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); SRight(); storedTime = recentTime; } if (change & held & CONTROL_RIGHT) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); RRight(); storedTime = recentTime; } if (change & held & CONTROL_BACK) { llStartAnimation(bckanim); llSetTimerEvent(0.25); strike_type = KICK; } } if (~held & change & (CONTROL_ML_LBUTTON | CONTROL_FWD)) { llStopAnimation(pgdwnanim); } if (held & change & CONTROL_DOWN) { llStartAnimation(pgdwnanim); llTriggerSound(swdswing, 1.0); llSetTimerEvent(0.01); strike_type = BLOCK; llMoveToTarget(llGetPos(), 0.25); llSleep(1.0); llStopMoveToTarget(); } if (~held & change & CONTROL_DOWN) { llStopAnimation(pgdwnanim); } } //Module 6e: Actions to Perform When the Timer Event is Triggered timer() { if (strike_type == SWORDFWD) { llTriggerSound(swdswing, 1.0); llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5); } if (strike_type == SWORDRGT) { llTriggerSound(swdswing, 1.0); llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO); } if (strike_type == SWORDLFT) { llTriggerSound(swdswing, 1.0); llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO); } if (strike_type == BLOCK) { llSensor("", "", ACTIVE | AGENT, 2.0, PI_BY_TWO); } if (strike_type == KICK) { llTriggerSound(swdswing, 1.0); llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5); } if (strike_type == SPECIALATK) { llTriggerSound(swdswing, 1.0); llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5); } llSetTimerEvent(0.0); } //Module 6f: Actions to Perform if There's a Valid Target within the Predefined Sensor Range sensor(integer tnum) { vector dir = llDetectedPos(0) - llGetPos(); dir.z = 0.0; dir = llVecNorm(dir); rotation rot = llGetRot(); if (strike_type == SWORDFWD) { llTriggerSound(swdconnectflsh, 1.0); llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE); dir += llRot2Up(rot); dir *= 200.0; llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE); } else if (strike_type == SWORDRGT) { llTriggerSound(swdconnectflsh, 1.0); llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE); dir += dir; dir *= 100.0; llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE); } else if (strike_type == SWORDLFT) { llTriggerSound(swdconnectflsh, 1.0); llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE); dir -= llRot2Left(rot); dir *= 100.0; llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE); } else if (strike_type == KICK) { llTriggerSound(kickconnect, 1.0); dir += dir; dir *= 100.0; llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE); } else if (strike_type == BLOCK) { llTriggerSound(blockconnect, 1.0); } else if (strike_type == SPECIALATK) { llTriggerSound(swdswing, 1.0); llPushObject(llDetectedKey(0), <0,0,150>, ZERO_VECTOR, FALSE); } strike_type= 0; } } Edited February 20 by KeeperS Karu Link to comment Share on other sites More sharing options...
KeeperS Karu Posted February 26 Author Share Posted February 26 Heyla! I've tweaked the script again. Tweak 2 works in conjunction with the draw/sheathe scripts I've made to go with the main melee weapon script. In it, if the user draws their weapon, their weapon becomes active and ready for use. If the user sheathes their weapon, the weapon becomes inactive, releasing controls so the user doesn't accidentally use their weapon when they expect it to be inactive. (I wish I could say that I was brilliant and came up with the code, myself. Instead, it was code I learned while studying the Myriad Lite script-set, a free and open-source combat system. Credit where credit is due.) I'm also including in this post the draw/sheathe scripts for examination and feedback. I am especially hoping for feedback on how to better go about making the sword and hilt visible and invisible when they use PBR materials. Right now, as it stands, it's not very flexible. To become invisible, it removes the PBR material, and to become visible, it adds the specific material back to the weapon. I'm hoping there's an alpha function for PBR materials that I just haven't seen yet. Thanks for reading, and I look forward to your feedback and advice! Keeper S. Karu (KeeperS Karu) The Melee Weapon Script, Tweak #2: //PREAMBLE: Module Names //Module 1: Defining Global String Variables - Animation Names //Module 2: Defining Global String Variables - Sound Effect Names //Module 3: Defining Global String Variables - Bloodsplatter Object Name //Module 4: Defining Global Variables - MISC //Module 4A: Attack Types //Module 4B: Weapon Safety Variables //Module 5: The Safety Functions //Module 5A: Safety On //Module 5B: Safety Off //Module 6: The Double Tap Code //Module 6A: Defining the Double-Tap Global Vairables //Module 6B: Obtaining the Time the Key Was Pressed //Module 6C: Comparing the Time Between Key Presses //Module 6D: Resetting the storedTime Variable //Module 6E: Double Tap //Module 7: The Sword Script //Module 7A: The Default State of the Sword Object When the Script Is First Executed //Module 7a: The Sword's Status When the Script is Reset - It Cannot Be Grabbed and Physically Dragged //Module 7b: Actions to Take When the Sword is Attached and Detached From the Avatar //Module 7c: If Permission Has Been Given, Take Over Keyboard Functions //Module 7d: Is The Safety On? //Module 7e: Defining the Keyboard Controls //Module 7f: Actions to Perform When the Timer Event is Triggered //Module 7g: Actions to Perform if There's a Valid Target within the Predefined Sensor Range //Module 1: Defining Global String Variables - Animation Names string fwdanim = "overhead_strike_exaggerated"; string bckanim = "high_kick"; string rotrightanim = "diagonal_left_strike_exag"; string rotleftanim = "diagonal_right_strike_exag"; string straferightanim = "upward_left_strike_exag"; string strafeleftanim = "upward_right_strike_exag"; string pgdwnanim = "basic_angle_block"; string pgupanim = "backflip"; //Module 2: Defining Global String Variables - Sound Effects Names string swdswing = "swordswing01"; string swdconnectflsh = "sword_flesh_01"; //string block swing; - If different from the other sound effects, enter them, here, as well as in the appropriate area of the code, below string blockconnect = "sword05"; //string kick swing; - If different from the other sound effects, enter them, here, as well as in the appropriate area of the code, below string kickconnect = "Punch04"; //Module 3: Defining Global String Variables - Bloodsplatter Object Name string bloodsplatter = "!bloodsplatter"; //Module 4: Defining Global Variables - MISC //Module 4A: Attack Types integer SWORDFWD = 1; integer SWORDRGT = 2; integer SWORDLFT = 3; integer BLOCK = 4; integer KICK = 5; integer SPECIALATK = 6; integer strike_type; //4Module 4B: Weapon Safety Variables string g_message; integer listen_handle; integer SAFETY_ON = TRUE; //Module 5: The Safety Functions //Module 5A: Safety On SAFETYON() { SAFETY_ON = TRUE; // switch the safety on llSay(0, "releasing controls"); llReleaseControls(); } //Module 5B: Safety Off SAFETYOFF() { SAFETY_ON = FALSE; // switch the safety off llRequestPermissions(llGetOwner(),PERMISSION_TAKE_CONTROLS|PERMISSION_TRIGGER_ANIMATION); // request permissions } //Module 6: The Double Tap Code //Module 6A: Defining the Double-Tap Global Vairables float strTime; float time; float storedTime; float recentTime; string anim = "hover"; float interval = 1.0; //Module 6B: Obtaining the Time the Key Was Pressed getSeconds() { string timestamp = llGetTimestamp(); string subTime = llGetSubString(timestamp, 19, 25); float wallclock = llGetWallclock(); strTime = (float)subTime + wallclock; } //Module 6C: Comparing the Time Between Key Presses compareTimes(float stored, float recent) { time = recent - stored; } //Module 6D: Resetting the storedTime Variable resetStored() { storedTime = 0; } //Module 6E: Double Tap FStrike() { if ( time <= interval | time > interval ) { llStartAnimation(fwdanim); llSetTimerEvent(0.75); strike_type = SWORDFWD; } } BStrike() { if ( time <= interval ) { llStartAnimation(bckanim); llSetTimerEvent(0.25); strike_type = KICK; } else { llStartAnimation(fwdanim); llSetTimerEvent(0.25); strike_type = KICK; } } RLeft() { if ( time <= interval ) { llStartAnimation(rotleftanim); llSetTimerEvent(0.75); strike_type = SWORDLFT; } else { llStartAnimation(strafeleftanim); llSetTimerEvent(0.75); strike_type = SWORDLFT; } } SLeft() { if ( time <= interval ) { llStartAnimation(strafeleftanim); llSetTimerEvent(0.75); strike_type = SWORDLFT; } else { llStartAnimation(rotleftanim); llSetTimerEvent(0.75); strike_type = SWORDLFT; } } RRight() { if( time <= interval) { llStartAnimation(rotrightanim); llSetTimerEvent(0.75); strike_type = SWORDRGT; } else { llStartAnimation(straferightanim); llSetTimerEvent(0.75); strike_type = SWORDRGT; } } SRight() { if ( time <= interval ) { llStartAnimation(straferightanim); llSetTimerEvent(0.75); strike_type = SWORDRGT; } else { llStartAnimation(rotrightanim); llSetTimerEvent(0.75); strike_type = SWORDRGT; } } //Module 7: The Sword Script //Module 7A: The Default State of the Sword Object When the Script Is First Executed default { //Module 7a: The Sword's Status When the Script is Reset - It Cannot Be Grabbed and Physically Dragged state_entry() { llSetStatus(STATUS_BLOCK_GRAB, TRUE); llListenRemove(listen_handle); listen_handle = llListen(5, "", llGetOwner(), ""); } //Module 7b: Actions to Take When the Sword is Attached and Detached From the Avatar attach(key on) { if (on != NULL_KEY) { integer perm = llGetPermissions(); if (perm != (PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION)) { llRequestPermissions(on, PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION); } else { llTakeControls(CONTROL_ML_LBUTTON | CONTROL_LBUTTON | CONTROL_UP | CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_RIGHT, TRUE, TRUE); } } else { llSay(0, "releasing controls"); llReleaseControls(); } } //Module 7c: If Permission Has Just Been Given, Take Over Keyboard Functions run_time_permissions(integer perm) { if (perm) { llTakeControls(CONTROL_ML_LBUTTON | CONTROL_LBUTTON | CONTROL_UP | CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_RIGHT | CONTROL_DOWN, TRUE, TRUE); } } //Module 7d: Is The Safety On? listen(integer channel, string name, key id, string message) { g_message = llToLower(message); if( g_message == "hdraw" ) { SAFETYOFF(); } if( g_message == "sdraw" ) { SAFETYOFF(); } else if(g_message == "hsheathe") { SAFETYON(); } else if(g_message == "ssheathe") { SAFETYON(); } } //Module 7e: Defining the Keyboard Controls control(key owner, integer held, integer change) { if (held & (CONTROL_ML_LBUTTON | CONTROL_FWD)) { if (change & held & CONTROL_UP) { llApplyImpulse(<0,0,3.5>,FALSE); llStartAnimation(pgupanim); llSetTimerEvent(0.25); strike_type = SPECIALATK; } if (change & held & CONTROL_FWD) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); FStrike(); storedTime = recentTime; } if (change & held & CONTROL_ROT_LEFT) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); SLeft(); storedTime = recentTime; } if (change & held & CONTROL_LEFT) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); RLeft(); storedTime = recentTime; } if (change & held & CONTROL_ROT_RIGHT) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); SRight(); storedTime = recentTime; } if (change & held & CONTROL_RIGHT) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); RRight(); storedTime = recentTime; } if (change & held & CONTROL_BACK) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); BStrike(); storedTime = recentTime; } } if (~held & change & (CONTROL_ML_LBUTTON | CONTROL_FWD)) { llStopAnimation(pgdwnanim); } if (held & change & CONTROL_DOWN) { llStartAnimation(pgdwnanim); llTriggerSound(swdswing, 1.0); llSetTimerEvent(0.01); strike_type = BLOCK; llMoveToTarget(llGetPos(), 0.25); llSleep(1.0); llStopMoveToTarget(); } if (~held & change & CONTROL_DOWN) { llStopAnimation(pgdwnanim); } } //Module 7f: Actions to Perform When the Timer Event is Triggered timer() { if (strike_type == SWORDFWD) { llTriggerSound(swdswing, 1.0); llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5); } if (strike_type == SWORDRGT) { llTriggerSound(swdswing, 1.0); llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO); } if (strike_type == SWORDLFT) { llTriggerSound(swdswing, 1.0); llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO); } if (strike_type == BLOCK) { llSensor("", "", ACTIVE | AGENT, 2.0, PI_BY_TWO); } if (strike_type == KICK) { llTriggerSound(swdswing, 1.0); llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5); } if (strike_type == SPECIALATK) { llTriggerSound(swdswing, 1.0); llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5); } llSetTimerEvent(0.0); } //Module 7g: Actions to Perform if There's a Valid Target within the Predefined Sensor Range sensor(integer tnum) { vector dir = llDetectedPos(0) - llGetPos(); dir.z = 0.0; dir = llVecNorm(dir); rotation rot = llGetRot(); if (strike_type == SWORDFWD) { llTriggerSound(swdconnectflsh, 1.0); llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE); dir += llRot2Up(rot); dir *= 200.0; llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE); } else if (strike_type == SWORDRGT) { llTriggerSound(swdconnectflsh, 1.0); llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE); dir += dir; dir *= 100.0; llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE); } else if (strike_type == SWORDLFT) { llTriggerSound(swdconnectflsh, 1.0); llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE); dir -= llRot2Left(rot); dir *= 100.0; llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE); } else if (strike_type == KICK) { llTriggerSound(kickconnect, 1.0); dir += dir; dir *= 100.0; llPushObject(llDetectedKey(0), dir, ZERO_VECTOR, FALSE); } else if (strike_type == BLOCK) { llTriggerSound(blockconnect, 1.0); } else if (strike_type == SPECIALATK) { llTriggerSound(swdswing, 1.0); llPushObject(llDetectedKey(0), <0,0,150>, ZERO_VECTOR, FALSE); } strike_type= 0; } } The Draw/Sheathe Script for the weapon: //PREAMBLE: Module Names //Module 1: Defining Global String Varaibles - Animation Names //Module 2: Defining Global String Variables - Sound Effects Names //Module 3: Defining Global String Variables - String Parameters //Module 4: Defining Global Integer Variable - Integer Parameters //Module 5: The Draw/Sheathe Script //Module 5A: Reset the Script Whenever the Object is Rezzed //Module 5B: Obtain Permission to Animate the Avatar & Listen for Commands From the Avatar //Module 5C: If Permission Has Been Given, Then Letthe Following Conditions Be True //Module 5D: Actions to Take When the Avatar Delivers the Draw and Sheathe Commands Via Chat //Module 5E: Trigger the Sword Draw Sound Effect and Render the Sword Visible or Invisible, As Appropriate //Module 1: Defining Global String Varaibles - Animation Names string hdraw = "hip_draw"; string hsheathe = "hip_sheathe"; string sdraw = "Draw - .7 Seconds"; string ssheathe = "Sheathe - 0.77 Sec"; string stance = "basic_stance"; //Module 2: Defining Global String Variables - Sound Effects Names string sworddraw = "swordraw"; //Module 3: Defining Global String Variables - String Parameters string g_message; //Module 4: Defining Global Integer Variable - Integer Parameters integer listen_handle; integer permissions; //Module 5: The Draw/Sheathe Script default { //Module 5A: Reset the Script Whenever the Object is Rezzed on_rez(integer start_param) { llResetScript(); } //Module 5B: Obtain Permission to Animate the Avatar & Listen for Commands From the Avatar state_entry() { if( llGetAttached() ); { llRequestPermissions(llGetOwner(), PERMISSION_TRIGGER_ANIMATION); } llListenRemove(listen_handle); listen_handle = llListen(5, "", llGetOwner(), ""); } //Module 5C: If Permission Has Been Given, Then Let The Following Conditions Be True run_time_permissions(integer perms) { if( perms & PERMISSION_TRIGGER_ANIMATION ) { permissions = TRUE; } } //Module 5D: Actions to Take When the Avatar Delivers the Draw and Sheathe Commands Via Chat listen(integer channel, string name, key id, string message) { g_message = llToLower(message); if( g_message == "hdraw" ) { if(permissions) { llStartAnimation(hdraw); llStartAnimation(stance); llSetTimerEvent(0.25); } } if( g_message == "sdraw" ) { if(permissions) { llStartAnimation(sdraw); llStartAnimation(stance); llSetTimerEvent(0.25); } } else if(g_message == "hsheathe") { if(permissions) { llStartAnimation(hsheathe); llStopAnimation(stance); llSetTimerEvent(0.75); } } else if(g_message == "ssheathe") { if(permissions) { llStartAnimation(ssheathe); llStopAnimation(stance); llSetTimerEvent(0.75); } } } //Module 5E: Trigger the Sword Draw Sound Effect and Render the Sword Visible or Invisible, As Appropriate timer() { if( g_message == "hdraw") { if( permissions ) { llTriggerSound(sworddraw, 1.0); llSetLinkAlpha(LINK_SET,1.0, ALL_SIDES); llSetPrimitiveParams([PRIM_RENDER_MATERIAL, ALL_SIDES, "Texture UUID Here"]); } } if( g_message == "sdraw") { if( permissions ) { llTriggerSound(sworddraw, 1.0); llSetLinkAlpha(LINK_SET,1.0, ALL_SIDES); llSetPrimitiveParams([PRIM_RENDER_MATERIAL, ALL_SIDES, "Texture UUID Here"]); } } else if( g_message == "hsheathe") { if( permissions ) { llTriggerSound(sworddraw, 1.0); llSetLinkAlpha(LINK_SET,0, ALL_SIDES); llSetPrimitiveParams([PRIM_RENDER_MATERIAL, ALL_SIDES, NULL_KEY]); } } else if( g_message == "ssheathe") { if( permissions ) { llTriggerSound(sworddraw, 1.0); llSetLinkAlpha(LINK_SET,0, ALL_SIDES); llSetPrimitiveParams([PRIM_RENDER_MATERIAL, ALL_SIDES, NULL_KEY]); } } llSetTimerEvent(0); } } The Draw/Sheathe Script for the Sheath: //PREAMBLE: Module Names //Module 1: Defining Global String Variables - String Parameters //Module 2: Defining Global Integer Variable - Integer Parameters //Module 3: The Draw/Sheathe Script //Module 3A: Reset the Script Whenever the Object is Rezzed //Module 3B: Listen for Commands From the Avatar //Module 3C: Actions to Take When the Avatar Delivers the Draw and Sheathe Commands Via Chat //Module 3D: Trigger the Sword Draw Sound Effect and Render the Sword Visible or Invisible, As Appropriate //Module 1: Defining Global String Variables - String Parameters string g_message; //Module 2: Defining Global Integer Variable - Integer Parameters integer listen_handle; //Module 3: The Draw/Sheathe Script default { //Module 3A: Reset the Script Whenever the Object is Rezzed on_rez(integer start_param) { llResetScript(); } //Module 3B: Listen for Commands From the Avatar state_entry() { llListenRemove(listen_handle); listen_handle = llListen(5, "", llGetOwner(), ""); } //Module 3C: Actions to Take When the Avatar Delivers the Draw and Sheathe Commands Via Chat listen(integer channel, string name, key id, string message) { g_message = llToLower(message); if(g_message == "hdraw") { llSetTimerEvent(0.25); } if(g_message == "sdraw") { llSetTimerEvent(0.25); } else if(g_message == "hsheathe") { llSetTimerEvent(0.75); } else if(g_message == "ssheathe") { llSetTimerEvent(0.75); } } //Module 3D: Render the Sword Hilt Visible or Invisible, As Appropriate timer() { if( g_message == "hdraw" ) { llSetAlpha(0.0, ALL_SIDES); llSetPrimitiveParams([PRIM_RENDER_MATERIAL, ALL_SIDES, NULL_KEY]); } if( g_message == "sdraw" ) { llSetAlpha(0.0, ALL_SIDES); llSetPrimitiveParams([PRIM_RENDER_MATERIAL, ALL_SIDES, NULL_KEY]); } else if( g_message == "hsheathe" ) { llSetAlpha(1.0, ALL_SIDES); llSetPrimitiveParams([PRIM_RENDER_MATERIAL, 1, "Texture UUID Here"]); llSetPrimitiveParams([PRIM_RENDER_MATERIAL, 2, "Texture UUID Here"]); llSetPrimitiveParams([PRIM_RENDER_MATERIAL, 3, "Texture UUID Here"]); llSetPrimitiveParams([PRIM_RENDER_MATERIAL, 4, "Texture UUID Here"]); } else if( g_message == "ssheathe" ) { llSetAlpha(1.0, ALL_SIDES); llSetPrimitiveParams([PRIM_RENDER_MATERIAL, 1, "Texture UUID Here"]); llSetPrimitiveParams([PRIM_RENDER_MATERIAL, 2, "Texture UUID Here"]); llSetPrimitiveParams([PRIM_RENDER_MATERIAL, 3, "Texture UUID Here"]); llSetPrimitiveParams([PRIM_RENDER_MATERIAL, 4, "Texture UUID Here"]); } llSetTimerEvent(0); } } Link to comment Share on other sites More sharing options...
PheebyKatz Posted February 28 Share Posted February 28 (edited) I've never had to get that involved with a melee weapon. This all looks a lot like someone taking Aley's old pirate sword script and trying to make it into a working weapon, instead of a theatrical prop (I did this myself years ago, so yeah, looks reeeeally familiar). Lightsabers tend to be made this way, too. When I decided to make melee weapons, I just made them shoot people with invisible bullets, timed to die at close range. As for using a sensor, I'd use that to message the opponent when hit, and tell the meter (if using one) that they've been hit (if it works that way). Pushing is unreliable. And pushing them across the sim is probably a bit unreasonable. As for left clicking and arrow keys, I'm used to that being how you use a sword outside of Mouselook, not in it. Also, the misspellings in the listen section of your draw/sheath script will cause it to malfunction. Hope it helps. Edited February 28 by PheebyKatz Link to comment Share on other sites More sharing options...
KeeperS Karu Posted February 28 Author Share Posted February 28 Thank you, very much, for your feedback. Yeah. I've been playing around with the old freebie swordfighting script for years. It's the basis of the script. I've had this script since I started SL in 2008. lol Where are the misspellings in the draw/sheathe script? I'll get those sorted. Yeah. Like I said, for the most part, I've been trying to figure out a third person control scheme that works well while in Third Person Mode. Having to left click and use the movement keys (I use WASD for movement) takes away the ability to use Mouse Steering, which makes moving the avie awkward. I wanted a control scheme that lets you use Mouse Steering while activating the sword strikes in a way that feels comfortable for most players. I'm eager to see what people think of the control scheme. I'm not sure how I feel about the bullet system for melee weapons. I've played with a few that used it. Not quite sure how I felt about it. But I'll definitely consider it. As for pushing, yeah. That's just something that never got changed, as I was focused on the controls, rather than the means of dealing actual damage. I'll be honest, I've been more focused on the controls than in the combat system as a whole. lol! I know I'm not good enough to put together a *real* combat system. I just want to see if I can set up a control scheme that people like and are willing to incorporate into their own combat systems. If I could participate in combat using others' systems, that'd be great. As it stands, it's all Mouselook, which, due to reasons, means I can't participate in the combat. Hence why I've been scratching my head trying to think of a system that will work well in Third Person. I really, really hope that people like the control scheme, or better yet, help me improve on it so it's comfortable for most people to use in Third Person! Link to comment Share on other sites More sharing options...
PheebyKatz Posted March 5 Share Posted March 5 (edited) Using a short-range sensor is probably fine, as long as it can communicate somehow with any combat meter you might want to employ. I just have my stuff message them on a negative-numbered channel (to avoid snooping/cheating), and tell the meter they've been hit. Of course, I made the meter to go with it, so it'd always work. As for invisible bullets, think like a slat of board being thrown at them, that dies on contact, or by the time it's gone out of melee range, whichever comes sooner. Not naming any names, but a lot of fantasy combat sword makers use this approach. I'd love to see it just come down to having the weapon touch the opponent and registering hits, but attachments are all phantom, just to keep people from getting their eyes poked out at marshmallow roasts and stuff. ^-^; And despite my edging on snarky with my first reply, because I was like, why is it this old thing again, I agree that making it do what you want is a worthy goal. Even if you end up not liking it as much as the way it worked before, you tried and made it go. And besides, it could actually turn out to be a big improvement. So yeah, keep us updated and stuff! Edited March 5 by PheebyKatz Link to comment Share on other sites More sharing options...
KeeperS Karu Posted March 9 Author Share Posted March 9 On 3/4/2024 at 9:54 PM, PheebyKatz said: Using a short-range sensor is probably fine, as long as it can communicate somehow with any combat meter you might want to employ. I just have my stuff message them on a negative-numbered channel (to avoid snooping/cheating), and tell the meter they've been hit. Of course, I made the meter to go with it, so it'd always work. As for invisible bullets, think like a slat of board being thrown at them, that dies on contact, or by the time it's gone out of melee range, whichever comes sooner. Not naming any names, but a lot of fantasy combat sword makers use this approach. I'd love to see it just come down to having the weapon touch the opponent and registering hits, but attachments are all phantom, just to keep people from getting their eyes poked out at marshmallow roasts and stuff. ^-^; And despite my edging on snarky with my first reply, because I was like, why is it this old thing again, I agree that making it do what you want is a worthy goal. Even if you end up not liking it as much as the way it worked before, you tried and made it go. And besides, it could actually turn out to be a big improvement. So yeah, keep us updated and stuff! Well, I hadn't intended to build a whole combat system. Like I said, I was just trying to see if the controls feel okay enough in Third Person Mode for others to adopt the control scheme in their systems. I like the idea of SL combat, but it's all done in First Person, and I can't really do First Person. While the combat system supposedly works in Third Person, the problem is that the strikes are activated by holding down the left mouse button along with the directional keys. This takes away the ability to use Mouse Steering (where you left click on your avatar and drag the mouse left and right to rotate it), which is essential for smooth navigation in Third Person. So my hope is to come up with a control scheme that works in Third Person and lets you use Mouse Steering while still activating the strikes. I'm hoping people like this enough to want to see it in popular combat systems. Link to comment Share on other sites More sharing options...
ItHadToComeToThis Posted March 10 Share Posted March 10 22 hours ago, KeeperS Karu said: Well, I hadn't intended to build a whole combat system. Like I said, I was just trying to see if the controls feel okay enough in Third Person Mode for others to adopt the control scheme in their systems. I like the idea of SL combat, but it's all done in First Person, and I can't really do First Person. While the combat system supposedly works in Third Person, the problem is that the strikes are activated by holding down the left mouse button along with the directional keys. This takes away the ability to use Mouse Steering (where you left click on your avatar and drag the mouse left and right to rotate it), which is essential for smooth navigation in Third Person. So my hope is to come up with a control scheme that works in Third Person and lets you use Mouse Steering while still activating the strikes. I'm hoping people like this enough to want to see it in popular combat systems. I make all my melee work via left click in general that Includes both standard and mouse look clicking. A good method I found was to use gestures. Use left click for your base rotation of moves and use gestures to activate more complex attacks on your next click. If you really want to do multi key combos. I posted something a while back that was a VERY rough draft of exactly that. I managed to achieve quite a significant number of combinations and there were still more that could be done. If you go back through this forum you will find it. It’s very rough though and not even remotely polished. More of code dump brain storming session. If you wanted avoid sensors and raycast. You could use llGetRegionList. Then loop through and detect how many avatars are around you, and how many of those are in front of you within X angle. It works just as well as a sensor and just as quickly. 1 Link to comment Share on other sites More sharing options...
Quistess Alpha Posted March 10 Share Posted March 10 49 minutes ago, ItHadToComeToThis said: [llGetRegionList] It works just as well as a sensor and just as quickly. llGetRegionList returns up to 100 avatars, in no sensible order; Sensor only up to 20 or so, and sorted by distance. In the (extremely unlikely) case that there are over 100 agents in the region, you may fail to find one even if it's right in front of you. Link to comment Share on other sites More sharing options...
ItHadToComeToThis Posted March 10 Share Posted March 10 (edited) 15 minutes ago, Quistess Alpha said: llGetRegionList returns up to 100 avatars, in no sensible order; Sensor only up to 20 or so, and sorted by distance. In the (extremely unlikely) case that there are over 100 agents in the region, you may fail to find one even if it's right in front of you. This works pretty well each time, iv used it in a system in the past. I was trying to achieve it a number of years ago, and managed to get quite far, but was unsure of how to calculate the angle as it wasn't something I had done before in this way. @Rolig Loon was kind enough to help me figure it out at the time. Though I do get what you are saying about +100 avatars, you would need to figure out a way to factor that in if possible. avatarInFront(){ list avatars=llGetAgentList(AGENT_LIST_REGION,[]); integer i=-1; while(++i<llGetListLength(avatars)){ list temp=llGetObjectDetails((key)llList2String(avatars,i),[OBJECT_POS]); vector myPos=llGetPos(); vector avdir=llVecNorm((vector)llList2String(temp,0)-myPos); vector lookdir=llRot2Fwd(llGetRot()); float dp=avdir*lookdir; if(RAD_TO_DEG*llAcos(dp)<45.0){ if((key)llList2String(avatars,i)!=llGetOwner()){ if(llVecDist(myPos,(vector)llList2String(temp,0))<2){ llOwnerSay("Found Avatar : "+llKey2Name(llList2Key(avatars,i))); } } } } } default{ touch_start(integer x){ avatarInFront(); } } Edited March 10 by ItHadToComeToThis 1 Link to comment Share on other sites More sharing options...
KeeperS Karu Posted March 10 Author Share Posted March 10 2 hours ago, ItHadToComeToThis said: I make all my melee work via left click in general that Includes both standard and mouse look clicking. A good method I found was to use gestures. Use left click for your base rotation of moves and use gestures to activate more complex attacks on your next click. If you really want to do multi key combos. I posted something a while back that was a VERY rough draft of exactly that. I managed to achieve quite a significant number of combinations and there were still more that could be done. If you go back through this forum you will find it. It’s very rough though and not even remotely polished. More of code dump brain storming session. If you wanted avoid sensors and raycast. You could use llGetRegionList. Then loop through and detect how many avatars are around you, and how many of those are in front of you within X angle. It works just as well as a sensor and just as quickly. Hm. How'd you solve the problem of needing Mouse Steering at the same time of needing to Left Click? Because the way it's described, you have to stop Mouse Steering in order to make the attack, and the opponent could have already moved away by the time you attack, and you can't react fast enough to go back to Mouse Steering. Link to comment Share on other sites More sharing options...
PheebyKatz Posted March 12 Share Posted March 12 This thread has officially raised my Spock eyebrow now. I will be watching. Link to comment Share on other sites More sharing options...
KeeperS Karu Posted March 12 Author Share Posted March 12 (edited) You know, I just realized I'm making a big assumption here. I've talked to at least 4 friends recently and found out that, after all these years, they didn't know that Avatar Mouse Steering was a thing. So for people who may not know what in the world I'm referring to, Avatar Mouse Steering is the following: A quick thing I'd like to share: Avatar Mouse Steering works if you left click and hold on your avatar name tag. So if you have things on you that you might end up clicking if you clicked directly on your avatar, click your name tag instead. If you find you need your name tag to be higher, you can set your name tag higher above you by going (on Firestorm, at least) to Preferences-->Colors-->Name Tags-->Name Tag Z-Offset. Edited March 12 by KeeperS Karu 1 Link to comment Share on other sites More sharing options...
Bleuhazenfurfle Posted March 13 Share Posted March 13 16 hours ago, KeeperS Karu said: A quick thing I'd like to share: Avatar Mouse Steering works if you left click and hold on your avatar name tag. So if you have things on you that you might end up clicking if you clicked directly on your avatar, click your name tag instead. If you find you need your name tag to be higher, you can set your name tag higher above you by going (on Firestorm, at least) to Preferences-->Colors-->Name Tags-->Name Tag Z-Offset. Damn. Knew about mouse steering, but I'd forgotten the nametag thing, so haven't been using it — with a tail, wings, and long hair, finding a clear spot for that mouse steering can be a little tricky… I also keep forgetting you have to click on the avatar (because a game I been playing a bit lately uses it, too, a but a little differently), and accidentally selecting some random pie menu option. Haven't, like, accidentally deleted or returned a friends house yet, or anything, but, I'm rueing the day… (Is that even how that word works? meh, nvm) Link to comment Share on other sites More sharing options...
PheebyKatz Posted March 13 Share Posted March 13 (edited) Okay, the nametag thingy is super neato. I get it now. I've never seen combat stuff made with that in mind, like, at all. That I know of. When you get this working in anything like a satisfactory fashion, please let us know how you made it go. Even if it's just adding a different key to press in the control event or something, to trigger the attack/strike. This sort of thing is waaay up my alley, and I would love to see it work. Make it so that it's optional, and can be switched from "normal" mode to mouse steering mode, and I bet you five bucks it catches on somewhere out there. It's a neato idea, and a worthy project, IMO. Edited March 13 by PheebyKatz Link to comment Share on other sites More sharing options...
KeeperS Karu Posted March 13 Author Share Posted March 13 2 hours ago, PheebyKatz said: Okay, the nametag thingy is super neato. I get it now. I've never seen combat stuff made with that in mind, like, at all. That I know of. When you get this working in anything like a satisfactory fashion, please let us know how you made it go. Even if it's just adding a different key to press in the control event or something, to trigger the attack/strike. This sort of thing is waaay up my alley, and I would love to see it work. Make it so that it's optional, and can be switched from "normal" mode to mouse steering mode, and I bet you five bucks it catches on somewhere out there. It's a neato idea, and a worthy project, IMO. Ah! Okay! I'll work on it being an optional mode! Right now, things operate so that holding down the forward key in combination with the other directional keys will activate the strikes. I actually like it and find it super comfortable. I decided against using the crouch or jump keys because I wanted to have those available. The crouch key is usually used for blocking, and I want to give my players the ability to jump when they need to. So that left the forward key, and things worked out pretty well. I'm comfortable with it. Now, I'm just trying to see if others are comfortable with it. Link to comment Share on other sites More sharing options...
KeeperS Karu Posted April 16 Author Share Posted April 16 Okay. So I discovered some flaws in my draw/sheathe scripts. The alphas weren't being applied correctly. Fixed the problem I was having, so here are the scripts. The Draw/Sheathe Script For the Sheath: //PREAMBLE: Module Names //Module 1: Defining Global String Variables - String Parameters //Module 2: Defining Global Integer Variable - Integer Parameters //Module 3: The Draw/Sheathe Script //Module 3A: Reset the Script Whenever the Object is Rezzed //Module 3B: Listen for Commands From the Avatar //Module 3C: Actions to Take When the Avatar Delivers the Draw and Sheathe Commands Via Chat //Module 3D: Trigger the Sword Draw Sound Effect and Render the Sword Visible or Invisible, As Appropriate //Module 1: Defining Global String Variables - String Parameters string g_message; //Module 2: Defining Global Integer Variable - Integer Parameters integer listen_handle; //Module 3: The Draw/Sheathe Script default { //Module 3A: Reset the Script Whenever the Object is Rezzed on_rez(integer start_param) { llResetScript(); } //Module 3B: Listen for Commands From the Avatar state_entry() { llListenRemove(listen_handle); listen_handle = llListen(5, "", llGetOwner(), ""); } //Module 3C: Actions to Take When the Avatar Delivers the Draw and Sheathe Commands Via Chat listen(integer channel, string name, key id, string message) { g_message = llToLower(message); if(g_message == "hdraw") { llSetTimerEvent(0.25); } if(g_message == "sdraw") { llSetTimerEvent(0.25); } else if(g_message == "hsheathe") { llSetTimerEvent(0.75); } else if(g_message == "ssheathe") { llSetTimerEvent(0.75); } } //Module 3D: Render the Sword Hilt Visible or Invisible, As Appropriate timer() { if( g_message == "hdraw" ) { llSetAlpha(0.0, ALL_SIDES); llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, ALL_SIDES, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 0, 1, 1, 0]); } if( g_message == "sdraw" ) { llSetAlpha(0.0, ALL_SIDES); llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, ALL_SIDES, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 0, 1, 1, 0]); } else if( g_message == "hsheathe" ) { llSetAlpha(1.0, 1); llSetAlpha(1.0, 2); llSetAlpha(1.0, 3); llSetAlpha(1.0, 4); llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 1, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]); llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 2, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]); llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 3, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]); llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 4, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]); } else if( g_message == "ssheathe" ) { llSetAlpha(1.0, 1); llSetAlpha(1.0, 2); llSetAlpha(1.0, 3); llSetAlpha(1.0, 4); llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 1, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]); llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 2, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]); llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 3, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]); llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 4, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]); } llSetTimerEvent(0); } } And here's the Draw/Sheathe Script for the Melee Weapon: //PREAMBLE: Module Names //Module 1: Defining Global String Variables - String Parameters //Module 2: Defining Global Integer Variable - Integer Parameters //Module 3: The Draw/Sheathe Script //Module 3A: Reset the Script Whenever the Object is Rezzed //Module 3B: Listen for Commands From the Avatar //Module 3C: Actions to Take When the Avatar Delivers the Draw and Sheathe Commands Via Chat //Module 3D: Trigger the Sword Draw Sound Effect and Render the Sword Visible or Invisible, As Appropriate //Module 1: Defining Global String Variables - String Parameters string g_message; //Module 2: Defining Global Integer Variable - Integer Parameters integer listen_handle; //Module 3: The Draw/Sheathe Script default { //Module 3A: Reset the Script Whenever the Object is Rezzed on_rez(integer start_param) { llResetScript(); } //Module 3B: Listen for Commands From the Avatar state_entry() { llListenRemove(listen_handle); listen_handle = llListen(5, "", llGetOwner(), ""); } //Module 3C: Actions to Take When the Avatar Delivers the Draw and Sheathe Commands Via Chat listen(integer channel, string name, key id, string message) { g_message = llToLower(message); if(g_message == "hdraw") { llSetTimerEvent(0.25); } if(g_message == "sdraw") { llSetTimerEvent(0.25); } else if(g_message == "hsheathe") { llSetTimerEvent(0.75); } else if(g_message == "ssheathe") { llSetTimerEvent(0.75); } } //Module 3D: Render the Sword Hilt Visible or Invisible, As Appropriate timer() { if( g_message == "hdraw" ) { llSetAlpha(0.0, ALL_SIDES); llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, ALL_SIDES, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 0, 1, 1, 0]); } if( g_message == "sdraw" ) { llSetAlpha(0.0, ALL_SIDES); llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, ALL_SIDES, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 0, 1, 1, 0]); } else if( g_message == "hsheathe" ) { llSetAlpha(1.0, 1); llSetAlpha(1.0, 2); llSetAlpha(1.0, 3); llSetAlpha(1.0, 4); llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 1, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]); llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 2, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]); llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 3, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]); llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 4, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]); } else if( g_message == "ssheathe" ) { llSetAlpha(1.0, 1); llSetAlpha(1.0, 2); llSetAlpha(1.0, 3); llSetAlpha(1.0, 4); llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 1, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]); llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 2, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]); llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 3, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]); llSetPrimitiveParams([PRIM_GLTF_BASE_COLOR, 4, "", <1,1,1>, ZERO_VECTOR, 0, <1,1,1>, 1, 0, 1, 0]); } llSetTimerEvent(0); } } Haven't fiddled with the main melee weapon script in a while. Link to comment Share on other sites More sharing options...
KeeperS Karu Posted April 21 Author Share Posted April 21 All righty! Thanks to help from someone (I need to ask them permission to mention them specifically), I was able to modify the melee weapon script so that by clicking the weapon, the player can choose which control scheme they want to use: Standard or mine. Here's the modified script. As usual, I'd love for some feedback on it. Eventually, I'm going to ask questions on what it means to "optimize" a script and how I can go about doing that for this script. But right now, I want to make sure it all works the way it's supposed to. And if it does, is there a better way to approach the situation? I have a way of complicating things more than they need to be. //PREAMBLE: Module Names //Module 1: Defining Global String Variables - Animation Names //Module 2: Defining Global String Variables - Sound Effect Names //Module 3: Defining Global String Variables - Bloodsplatter Object Name //Module 4: Defining Global Variables - MISC //Module 4A: Attack Types //Module 4B: Weapon Safety Variables //Module 4C: Weapon Control Scheme Variables //Module 5: The Safety & Release/Reset Functions //Module 5A: Safety On //Module 5B: Safety Off //Module 5C: Release Controls and Reset Script //Module 6: The Double Tap Code //Module 6A: Defining the Double-Tap Global Vairables //Module 6B: Obtaining the Time the Key Was Pressed //Module 6C: Comparing the Time Between Key Presses //Module 6D: Resetting the storedTime Variable //Module 6E: Double Tap //Module 7: The Sword Script //Module 7A: The Default State of the Sword Object When the Script Is First Executed //Module 7Aa: The Sword's Status When the Script is Reset - It Cannot Be Grabbed and Physically Dragged; Instruct Owner To Touch Sword For Options //Module 7Ab: Touch Weapon To Choose Control Scheme //Module 7Ac: Actions to Take When the Sword is Attached and Detached From the Avatar //Module 7Ad: If Permission Has Been Given, Take Over Keyboard Functions //Module 7Ae: Menu Choices //Module 7Af: Actions to Perform When the Timer Event is Triggered //Module 7B: When In The Keeper State, Use Keeper's Third Person Control Scheme //Module 7Ba: Actions To Take When The Weapon Is Attached/Detached //Module 7Bb: Preliminary Actions On Entering State //Module 7Bc: What To Do When The Weapon Is Drawn & Sheathed //Module 7Bd: The Control Scheme, Keeper's Third Person //Module 7Be: What To Do When The Object Changes Owner //Module 7C: When In State Standard, Use Standard Control Scheme //Module 7Ca: Actions To Take When The Weapon Is Attached/Detached //Module 7Cb: Preliminary Actions On Entering State //Module 7Cc: What To Do When The Weapon Is Drawn & Sheathed //Module 7Cd: The Control Scheme, Standard Controls //Module 7Ce: What To Do When The Object Changes Owner //Module 7D: What To Do When When The Weapon Controls Are Used //Module 7Da: Setting The Timers //Module 7Db: What Happens When The Timers Go Off //Module 7Dc: Actions to Perform if There's a Valid Target within the Predefined Sensor Range //Module 7Dd: Actions To Take When There Is No Target Within Range //Module 1: Defining Global String Variables - Animation Names string fwdanim = "overhead_strike_exaggerated P6"; string bckanim = "high_kick P6"; string rotrightanim = "diagonal_left_strike_exag P6"; string rotleftanim = "diagonal_right_strike_exag P6"; string straferightanim = "upward_left_strike_exag"; string strafeleftanim = "upward_right_strike_exag"; string pgdwnanim = "basic_angle_block"; string pgupanim = "backflip"; //Module 2: Defining Global String Variables - Sound Effects Names string swdswing = "swordswing01"; string swdconnectflsh = "sword_flesh_01"; //string block swing; - If different from the other sound effects, enter them, here, as well as in the appropriate area of the code, below string blockconnect = "sword05"; //string kick swing; - If different from the other sound effects, enter them, here, as well as in the appropriate area of the code, below string kickconnect = "Punch04"; //Module 3: Defining Global String Variables - Bloodsplatter Object Name string bloodsplatter = "!bloodsplatter"; //Module 4: Defining Global Variables - MISC //Module 4A: Attack Types integer SWORDFWD = 1; integer SWORDRGT = 2; integer SWORDLFT = 3; integer BLOCK = 4; integer KICK = 5; integer SPECIALATK = 6; integer strike_type; //Module 4B: Weapon Safety Variables string g_message; integer listen_handle; integer SAFETY_ON = TRUE; integer perm; //Module 4C: Weapon Control Scheme Variables integer gListener; string menuText = "\nChoose the movement controls you wish to use."; // you can change this to say whatever you want list menuButtons = ["Keeper","Standard","Cancel"]; // these are the buttons that will appear in the menu, you can change these integer menuChan; // channel that the dialog box talks on, will make this some large random negative number later on integer menuUsed = FALSE; integer KeeperS = FALSE; integer standardS = FALSE; //Module 5: The Safety & Release/Reset Functions //Module 5A: Safety On SAFETYON() { SAFETY_ON = TRUE; // switch the safety on llSay(0, "releasing controls"); llReleaseControls(); } //Module 5B: Safety Off SAFETYOFF() { SAFETY_ON = FALSE; // switch the safety off llRequestPermissions(llGetOwner(),PERMISSION_TAKE_CONTROLS|PERMISSION_TRIGGER_ANIMATION); // request permissions integer perm = llGetPermissions(); if (perm != (PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION)) { llRequestPermissions(llGetOwner(),PERMISSION_TAKE_CONTROLS|PERMISSION_TRIGGER_ANIMATION); // request permissions } else { llTakeControls(CONTROL_ML_LBUTTON | CONTROL_LBUTTON | CONTROL_UP | CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_RIGHT, TRUE, TRUE); } } //Module 5C: Release Controls and Reset Script ReleaseReset() { llSay(0, "releasing controls"); llReleaseControls(); llResetScript(); } //Module 6: The Double Tap Code //Module 6A: Defining the Double-Tap Global Vairables float strTime; float time; float storedTime; float recentTime; float interval = 1.25; //Module 6B: Obtaining the Time the Key Was Pressed getSeconds() { string timestamp = llGetTimestamp(); string subTime = llGetSubString(timestamp, 19, 25); float wallclock = llGetWallclock(); strTime = (float)subTime + wallclock; } //Module 6C: Comparing the Time Between Key Presses compareTimes(float stored, float recent) { time = recent - stored; } //Module 6D: Resetting the storedTime Variable resetStored() { storedTime = 0; } //Module 6E: Double Tap FStrike() { if (KeeperS == TRUE) { if ( time <= interval | time > interval ) { llStartAnimation(fwdanim); strike_type = SWORDFWD; } } else if (standardS = TRUE) { llStartAnimation(fwdanim); strike_type = SWORDFWD; } } BStrike() { if ( time >= interval ) { llStartAnimation(bckanim); strike_type = KICK; } else { llStartAnimation(fwdanim); strike_type = KICK; } } RLeft() { if ( time <= interval ) { llStartAnimation(rotleftanim); strike_type = SWORDLFT; } else { llStartAnimation(strafeleftanim); strike_type = SWORDLFT; } } SLeft() { if ( time <= interval ) { llStartAnimation(strafeleftanim); strike_type = SWORDLFT; } else { llStartAnimation(rotleftanim); strike_type = SWORDLFT; } } RRight() { if( time <= interval) { llStartAnimation(rotrightanim); strike_type = SWORDRGT; } else { llStartAnimation(straferightanim); strike_type = SWORDRGT; } } SRight() { if ( time <= interval ) { llStartAnimation(straferightanim); strike_type = SWORDRGT; } else { llStartAnimation(rotrightanim); strike_type = SWORDRGT; } } //Module 7: The Sword Script //Module 7A: The Default State of the Sword Object When the Script Is First Executed default { //Module 7Aa: The Sword's Status When the Script is Reset - It Cannot Be Grabbed and Physically Dragged; Instruct Owner To Touch Sword For Options state_entry() { llSetStatus(STATUS_BLOCK_GRAB, TRUE); llOwnerSay("Touch the weapon to choose which movement controls you would like to use."); } //Module 7Ab: Touch Weapon To Choose Control Scheme touch_end(integer num_detected) { menuChan = (integer)(llFrand(999999.0) * -1); // this just comes up with some big random negative number to use as the channel for the menu to work on llListenRemove(gListener); gListener = llListen(menuChan,"",llGetOwner(),""); llDialog(llGetOwner(),menuText,menuButtons,menuChan); llSetTimerEvent(30.0); // just in case the person does not make a selection after clicking the weapon } //Module 7Ac: Actions to Take When the Sword is Attached and Detached From the Avatar attach(key on) { if (on != NULL_KEY) { integer perm = llGetPermissions(); if (perm != (PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION)) { llRequestPermissions(on, PERMISSION_TAKE_CONTROLS | PERMISSION_TRIGGER_ANIMATION); } else { llTakeControls(CONTROL_ML_LBUTTON | CONTROL_LBUTTON | CONTROL_UP | CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_RIGHT, TRUE, TRUE); } } else { //llSay(0, "releasing controls"); //llReleaseControls(); ReleaseReset(); } } //Module 7Ad: If Permission Has Just Been Given, Take Over Keyboard Functions run_time_permissions(integer perm) { if (perm) { llTakeControls(CONTROL_ML_LBUTTON | CONTROL_LBUTTON | CONTROL_UP | CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_ROT_RIGHT | CONTROL_DOWN, TRUE, TRUE); } } //Module 7Ae: Menu Choices listen(integer channel, string name, key id, string message) { if(channel == menuChan) { if(message == "Cancel") // give the user an opportunity to cancel out of the menu { menuUsed = TRUE; return; } if(message == "Keeper") // if you change what the button name is on line 3, change this to match { menuUsed = TRUE; state Keeper; // go to the keeper state } if(message == "Standard") // if you change what the button name is on line 3, change this to match { menuUsed = TRUE; state standard; // go to the 'usual' movement state } } } //Module 7Af: Actions to Perform When the Timer Event is Triggered timer() { if (menuUsed == TRUE) { } else { llListenRemove(gListener); llResetScript(); } llSetTimerEvent(0.0); } } //Module 7B: When In The Keeper State, Use Keeper's Third Person Control Scheme state Keeper { //Module 7Ba: Actions To Take When The Weapon Is Attached/Detached attach (key on) { if(on) { } else { ReleaseReset(); } } //Module 7Bb: Preliminary Actions On Entering State state_entry() { llListenRemove(listen_handle); listen_handle = llListen(5, "", llGetOwner(), ""); SAFETYOFF(); KeeperS = TRUE; } //Module 7Bc: What To Do When The Weapon Is Drawn & Sheathed listen(integer channel, string name, key id, string message) { if(channel == 5) { g_message = llToLower(message); if( g_message == "hdraw" ) { SAFETYOFF(); } if( g_message == "sdraw" ) { SAFETYOFF(); } else if(g_message == "hsheathe") { SAFETYON(); } else if(g_message == "ssheathe") { SAFETYON(); } } } //Module 7Bd: The Control Scheme, Keeper's Third Person control(key owner, integer held, integer change) { if (held & (CONTROL_ML_LBUTTON | CONTROL_FWD)) { if (change & held & CONTROL_UP) { llApplyImpulse(<0,0,3.5>,FALSE); llStartAnimation(pgupanim); strike_type = SPECIALATK; state WeaponStrike; } if (change & held & CONTROL_FWD) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); storedTime = recentTime; FStrike(); state WeaponStrike; } if (change & held & CONTROL_ROT_LEFT) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); storedTime = recentTime; SLeft(); state WeaponStrike; } if (change & held & CONTROL_LEFT) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); storedTime = recentTime; RLeft(); state WeaponStrike; } if (change & held & CONTROL_ROT_RIGHT) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); storedTime = recentTime; SRight(); state WeaponStrike; } if (change & held & CONTROL_RIGHT) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); storedTime = recentTime; RRight(); state WeaponStrike; } if (change & held & CONTROL_BACK) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); storedTime = recentTime; BStrike(); state WeaponStrike; } } if (~held & change & (CONTROL_ML_LBUTTON | CONTROL_FWD)) { llStopAnimation(pgdwnanim); } if (held & change & CONTROL_DOWN) { llStartAnimation(pgdwnanim); llTriggerSound(swdswing, 1.0); llSetTimerEvent(0.01); strike_type = BLOCK; llMoveToTarget(llGetPos(), 0.25); llSleep(1.0); llStopMoveToTarget(); } if (~held & change & CONTROL_DOWN) { llStopAnimation(pgdwnanim); } } //Module 7Be: What To Do When The Object Changes Owner changed(integer change) { if(change & CHANGED_OWNER) // reset the script when a new person owns the weapon { llResetScript(); } } } //Modeul 7C: When In State Standard, Use Standard Control Scheme state standard { //Module 7Ca: Actions To Take When The Weapon Is Attached/Detached attach (key on) { if(on) { } else { ReleaseReset(); } } //Module 7Cb: Preliminary Actions On Entering State state_entry() { llListenRemove(listen_handle); listen_handle = llListen(5, "", llGetOwner(), ""); SAFETYOFF(); standardS = TRUE; } //Module 7Cc: What To Do When The Weapon Is Drawn & Sheathed listen(integer channel, string name, key id, string message) { if(channel == 5) { g_message = llToLower(message); if( g_message == "hdraw" ) { SAFETYOFF(); } if( g_message == "sdraw" ) { SAFETYOFF(); } else if(g_message == "hsheathe") { SAFETYON(); } else if(g_message == "ssheathe") { SAFETYON(); } } } //Module 7Cd: The Control Scheme, Standard Controls control(key owner, integer held, integer change) { if (held & (CONTROL_ML_LBUTTON | CONTROL_LBUTTON)) { if (change & held & CONTROL_UP) { llApplyImpulse(<0,0,3.5>,FALSE); llStartAnimation(pgupanim); strike_type = SPECIALATK; state WeaponStrike; } if (change & held & CONTROL_FWD) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); storedTime = recentTime; FStrike(); state WeaponStrike; } if (change & held & CONTROL_ROT_LEFT) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); storedTime = recentTime; SLeft(); state WeaponStrike; } if (change & held & CONTROL_LEFT) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); storedTime = recentTime; RLeft(); state WeaponStrike; } if (change & held & CONTROL_ROT_RIGHT) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); storedTime = recentTime; SRight(); state WeaponStrike; } if (change & held & CONTROL_RIGHT) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); storedTime = recentTime; RRight(); state WeaponStrike; } if (change & held & CONTROL_BACK) { getSeconds(); recentTime = strTime; compareTimes(storedTime, recentTime); storedTime = recentTime; BStrike(); state WeaponStrike; } } if (~held & change & (CONTROL_ML_LBUTTON | CONTROL_LBUTTON)) { llStopAnimation(pgdwnanim); } if (held & change & CONTROL_DOWN) { llStartAnimation(pgdwnanim); llTriggerSound(swdswing, 1.0); llSetTimerEvent(0.01); strike_type = BLOCK; llMoveToTarget(llGetPos(), 0.25); llSleep(1.0); llStopMoveToTarget(); } if (~held & change & CONTROL_DOWN) { llStopAnimation(pgdwnanim); } } changed(integer change) { if(change & CHANGED_OWNER) // reset the script when a new person owns the weapon { llResetScript(); } } } //Module 7D: What To Do When When The Weapon Controls Are Used state WeaponStrike { //Module 7Da: Setting The Timers state_entry() { if (strike_type == KICK | strike_type == SPECIALATK) { llSetTimerEvent(0.25); } else { llSetTimerEvent(0.75); } //llOwnerSay("Test"); } //Module 7Db: What Happens When The Timers Go Off timer() { if (strike_type == SWORDFWD) { llTriggerSound(swdswing, 1.0); llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5); } if (strike_type == SWORDRGT) { llTriggerSound(swdswing, 1.0); llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO); } if (strike_type == SWORDLFT) { llTriggerSound(swdswing, 1.0); llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO); } if (strike_type == BLOCK) { llSensor("", "", ACTIVE | AGENT, 2.0, PI_BY_TWO); } if (strike_type == KICK) { llTriggerSound(swdswing, 1.0); llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5); } if (strike_type == SPECIALATK) { llTriggerSound(swdswing, 1.0); llSensor("", "", ACTIVE | AGENT, 3.0, PI_BY_TWO*0.5); } llSetTimerEvent(0.0); } //Module 7Dc: Actions to Perform if There's a Valid Target within the Predefined Sensor Range sensor(integer tnum) { vector dir = llDetectedPos(0) - llGetPos(); dir.z = 0.0; dir = llVecNorm(dir); rotation rot = llGetRot(); if (strike_type == SWORDFWD) { llTriggerSound(swdconnectflsh, 1.0); llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE); dir += llRot2Up(rot); dir *= 200.0; } else if (strike_type == SWORDRGT) { llTriggerSound(swdconnectflsh, 1.0); llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE); dir += dir; dir *= 100.0; } else if (strike_type == SWORDLFT) { llTriggerSound(swdconnectflsh, 1.0); llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE); dir -= llRot2Left(rot); dir *= 100.0; } else if (strike_type == KICK) { llTriggerSound(kickconnect, 1.0); dir += dir; dir *= 100.0; } else if (strike_type == BLOCK) { llTriggerSound(blockconnect, 1.0); } else if (strike_type == SPECIALATK) { llTriggerSound(swdconnectflsh, 1.0); llRezObject(bloodsplatter,llDetectedPos(0),<0,0,0>,ZERO_ROTATION,TRUE); } strike_type= 0; if (standardS == TRUE) { state standard; } else if (KeeperS == TRUE) { state Keeper; } } //Module 7Dd: Actions To Take When There Is No Target Within Range no_sensor() { if (standardS == TRUE) { state standard; } else if (KeeperS == TRUE) { state Keeper; } } } Link to comment Share on other sites More sharing options...
Recommended Posts
Please sign in to comment
You will be able to leave a comment after signing in
Sign In Now