SRL Archive - RS3 Outdated / Broken Scripts

Tvs-Farm-Boy


Tv-XxX

2008-02-11 13:08:53


Introduction

Well Someone Had To Do It, and I Decided It Should Be Me :)
Here Is The First Farming Script, At The Moment, It's Not Very Good, But I've Only Spent An Hour On It So Far, But… It Weeds :)

What It Does

Version 0.1 - It Weeds and Adds It To The Compost Bin.
Version 0.11 - Improved Weeding and Composting, Now Has Rake Check and Axe Check. (and Bucket)
Version 0.11 (#16) - Made It Work With Rev 16, (Note: Big Update Coming)

Bugs

Well It's Version 0.1, Lets Just Say There are… LOTS. But I'll Fix Them ASAP.

Instructions

Start At The Farm Patch South-East Of Falidor.
Have A Rake In The Inventory.
Thats It Lol.
I Use Scar 3.14 and SRL Rev #13

Notes

I'll Make It Better ASAP, But Srl (I'm Sad To Say) Isn't My Number One Priority, As I'm Actually A Games Designer (Check Out My Website) So, I Will Get Round To It.

Cazax

2008-02-11 13:13:47

you left a password there! and its a member acc! i changed the password for you. im going to PM you.

cheater95

2008-02-11 15:29:19

You deserve a clap or the first farming script. Btw are you gonna add more things like putting in seeds and stuff? Just wondering. :)

FagetHax0r

2008-02-11 15:33:10

Very Nice


You should update it with Planting seeds and who does everything cure plants ETC.

Tv-XxX

2008-02-12 07:22:52

You deserve a clap or the first farming script. Btw are you gonna add more things like putting in seeds and stuff? Just wondering.


Very Nice
You should update it with Planting seeds and who does everything cure plants ETC.


Thank You For The Clap Lol :) and Yerp I Am Gonna Add Composting The Plots, Seeding, Rake Fixing, Randoms, Cure Plants and Harvesting :) Also As It Takes A While For The Plants To Grow, Or The Compost To Mature I Thought I Might Add A W/C In It Aswell, So You Get Farming Exp and W/C Exp :)

Yours Tv.

skilld u

2008-02-12 07:29:19

looks, pretty good but i have to go to school so i will post with suggestions once i get back :p.

Main

2008-02-12 18:15:45

i got a question, but not about your script, but about the game video on your site..


#1 which programming language(s) did you programed it in?
#2 did you do it alone or with a team?
#3 tutorial to the proggraming language(s)?

Tv-XxX

2008-02-12 18:51:12

Hi, and Firstly Thanks For Viewing My Site :)
I Used DBPro To Code In, Which Basically Is A Pretty Version Of C++ and I Have A Team But I Am The Main Programmer (Check Out The Forum For Other Members) and As For Tutorials On The Website Theres A Link Called TGC Forums, Everything You Need Is On There.

Yours Tv.

FagetHax0r

2008-02-13 04:06:03

If you add that shit with New Update i gonna use it

So then i post proggy'' s :spot: ;)

Tv-XxX

2008-02-14 13:21:19

New Realise In Original Post.

Enjoy

Yours Tv.

ShowerThoughts

2008-02-14 13:27:22

dude add me on msn and ill help you a bit…


here:

 
Rake := DTMFromString('78DA63CC616660D8CCC80002109281212B2D8' +
'94112CAFF0F048CB94035EB61B23080AA873111610E4E35C94035' +
'3B08A84903AAD949404D0150CD2E026A6A806A161250530254B38' +
'2809A2AA09AA5F8D50000217C0F92');

StrikerX

2008-02-15 02:48:17

congratulations on the first farming script i dont have a mems account right now but i will defiantly test

Rencuz

2008-02-15 08:39:13

Wow farming script :D

Tv-XxX

2008-02-15 15:07:54

I Started Re Doing The Whole Script, and Already It's Allot Better, It Now Uses DTM Map Checking, So It Will Deffenatly Weed All The Patches, and Compost All The Patches and SEED all the Patches (Only With Potatoes Atmo) This Is Version 1.2 Lol and Will Be Released Some Time Next Week After The Final Bugs Are Removed.

cheater95

2008-02-17 11:51:11

Yay my farming is almost 20 now with this it may be in the highscores soon.:)

xKYLESTEGALx

2008-02-18 17:49:58

Wow, very nice. You should justy make a straight up garden tender. (Ex. Does weeding, Plant Curing, Plant Picking, Watering, PLANTING.. and anything else im not thinking of.) That would define 1337.

moosildinho

2008-02-19 03:29:59

If you add that shit with New Update i gonna use it

So then i post proggy'' s

elegantly put… haha. hey great idea, great initiative! hope you will get around to adding in the extras. Also, small idea for later on, if you would care to make this a semi-hybrid script, you could make it fletch the logs into shafts/bows (shafts would be easier because there is no dropping involved… but bows would be much better if you can be bothered with adding in dropping.) well, just an idea to think about later on 'down the track'. keep it up and ill be sure to post proggies! cheers, moose.

stnrscott2

2008-02-20 00:38:22

Love the idea x]

I also checked your site out and sent you a private message..

rodnman1234

2008-02-27 15:16:35

Nice job man! I didnt think this was possible, you sure proved me wrong :p

OpenHearts

2008-02-29 07:57:28

arlight script, maybe u should try and improve it, e.g. make it a hybird and put an alcher in there, so u alch/farm

shrubie1

2008-03-05 05:32:45

once you work out all the kinks in this script, it will go down as a pioneer for farming in rs.

i salute you.

thedetro125

2008-03-20 17:43:20

haha i like the original weeder- im a bit late on the posts, but i think its great.

ZaSz

2008-03-20 19:49:44

I think he has quit on the script guys. He was BRAVE to do this. LEGENDARY - kidding

Nava2

2008-03-30 15:12:30

I won't test this because my farming is too high to make this worth it..

Suggestion:

Maybe aways down the road set up a chain farming run? For herbs etc.

Nava2

shrubie1

2008-04-02 06:45:23

w00t for farming!

Pwnt by Pwnt

2008-04-05 04:46:49

just had to change SendText2 to TypeSend (I think…) I can't try cuz no member accs… but it should work… can't guarantee it tho :\ nice first farming script tho, Tv, even though you probably won't read this… (I'm using SCAR 3.15, Rev 14)

program Tvs_Farm_Boy;
{.include SRL/SRL/Misc/Smart.scar}
{.include SRL/SRL.scar}
Var
RakePosX, RakePosY, BuckPosX, BuckPosY, CanCut, LogsChopped : Integer;
TvAxeType,Player_1_Username,Player_1_Password,Player_1_Nickname : String;
Player_2_Username,Player_2_Password,Player_2_Nickname : String;
Player_3_Username,Player_3_Password,Player_3_Nickname : String;
Your_Username,Your_Password,Your_Nickname : String;
Const
SmWorld = 111;
Player_1_UsernameC = 'Tv-XxXs';
Player_1_PasswordC = 'Farming';
Player_1_NicknameC = 'Script';
Player_2_UsernameC = '';
Player_2_PasswordC = '';
Player_2_NicknameC = '';
Player_3_UsernameC = '';
Player_3_PasswordC = '';
Player_3_NicknameC = '';

Procedure TvRandoms;
Begin
FindNormalRandoms;
Wait(10)
FindFight;
Wait(10)
FindDead;
end;

Procedure TvAntiBan;
Begin
case 20 of
0: TypeSend('Grrr At The Weeds');
2: HoverSkill('random',False);
4: begin
MouseSpeed := 17 + Random(10);
Writeln('MouseSpeed changed to: '+IntToStr(MouseSpeed)+'.');
end;
6: Wait(1+Random(100));
8: begin
GameTab(1+Random(6));
Wait(Random(100));
Writeln('Switched to GameTab '+IntToStr(GetCurrentTab)+'.');
Wait(100+Random(6000));
GameTab(4);
FindNormalRandoms;
end;
10: begin
MouseSpeed := 20 + Random(10);
Writeln('MouseSpeed changed to: '+IntToStr(MouseSpeed)+'.');
end;
12: TypeSend('Wooooo Farming Lvl');
14: begin
Mouse(random(MSX2),random(MSY2),0,0, False);
Wait(10+Random(100));
if ChooseOption('xamine') then
begin
Writeln('Examined something...');
end else
begin
Writeln('Faled to Examine an Object.');
end;
end;
end;
End;

