1. #1

    MineSweeper Addon Testers Needed for New Beta Release

    Hey guys, I am a new to addon development and I just released my first addon for WoW which is a minesweeper clone. You can find it on curse by simply searching for MineSweeper.

    It has a lot of cool features like guild and friends list leaderboards and automated messages when you achieve a new high score. I was hoping, if anyone was interested, they could download my addon and give me feedback about it here. Because of the nature of the addon, with the guild and friends list leaderboards, it requires a large test group to weed out all of the bugs and if anyone has any new feature ideas I am all ears.

    Thanks

  2. #2
    Deleted
    http://wow.curse.com/downloads/wow-a...nesweeper.aspx

    out of curiosity: how did you manage to get the look and feel from minesweeper into WoW? and isn't minesweeper copyrighted by Microsoft?

    edit: minesweeper has a cheat code in windows. if you type "xyzzy" and then hit shift + enter at the same time, then hide all windows except for the minesweeper window itself, the upper-left most pixel on your desktop turns black when you mouse over a mine, and white when you can click. have you replicated that functionality?
    Last edited by mmocb0245d6bcb; 2011-03-29 at 06:16 PM.

  3. #3
    I did not implement that functionality because it isn't part of the game, and an appeal of the addon is you are competing with your friends and guild mates and that would all be null and void if you could cheat like that.

  4. #4
    Seems cool, thanks for posting it here.
    Quote Originally Posted by Grokan View Post
    Yelling at the leaky gas tank is much less effective than patching it up.

  5. #5
    Does anyone who tried it have any feedback? Thanks

  6. #6
    when I saw this topic, my first reaction was, "GOTTA DOWNLOAD THIS RIGHT AWAY!!!"
    the last few weeks, I've been kinda addicted to minesweeper, kinda pathetic, but its fun I've been playing it a lot while in queues, to pass the time.. even better if I can do it while in wow..
    going to try it now.. will come back with feedback

    *Edit*:
    tried for a while.. seems nice, easy to use, feels the way the Microsoft one does..
    though, a few suggestions, add a win/loss counter, so that you can see how many times you've won, and make it show how many percent of the games you've won, so that you can keep track of that, as well as your time.. you did add the possibility to left and right click at the same time to remove places with no bombs (or how you'd explain it) but it doesn't work if you just double click...
    and as mentioned below, if you click a bomb but don't release your mouse button you're screwed

    all in all, a nice add-on, which we should've had a long time ago


    *2nd edit*:
    just noticed a bug, I don't want to post it here, because it makes you able to reach a score of 0 seconds, without much trouble.. will send it in a PM instead
    Last edited by daluur; 2011-03-30 at 03:52 PM. Reason: clarification

  7. #7
    I'll try it, looks cool.

    ---edit---

    Ok so i tried it and it works fine but I'd recommend turning the notifications off by default, maybe leave guild chat on but whispering all my friend list was not good.

    And maybe options button but i can live without it.
    Last edited by BooMsx; 2011-03-30 at 03:35 PM.

  8. #8
    Over-all it's well done. Feels like the normal game, and the scoreboard things are pretty cool.

    The one thing I noticed that was frustrating is if you click on a square you didn't mean to, you are unable to release the mouse button without setting off the mine. I sometimes get going pretty fast on it, and in the regular windows version if you hold down the button you can release it if you want without losing the game. I don't know if it's something that can be changed or not, just the main thing that jumped out at me after losing a few games this morning because of it.

    I'll try and get some guildies to try it later today, to check out the scoreboards.

    Nice work overall
    Profanity is the inevitable linguistic crutch of the inarticulate mother%$#@er.
    -
    Jamboro: 110 SPriest, Jamb: 110 Blood DK, Jambori: 110 Prot. Warrior,Jambro: 110 Frost Mage, etc.

  9. #9
    Quote Originally Posted by daluur View Post
    ...you did add the possibility to left and right click at the same time to remove places with no bombs (or how you'd explain it) but it doesn't work if you just double click... and as mentioned below, if you click a bomb but don't release your mouse button you're screwed...
    I was hoping you could explain what you mean by double click. Thanks again though for the excellent feedback.

  10. #10
    Quote Originally Posted by Midwayer View Post
    I was hoping you could explain what you mean by double click. Thanks again though for the excellent feedback.
    when you play minesweeper on windows, and you double click a number, and you have put the same amount of flags next to square as the number says, and you double click it, it removes all the tiles, which is connected to the number, but isn't 'flagged', currently the addon lets you do the exact thing if you left+right click a tile, but not if you double click it... it doesn't bother me, but it might bother others ^^

  11. #11
    Oh ok I get it now. Yea I don't think I can implement that easily given what I have to work with.

  12. #12
    Has anyone had any trouble with the leaderboards? If not I will probably be releasing a stable version tomorrow.

  13. #13
    For those interested, I have uploaded a new, stable release of MineSweeper on all of the addon websites (curse, wowinterface, wowui). It includes less intrusive default settings and a personal leaderboard that keeps track of your high scores in all difficulties and gives enhanced statistics on each personal win (clicks/s and 3bv). Hope you enjoy it.

  14. #14
    Quote Originally Posted by Midwayer View Post
    Hey guys, I am a new to addon development and I just released my first addon for WoW which is a minesweeper clone. You can find it on curse by simply searching for MineSweeper.
    I am simply amazed.
    If this is your first addon, then you sure do have a lot of talent! (O.o)

  15. #15
    Deleted
    All your files are using quite some globals repeatedly. Upvalue those.

    However, I was pretty shocked by your Board.lua file. You're leaking one-letter globals.

    Code:
    main <Board.lua:0,0> (18 instructions, 72 bytes at 005D1550)
    	[11]	SETGLOBAL	3 -6	; createBoard
    function createBoard()	<Board.lua:11,13> (6 instructions, 24 bytes at 0028EEF0)
    function Board:generateBoard(width, maxWidth, height, maxHeight, numberOfMines)	<Board.lua:16,35> (67 instructions, 268 bytes at 005D1760)
    function Board:setBoard(width, height, numberOfMines, firstClickI, firstClickJ)	<Board.lua:56,96> (217 instructions, 868 bytes at 0028EE40)
    	[71]	SETGLOBAL	9 -5	; ratioOfCurrentSquare
    	[86]	SETGLOBAL	14 -11	; j
    	[86]	SETGLOBAL	13 -10	; i
    Make those either local, use the addon parent table (arg2 passed to your addon lua using ...), or make a global MineSweeper table and put them in there. But if any other addon uses a global called "j" or "i", you'll have your entire code crashing down on you.

    Same for your Square.lua, though it's not quite as bad there.
    Code:
    main <Square.lua:0,0> (52 instructions, 208 bytes at 00571550)
    	[13]	SETGLOBAL	4 -9	; createSquare
    	[18]	SETGLOBAL	3 -10	; createDefaultSquare
    	[61]	SETGLOBAL	3 -13	; createEmptySquare
    Those are far too generic names for global functions - especially since I don't see any reason to have them as globals.

    ---------- Post added 2011-04-04 at 04:36 PM ----------

    Full global dumps:

    Board.lua:
    Code:
    main <Board.lua:0,0> (18 instructions, 72 bytes at 001E1550)
    	[11]	SETGLOBAL	3 -6	; createBoard
    function createBoard()	<Board.lua:11,13> (6 instructions, 24 bytes at 004CEEF0)
    	[12]	GETGLOBAL	0 -1	; setmetatable
    function Board:generateBoard(width, maxWidth, height, maxHeight, numberOfMines)	<Board.lua:16,35> (67 instructions, 268 bytes at 001E1760)
    	[22]	GETGLOBAL	11 -5	; createEmptySquare
    	[23]	GETGLOBAL	11 -5	; createEmptySquare
    	[27]	GETGLOBAL	11 -5	; createEmptySquare
    	[28]	GETGLOBAL	12 -5	; createEmptySquare
    	[30]	GETGLOBAL	15 -6	; createDefaultSquare
    function Board:setBoard(width, height, numberOfMines, firstClickI, firstClickJ)	<Board.lua:56,96> (217 instructions, 868 bytes at 004CEE40)
    	[71]	SETGLOBAL	9 -5	; ratioOfCurrentSquare
    	[76]	GETGLOBAL	17 -6	; random
    	[86]	SETGLOBAL	14 -11	; j
    	[86]	SETGLOBAL	13 -10	; i
    	[87]	GETGLOBAL	14 -10	; i
    	[87]	GETGLOBAL	14 -11	; j
    	[87]	GETGLOBAL	15 -10	; i
    	[87]	GETGLOBAL	15 -11	; j
    	[88]	GETGLOBAL	14 -10	; i
    	[88]	GETGLOBAL	14 -11	; j
    	[88]	GETGLOBAL	15 -10	; i
    	[88]	GETGLOBAL	15 -11	; j
    	[89]	GETGLOBAL	14 -10	; i
    	[89]	GETGLOBAL	14 -11	; j
    	[89]	GETGLOBAL	15 -10	; i
    	[89]	GETGLOBAL	15 -11	; j
    	[90]	GETGLOBAL	14 -10	; i
    	[90]	GETGLOBAL	14 -11	; j
    	[90]	GETGLOBAL	15 -10	; i
    	[90]	GETGLOBAL	15 -11	; j
    	[91]	GETGLOBAL	14 -10	; i
    	[91]	GETGLOBAL	14 -11	; j
    	[91]	GETGLOBAL	15 -10	; i
    	[91]	GETGLOBAL	15 -11	; j
    	[92]	GETGLOBAL	14 -10	; i
    	[92]	GETGLOBAL	14 -11	; j
    	[92]	GETGLOBAL	15 -10	; i
    	[92]	GETGLOBAL	15 -11	; j
    	[93]	GETGLOBAL	14 -10	; i
    	[93]	GETGLOBAL	14 -11	; j
    	[93]	GETGLOBAL	15 -10	; i
    	[93]	GETGLOBAL	15 -11	; j
    	[94]	GETGLOBAL	14 -10	; i
    	[94]	GETGLOBAL	14 -11	; j
    	[94]	GETGLOBAL	15 -10	; i
    	[94]	GETGLOBAL	15 -11	; j
    Core.lua:
    Code:
    main <Core.lua:0,0> (269 instructions, 1076 bytes at 00591550)
    	[144]	SETGLOBAL	3 -83	; getMineSweeper
    function MineSweeper:resetBoard()	<Core.lua:161,176> (59 instructions, 236 bytes at 0045ECF8)
    	[167]	GETGLOBAL	3 -12	; string
    	[168]	GETGLOBAL	3 -12	; string
    function MineSweeper:handleNewHighScoreMessage(db, name, score, scoreDate)	<Core.lua:178,191> (38 instructions, 152 bytes at 0059BFA8)
    	[179]	GETGLOBAL	6 -1	; tonumber
    function MineSweeper:handleEvent(this, event, prefix, message, channel, sender)	<Core.lua:208,258> (150 instructions, 600 bytes at 0059FE58)
    	[214]	GETGLOBAL	10 -6	; GetUnitName
    	[230]	GETGLOBAL	7 -17	; IsInInstance
    	[242]	GETGLOBAL	9 -23	; GetNumRaidMembers
    	[242]	GETGLOBAL	9 -26	; GetNumPartyMembers
    function MineSweeper:showGameOnFlight()	<Core.lua:272,276> (8 instructions, 32 bytes at 0046D470)
    	[273]	GETGLOBAL	1 -1	; UnitOnTaxi
    function MineSweeper:OnInitialize()	<Core.lua:490,543> (237 instructions, 948 bytes at 0046EC10)
    	[491]	GETGLOBAL	1 -2	; LibStub
    	[494]	GETGLOBAL	1 -13	; getMineSweeperFrame
    	[509]	GETGLOBAL	1 -36	; CreateFrame
    	[509]	GETGLOBAL	4 -38	; UIParent
    	[520]	GETGLOBAL	6 -55	; GetNumGuildMembers
    	[521]	GETGLOBAL	6 -57	; SendAddonMessage
    	[522]	GETGLOBAL	6 -57	; SendAddonMessage
    	[523]	GETGLOBAL	6 -57	; SendAddonMessage
    	[526]	GETGLOBAL	6 -60	; BNGetNumFriends
    	[528]	GETGLOBAL	12 -61	; BNGetFriendInfo
    	[530]	GETGLOBAL	26 -63	; BNSendWhisper
    	[531]	GETGLOBAL	26 -63	; BNSendWhisper
    	[532]	GETGLOBAL	26 -63	; BNSendWhisper
    	[536]	GETGLOBAL	6 -68	; GetNumFriends
    	[538]	GETGLOBAL	12 -69	; GetFriendInfo
    	[539]	GETGLOBAL	13 -57	; SendAddonMessage
    	[540]	GETGLOBAL	13 -57	; SendAddonMessage
    	[541]	GETGLOBAL	13 -57	; SendAddonMessage
    function MineSweeper:createFrameAndBoard()	<Core.lua:545,550> (31 instructions, 124 bytes at 0046ECC0)
    	[547]	GETGLOBAL	3 -6	; string
    	[548]	GETGLOBAL	1 -11	; createBoard
    function MineSweeper:wonGame()	<Core.lua:566,619> (296 instructions, 1184 bytes at 0046ED70)
    	[569]	GETGLOBAL	1 -4	; ipairs
    	[575]	GETGLOBAL	2 -13	; CalendarGetDate
    	[577]	GETGLOBAL	6 -20	; GetNumGuildMembers
    	[578]	GETGLOBAL	6 -22	; SendChatMessage
    	[578]	GETGLOBAL	10 -27	; GetChannelName
    	[580]	GETGLOBAL	6 -30	; GetNumRaidMembers
    	[581]	GETGLOBAL	6 -22	; SendChatMessage
    	[581]	GETGLOBAL	10 -27	; GetChannelName
    	[582]	GETGLOBAL	6 -34	; GetNumPartyMembers
    	[583]	GETGLOBAL	6 -22	; SendChatMessage
    	[583]	GETGLOBAL	10 -27	; GetChannelName
    	[586]	GETGLOBAL	6 -22	; SendChatMessage
    	[586]	GETGLOBAL	10 -27	; GetChannelName
    	[589]	GETGLOBAL	7 -20	; GetNumGuildMembers
    	[590]	GETGLOBAL	7 -42	; SendAddonMessage
    	[593]	GETGLOBAL	7 -44	; BNGetNumFriends
    	[595]	GETGLOBAL	13 -45	; BNGetFriendInfo
    	[597]	GETGLOBAL	27 -47	; BNSendWhisper
    	[601]	GETGLOBAL	7 -50	; GetNumFriends
    	[603]	GETGLOBAL	13 -42	; SendAddonMessage
    	[603]	GETGLOBAL	17 -52	; GetFriendInfo
    	[605]	GETGLOBAL	13 -22	; SendChatMessage
    	[605]	GETGLOBAL	17 -52	; GetFriendInfo
    	[610]	GETGLOBAL	18 -64	; string
    	[612]	GETGLOBAL	15 -64	; string
    function MineSweeper:lostGame(mine)	<Core.lua:621,639> (85 instructions, 340 bytes at 0046EDC8)
    	[630]	GETGLOBAL	2 -12	; ipairs
    function MineSweeper:incrementTime()	<Core.lua:649,656> (18 instructions, 72 bytes at 0046EED0)
    	[655]	GETGLOBAL	3 -6	; string
    function MineSweeper:incrementNumberOfMinesLeft()	<Core.lua:678,681> (12 instructions, 48 bytes at 0046F0E0)
    	[680]	GETGLOBAL	3 -4	; string
    function MineSweeper:decrementNumberOfMinesLeft()	<Core.lua:683,686> (12 instructions, 48 bytes at 0046F138)
    	[685]	GETGLOBAL	3 -4	; string
    Frame.lua:
    Code:
    main <Frame.lua:0,0> (89 instructions, 356 bytes at 00821550)
    	[21]	SETGLOBAL	2 -25	; getMineSweeperFrame
    function MineSweeperFrame:frameEndMove(move)	<Frame.lua:29,32> (22 instructions, 88 bytes at 008286D0)
    	[31]	SETGLOBAL	6 -3	; _
    	[31]	SETGLOBAL	5 -3	; _
    function MineSweeperFrame:dialogFrameEndMove(move)	<Frame.lua:38,41> (22 instructions, 88 bytes at 00827FF0)
    	[40]	SETGLOBAL	6 -3	; _
    	[40]	SETGLOBAL	5 -3	; _
    function MineSweeperFrame:createDialogFrame()	<Frame.lua:43,452> (1578 instructions, 6312 bytes at 008280F0)
    	[44]	GETGLOBAL	1 -2	; CreateFrame
    	[44]	GETGLOBAL	4 -4	; UIParent
    	[54]	GETGLOBAL	1 -2	; CreateFrame
    	[70]	GETGLOBAL	3 -2	; CreateFrame
    	[94]	GETGLOBAL	7 -2	; CreateFrame
    	[103]	GETGLOBAL	9 -2	; CreateFrame
    	[114]	GETGLOBAL	11 -2	; CreateFrame
    	[125]	GETGLOBAL	13 -2	; CreateFrame
    	[136]	GETGLOBAL	15 -2	; CreateFrame
    	[147]	GETGLOBAL	17 -2	; CreateFrame
    	[158]	GETGLOBAL	19 -2	; CreateFrame
    	[169]	GETGLOBAL	21 -2	; CreateFrame
    	[180]	GETGLOBAL	23 -2	; CreateFrame
    	[195]	GETGLOBAL	26 -2	; CreateFrame
    	[206]	GETGLOBAL	28 -2	; CreateFrame
    	[217]	GETGLOBAL	30 -2	; CreateFrame
    	[228]	GETGLOBAL	32 -2	; CreateFrame
    	[239]	GETGLOBAL	34 -2	; CreateFrame
    	[250]	GETGLOBAL	36 -2	; CreateFrame
    	[265]	GETGLOBAL	39 -2	; CreateFrame
    	[269]	GETGLOBAL	40 -2	; CreateFrame
    	[282]	GETGLOBAL	41 -2	; CreateFrame
    	[294]	GETGLOBAL	42 -2	; CreateFrame
    	[305]	GETGLOBAL	43 -2	; CreateFrame
    	[310]	GETGLOBAL	44 -2	; CreateFrame
    	[315]	GETGLOBAL	45 -2	; CreateFrame
    	[323]	GETGLOBAL	45 -2	; CreateFrame
    	[328]	GETGLOBAL	46 -2	; CreateFrame
    	[341]	GETGLOBAL	47 -2	; CreateFrame
    	[347]	GETGLOBAL	47 -2	; CreateFrame
    	[367]	GETGLOBAL	52 -182	; string
    	[394]	GETGLOBAL	60 -182	; string
    	[395]	GETGLOBAL	60 -182	; string
    	[396]	GETGLOBAL	60 -182	; string
    	[397]	GETGLOBAL	60 -182	; string
    	[398]	GETGLOBAL	60 -182	; string
    	[400]	GETGLOBAL	60 -182	; string
    	[403]	GETGLOBAL	60 -182	; string
    	[404]	GETGLOBAL	60 -182	; string
    	[413]	GETGLOBAL	49 -2	; CreateFrame
    	[419]	GETGLOBAL	50 -2	; CreateFrame
    	[425]	GETGLOBAL	51 -2	; CreateFrame
    	[431]	GETGLOBAL	52 -2	; CreateFrame
    	[437]	GETGLOBAL	53 -218	; PanelTemplates_SetNumTabs
    	[439]	GETGLOBAL	53 -219	; PanelTemplates_SetTab
    	[440]	GETGLOBAL	53 -220	; FauxScrollFrame_Update
    	[442]	GETGLOBAL	53 -219	; PanelTemplates_SetTab
    	[443]	GETGLOBAL	53 -220	; FauxScrollFrame_Update
    	[445]	GETGLOBAL	53 -219	; PanelTemplates_SetTab
    	[446]	GETGLOBAL	53 -220	; FauxScrollFrame_Update
    	[448]	GETGLOBAL	53 -219	; PanelTemplates_SetTab
    function(self, offset)	<Frame.lua:350,350> (8 instructions, 32 bytes at 00461C80)
    	[350]	GETGLOBAL	2 -1	; FauxScrollFrame_OnVerticalScroll
    function MineSweeperFrame:reloadLeaderboard()	<Frame.lua:481,527> (274 instructions, 1096 bytes at 00461F40)
    	[496]	GETGLOBAL	6 -21	; string
    	[503]	GETGLOBAL	3 -27	; FauxScrollFrame_Update
    	[514]	GETGLOBAL	9 -21	; string
    	[515]	GETGLOBAL	9 -21	; string
    	[516]	GETGLOBAL	9 -21	; string
    	[517]	GETGLOBAL	9 -21	; string
    	[518]	GETGLOBAL	9 -21	; string
    	[520]	GETGLOBAL	9 -21	; string
    	[523]	GETGLOBAL	9 -21	; string
    	[524]	GETGLOBAL	9 -21	; string
    function MineSweeperFrame:setTab(id, associatedFrame, hideFrame)	<Frame.lua:555,580> (74 instructions, 296 bytes at 00462048)
    	[556]	GETGLOBAL	4 -1	; PanelTemplates_SetTab
    function MineSweeperFrame:createFrame(width, height)	<Frame.lua:582,695> (430 instructions, 1720 bytes at 004620A0)
    	[583]	GETGLOBAL	3 -2	; CreateFrame
    	[583]	GETGLOBAL	6 -4	; UIParent
    	[595]	GETGLOBAL	3 -2	; CreateFrame
    	[604]	GETGLOBAL	4 -2	; CreateFrame
    	[613]	GETGLOBAL	5 -2	; CreateFrame
    	[615]	GETGLOBAL	6 -47	; UIDropDownMenu_Initialize
    	[616]	GETGLOBAL	6 -48	; UIDropDownMenu_SetWidth
    	[618]	GETGLOBAL	6 -2	; CreateFrame
    	[628]	GETGLOBAL	8 -2	; CreateFrame
    	[652]	GETGLOBAL	12 -2	; CreateFrame
    	[662]	GETGLOBAL	13 -2	; CreateFrame
    	[672]	GETGLOBAL	14 -2	; CreateFrame
    	[678]	GETGLOBAL	15 -2	; CreateFrame
    	[687]	GETGLOBAL	15 -2	; CreateFrame
    function()	<Frame.lua:619,619> (9 instructions, 36 bytes at 00462258)
    	[619]	GETGLOBAL	0 -1	; ToggleDropDownMenu
    function MineSweeperFrame:dropDownMenuOnLoad(self, level)	<Frame.lua:697,717> (33 instructions, 132 bytes at 00462410)
    	[703]	GETGLOBAL	4 -6	; UIDropDownMenu_AddButton
    	[709]	GETGLOBAL	5 -6	; UIDropDownMenu_AddButton
    	[715]	GETGLOBAL	6 -6	; UIDropDownMenu_AddButton
    Square.lua:
    Code:
    main <Square.lua:0,0> (52 instructions, 208 bytes at 008A1550)
    	[13]	SETGLOBAL	4 -9	; createSquare
    	[18]	SETGLOBAL	3 -10	; createDefaultSquare
    	[61]	SETGLOBAL	3 -13	; createEmptySquare
    function createSquare()	<Square.lua:13,15> (6 instructions, 24 bytes at 008A16B0)
    	[14]	GETGLOBAL	0 -1	; setmetatable
    function createDefaultSquare(i, j)	<Square.lua:18,28> (37 instructions, 148 bytes at 0025EE10)
    	[19]	GETGLOBAL	2 -1	; createSquare
    	[20]	GETGLOBAL	3 -3	; CreateFrame
    function createEmptySquare()	<Square.lua:61,65> (5 instructions, 20 bytes at 008ABED0)
    	[62]	GETGLOBAL	0 -1	; createSquare

  16. #16
    Whoa thanks Treeston, I'll get on it.

  17. #17
    Treeston, what exactly are you using to find all the globals?
    I know about FindGlobals, but I didn't really understand as how to use it ..

    Can you maybe explain it to me in a "Finding Globals for Dummies" way please?

  18. #18
    Deleted
    Sure. First, get a Lua interpreter.
    Next, add it to your CMD path. (Windows+pause/break -> advanced system settings -> environment variables -> edit PATH, add ";C:\path\to\lua" at the end, don't forget the semicolon).
    Then, open cmd. Verify that you've correctly added lua to PATH by simply entering "lua", then ctrl+c to get out of it again.

    Next, go to your addon's directory (use cd), then run:
    Code:
    luac -l -p yourfile.lua | lua C:\path\to\globals.lua yourfile.lua
    Done.

  19. #19
    Thanks Treeston, your explanation is so much more easier and straightforward
    I'm also going to need to squash me some globals now

    And sorry for sidetracking the thread; I checked the source code from MineSweeper, and I'm just in awe at Midwayer's skill ...

  20. #20
    Thanks for the compliments Ketho, most of the work is in the ideas and to be fair I do have a degree in computer science so although this is my first addon this isn't my first programming project.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •