-
Mar 03 2012 09:11 PM #1
First Plugin attempt, decided to take errors to wiser heads than my own.
I want to eventually create a basic calculator that does operations like -*/+. Here's what I have so far. I'm trying to assign a chat command:
When I run it though, I get:import "Turbine"
Turbine.Shell.WriteLine("Basic Calculator by Cerridan");
BasicCalc = class( Turbine.ShellCommand );
function BasicCalc:Execute( command, arguments )
if((arguments == nil) or (string.len(arguments) == 0)) then
Turbine.Shell.WriteLine("Inval id Arguments!");
end
--Assigning integers and symbols to separate arrays.
local ints = {};
local index = 1;
local symbols = {};
for word in arguments:gmatch( "%d+" ) do
ints[index] = word;
index = index + 1;
end
index = 1;
for word in arguments:gmatch( "%[/*%-+]" ) do
symbols[index] = word;
index = index + 1;
end
end
Calc = BasicCalc();
Turbine.Shell.AddCommand( "calc", BasicCalc );
This may be the totally wrong way to assign a command but any help on it would be appreciated. I've got some Java experience, if anyone feels like explaining in terms of Java code."...BasicCalculator\Main.lua:3 : attempt to call global 'class' (a nil value)"
Thanks!
Cerridan of Firefoot
-
Mar 03 2012 11:31 PM #2
Re: First Plugin attempt, decided to take errors to wiser heads than my own.
You mean like http://www.lotrointerface.com/downlo...alculator.html?
The "class" definition is not imported with the default Turbine import (or any of the Turbine imports), and it is not a standard feature of lua. If you want to use classes (of course you do), you need to copy the "Class.lua" file from the Turbine Examples folder into your plugin (and you probably want "Type.lua" too) and import them in the right order (Class before Type iirc).
-
Mar 04 2012 12:00 AM #3
Re: First Plugin attempt, decided to take errors to wiser heads than my own.
I think I fixed it. I put in
instead of the class() definition.BasicCalc = Turbine.ShellCommand();
I'm aiming to make a calculator that you can run via a text command that doesn't require UI, ie (works at the time of writing):
/bc 20+3
would print out
20 + 3 = 23
-
Mar 04 2012 01:50 AM #4
Re: First Plugin attempt, decided to take errors to wiser heads than my own.
Replace:
with:Code:Calc = BasicCalc(); Turbine.Shell.AddCommand( "calc", BasicCalc );
You need to pass AddCommand an instance of a command and not the command class itself.Code:Calc = BasicCalc(); Turbine.Shell.AddCommand( "calc", Calc );
This has the potential to get messy - it'll depend on how you approach it. Good luck.
Massive edit: Although this is technically a parsing problem, you don't have to really use the full set of parsing tools to do it. I think.Last edited by moebius92; Mar 04 2012 at 02:02 AM.
-
Mar 04 2012 11:18 AM #5
Re: First Plugin attempt, decided to take errors to wiser heads than my own.
Code:import "Turbine" --[[ Currently supported commands # represents positive numbers # may be substituted for "ans" #[/*-+^]# [/*-+^]# #[/*-+^] --]] --Version tracker versionNum = "1.0.1" --Warnings warn = true; warning = "!!This code does not support negative numbers!!"; --Make this a command to be executed each time command called BasicCalc = Turbine.ShellCommand(); --Create Previous Answer Variable prevValue = 1; --What to do every time user types in chat command function BasicCalc:Execute( command, arguments ) --If user types in base command then print help if((arguments == nil) or (string.len(arguments) < 2)) then Turbine.Shell.WriteLine(self:GetHelp()); return; end --Answer assumption cases - if the first char of the string is an operator --then append previous answer value to the front if(arguments:sub(1,1):match("[%^/*%-+x]")) then arguments = prevValue .. arguments; end --If the last char of the string is an operator then append to back if(arguments:sub(arguments:len(), arguments:len()):match("[%^/*%-+x]")) then arguments = arguments .. prevValue; end --Split by operators arr = self:Split(arguments, "[ +%-*/x%^]"); --Kill invalid cases if(arr[1] == nil or arr[2] == nil) then Turbine.Shell.WriteLine("Arguments Invalid!"); return; end --Get operator find = string.find(arguments, "[/*%-+x%^]"); oper = string.sub(arguments, find, find); --If user entered "ans" for front, back, or both operators then replace with actual value. if(arr[1] == "ans") then arr[1] = prevValue; end if(arr[2] == "ans") then arr[2] = prevValue; end --If multiplication, replace with x to make it look nicer if(oper == "*") then oper = "x"; end --Result Variable out = 0; --Failure variable fail = false; --Operator Cases if(oper == "+") then out = arr[1] + arr[2]; elseif(oper == "-") then out = arr[1] - arr[2]; elseif(oper == "x") then out = arr[1] * arr[2]; elseif(oper == "/") then out = arr[1] / arr[2]; elseif(oper == "^") then out = math.pow(arr[1], arr[2]); else fail = true; Turbine.Shell.WriteLine("Unrecognized Operator!"); end --Write a line out with the equation input and the resultant number. if(fail == false) Turbine.Shell.WriteLine(arr[1] .. " " .. oper .. " " .. arr[2] .. " = " .. out); --Store answer in answer variable if not negative if(out >= 0) prevValue = out; end end end --Get help strings. function BasicCalc:GetHelp() return self:GetShortHelp() .. "\nCerridan's Calculator Plugin"; end function BasicCalc:GetShortHelp() return "/bc | /calc [#|ans] [/*-+] [#|ans]"; end --Split method, not written by me. function BasicCalc:Split(str, delim, maxNb) -- Eliminate bad cases... if string.find(str, delim) == nil then return { str } end if maxNb == nil or maxNb < 1 then maxNb = 0 -- No limit end local result = {} local pat = "(.-)" .. delim .. "()" local nb = 0 local lastPos for part, pos in string.gfind(str, pat) do nb = nb + 1 result[nb] = part lastPos = pos if nb == maxNb then break end end -- Handle the last field if nb ~= maxNb then result[nb + 1] = string.sub(str, lastPos) end return result end --Text written on initialization Turbine.Shell.WriteLine("Basic Calculator " .. versionNum .. " by Cerridan"); if(warn) then Turbine.Shell.WriteLine(warning); end Turbine.Shell.WriteLine("Usage: /bc | /calc [#|ans] [/*-+] [#|ans]"); --Add commands so they can be called from the chatbox Turbine.Shell.AddCommand( "calc", BasicCalc ); Turbine.Shell.AddCommand( "bc", BasicCalc );
That's what I have so far, planning to add square roots, and negative number support...Last edited by Llandor; Mar 04 2012 at 11:25 AM.

-
Mar 04 2012 01:18 PM #6
Re: First Plugin attempt, decided to take errors to wiser heads than my own.
A couple of pointers.
First, you can combine the AddCommand lines so that you assign all aliases for the same command in one line by separating the aliases with a semi-colon:
Turbine.Shell.AddCommand( "calc;bc", BasicCalc );
Second, and really more important, you should remove any alias commands that you add. The most common means is to use an Unload event handler. Failure to remove commands can have undesirable results including crashing the client in certain circumstances. The simplest Unload event handler would be:
plugin.Unload = function()
Turbine.Shell.RemoveCommand( BasicCalc );
end
Third, you can access the version info from the .plugin file instead of using a separate variable by using:
Turbine.Shell.WriteLine( "Basic Calculator " .. plugin:GetVersion() .. " by Cerridan" );
so that you only have to update the version number in the .plugin file (and the .plugincompendium file if you want to be supported by Plugin Compendium).
Note that "plugin" is a special variable created by Turbine which is only valid during the initialization of your plugin - basically the time when your main plugin file is being parsed and executed - once the plugin is loaded, the "plugin" variable will no longer be accessible so don't reference it in event handlers, instead use Plugins["Calc"] (where "Calc" is the actual name of your plugin from the <name> tag of your .plugin file).
As a rule, anything you create, you should destroy before unloading. That includes commands, eventhandlers, etc. That will help minimize the chances of your plugin causing undesirable results.Last edited by Garan; Mar 04 2012 at 01:56 PM.
Gnashtooth - Rank 10 Warg - My breath's worse than my bite - but what d'ya want? I eat Hobbitsess fer cryin' out loud
Garan - Captain of little note - got parked at a Fell Scrying Pool so long it dried up and blew away
and many, many others...
"No, no, the hamsters are for the forums. The servers run on chinchillas!"-Patience 7/20/2007
-
Mar 04 2012 01:47 PM #7
Re: First Plugin attempt, decided to take errors to wiser heads than my own.
Thanks for all the help!
The plugin thus far:
Code:import "Turbine" --[[ Currently supported commands # represents positive numbers # may be substituted for "ans" #[/*-+^]# [/*-+^]# #[/*-+^] # may not be substituted for ans in the below cases: sqrt# sin# cos# tan# --]] --Warnings warn = true; warning = "!!This code does not support negative numbers!!"; --Make this a command to be executed each time command called BasicCalc = Turbine.ShellCommand(); --Create Previous Answer Variable prevValue = 1; --What to do every time user types in chat command function BasicCalc:Execute( command, arguments ) --If user types in base command then print help if((arguments == nil) or (string.len(arguments) < 2)) then Turbine.Shell.WriteLine(self:GetHelp()); return; end --Check for special functions if(arguments:len() >= 5 and arguments:sub(1,4) == "sqrt") then self:PrintResult(arguments:sub(5, arguments:len()), nil, "sqrt", math.sqrt(arguments:sub(5, arguments:len()))); return; elseif(arguments:len() >= 4 and arguments:sub(1, 3) == "sin") then self:PrintResult(arguments:sub(4, arguments:len()), nil, "sin", math.sin(arguments:sub(4, arguments:len()))); return; elseif(arguments:len() >= 4 and arguments:sub(1, 3) == "cos") then self:PrintResult(arguments:sub(4, arguments:len()), nil, "cos", math.cos(arguments:sub(4, arguments:len()))); return; elseif(arguments:len() >= 4 and arguments:sub(1, 3) == "tan") then self:PrintResult(arguments:sub(4, arguments:len()), nil, "tan", math.tan(arguments:sub(4, arguments:len()))); return; end --Answer assumption cases - if the first char of the string is an operator --then append previous answer value to the front if(arguments:sub(1,1):match("[%^/*%-+x]")) then arguments = prevValue .. arguments; end --If the last char of the string is an operator then append to back if(arguments:sub(arguments:len(), arguments:len()):match("[%^/*%-+x]")) then arguments = arguments .. prevValue; end --Split by operators arr = self:Split(arguments, "[ +%-*/x%^]"); --Kill invalid cases if(arr[1] == nil or arr[2] == nil) then Turbine.Shell.WriteLine("Arguments Invalid!"); return; end --Get operator find = string.find(arguments, "[/*%-+x%^]"); oper = string.sub(arguments, find, find); --If user entered "ans" for front, back, or both operators then replace with actual value. if(arr[1] == "ans") then arr[1] = prevValue; end if(arr[2] == "ans") then arr[2] = prevValue; end --If multiplication, replace with x to make it look nicer if(oper == "*") then oper = "x"; end --Result Variable out = 0; --Failure variable fail = false; --Operator Cases if(oper == "+") then out = arr[1] + arr[2]; elseif(oper == "-") then out = arr[1] - arr[2]; elseif(oper == "x") then out = arr[1] * arr[2]; elseif(oper == "/") then out = arr[1] / arr[2]; elseif(oper == "^") then out = math.pow(arr[1], arr[2]); else fail = true; Turbine.Shell.WriteLine("Unrecognized Operator!"); end --Write a line out with the equation input and the resultant number. if(fail == false) then self:PrintResult(arr[1], arr[2], oper, out); end end function BasicCalc:PrintResult(one, two, oper, out) if(oper == "sqrt" or oper == "sin" or oper == "cos" or oper == "tan") then Turbine.Shell.WriteLine(oper .. "(" .. one .. ") = " .. out); else Turbine.Shell.WriteLine(arr[1] .. " " .. oper .. " " .. arr[2] .. " = " .. out); end --Store answer in answer variable if not negative if(out >= 0) then prevValue = out; end end --Get help strings. function BasicCalc:GetHelp() return self:GetShortHelp() .. "\nCerridan's Calculator Plugin"; end function BasicCalc:GetShortHelp() return "/bc | /calc [#|ans] [/*-+] [#|ans]"; end --Split method, not written by me. function BasicCalc:Split(str, delim, maxNb) -- Eliminate bad cases... if string.find(str, delim) == nil then return { str } end if maxNb == nil or maxNb < 1 then maxNb = 0 -- No limit end local result = {} local pat = "(.-)" .. delim .. "()" local nb = 0 local lastPos for part, pos in string.gfind(str, pat) do nb = nb + 1 result[nb] = part lastPos = pos if nb == maxNb then break end end -- Handle the last field if nb ~= maxNb then result[nb + 1] = string.sub(str, lastPos) end return result end --Unload handler plugin.Unload = function() Turbine.Shell.RemoveCommand(BasicCalc); end --Text written on initialization Turbine.Shell.WriteLine("Basic Calculator " .. plugin:GetVersion() .. " by Cerridan"); if(warn) then Turbine.Shell.WriteLine(warning); end Turbine.Shell.WriteLine("Usage: /bc | /calc [#|ans] [/*-+] [#|ans]"); --Add commands so they can be called from the chatbox Turbine.Shell.AddCommand( "calc;bc", BasicCalc );Last edited by Llandor; Mar 04 2012 at 01:53 PM.

-
Mar 04 2012 08:08 PM #8
Re: First Plugin attempt, decided to take errors to wiser heads than my own.
Hmm... had an odd thought and did some poking around. You may want to check out the loadstring function. Apparently, it's Lua's version of eval().
-
- Community Guidelines
- New Posts
- Dev Tracker
- Forum List
- Discussion Forums
- Classes
-
Worlds
- Arkenstone
- Brandywine
- Crickhollow
- Dwarrowdelf
- Eldar
- Elendilmir
- Evernight
- Firefoot
- Gilrain
- Gladden
- Imladris
- Landroval [EN-RE]
- Laurelin [EN-RP]
- Meneldor
- Nimrodel
- Riddermark
- Silverlode
- Snowbourn
- Vilya
- Windfola
- Withywindle
- Anduin [DE]
- Belegaer [DE-RP]
- Gwaihir [DE]
- Maiar [DE]
- Morthond [DE]
- Vanyar [DE]
- Estel [FR-RP]
- Sirannon [FR]
- Bullroarer (Public Test Server)
- Community
- Gameplay
- PvMP






Reply With Quote