Procedure TvLogin(UserName,Password,Nickname: string);
begin
Getapplication.minimize;
ActivateClient;
Begin
NumberOfPlayers(1);
Players[0].Name := UserName;
Players[0].Pass := Password;
Players[0].nick := Nickname;
Players[0].Active := True;
cleardebug;
clearreport;
AddToReport('===========USERS============')
AddToReport('Player One = '+Player_1_Username)
AddToReport('Player Two = '+Player_1_Username)
AddToReport('Player Three = '+Player_1_Username)
AddToReport('============================')
If Not LoggedIn Then Loginplayer;
SetAngle(True);
MakeCompass('n');
GameTab(4)
TvRandoms;
End;
end;

Procedure TvSetup;
begin
Player_1_Username:= Player_1_UsernameC
Player_1_Password:= Player_1_PasswordC
Player_1_Nickname:= Player_1_NicknameC
Player_2_Username:= Player_2_UsernameC
Player_2_Password:= Player_2_PasswordC
Player_2_Nickname:= Player_2_NicknameC
Player_3_Username:= Player_3_UsernameC
Player_3_Password:= Player_3_PasswordC
Player_3_Nickname:= Player_3_NicknameC
If(Player_1_Username = '')Then Begin Writeln('No Username Is Set For Player One'); TerminateScript; End;
If(Player_1_Password = '')Then Begin Writeln('No Password Is Set For Player One'); TerminateScript; End;
If(Player_1_Nickname = '')Then Begin Writeln('No Nickname Is Set For Player One'); TerminateScript; End;
If(Player_2_Username = '')Then Player_2_Username:= Player_1_Username;
If(Player_2_Password = '')Then Player_2_Password:= Player_1_Password;
If(Player_2_Nickname = '')Then Player_2_NickName:= Player_1_Nickname;
If(Player_3_Username = '')Then Player_3_Username:= Player_1_Username;
If(Player_3_Password = '')Then Player_3_Password:= Player_1_Password;
If(Player_3_Nickname = '')Then Player_3_NickName:= Player_1_Nickname;
Case 3 of
1: Your_Username:=Player_1_Username;
2: Your_Username:=Player_2_Username;
3: Your_Username:=Player_3_Username;
end;
Case 3 of
1: Your_Password:=Player_1_Password;
2: Your_Password:=Player_2_Password;
3: Your_Password:=Player_3_Password;
End;
Case 3 of
1: Your_Nickname:=Player_1_Nickname;
2: Your_Nickname:=Player_2_Nickname;
3: Your_Nickname:=Player_3_Nickname;
End;
TvLogin(Your_Username,Your_Password,Your_Nickname);
end;

Procedure CheckFarm;
Var
Tx,Ty,Rake,Bucket : Integer;
Begin
If FindSymbol(Tx,Ty,'farming spot')then
Begin
Writeln('You Are At The Farming Spot')
Mouse(Tx,Ty,4,4,True)
Flag;
End
Else
Begin
If(FindObjCustom(Tx,Ty,['Allotment','ment','otme','Patch','tch'],[746066,812885,2518366,2707802],10))Then
Begin
Writeln('You Are At The Farming Spot')
TvRandoms;
End
Else
Begin
Writeln('You Are Not At The Farming Spot')
TerminateScript;
End;
End;
Rake := DTMFromString('78DA632C666160C867644006E5C5F9601A26C' +
'A980554538CAA06260B579307545346404D11504D390135D54035' +
'2504D480DC9347404D39504D167E3500C05107C5');
If(DTMRotated(Rake,Tx,Ty,545,200,738,465))Then
Begin
Writeln('Found A Rake By DTM')
RakePosX := Tx
RakePosY := Ty
AddToReport('Rake Position = '+IntToStr(RakePosX)+', '+IntToStr(RakePosY))
TvAntiBan;
TvRandoms;
End
Else
Begin
If(FindColorSpiralTolerance(Tx,Ty,7040883,545,200,738,465,3))Then
Begin
MMouse(Tx,Ty,4,4)
Wait(500+random(100))
If(IsUpText('ake'))Then
Begin
Writeln('Found A Rake By Object Search')
RakePosX := Tx
RakePosY := Ty
AddToReport('Rake Position = '+IntToStr(RakePosX)+', '+IntToStr(RakePosY))
TvAntiBan;
TvRandoms;
End
Else
Begin
Writeln('Could Not Find A Rake')
TerminateScript;
End;
End
Else
Begin
Writeln('Could Not Find A Rake')
TerminateScript;
End;
End;
Wait(1000+random(500))
Bucket := DTMFromString('78DA635CC4C2C090CDC8800C7A4B9CC1344C9' +
'4712E504D39AA1A982C5CCD4AA09A12026A6603D5C41350B302A8' +
'2681809A19986E465703001AC107B7');
If(DTMRotated(Bucket,Tx,Ty,545,200,738,465))Then
Begin
Writeln('Found A Bucket By DTM')
BuckPosX := Tx
BuckPosY := Ty
AddToReport('Bucket Position = '+IntToStr(BuckPosX)+', '+IntToStr(BuckPosY))
TvRandoms;
End
Else
Begin
If(FindColorSpiralTolerance(Tx,Ty,7040883,545,200,738,465,3))Then
Begin
MMouse(Tx,Ty,4,4)
Wait(500+random(100))
If(IsUpText('ket'))Then
Begin
Writeln('Found A Bucket By Object Search')
RakePosX := Tx
RakePosY := Ty
AddToReport('Bucket Position = '+IntToStr(RakePosX)+', '+IntToStr(RakePosY))
TvRandoms;
End;
End
Else
Begin
Writeln('Could Not Find A Bucket')
TerminateScript;
End;
End;
End;

Procedure CheckRake;
Var
Tx, Ty, RakeHead : Integer;
Begin
TvAntiBan;
MMouse(RakePosX,RakePosY,4,4)
wait(500+random(100))
If(IsUpText('dle'))then
Begin
writeln('Rake Is Broken')
If(FindObjCustom(Tx,Ty,['ake','Rake'],[7764864,6053987,7896450],10))then
begin
Wait(500+random(100))
Mouse(Tx,Ty,4,4,true)
wait(500+random(100))
RakeHead := DTMFromString('78DA639CCAC4C0B087910119D4941731FC07D' +
'220D1FF40C0381BA8662BAA9A207F1F300D1305AB398CAA263E3A' +
'02554D1F50CD2E54353191A1A86A2600D51C4455D3DDDE88AA661' +
'6A69BD1ED02005486141B');
If(DTMRotated(RakeHead,Tx,Ty,0,0,0,0))Then
Begin
Mouse(Tx,Ty,4,4,True)
wait(100+random(500))
Mouse(RakePosX,RakePosY,4,4,True)
TvRandoms;
Wait(1000+random(1000))
Writeln('Fixed The Rake')
End
Else
Begin
Writeln('Sorry, Something Went Wrong')
TerminateScript;
End;
end
else
begin
Writeln('Im Afraid I Cant Find The Rake Head')
TerminateScript;
end;
End;
End;

Procedure WeedTheFarm;
Var
Tx,Ty,Ti : Integer;
Begin
Ti:=0
Repeat
Wait(1000+random(1000))
Mouse(RakePosx,RakePosY,4,4,True)
Wait(500+random(500))
If(FindObjCustom(Tx,Ty,['ment','otme','Patch','tch'],[2650209,2716772,881504,880476],4))Then
Begin
MMouse(Tx,Ty,4,4)
wait(500+random(100))
If(IsUpText('ment')or IsUpText('tch'))Then
Begin
Mouse(Tx,Ty,2,2,True);
Wait(2000+random(5000));
CheckRake;
TvRandoms;
TvAntiBan;
Wait(10000+random(5000));
End
Else
Begin
Wait(1000+random(1000));
If FindSymbol(Tx,Ty,'farming spot')then
Begin
Mouse(Tx,Ty,10,10,True)
Flag;
Ti:= Ti+1
Writeln('Weed Check = '+IntToStr(Ti))
TvRandoms;
End
Else
Begin
Wait(1000+random(1000))
End;
End;
End
Else
Begin
Wait(100+random(500))
Mouse(RakePosX,RakePosY,4,4,True)
Wait(1000+random(1000));
TvAntiBan;
TvRandoms;
End;
If invfull then Ti:= 10;
Until(Ti>5);
Writeln('Weeded All The Patches')
TvAntiBan;
TvRandoms;
end;

Procedure CompostWeeds;
Var
Tx,Ty,Weed,Tc, CompFullBMP : Integer;
Begin
If FindSymbol(Tx,Ty,'farming spot')then
Begin
Mouse(Tx,Ty,4,4,True)
Flag;
End;
SetAngle(False);
Weed := DTMFromString('78DA636461616098C9C8800CFCA214C1344C9' +
'49107A86605AA1A982C5CCD77660686B904D4FC06AAE927A0860B' +
'68D764026A18806A96E05703006A2B06A7');
Tc:=0;
Repeat
If(DTMRotated(Weed,Tx,Ty,545,200,738,465))Then
Begin
Mouse(Tx,Ty,4,4,True)
Wait(100+random(100))
TvRandoms;
Tc:=1;
End
Else
Begin
If(FindColorSpiralTolerance(Tx,Ty,2053449,545,200,738,465,3))Then
Begin
MMouse(Tx,Ty,4,4)
Wait(500+random(100))
If(IsUpText('eeds'))Then
Begin
Writeln('Found Weeds By Object Search')
TvRandoms;
Mouse(Tx,Ty,4,4,True)
Tc:= 1;
End
Else
Begin
Writeln('Could Not Find Weeds')
TerminateScript;
End;
End;
End;
If(FindObjCustom(Tx,Ty,['Comp','ost','Bin'],[3498352,4022122,5142663],10))Then
Begin
Mouse(Tx,Ty,4,4,False)
Wait(100+random(500))
ChooseOption('in')
Flag;
Wait(500+random(100))
End;
TvAntiBan;
If(FindBlackChatMessage('compost'))Then Tc:= 1;
Until(Tc=1)
CompFullBMP := BitmapFromString(26, 10, 'beNqNktENgCAMRNl/D' +
'n50EoNuoB+OIqbxeTnEQIg5W/o4a8t0lO4+t/knG3tfMgI9XkIh5f' +
'och9xu1xyeW0saSc8ClTqLKl4tFZC4xc4rHGFAi7dCb2lpbRBdmxC' +
'ClHkzsh7r0dQ/9qwDnzSmiDhA+oAfbQKfYDbs9w3Oic5zFbToTV09' +
'98zN');
If(findBitmap(CompFullBMP,Tx,Ty))Then
Begin
Writeln('Compost Is Already Full')
ClickToContinue;
end
else
Begin
Writeln('Compost Filled, Shutting Lid...')
If(FindObjCustom(Tx,Ty,['Comp','ost','Bin'],[3498352,4022122,5142663],10))Then
Begin
Mouse(Tx,Ty,4,4,False)
Wait(100+random(500))
ChooseOption('ose')
Flag;
Wait(500+random(100))
End;
end;
End;

Procedure GetAxeType;
Begin
If(IsUpText('onze'))then TvAxeType:='Bronze';
If(IsUpText('ron'))then TvAxeType:='Iron';
If(IsUpText('eel'))then TvAxeType:='Steel';
If(IsUpText('eral'))then TvAxeType:='Mith';
If(IsUpText('ment'))then TvAxeType:='Addy';
If(IsUpText('une'))then TvAxeType:='Rune';
If(IsUpText('agon'))Then TvAxeType:='Dragon';
If(IsUpText('oken'))Then TvAxeType:='Broken';
End;

Procedure CanCutTrees;
Var
Tx, Ty, EqAxe : Integer;
Begin
Mouse(675,185,4,4,True)
Wait(1000+random(500))
EqAxe := DTMFromString('78DA636C60616058CDC8800C82722AC0344C9' +
'4B10DA86613AA1A982C5C4D2750CD2A026A6A816A5610505349D8' +
'2E003C910744');
If(DTMRotated(EqAxe,Tx,Ty,545,200,738,465))Then
Begin
MMouse(Tx,Ty,4,4)
wait(500+random(100))
GetAxeType;
CanCut:=1;
AddToReport('You Have A '+TvAxeType+' Axe Weilded')
End
Else
Begin
MMouse(586,305,4,4)
Wait(500+random(500))
If(IsUpText('axe'))Then
Begin
GetAxeType;
MMouse(Tx,Ty,4,4)
wait(500+random(100))
CanCut:=1;
AddToReport('You Have A '+TvAxeType+' Axe Weilded')
If(TvAxeType = 'Broken')Then CanCut:=0;
End
Else
Begin
CanCut := 0;
Writeln('No Axe Found')
End;
End;
Mouse(645,185,4,4,True)
Wait(1000+random(1000))
End;

Procedure TvChopTrees;
Var
Tx,Ty : integer;
Begin
Repeat
If(FindObjCustom(Tx,Ty,['ree','Tre','ee'],[1797467,727573,2706759,1530708,4353163,2572371],10))Then
Begin
MMouse(Tx,Ty,4,4)
Wait(100+random(100))
If(IsUpText('ree'))Then
Begin
Mouse(Tx,Ty,4,4,True)
LogsChopped:= LogsChopped + 1
Wait(5000+random(10000))
End;
end
else
Begin
Writeln('Looking For Trees')
End;
Until(InvFull)
End;

Procedure CutWhilstWeWait;
Var
Tx,Ty,Ti : Integer;
Begin
Writeln('Well Lets Cut Some Trees')
SetAngle(True);
Ti:=0
Repeat
If(FindColorSpiralTolerance(Tx,Ty,2053449,545,200,738,465,3))Then
Begin
MMouse(Tx,Ty,4,4)
Wait(100+random(100))
If(IsUpText('eeds'))Then
Begin
Writeln('Found Weeds By Object Search')
TvRandoms;
Mouse(Tx,Ty,4,4,False)
Wait(200+random(300))
Chooseoption('rop')
wait(1000+random(1000))
End
Else
Begin
Writeln('Dropped All Weeds')
Ti:=1
End;
end
else
Begin
Writeln('Dropped All Weeds')
Ti:=1
End;
Until(Ti=1)
Mouse(629,63,10,10,true);
Flag;
TvChopTrees;
End;

begin
SmartSetupEx(SmWorld, false, true);
SetTargetDC(SmartGetDC);
SetupSRL;
TvSetup;
CheckFarm;
CanCutTrees;
Repeat
WeedTheFarm;
CompostWeeds;
If(CanCut=1)Then
Begin
CutWhilstWeWait;
End
Else
Begin
Writeln('Logging Out Whilst Compost Rots')
LogOut;
Wait(300000+random(300000))
TvSetup;
TvLogin(Your_Username,Your_Password,Your_Nickname);
End;
Until(false)
end.

(Btw, I did SCAR tags cuz i think its easier to do that and just cut and paste then it is to download a file.. ;))

T3CH N9NE

2008-04-05 16:21:07

the idea is really great. im curious to see what you can come up with. waiting for more updates! =P

shrubie1

2008-04-12 03:39:57

hmm, progress has been made in this script i see… cant wait till it is l33t. im only 22 farm wit 102 combat lol

Finta1

2008-05-27 18:22:41

From: Cazax
you left a password there! and its a member acc! i changed the password for you. im going to PM you.


Just proves the ammount of trust this guy deserves,
any other noob would be liek ZOMFG i did not know it was christmas.

if only everyone was liek you.

shrubie1

2008-05-28 18:46:47

From: Finta1
Just proves the ammount of trust this guy deserves,
any other noob would be liek ZOMFG i did not know it was christmas.

if only everyone was liek you.


LOL yeh i know. in a mining script i was just looking at some noob stole a LVL 5 WITH ONLY 5 MINING AND NO OTEHR SKILLS ABOVE 1. cause the scripter left its user/pass in it. we were like
ZOMFG

yourock12345

2008-07-26 21:43:06

can som1 update this script plz i dont know if this is gravedigging but i want really high farming lvl so som1 plz update? :)

rs2joke

2008-08-27 07:06:18

hope some one make this updated i hate farming so much…

lazar wolf

2008-12-12 11:39:01

wow this is the only farming script well it works so i give you that and trying something new cant wait for the update post back then

Pwnt by Pwnt

2008-12-18 17:25:47

this is kinda an old thread, I can work on it some if I get Tv's permission.. I'll pm him ;D

TomTuff

2009-04-07 10:47:11

From: Pwnt by Pwnt
this is kinda an old thread, I can work on it some if I get Tv's permission.. I'll pm him ;D


hahaha idk if this is gravedigging when its the only post in a forum, but i doubt TV-XxX stil even knows this is alive

:norris:, out

Sir R. M8gic1an

2009-04-23 08:39:48

closed.

Pm to re-open it if you want.

~RM